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;
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;
* イメージを保存するためのヘルパークラス.<br>
*/
public class ImageSaveHelper {
-
+
/**
* ロガー
*/
return isSupported(f);
}
-
+
protected boolean isSupported(File f) {
// サポートしている拡張子のいずれかにマッチするか?
// (大文字・小文字は区別しない.)
/**
* 現在の選択されたファイル名を取得し、そのファイル名がデフォルトの拡張子で終端していなければ
- * デフォルトの拡張子を設定してファイルチューザに設定し直す.<Br>
+ * デフォルトの拡張子を設定してファイルチューザに設定し直す.<Br>
* @param fileChooser ファイルチューザ
* @return デフォルトの拡張子で終端されたファイル
*/
if (outFile == null) {
return null;
}
-
+
if ( !isSupported(outFile)) {
String extName = "." + getSupprotedExtension()[0];
outFile = new File(outFile.getPath() + extName);
}
return outFile;
}
-
+
/**
* サポートするファイルの拡張子を取得する.<br>
* 最初のものがデフォルトの拡張子として用いられる.<br>
*/
protected abstract String[] getSupprotedExtension();
}
-
+
/**
* PNGファイルフィルタ
*/
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);
+
/**
* イメージビルダファクトリ
*/
* 未使用であれば規定値.<br>
*/
protected OutputOption outputOption;
-
+
/**
* 最後に使用したディレクトリ
*/
protected File lastUseSaveDir;
-
+
/**
* 最後に使用したフィルタ
*/
protected FileFilter lastUseFilter = pngFilter;
-
+
/**
* 最後に使用したディレクトリを設定する
* @param lastUseSaveDir 最後に使用したディレクトリ、設定しない場合はnull
public void setLastUseSaveDir(File lastUseSaveDir) {
this.lastUseSaveDir = lastUseSaveDir;
}
-
+
/**
* 最後に使用したディレクトリを取得する
* @return 最後に使用したディレクトリ、なければnull
public File getLastUsedSaveDir() {
return lastUseSaveDir;
}
-
+
/**
* コンストラクタ
if (selfilter instanceof ImageSaveHelperFilter) {
outFile = ((ImageSaveHelperFilter) selfilter).supplyDefaultExtension(this);
}
-
+
// ファイルが存在すれば上書き確認する.
if (outFile.exists()) {
Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
return;
}
}
-
+
super.approveSelection();
}
};
-
+
// // アクセサリパネルの追加˙
// final OutputOptionPanel accessoryPanel = new OutputOptionPanel(this.outputOption);
// fileChooser.setAccessory(accessoryPanel);
-
+
// ファイルフィルタ設定
fileChooser.setAcceptAllFileFilterUsed(false);
for (FileFilter fileFilter : fileFilters) {
if (ret != JFileChooser.APPROVE_OPTION) {
return null;
}
-
+
// // 出力オプションの保存
// OutputOption outputOption = accessoryPanel.getOutputOption();
// this.outputOption = outputOption;
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();
}
/**
+ * ファイルから拡張子を取得する。
+ * @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>
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 イメージ
savePicture(img, imgBgColor, iw, outstm, warnings);
outstm.flush();
}
-
+
protected void savePicture(BufferedImage img, Color imgBgColor, ImageWriter iw,
Object output, final StringBuilder warnings)
throws IOException {
iw.dispose();
}
}
-
+
/**
* ARGB形式から、アルファチャンネルを削除し、かわりに背景色を設定したBGR形式画像を返します.<br>
* JPEG画像として用いることを想定しています.<br>
}
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();
+ }
+ }
}
/**
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());
}
gbc.gridwidth = 1;
gbc.weightx = 0.;
add(Box.createHorizontalStrut(6), gbc);
-
+
// JPEG
gbc.gridx = 0;
gbc.gridy = 0;
strings.getProperty("outputOption.jpeg.caption"));
lblJpeg.setFont(lblJpeg.getFont().deriveFont(Font.BOLD));
add(lblJpeg, gbc);
-
+
gbc.gridx = 1;
gbc.gridy = 1;
gbc.gridwidth = 1;
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;
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;
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;
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;
gbc.gridwidth = 2;
gbc.weightx = 0.;
add(zoomAlgoCombo, gbc);
-
+
// 画像モード
gbc.gridx = 0;
gbc.gridy = 5;
strings.getProperty("outputOption.picture"));
lblPictureMode.setFont(lblJpeg.getFont().deriveFont(Font.BOLD));
add(lblPictureMode, gbc);
-
+
gbc.gridx = 1;
gbc.gridy = 6;
gbc.gridwidth = 1;
add(new JLabel(
strings.getProperty("outputOption.picture.type"),
JLabel.RIGHT), gbc);
-
+
this.pictureModeCombo = new JComboBox(PictureMode.values());
this.pictureModeCombo.setRenderer(
new LocalizedMessageComboBoxRender(strings));
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;
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));
outputOption.setZoomRenderingType((ZoomRenderingType) zoomAlgoCombo.getSelectedItem());
outputOption.setPictureMode((PictureMode) pictureModeCombo.getSelectedItem());
outputOption.setForceBgColor(checkForceBgColor.isSelected());
-
+
return outputOption;
}
}