OSDN Git Service

zipとpsd形式での保存に対応
[charactermanaj/CharacterManaJ.git] / src / main / java / charactermanaj / graphics / io / ImageSaveHelper.java
index b27d909..200e493 100644 (file)
@@ -11,11 +11,18 @@ import java.awt.Insets;
 import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -38,8 +45,12 @@ import javax.swing.JSpinner;
 import javax.swing.SpinnerNumberModel;
 import javax.swing.filechooser.FileFilter;
 
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipOutputStream;
+
 import charactermanaj.graphics.io.OutputOption.PictureMode;
 import charactermanaj.graphics.io.OutputOption.ZoomRenderingType;
+import charactermanaj.model.Layer;
 import charactermanaj.util.LocalizedMessageComboBoxRender;
 import charactermanaj.util.LocalizedResourcePropertyLoader;
 
@@ -48,7 +59,7 @@ import charactermanaj.util.LocalizedResourcePropertyLoader;
  * イメージを保存するためのヘルパークラス.<br>
  */
 public class ImageSaveHelper {
-       
+
        /**
         * ロガー
         */
@@ -74,7 +85,7 @@ public class ImageSaveHelper {
 
                        return isSupported(f);
                }
-               
+
                protected boolean isSupported(File f) {
                        // サポートしている拡張子のいずれかにマッチするか?
                        // (大文字・小文字は区別しない.)
@@ -89,7 +100,7 @@ public class ImageSaveHelper {
 
                /**
                 * 現在の選択されたファイル名を取得し、そのファイル名がデフォルトの拡張子で終端していなければ
-                * デフォルトの拡張子を設定してファイルチューザに設定し直す.<Br> 
+                * デフォルトの拡張子を設定してファイルチューザに設定し直す.<Br>
                 * @param fileChooser ファイルチューザ
                 * @return デフォルトの拡張子で終端されたファイル
                 */
@@ -98,7 +109,7 @@ public class ImageSaveHelper {
                        if (outFile == null) {
                                return null;
                        }
-                       
+
                        if ( !isSupported(outFile)) {
                                String extName = "." + getSupprotedExtension()[0];
                                outFile = new File(outFile.getPath() + extName);
@@ -106,7 +117,7 @@ public class ImageSaveHelper {
                        }
                        return outFile;
                }
-               
+
                /**
                 * サポートするファイルの拡張子を取得する.<br>
                 * 最初のものがデフォルトの拡張子として用いられる.<br>
@@ -114,7 +125,7 @@ public class ImageSaveHelper {
                 */
                protected abstract String[] getSupprotedExtension();
        }
-       
+
        /**
         * PNGファイルフィルタ
         */
@@ -156,13 +167,41 @@ public class ImageSaveHelper {
                        return new String[] {"bmp"};
                }
        };
-       
+
+       /**
+        * ZIPファイルフィルタ
+        */
+       protected static final FileFilter zipFilter = new ImageSaveHelperFilter() {
+               @Override
+               public String getDescription() {
+                       return "Zip Archive(*.zip)";
+               }
+               @Override
+               protected String[] getSupprotedExtension() {
+                       return new String[] {"zip"};
+               }
+       };
+
+       /**
+        * PSDファイルフィルタ
+        */
+       protected static final FileFilter psdFilter = new ImageSaveHelperFilter() {
+               @Override
+               public String getDescription() {
+                       return "Adobe Photoshop(*.psd)";
+               }
+               @Override
+               protected String[] getSupprotedExtension() {
+                       return new String[] {"psd"};
+               }
+       };
+
        /**
         * このヘルパクラスで定義されているファイルフィルタのリスト
         */
        protected static final List<FileFilter> fileFilters = Arrays.asList(
-                       pngFilter, jpegFilter, bmpFilter);
-       
+                       pngFilter, jpegFilter, bmpFilter, psdFilter, zipFilter);
+
        /**
         * イメージビルダファクトリ
         */
@@ -173,17 +212,17 @@ public class ImageSaveHelper {
         * 未使用であれば規定値.<br>
         */
        protected OutputOption outputOption;
-       
+
        /**
         * 最後に使用したディレクトリ
         */
        protected File lastUseSaveDir;
-       
+
        /**
         * 最後に使用したフィルタ
         */
        protected FileFilter lastUseFilter = pngFilter;
-       
+
        /**
         * 最後に使用したディレクトリを設定する
         * @param lastUseSaveDir 最後に使用したディレクトリ、設定しない場合はnull
@@ -191,7 +230,7 @@ public class ImageSaveHelper {
        public void setLastUseSaveDir(File lastUseSaveDir) {
                this.lastUseSaveDir = lastUseSaveDir;
        }
-       
+
        /**
         * 最後に使用したディレクトリを取得する
         * @return 最後に使用したディレクトリ、なければnull
@@ -199,7 +238,7 @@ public class ImageSaveHelper {
        public File getLastUsedSaveDir() {
                return lastUseSaveDir;
        }
-       
+
 
        /**
         * コンストラクタ
@@ -235,7 +274,7 @@ public class ImageSaveHelper {
                                if (selfilter instanceof ImageSaveHelperFilter) {
                                        outFile = ((ImageSaveHelperFilter) selfilter).supplyDefaultExtension(this);
                                }
-                               
+
                                // ファイルが存在すれば上書き確認する.
                                if (outFile.exists()) {
                                        Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
@@ -249,15 +288,15 @@ public class ImageSaveHelper {
                                                return;
                                        }
                                }
-                               
+
                                super.approveSelection();
                        }
                };
-               
+
 //             // アクセサリパネルの追加˙
 //             final OutputOptionPanel accessoryPanel = new OutputOptionPanel(this.outputOption);
 //             fileChooser.setAccessory(accessoryPanel);
-               
+
                // ファイルフィルタ設定
                fileChooser.setAcceptAllFileFilterUsed(false);
                for (FileFilter fileFilter : fileFilters) {
@@ -277,7 +316,7 @@ public class ImageSaveHelper {
                if (ret != JFileChooser.APPROVE_OPTION) {
                        return null;
                }
-               
+
 //             // 出力オプションの保存
 //             OutputOption outputOption = accessoryPanel.getOutputOption();
 //             this.outputOption = outputOption;
@@ -286,15 +325,15 @@ public class ImageSaveHelper {
                File outFile = fileChooser.getSelectedFile();
                lastUseSaveDir = outFile.getParentFile();
                lastUseFilter = fileChooser.getFileFilter();
-               
+
                // 選択したファイルを返す.
-               return outFile; 
+               return outFile;
        }
-       
+
        public OutputOption getOutputOption() {
                return outputOption.clone();
        }
-       
+
        public void setOutputOption(OutputOption outputOption) {
                if (outputOption == null) {
                        throw new IllegalArgumentException();
@@ -303,6 +342,22 @@ public class ImageSaveHelper {
        }
 
        /**
+        * ファイルから拡張子を取得する。
+        * @param outFile ファイル名
+        * @return 拡張子
+        * @throws IOException 拡張子がない場合
+        */
+       public String getFileExtension(File outFile) throws IOException {
+               // ファイル名から拡張子を取り出します.
+               String fname = outFile.getName();
+               int extpos = fname.lastIndexOf(".");
+               if (extpos < 0) {
+                       throw new IOException("missing file extension.");
+               }
+               return fname.substring(extpos + 1).toLowerCase();
+       }
+
+       /**
         * ファイル名を指定してイメージをファイルに出力します.<br>
         * 出力形式は拡張子より判定します.<br>
         * サポートされていない拡張子の場合はIOException例外が発生します.<br>
@@ -317,27 +372,21 @@ public class ImageSaveHelper {
                if (img == null || outFile == null) {
                        throw new IllegalArgumentException();
                }
-               
-               // ファイル名から拡張子を取り出します.
-               String fname = outFile.getName();
-               int extpos = fname.lastIndexOf(".");
-               if (extpos < 0) {
-                       throw new IOException("missing file extension.");
-               }
-               String ext = fname.substring(extpos + 1).toLowerCase();
+
+               String ext = getFileExtension(outFile);
 
                // 拡張子に対するImageIOのライタを取得します.
                Iterator<ImageWriter> ite = ImageIO.getImageWritersBySuffix(ext);
                if (!ite.hasNext()) {
                        throw new IOException("unsupported file extension: " + ext);
                }
-               
+
                ImageWriter iw = ite.next();
-               
+
                // ライタを使いイメージを書き込みます.
                savePicture(img, imgBgColor, iw, outFile, warnings);
        }
-       
+
        /**
         * イメージをMIMEで指定された形式で出力します.
         * @param img イメージ
@@ -370,7 +419,7 @@ public class ImageSaveHelper {
                savePicture(img, imgBgColor, iw, outstm, warnings);
                outstm.flush();
        }
-       
+
        protected void savePicture(BufferedImage img, Color imgBgColor, ImageWriter iw,
                        Object output, final StringBuilder warnings)
                        throws IOException {
@@ -440,7 +489,7 @@ public class ImageSaveHelper {
                        iw.dispose();
                }
        }
-       
+
        /**
         * ARGB形式から、アルファチャンネルを削除し、かわりに背景色を設定したBGR形式画像を返します.<br>
         * JPEG画像として用いることを想定しています.<br>
@@ -514,6 +563,121 @@ public class ImageSaveHelper {
                }
                return tmpImg;
        }
+
+       public static class LayerImage {
+
+               private String partsName;
+
+               private Layer layer;
+
+               private BufferedImage image;
+
+               public LayerImage(String partsName, Layer layer, BufferedImage image) {
+                       super();
+                       this.partsName = partsName;
+                       this.layer = layer;
+                       this.image = image;
+               }
+
+               public String getPartsName() {
+                       return partsName;
+               }
+
+               public Layer getLayer() {
+                       return layer;
+               }
+
+               public BufferedImage getImage() {
+                       return image;
+               }
+
+               @Override
+               public String toString() {
+                       return "(partsName=" + partsName + ", layer=" + layer + ")";
+               }
+       }
+
+       /**
+        * zipにレイヤーごとの画像とプレビュー画像をまとめて保存する
+        * @param outFile
+        * @param layerImages
+        * @param compositeImg
+        * @throws IOException
+        */
+       public void saveToZip(File outFile, Collection<LayerImage> layerImages, BufferedImage compositeImg)
+                       throws IOException {
+               ZipOutputStream zos = new ZipOutputStream(outFile);
+               try {
+                       if (layerImages != null) {
+                               for (LayerImage layerImage : layerImages) {
+                                       String partsName = layerImage.getPartsName();
+                                       Layer layer = layerImage.getLayer();
+                                       String dir = layer.getDir();
+                                       String fname = dir + "/" + partsName + ".png";
+
+                                       ZipEntry zipEntry = new ZipEntry(fname);
+                                       zos.putNextEntry(zipEntry);
+                                       ImageIO.write(layerImage.getImage(), "png", zos);
+                                       zos.closeEntry();
+                               }
+                       }
+                       if (compositeImg != null) {
+                               ZipEntry zipEntry = new ZipEntry("preview.png");
+                               zos.putNextEntry(zipEntry);
+                               ImageIO.write(compositeImg, "png", zos);
+                               zos.closeEntry();
+                       }
+
+               } finally {
+                       zos.close();
+               }
+       }
+
+       /**
+        * PSD形式で保存する
+        * @param outFile
+        * @param layerImages
+        * @param compositeImg
+        * @throws IOException
+        */
+       public void saveToPSD(File outFile, Collection<LayerImage> layerImages, BufferedImage compositeImg)
+                       throws IOException {
+               List<PSDCreator.LayerData> layerDatas = new ArrayList<PSDCreator.LayerData>();
+               Map<String, Integer> dupchk = new HashMap<String, Integer>();
+               for (LayerImage layerImage : layerImages) {
+                       Layer layer = layerImage.getLayer();
+                       String layerName = layer.getDir();
+                       Integer cnt = dupchk.get(layerName);
+                       if (cnt == null) {
+                               cnt = 1;
+                       } else {
+                               cnt = cnt + 1;
+                               layerName = layerName + "(" + cnt + ")";
+                       }
+                       dupchk.put(layerName, cnt);
+
+                       BufferedImage img = layerImage.getImage();
+                       PSDCreator.LayerData layerData = new PSDCreator.LayerData(layerName, img);
+                       layerDatas.add(layerData);
+               }
+               byte[] psdContents = PSDCreator.createPSD(layerDatas);
+
+               FileOutputStream fos = new FileOutputStream(outFile);
+               try {
+                       FileChannel fc = fos.getChannel();
+                       try {
+                               ByteBuffer buf = ByteBuffer.wrap(psdContents);
+                               while (buf.hasRemaining()) {
+                                       fc.write(buf);
+                               }
+
+                       } finally {
+                               fc.close();
+                       }
+               } finally {
+                       fos.close();
+               }
+       }
 }
 
 /**
@@ -524,18 +688,18 @@ class OutputOptionPanel extends JPanel {
        private static final long serialVersionUID = 1L;
 
        private JSpinner jpegQualitySpinner;
-       
+
        private JCheckBox lblZoom;
-       
+
        private JSpinner zoomSpinner;
-       
+
        private JComboBox zoomAlgoCombo;
-       
+
        private JComboBox pictureModeCombo;
-       
+
        private JCheckBox checkForceBgColor;
 
-       
+
        public OutputOptionPanel() {
                this(new OutputOption());
        }
@@ -566,7 +730,7 @@ class OutputOptionPanel extends JPanel {
                gbc.gridwidth = 1;
                gbc.weightx = 0.;
                add(Box.createHorizontalStrut(6), gbc);
-               
+
                // JPEG
                gbc.gridx = 0;
                gbc.gridy = 0;
@@ -576,7 +740,7 @@ class OutputOptionPanel extends JPanel {
                                strings.getProperty("outputOption.jpeg.caption"));
                lblJpeg.setFont(lblJpeg.getFont().deriveFont(Font.BOLD));
                add(lblJpeg, gbc);
-               
+
                gbc.gridx = 1;
                gbc.gridy = 1;
                gbc.gridwidth = 1;
@@ -584,10 +748,10 @@ class OutputOptionPanel extends JPanel {
                add(new JLabel(
                                strings.getProperty("outputOption.jpeg.quality"),
                                JLabel.RIGHT), gbc);
-               
+
                SpinnerNumberModel spmodel = new SpinnerNumberModel(100, 10, 100, 1);
                this.jpegQualitySpinner = new JSpinner(spmodel);
-               
+
                gbc.gridx = 2;
                gbc.gridy = 1;
                gbc.gridwidth = 1;
@@ -607,7 +771,7 @@ class OutputOptionPanel extends JPanel {
                lblZoom = new JCheckBox(strings.getProperty("outputOption.zoom.caption"));
                lblZoom.setFont(lblJpeg.getFont().deriveFont(Font.BOLD));
                add(lblZoom, gbc);
-               
+
                gbc.gridx = 1;
                gbc.gridy = 3;
                gbc.gridwidth = 1;
@@ -615,15 +779,15 @@ class OutputOptionPanel extends JPanel {
                gbc.insets = new Insets(3, 3, 3, 3);
                add(new JLabel(
                                strings.getProperty("outputOption.zoom.factor"), JLabel.RIGHT), gbc);
-               
+
                SpinnerNumberModel zoomSpModel = new SpinnerNumberModel(100, 20, 800, 1);
                this.zoomSpinner = new JSpinner(zoomSpModel);
-               
+
                gbc.gridx = 2;
                gbc.gridy = 3;
                gbc.gridwidth = 1;
                add(zoomSpinner, gbc);
-               
+
                gbc.gridx = 3;
                gbc.gridy = 3;
                gbc.gridwidth = 1;
@@ -636,7 +800,7 @@ class OutputOptionPanel extends JPanel {
                add(new JLabel(
                                strings.getProperty("outputOption.zoom.renderingMode"),
                                JLabel.RIGHT), gbc);
-               
+
                this.zoomAlgoCombo = new JComboBox(ZoomRenderingType.values());
                this.zoomAlgoCombo.setRenderer(new LocalizedMessageComboBoxRender(strings));
                gbc.gridx = 2;
@@ -644,7 +808,7 @@ class OutputOptionPanel extends JPanel {
                gbc.gridwidth = 2;
                gbc.weightx = 0.;
                add(zoomAlgoCombo, gbc);
-               
+
                // 画像モード
                gbc.gridx = 0;
                gbc.gridy = 5;
@@ -654,7 +818,7 @@ class OutputOptionPanel extends JPanel {
                                strings.getProperty("outputOption.picture"));
                lblPictureMode.setFont(lblJpeg.getFont().deriveFont(Font.BOLD));
                add(lblPictureMode, gbc);
-               
+
                gbc.gridx = 1;
                gbc.gridy = 6;
                gbc.gridwidth = 1;
@@ -662,7 +826,7 @@ class OutputOptionPanel extends JPanel {
                add(new JLabel(
                                strings.getProperty("outputOption.picture.type"),
                                JLabel.RIGHT), gbc);
-               
+
                this.pictureModeCombo = new JComboBox(PictureMode.values());
                this.pictureModeCombo.setRenderer(
                                new LocalizedMessageComboBoxRender(strings));
@@ -670,24 +834,24 @@ class OutputOptionPanel extends JPanel {
                gbc.gridy = 6;
                gbc.gridwidth = 2;
                gbc.weightx = 1.;
-               add(pictureModeCombo, gbc);             
-               
+               add(pictureModeCombo, gbc);
+
                gbc.gridx = 1;
                gbc.gridy = 7;
                gbc.gridwidth = 3;
                gbc.weightx = 0.;
                checkForceBgColor = new JCheckBox(
-                               strings.getProperty("outputOption.picture.forceBgColor"));  
+                               strings.getProperty("outputOption.picture.forceBgColor"));
                add(checkForceBgColor, gbc);
-               
+
                JPanel pnlBgAlpha = new JPanel(new BorderLayout(3, 3));
                pnlBgAlpha.add(new JLabel("背景アルファ"), BorderLayout.WEST);
-               
+
                SpinnerNumberModel bgAlphaModel = new SpinnerNumberModel(255, 0, 255, 1);
                JSpinner bgAlphaSpinner = new JSpinner(bgAlphaModel);
 
                pnlBgAlpha.add(bgAlphaSpinner, BorderLayout.CENTER);
-               
+
                gbc.gridx = 1;
                gbc.gridy = 8;
                gbc.gridwidth = 3;
@@ -701,16 +865,16 @@ class OutputOptionPanel extends JPanel {
                gbc.weightx = 1.;
                gbc.weighty = 1.;
                add(Box.createGlue(), gbc);
-               
+
                // update
                setOutputOption(outputOption);
        }
-       
+
        public void setOutputOption(OutputOption outputOption) {
                if (outputOption == null) {
                        outputOption = new OutputOption();
                }
-               
+
                jpegQualitySpinner.setValue((int) (outputOption.getJpegQuality() * 100));
                lblZoom.setSelected(outputOption.isEnableZoom());
                zoomSpinner.setValue((int) (outputOption.getZoomFactor() * 100));
@@ -728,7 +892,7 @@ class OutputOptionPanel extends JPanel {
                outputOption.setZoomRenderingType((ZoomRenderingType) zoomAlgoCombo.getSelectedItem());
                outputOption.setPictureMode((PictureMode) pictureModeCombo.getSelectedItem());
                outputOption.setForceBgColor(checkForceBgColor.isSelected());
-               
+
                return outputOption;
        }
 }