/*
* Copyright 1999-2101 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.simpleimage.util;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageOutputStream;
import javax.media.jai.PlanarImage;
import org.w3c.dom.Node;
import com.alibaba.simpleimage.ImageFormat;
import com.alibaba.simpleimage.ImageWrapper;
import com.alibaba.simpleimage.SimpleImageException;
import com.alibaba.simpleimage.render.WriteParameter;
import com.sun.image.codec.jpeg.ImageFormatException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
public class ImageWriteHelper {
public static final int DEFAULT_MIN_QUALITY = 50;
public static void write(ImageWrapper imgWrapper, OutputStream os, ImageFormat format, WriteParameter param)
throws SimpleImageException {
if (format == ImageFormat.JPEG) {
writeJPEG(imgWrapper, os, param);
} else if (format == ImageFormat.GIF) {
writeGIF(imgWrapper, os, param.getQuantAlgorithm());
} else if (format == ImageFormat.TIFF || format == ImageFormat.PNG || format == ImageFormat.BMP) {
try {
ImageIO.write(imgWrapper.getAsBufferedImage(), format.getDesc(), os);
} catch (IOException e) {
throw new SimpleImageException(e);
}
} else {
throw new IllegalArgumentException("Unsupported output format, only JPEG, BMP, GIF, PNG and TIFF are ok");
}
}
public static void writeJPEG(ImageWrapper imgWrapper, OutputStream os, WriteParameter inParam)
throws SimpleImageException {
BufferedImage img = imgWrapper.getAsBufferedImage();
int channels = img.getColorModel().getNumComponents();
// Convert RGBA colorspace to RGB
if (channels == 4 && img.getColorModel().getColorSpace().getType() != ColorSpace.TYPE_CMYK) {
img = ImageColorConvertHelper.convertRGBA2RGB(PlanarImage.wrapRenderedImage(img)).getAsBufferedImage();
channels = img.getColorModel().getNumComponents();
}
JPEGEncodeParam encodeParam = JPEGCodec.getDefaultJPEGEncodeParam(img);
if (inParam.isSamplingSet()) {
encodeParam.setHorizontalSubsampling(0, inParam.getHorizontalSubsampling(0));
encodeParam.setVerticalSubsampling(0, inParam.getVerticalSubsampling(0));
if (channels >= 3) {
encodeParam.setHorizontalSubsampling(1, inParam.getHorizontalSubsampling(1));
encodeParam.setVerticalSubsampling(1, inParam.getVerticalSubsampling(1));
encodeParam.setHorizontalSubsampling(2, inParam.getHorizontalSubsampling(2));
encodeParam.setVerticalSubsampling(2, inParam.getVerticalSubsampling(2));
}
if (channels >= 4) {
encodeParam.setHorizontalSubsampling(3, inParam.getHorizontalSubsampling(3));
encodeParam.setVerticalSubsampling(3, inParam.getVerticalSubsampling(3));
}
} else {
encodeParam.setHorizontalSubsampling(0, imgWrapper.getHorizontalSubsampling(0));
encodeParam.setVerticalSubsampling(0, imgWrapper.getVerticalSubsampling(0));
if (channels >= 3) {
encodeParam.setHorizontalSubsampling(1, imgWrapper.getHorizontalSubsampling(1));
encodeParam.setVerticalSubsampling(1, imgWrapper.getVerticalSubsampling(1));
encodeParam.setHorizontalSubsampling(2, imgWrapper.getHorizontalSubsampling(2));
encodeParam.setVerticalSubsampling(2, imgWrapper.getVerticalSubsampling(2));
}
if (channels >= 4) {
encodeParam.setHorizontalSubsampling(3, imgWrapper.getHorizontalSubsampling(3));
encodeParam.setVerticalSubsampling(3, imgWrapper.getVerticalSubsampling(3));
}
}
if (inParam.isQualitySet()) {
encodeParam.setQuality(inParam.getDefaultQuality(), false);
} else {
int q = imgWrapper.getQuality();
if (q < DEFAULT_MIN_QUALITY) {
q = DEFAULT_MIN_QUALITY;
}
encodeParam.setQuality(q / 100.0f, false);
}
try {
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os, encodeParam);
encoder.encode(img);
} catch (IOException e) {
throw new SimpleImageException(e);
} catch (ImageFormatException e) {
throw new SimpleImageException(e);
}
}
public static void writeGIF(ImageWrapper imgWrapper, OutputStream os, WriteParameter.QuantAlgorithm quantAlg)
throws SimpleImageException {
ImageOutputStream imageOut = null;
ImageWriter writer = null;
BufferedImage[] images = imgWrapper.getAsBufferedImages();
Node[] metadatas = imgWrapper.getMetadatas();
if (metadatas == null || imgWrapper.getStreamMetadata() == null) {
try {
imageOut = ImageIO.createImageOutputStream(os);
RenderedImage img = images[0];
if (IndexImageBuilder.needConvertToIndex(images[0])) {
img = IndexImageBuilder.createIndexedImage(images[0], quantAlg);
}
ImageIO.write(img, "GIF", imageOut);
} catch (IOException e) {
throw new SimpleImageException(e);
} finally {
ImageUtils.closeQuietly(imageOut);
}
return;
}
try {
imageOut = ImageIO.createImageOutputStream(os);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("GIF");
while (writers.hasNext()) {
writer = writers.next();
if (writer.canWriteSequence()) {
break;
}
}
if (writer == null || !writer.canWriteSequence()) {
throw new IllegalStateException("No GIF writer matched");
}
writer.setOutput(imageOut);
ImageWriteParam param = writer.getDefaultWriteParam();
IIOMetadata streamMeta = writer.getDefaultStreamMetadata(param);
//merge stream metadata
streamMeta.mergeTree(ImageWrapper.GIF_STREAM_METADATA_NAME, imgWrapper.getStreamMetadata());
writer.prepareWriteSequence(streamMeta);
for (int i = 0; i < images.length; i++) {
ImageTypeSpecifier imageType = new ImageTypeSpecifier(images[i].getColorModel(),
images[i].getSampleModel());
RenderedImage renderedImg = images[i];
if (IndexImageBuilder.needConvertToIndex(renderedImg)) {
NodeUtils.removeChild(metadatas[i], "LocalColorTable");
renderedImg = IndexImageBuilder.createIndexedImage(renderedImg, quantAlg);
}
IIOMetadata meta = writer.getDefaultImageMetadata(imageType, param);
meta.mergeTree(ImageWrapper.GIF_IMAGE_METADATA_NAME, metadatas[i]);
IIOImage img = new IIOImage(renderedImg, null, meta);
writer.writeToSequence(img, param);
}
writer.endWriteSequence();
imageOut.flush();
} catch (IOException e) {
throw new SimpleImageException(e);
} finally {
ImageUtils.closeQuietly(imageOut);
if (writer != null) {
writer.dispose();
}
}
}
}