blob: 6a80ef79101b57f6ee1de71831d8e3532ab774c6 [file] [log] [blame]
/*
* 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.
*/
package org.apache.commons.imaging.formats.png;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.common.BinaryFileParser;
import org.apache.commons.imaging.formats.png.chunks.PngChunkPlte;
import org.apache.commons.imaging.formats.png.scanlinefilters.ScanlineFilter;
import org.apache.commons.imaging.formats.png.scanlinefilters.ScanlineFilterAverage;
import org.apache.commons.imaging.formats.png.scanlinefilters.ScanlineFilterNone;
import org.apache.commons.imaging.formats.png.scanlinefilters.ScanlineFilterPaeth;
import org.apache.commons.imaging.formats.png.scanlinefilters.ScanlineFilterSub;
import org.apache.commons.imaging.formats.png.scanlinefilters.ScanlineFilterUp;
import org.apache.commons.imaging.formats.transparencyfilters.TransparencyFilter;
public abstract class ScanExpediter extends BinaryFileParser
{
protected final int width;
protected final int height;
protected final InputStream is;
protected final BufferedImage bi;
protected final int colorType;
protected final int bitDepth;
protected final int bytesPerPixel;
protected final int bitsPerPixel;
protected final PngChunkPlte pngChunkPLTE;
protected final GammaCorrection gammaCorrection;
protected final TransparencyFilter transparencyFilter;
public ScanExpediter(int width, int height, InputStream is,
BufferedImage bi, int color_type, int bitDepth, int bitsPerPixel,
PngChunkPlte pngChunkPLTE, GammaCorrection gammaCorrection,
TransparencyFilter transparencyFilter)
{
this.width = width;
this.height = height;
this.is = is;
this.bi = bi;
this.colorType = color_type;
this.bitDepth = bitDepth;
this.bytesPerPixel = this.getBitsToBytesRoundingUp(bitsPerPixel);
this.bitsPerPixel = bitsPerPixel;
this.pngChunkPLTE = pngChunkPLTE;
this.gammaCorrection = gammaCorrection;
this.transparencyFilter = transparencyFilter;
}
protected int getBitsToBytesRoundingUp(int bits)
{
int bytes = bits / 8;
if ((bits % 8 > 0))
bytes++;
return bytes;
}
protected final int getPixelARGB(int alpha, int red, int green, int blue)
{
int rgb = ((0xff & alpha) << 24) | ((0xff & red) << 16)
| ((0xff & green) << 8) | ((0xff & blue) << 0);
return rgb;
}
protected final int getPixelRGB(int red, int green, int blue)
{
return getPixelARGB(0xff, red, green, blue);
}
public abstract void drive() throws ImageReadException, IOException;
protected int getRGB(BitParser bitParser, int pixelIndexInScanline)
throws ImageReadException, IOException
{
switch (colorType)
{
case 0: // 1,2,4,8,16 Each pixel is a grayscale sample.
{
int sample = bitParser.getSampleAsByte(pixelIndexInScanline, 0);
if (gammaCorrection != null)
{
sample = gammaCorrection.correctSample(sample);
}
int rgb = getPixelRGB(sample, sample, sample);
if (transparencyFilter != null)
rgb = transparencyFilter.filter(rgb, sample);
return rgb;
}
case 2: // 8,16 Each pixel is an R,G,B triple.
{
int red = bitParser.getSampleAsByte(pixelIndexInScanline, 0);
int green = bitParser.getSampleAsByte(pixelIndexInScanline, 1);
int blue = bitParser.getSampleAsByte(pixelIndexInScanline, 2);
int rgb = getPixelRGB(red, green, blue);
if (transparencyFilter != null)
rgb = transparencyFilter.filter(rgb, -1);
if (gammaCorrection != null)
{
int alpha = (0xff000000 & rgb) >> 24; // make sure to preserve
// transparency
red = gammaCorrection.correctSample(red);
green = gammaCorrection.correctSample(green);
blue = gammaCorrection.correctSample(blue);
rgb = getPixelARGB(alpha, red, green, blue);
}
return rgb;
}
//
case 3: // 1,2,4,8 Each pixel is a palette index;
// a PLTE chunk must appear.
{
int index = bitParser.getSample(pixelIndexInScanline, 0);
int rgb = pngChunkPLTE.getRGB(index);
if (transparencyFilter != null)
rgb = transparencyFilter.filter(rgb, index);
return rgb;
}
case 4: // 8,16 Each pixel is a grayscale sample,
// followed by an alpha sample.
{
int sample = bitParser.getSampleAsByte(pixelIndexInScanline, 0);
int alpha = bitParser.getSampleAsByte(pixelIndexInScanline, 1);
if (gammaCorrection != null)
sample = gammaCorrection.correctSample(sample);
int rgb = getPixelARGB(alpha, sample, sample, sample);
return rgb;
}
case 6: // 8,16 Each pixel is an R,G,B triple,
{
int red = bitParser.getSampleAsByte(pixelIndexInScanline, 0);
int green = bitParser.getSampleAsByte(pixelIndexInScanline, 1);
int blue = bitParser.getSampleAsByte(pixelIndexInScanline, 2);
int alpha = bitParser.getSampleAsByte(pixelIndexInScanline, 3);
if (gammaCorrection != null)
{
red = gammaCorrection.correctSample(red);
green = gammaCorrection.correctSample(green);
blue = gammaCorrection.correctSample(blue);
}
int rgb = getPixelARGB(alpha, red, green, blue);
return rgb;
}
default:
throw new ImageReadException("PNG: unknown color type: "
+ colorType);
}
}
protected ScanlineFilter getScanlineFilter(int filter_type,
int BytesPerPixel) throws ImageReadException
{
ScanlineFilter filter;
switch (filter_type)
{
case 0: // None
filter = new ScanlineFilterNone();
break;
case 1: // Sub
filter = new ScanlineFilterSub(BytesPerPixel);
break;
case 2: // Up
filter = new ScanlineFilterUp(BytesPerPixel);
break;
case 3: // Average
filter = new ScanlineFilterAverage(BytesPerPixel);
break;
case 4: // Paeth
filter = new ScanlineFilterPaeth(BytesPerPixel);
break;
default:
throw new ImageReadException("PNG: unknown filter_type: "
+ filter_type);
}
return filter;
}
protected byte[] unfilterScanline(int filter_type, byte src[], byte prev[],
int BytesPerPixel) throws ImageReadException, IOException
{
ScanlineFilter filter = getScanlineFilter(filter_type, BytesPerPixel);
byte dst[] = new byte[src.length];
filter.unfilter(src, dst, prev);
return dst;
}
protected byte[] getNextScanline(InputStream is, int length, byte prev[],
int BytesPerPixel) throws ImageReadException, IOException
{
int filterType = is.read();
if (filterType < 0)
throw new ImageReadException("PNG: missing filter type");
byte scanline[] = this.readByteArray("scanline", length, is,
"PNG: missing image data");
byte unfiltered[] = unfilterScanline(filterType, scanline, prev,
BytesPerPixel);
return unfiltered;
}
}