/*
* 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.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.ParameterBlock;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.operator.ColorQuantizerDescriptor;
import javax.media.jai.operator.ColorQuantizerType;
import com.alibaba.simpleimage.render.WriteParameter;
/**
* 类PaletteBuilder2.java的实现描述:TODO 类实现描述
*
* @author wendell 2011-8-5 下午02:11:53
*/
public class IndexImageBuilder {
public static RenderedImage createIndexedImage(RenderedImage src, WriteParameter.QuantAlgorithm quantAlgorithm) {
IndexImageBuilder builder = new IndexImageBuilder(src, quantAlgorithm);
return builder.createIndexedImage();
}
public static boolean needConvertToIndex(RenderedImage image) {
SampleModel sampleModel = image.getSampleModel();
ColorModel colorModel = image.getColorModel();
return sampleModel.getNumBands() != 1 || sampleModel.getSampleSize()[0] > 8
|| colorModel.getComponentSize()[0] > 8;
}
protected RenderedImage src;
protected WriteParameter.QuantAlgorithm quantAlgorithm;
protected IndexImageBuilder(RenderedImage src, WriteParameter.QuantAlgorithm quantAlgorithm){
this.src = src;
this.quantAlgorithm = quantAlgorithm;
}
protected RenderedImage createIndexedImage() {
if(quantAlgorithm == WriteParameter.QuantAlgorithm.OctTree) {
return PaletteBuilder.createIndexedImage(src);
}
SampleModel sm = src.getSampleModel();
if(!(sm.getNumBands() != 3 && sm.getDataType() == DataBuffer.TYPE_BYTE)) {
PlanarImage pi = PlanarImage.wrapRenderedImage(src);
ParameterBlock pb = new ParameterBlock();
pb.addSource(pi);
pb.add(getQuantizationAlgorithm(quantAlgorithm));
pi = JAI.create("ColorQuantizer", pb);
return pi;
}
return PaletteBuilder.createIndexedImage(src);
}
private ColorQuantizerType getQuantizationAlgorithm(WriteParameter.QuantAlgorithm quantAlg) {
if (quantAlg == WriteParameter.QuantAlgorithm.OctTree) {
return ColorQuantizerDescriptor.OCTTREE;
} else if (quantAlg == WriteParameter.QuantAlgorithm.NeuQuant) {
return ColorQuantizerDescriptor.NEUQUANT;
} else if (quantAlg == WriteParameter.QuantAlgorithm.MedianCut) {
return ColorQuantizerDescriptor.MEDIANCUT;
} else {
throw new IllegalArgumentException("Unknown quantization algorithm " + quantAlg);
}
}
/**
* 此方法暂时不用,但是不删,做以后参考
* @return
*/
RenderedImage createSimpleIndexImage() {
ColorModel srcCM = src.getColorModel();
if(srcCM instanceof IndexColorModel) {
return src;
}
Raster srcRaster = src.getData();
boolean hasTransparent = srcCM.getTransparency() != Transparency.OPAQUE;
int maxColorCount = 256;
if(hasTransparent) {
maxColorCount = 255;
}
int num = 0;
Set<Integer> colorSet = new HashSet<Integer>();
int[] colorArrays = new int[maxColorCount];
for(int x = 0; x < src.getWidth(); x++) {
for(int y = 0; y < src.getHeight(); y++) {
int rgb = srcCM.getRGB(srcRaster.getDataElements(x, y, null)) & 0xFFFFFF;
if(!colorSet.contains(rgb)) {
if(num == maxColorCount) {
return null;
}
colorArrays[num++] = rgb;
colorSet.add(rgb);
}
}
}
if(num == 0) {
throw new IllegalStateException("This image has no color");
}
int[] colors = null;
if(hasTransparent) {
colors = new int[num + 1];
System.arraycopy(colorArrays, 0, colors, 1, num);
colors[0] = 0;
} else {
colors = new int[num];
System.arraycopy(colorArrays, 0, colors, 0, num);
}
Arrays.sort(colors);
byte[] red = new byte[colors.length];
byte[] green = new byte[colors.length];
byte[] blue = new byte[colors.length];
for(int i = 0; i < colors.length; i++) {
red[i] = (byte)((colors[i] >> 16) & 0xFF);
green[i] = (byte)((colors[i] >> 8) & 0xFF);
blue[i] = (byte)((colors[i]) & 0xFF);
}
IndexColorModel destCM = null;
if(hasTransparent) {
destCM = new IndexColorModel(8, colors.length, red, green, blue, 0);
} else {
destCM = new IndexColorModel(8, colors.length, red, green, blue);
}
BufferedImage image = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, destCM);
WritableRaster raster = image.getRaster();
for (int x = 0; x < src.getWidth(); x++) {
for (int y = 0; y < src.getHeight(); y++) {
int argb = srcCM.getRGB(srcRaster.getDataElements(x, y, null));
if(hasTransparent && ((argb & 0xFF000000) != 0xFF000000)) {
raster.setSample(x, y, 0, 0);
} else {
int index = Arrays.binarySearch(colors, (argb & 0x00FFFFFF));
if(index < 0) {
throw new IllegalStateException("Some colors not indexed");
}
raster.setSample(x, y, 0, index);
}
}
}
return image;
}
}