/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* @author Rustem V. Rafikov
*/
package org.apache.harmony.x.imageio.plugins.jpeg;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.harmony.luni.util.NotImplementedException;
import org.apache.harmony.x.imageio.internal.nls.Messages;
import org.apache.sanselan.ImageFormat;
import org.apache.sanselan.ImageWriteException;
import org.apache.sanselan.Sanselan;
import com.google.code.appengine.awt.color.ColorSpace;
import com.google.code.appengine.awt.image.BufferedImage;
import com.google.code.appengine.awt.image.ColorModel;
import com.google.code.appengine.awt.image.IndexColorModel;
import com.google.code.appengine.awt.image.Raster;
import com.google.code.appengine.awt.image.RenderedImage;
import com.google.code.appengine.awt.image.WritableRaster;
import com.google.code.appengine.imageio.IIOImage;
import com.google.code.appengine.imageio.ImageTypeSpecifier;
import com.google.code.appengine.imageio.ImageWriteParam;
import com.google.code.appengine.imageio.ImageWriter;
import com.google.code.appengine.imageio.metadata.IIOMetadata;
import com.google.code.appengine.imageio.plugins.jpeg.JPEGImageWriteParam;
import com.google.code.appengine.imageio.spi.ImageWriterSpi;
import com.google.code.appengine.imageio.stream.ImageOutputStream;
/**
* @author Rustem V. Rafikov
*/
public class JPEGImageWriter extends ImageWriter {
private Raster sourceRaster;
private WritableRaster scanRaster;
private int srcXOff = 0;
private int srcYOff = 0;
private int srcWidth;
private int srcHeight;
//-- y step for image subsampling
private int deltaY = 1;
//-- x step for image subsampling
private int deltaX = 1;
private ImageOutputStream ios;
public JPEGImageWriter(ImageWriterSpi imageWriterSpi) {
super(imageWriterSpi);
}
@Override
public void write(IIOMetadata iioMetadata, IIOImage iioImage, ImageWriteParam param)
throws IOException {
if (ios == null) {
throw new IllegalArgumentException(Messages.getString("imageio.7F"));
}
RenderedImage img = null;
if (!iioImage.hasRaster()) {
img = iioImage.getRenderedImage();
if (img instanceof BufferedImage) {
sourceRaster = ((BufferedImage) img).getRaster();
} else {
sourceRaster = img.getData();
}
} else {
sourceRaster = iioImage.getRaster();
}
Map params = new HashMap();
try {
Sanselan.writeImage((BufferedImage)img,
(OutputStream)ios,
ImageFormat.IMAGE_FORMAT_JPEG,
params);
} catch (ImageWriteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void dispose() {
super.dispose();
ios = null;
}
public IIOMetadata getDefaultStreamMetadata(ImageWriteParam imageWriteParam) throws NotImplementedException {
// TODO: implement
throw new NotImplementedException();
}
public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) throws NotImplementedException {
// TODO: implement
throw new NotImplementedException();
}
@Override
public IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata, ImageWriteParam imageWriteParam) throws NotImplementedException {
// TODO: implement
throw new NotImplementedException();
}
@Override
public IIOMetadata convertImageMetadata(IIOMetadata iioMetadata, ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) throws NotImplementedException {
// TODO: implement
throw new NotImplementedException();
}
@Override
public void setOutput(Object output) {
super.setOutput(output);
ios = (ImageOutputStream) output;
sourceRaster = null;
scanRaster = null;
srcXOff = 0;
srcYOff = 0;
srcWidth = 0;
srcHeight = 0;
deltaY = 1;
}
/**
* Callback for getting a next scanline
* @param scanline scan line number
*/
@SuppressWarnings("unused")
private void getScanLine(int scanline) {
Raster child = sourceRaster.createChild(srcXOff,
srcYOff + scanline * deltaY, srcWidth, 1, 0, 0, null);
scanRaster.setRect(child);
// broadcast the current percentage of image completion
processImageProgress((float) scanline / (float) srcHeight * 100.0f);
}
/**
* Maps color space types to IJG color spaces
* @param image
* @return
*/
private int getSourceCSType(RenderedImage image) {
int type = JPEGConsts.JCS_UNKNOW;
ColorModel cm = image.getColorModel();
if (null == cm) {
return type;
}
if (cm instanceof IndexColorModel) {
// TODO: implement
throw new UnsupportedOperationException(Messages.getString("imageio.80"));
}
boolean hasAlpha = cm.hasAlpha();
ColorSpace cs = cm.getColorSpace();
switch(cs.getType()) {
case ColorSpace.TYPE_GRAY:
type = JPEGConsts.JCS_GRAYSCALE;
break;
case ColorSpace.TYPE_RGB:
type = hasAlpha ? JPEGConsts.JCS_RGBA : JPEGConsts.JCS_RGB;
break;
case ColorSpace.TYPE_YCbCr:
type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
break;
case ColorSpace.TYPE_3CLR:
type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC;
break;
case ColorSpace.TYPE_CMYK:
type = JPEGConsts.JCS_CMYK;
break;
}
return type;
}
/**
* Returns destination color space.
* (YCbCr[A] for RGB)
*
* @param image
* @return
*/
private int getDestinationCSType(RenderedImage image) {
int type = JPEGConsts.JCS_UNKNOW;
ColorModel cm = image.getColorModel();
if (null != cm) {
boolean hasAlpha = cm.hasAlpha();
ColorSpace cs = cm.getColorSpace();
switch(cs.getType()) {
case ColorSpace.TYPE_GRAY:
type = JPEGConsts.JCS_GRAYSCALE;
break;
case ColorSpace.TYPE_RGB:
type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
break;
case ColorSpace.TYPE_YCbCr:
type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
break;
case ColorSpace.TYPE_3CLR:
type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC;
break;
case ColorSpace.TYPE_CMYK:
type = JPEGConsts.JCS_CMYK;
break;
}
}
return type;
}
public ImageWriteParam getDefaultWriteParam() {
return new JPEGImageWriteParam(getLocale());
}
}