diff options
Diffstat (limited to 'libjava/classpath/gnu/javax/imageio/jpeg')
14 files changed, 3191 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/DCT.java b/libjava/classpath/gnu/javax/imageio/jpeg/DCT.java new file mode 100644 index 000000000..fda52e5f5 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/DCT.java @@ -0,0 +1,347 @@ +/* DCT.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +/** + * Discrete Cosine Transformations. + */ +public class DCT +{ + + /** + * Cosine matrix + */ + public double c[][] = new double[8][8]; + + /** + * Transformed cosine matrix + */ + public double cT[][] = new double[8][8]; + + public DCT() + { + initMatrix(); + } + + /** + * Figure A.3.3 IDCT, Cu Cv on A-5 of the ISO DIS 10918-1. Requirements and + * Guidelines. + * + * @param u + * @return + */ + public static double C(int u) + { + return ((u == 0) ? (double) 1 / (double) Math.sqrt((double) 2) + : (double) 1); + } + + /** + * Initialize matrix values for the fast_idct function + */ + private void initMatrix() + { + for (int j = 0; j < 8; j++) + { + double nn = (double) (8); + c[0][j] = 1.0 / Math.sqrt(nn); + cT[j][0] = c[0][j]; + } + for (int i = 1; i < 8; i++) + { + for (int j = 0; j < 8; j++) + { + double jj = (double) j; + double ii = (double) i; + c[i][j] = + Math.sqrt(2.0 / 8.0) + * Math.cos(((2.0 * jj + 1.0) * ii * Math.PI) / (2.0 * 8.0)); + cT[j][i] = c[i][j]; + } + } + } + + /** + * slow_idct - Figure A.3.3 IDCT (informative) on A-5 of the ISO DIS + * 10918-1. Requirements and Guidelines. This is a slow IDCT, there are + * better algorithms to use, it's fairly expensive with processor speed. + * + * @param matrix + * @return + */ + public static double[][] slow_idct(double[][] matrix) + { + double[][] output = new double[matrix.length][matrix.length]; + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x++) + { + double val = 0; + for (double v = 0; v < 8; v++) + { + double innerloop = 0; + for (double u = 0; u < 8; u++) + innerloop += (DCT.C((int) u) / (double) 2) + * matrix[(int) v][(int) u] + * Math.cos((2 * x + 1) * u * Math.PI / (double) 16) + * Math.cos((2 * y + 1) * v * Math.PI / (double) 16); + val += (DCT.C((int) v) / (double) 2) * innerloop; + } + output[y][x] = (val + 128); + } + } + return (output); + } + + public static float[][] slow_fdct(float[][] value) + { + float[][] buffer = new float[8][8]; + + for (int u = 0; u < 8; u++) + { + for (int v = 0; v < 8; v++) + { + buffer[u][v] = + (float) (1 / 4) * (float) C((int) u) * (float) C((int) v); + float innerval = 0; + for (int x = 0; x < 8; x++) + { + for (int y = 0; y < 8; y++) + { + innerval += value[y][x] + * Math.cos(((2 * x + 1) * u * Math.PI) / 16) + * Math.cos(((2 * y + 1) * v * Math.PI) / 16); + } + } + buffer[u][v] *= innerval; + } + } + return (buffer); + } + + public float[][] fast_fdct(float[][] input) + { + float output[][] = new float[8][8]; + double temp[][] = new double[8][8]; + double temp1; + int i; + int j; + int k; + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp[i][j] = 0.0; + for (k = 0; k < 8; k++) + { + temp[i][j] += (((int) (input[i][k]) - 128) * cT[k][j]); + } + } + } + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp1 = 0.0; + + for (k = 0; k < 8; k++) + { + temp1 += (c[i][k] * temp[k][j]); + } + + output[i][j] = (int) Math.round(temp1) * 8; + } + } + + return output; + } + + /** + * fast_idct - Figure A.3.3 IDCT (informative) on A-5 of the ISO DIS + * 10918-1. Requires and Guidelines. This is a fast IDCT, it much more + * effecient and only inaccurate at about 1/1000th of a percent of values + * analyzed. Cannot be static because initMatrix must run before any + * fast_idct values can be computed. + * + * @param input + * @return + */ + public double[][] fast_idct(double[][] input) + { + double output[][] = new double[8][8]; + double temp[][] = new double[8][8]; + double temp1; + int i, j, k; + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp[i][j] = 0.0; + for (k = 0; k < 8; k++) + { + temp[i][j] += input[i][k] * c[k][j]; + } + } + } + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp1 = 0.0; + for (k = 0; k < 8; k++) + temp1 += cT[i][k] * temp[k][j]; + temp1 += 128.0; + if (temp1 < 0) + output[i][j] = 0; + else if (temp1 > 255) + output[i][j] = 255; + else + output[i][j] = (int) Math.round(temp1); + } + } + return output; + } + + public double[][] idj_fast_fdct(float input[][]) + { + double output[][] = new double[8][8]; + double tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + double tmp10, tmp11, tmp12, tmp13; + double z1, z2, z3, z4, z5, z11, z13; + int i; + int j; + + // Subtracts 128 from the input values + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + output[i][j] = ((double) input[i][j] - (double) 128.0); + // input[i][j] -= 128; + + } + } + + for (i = 0; i < 8; i++) + { + tmp0 = output[i][0] + output[i][7]; + tmp7 = output[i][0] - output[i][7]; + tmp1 = output[i][1] + output[i][6]; + tmp6 = output[i][1] - output[i][6]; + tmp2 = output[i][2] + output[i][5]; + tmp5 = output[i][2] - output[i][5]; + tmp3 = output[i][3] + output[i][4]; + tmp4 = output[i][3] - output[i][4]; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + output[i][0] = tmp10 + tmp11; + output[i][4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * (double) 0.707106781; + output[i][2] = tmp13 + z1; + output[i][6] = tmp13 - z1; + + tmp10 = tmp4 + tmp5; + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + z5 = (tmp10 - tmp12) * (double) 0.382683433; + z2 = ((double) 0.541196100) * tmp10 + z5; + z4 = ((double) 1.306562965) * tmp12 + z5; + z3 = tmp11 * ((double) 0.707106781); + + z11 = tmp7 + z3; + z13 = tmp7 - z3; + + output[i][5] = z13 + z2; + output[i][3] = z13 - z2; + output[i][1] = z11 + z4; + output[i][7] = z11 - z4; + } + + for (i = 0; i < 8; i++) + { + tmp0 = output[0][i] + output[7][i]; + tmp7 = output[0][i] - output[7][i]; + tmp1 = output[1][i] + output[6][i]; + tmp6 = output[1][i] - output[6][i]; + tmp2 = output[2][i] + output[5][i]; + tmp5 = output[2][i] - output[5][i]; + tmp3 = output[3][i] + output[4][i]; + tmp4 = output[3][i] - output[4][i]; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + output[0][i] = tmp10 + tmp11; + output[4][i] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * (double) 0.707106781; + output[2][i] = tmp13 + z1; + output[6][i] = tmp13 - z1; + + tmp10 = tmp4 + tmp5; + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + z5 = (tmp10 - tmp12) * (double) 0.382683433; + z2 = ((double) 0.541196100) * tmp10 + z5; + z4 = ((double) 1.306562965) * tmp12 + z5; + z3 = tmp11 * ((double) 0.707106781); + + z11 = tmp7 + z3; + z13 = tmp7 - z3; + + output[5][i] = z13 + z2; + output[3][i] = z13 - z2; + output[1][i] = z11 + z4; + output[7][i] = z11 - z4; + } + + return output; + } + +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java b/libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java new file mode 100644 index 000000000..78f3c1c4f --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java @@ -0,0 +1,207 @@ +/* HuffmanTable.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + + +/** + * This Object construct a JPEGHuffmanTable which can be used to encode/decode + * a scan from a JPEG codec stream. The table must be initalized with either a + * BITS byte amount and a Huffman Table Value for decoding or a Huffman Size + * and Huffman Code table for encoding. + */ +public class HuffmanTable +{ + public final static int HUFFMAN_MAX_TABLES = 4; + + private short[] huffcode = new short[256]; + private short[] huffsize = new short[256]; + private short[] EHUFCO; + private short[] EHUFSI; + private short[] valptr = new short[16]; + private short[] mincode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1,-1,-1}; + private short[] maxcode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}; + private short[] huffval; + private short[] bits; + + static byte JPEG_DC_TABLE = 0; + static byte JPEG_AC_TABLE = 1; + + private short lastk = 0; + + public HuffmanTable(JPEGHuffmanTable table) + { + huffcode = table.getValues(); + bits = table.getLengths(); + } + + /** + * Generated from FIGURE C.1 - Generation of table of Huffman code sizes on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateSizeTable() + { + short index=0; + for(short i=0; i < bits.length ; i++) + { + for(short j=0; j < bits[i] ; j++) + { + huffsize[index] = (short) (i+1); + index++; + } + } + lastk = index; + } + + /** + * Generated from FIGURE C.2 - Generation of table of Huffman codes on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateCodeTable() + { + short k=0; + short si = huffsize[0]; + short code = 0; + for(short i=0; i < huffsize.length ; i++) + { + while(huffsize[k]==si) + { + huffcode[k] = code; + code++; + k++; + } + code <<= 1; + si++; + } + } + + /** + * Generated from FIGURE F.15 - Generation of decode table generation on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateDecoderTables() + { + short bitcount = 0; + for(int i=0; i < 16 ; i++) + { + if(bits[i]!=0) + valptr[i] = bitcount; + for(int j=0 ; j < bits[i] ; j++) + { + if(huffcode[j+bitcount] < mincode[i] || mincode[i] == -1) + mincode[i] = huffcode[j+bitcount]; + + if(huffcode[j+bitcount] > maxcode[i]) + maxcode[i] = huffcode[j+bitcount]; + } + if(mincode[i]!=-1) + valptr[i] = (short) (valptr[i] - mincode[i]); + bitcount += bits[i]; + } + } + + /** + * Generated from FIGURE C.3 - Generation of Order Codes and tables EHUFCO + * and EHUFSI from the ISO DIS 10918-1. Requirements and Guidelines + */ + public void orderCodes(boolean isDC) + { + EHUFCO = new short[isDC ? 15 : 255]; + EHUFSI = new short[isDC ? 15 : 255]; + + for (int p=0; p < lastk ; p++) + { + int i = huffval[p]; + if(i < 0 || i > EHUFCO.length || EHUFSI[i]!=0) + System.err.println("Error, bad huffman table."); + EHUFCO[i] = huffcode[p]; + EHUFSI[i] = huffsize[p]; + } + } + + /** + * Generated from FIGURE F.12 - Extending the sign bit of a decoded value in on + * ISO DIS 10918-1. Requirements and Guidelines<p> + * + * @param diff TODO + * @param t TODO + * @return TODO + */ + public static int extend(int diff, int t) + { + int Vt = (int)Math.pow(2,(t-1)); + if(diff<Vt) + { + Vt=(-1 << t)+1; + diff=diff+Vt; + } + return diff; + } + + /** + * Generated from FIGURE F.16 - Procedure for DECODE on + * ISO DIS 10918-1. Requirements and Guidelines<p> + * + * This function takes in a dynamic amount of bits and using the Huffman + * table returns information on how many bits must be read in to a byte in + * order to reconstruct said byte. + * + * @param JPEGStream the bits of the data stream. + */ + public int decode(JPEGImageInputStream JPEGStream) + throws IOException, JPEGException + { + int i=0; + short code = (short) JPEGStream.readBits(1); + while(code > maxcode[i]) + { + i++; + code <<= 1; + code |= JPEGStream.readBits(1); + } + int val = huffval[code+(valptr[i])]; + if(val < 0) + val = 256 + val; + return val; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java new file mode 100644 index 000000000..7be67a02a --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java @@ -0,0 +1,351 @@ +/* JPEGComponent.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.util.ArrayList; +import java.io.IOException; +import java.awt.image.WritableRaster; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + +/** + * This class holds the methods to decode and write a component information to + * a raster. + */ +public class JPEGComponent +{ + public byte factorH, factorV, component_id, quant_id; + public int width = 0, height = 0, maxV = 0, maxH = 0; + public HuffmanTable ACTable; + public HuffmanTable DCTable; + public int[] quantizationTable; + public double previousDC = 0; + ArrayList data = new ArrayList(); + + /** + * Initializes the component + * + * @param id + * @param factorHorizontal + * @param factorVertical + * @param quantizationID + */ + public JPEGComponent(byte id, byte factorHorizontal, byte factorVertical, + byte quantizationID) + { + component_id = id; + factorH = factorHorizontal; + factorV = factorVertical; + quant_id = quantizationID; + } + + /** + * If a restart marker is found with too little of an MCU count (i.e. our + * Restart Interval is 63 and we have 61 we copy the last MCU until it's + * full) + * + * @param index + * @param length + */ + public void padMCU(int index, int length) + { + double[] src = (double[]) data.get(index - 1); + for (int i = 0; i < length; i++) + data.add(index, src); + } + + /** + * Reset the interval by setting the previous DC value + */ + public void resetInterval() + { + previousDC = 0; + } + + /** + * Run the Quantization backward method on all of the block data. + */ + public void quantitizeData() + { + for (int i = 0; i < data.size(); i++) + { + double[] mydata = (double[]) data.get(i); + for (int j = 0; j < mydata.length; j++) + mydata[j] *= quantizationTable[j]; + } + } + + public void setDCTable(JPEGHuffmanTable table) + { + DCTable = new HuffmanTable(table); + } + + public void setACTable(JPEGHuffmanTable table) + { + ACTable = new HuffmanTable(table); + } + + /** + * Run the Inverse DCT method on all of the block data + */ + public void idctData(DCT myDCT) + { + for (int i = 0; i < data.size(); i++) + data.add(i,myDCT.fast_idct(ZigZag.decode8x8_map((double[]) data.remove(i)))); + } + + /** + * This scales up the component size based on the factor size. This + * calculates everyting up automatically so it's simply ran at the end of + * the frame to normalize the size of all of the components. + */ + public void scaleByFactors() + { + int factorUpVertical = maxV / factorV; + int factorUpHorizontal = maxH / factorH; + + if (factorUpVertical > 1) + { + for (int i = 0; i < data.size(); i++) + { + double[][] src = (double[][]) data.remove(i); + double[][] dest = + new double[src.length * factorUpVertical][src[0].length]; + for (int j = 0; j < src.length; j++) + { + for (int u = 0; u < factorUpVertical; u++) + { + dest[j * factorUpVertical + u] = src[j]; + } + } + data.add(i, dest); + } + } + + if (factorUpHorizontal > 1) + { + for (int i = 0; i < data.size(); i++) + { + double[][] src = (double[][]) data.remove(i); + double[][] dest = + new double[src.length][src[0].length * factorUpHorizontal]; + for (int j = 0; j < src.length; j++) + { + for (int u = 0; u < src[0].length; u++) + { + for (int v = 0; v < factorUpHorizontal; v++) + dest[j][u * factorUpHorizontal + v] = src[j][u]; + } + } + data.add(i, dest); + } + } + } + + /** + * This write the block of data to the raster throwing out anything that + * spills over the raster width or height. + * + * @param raster + * @param data + * @param compIndex + * @param x + * @param y + */ + public void writeBlock(WritableRaster raster, double[][] data, + int compIndex, int x, int y) + { + for (int yIndex = 0; yIndex < data.length; yIndex++) + { + for (int xIndex = 0; xIndex < data[yIndex].length; xIndex++) + { + // The if statement is needed because blocks can spill over the + // frame width because they are padded to make sure we keep the + // height of the block the same as the width of the block + if (x + xIndex < raster.getWidth() + && y + yIndex < raster.getHeight()) + raster.setSample(x + xIndex, y + yIndex, compIndex, + data[yIndex][xIndex]); + } + } + } + + /** + * This writes data to a raster block, so really it's reading not writing + * but it writes the data to the raster block by factor size in a zig zag + * fashion. This has the helper function writeBlock which does the actual + * writing. + * + * @param raster + * @param componentIndex + */ + public void writeData(WritableRaster raster, int componentIndex) + { + int x = 0, y = 0, lastblockheight = 0, incrementblock = 0; + + // Keep looping through all of the blocks until there are no more. + while(data.size() > 0) + { + int blockwidth = 0; + int blockheight = 0; + + if (x >= raster.getWidth()) + { + x = 0; + y += incrementblock; + } + + // Loop through the horizontal component blocks of the MCU first + // then for each horizontal line write out all of the vertical + // components + for (int factorVIndex = 0; factorVIndex < factorV; factorVIndex++) + { + blockwidth = 0; + + for (int factorHIndex = 0; factorHIndex < factorH; factorHIndex++) + { + // Captures the width of this block so we can increment the + // X coordinate + double[][] blockdata = (double[][]) data.remove(0); + + // Writes the data at the specific X and Y coordinate of + // this component + writeBlock(raster, blockdata, componentIndex, x, y); + blockwidth += blockdata[0].length; + x += blockdata[0].length; + blockheight = blockdata.length; + } + y += blockheight; + x -= blockwidth; + lastblockheight += blockheight; + } + y -= lastblockheight; + incrementblock = lastblockheight; + lastblockheight = 0; + x += blockwidth; + } + } + + /** + * Set the quantization table for this component. + * + * @param quanttable + */ + public void setQuantizationTable(int[] quanttable) + { + quantizationTable = quanttable; + } + + /** + * Read in a partial MCU for this component + * + * @param stream TODO + * @throws JPEGException TODO + * @throws IOException TODO + */ + public void readComponentMCU(JPEGImageInputStream stream) + throws JPEGException, IOException + { + for (int i = 0; i < factorH * factorV; i++) + { + double dc = decode_dc_coefficient(stream); + double[] datablock = decode_ac_coefficients(stream); + datablock[0] = dc; + data.add(datablock); + } + } + + /** + * Generated from text on F-22, F.2.2.1 - Huffman decoding of DC + * coefficients on ISO DIS 10918-1. Requirements and Guidelines. + * + * @param JPEGStream TODO + * + * @return TODO + * @throws JPEGException TODO + * @throws IOException TODO + */ + public double decode_dc_coefficient(JPEGImageInputStream JPEGStream) + throws JPEGException, IOException + { + int t = DCTable.decode(JPEGStream); + double diff = JPEGStream.readBits(t); + diff = HuffmanTable.extend((int) diff, t); + diff = (previousDC + diff); + previousDC = diff; + return diff; + } + + /** + * Generated from text on F-23, F.13 - Huffman decoded of AC coefficients + * on ISO DIS 10918-1. Requirements and Guidelines. + * + * @param JPEGStream TODO + * @return TODO + * + * @throws JPEGException TODO + * @throws IOException TODO + */ + public double[] decode_ac_coefficients(JPEGImageInputStream JPEGStream) + throws JPEGException, IOException + { + double[] zz = new double[64]; + + for (int k = 1; k < 64; k++) + { + int s = ACTable.decode(JPEGStream); + int r = s >> 4; + s &= 15; + + if (s != 0) + { + k += r; + r = (int) JPEGStream.readBits(s); + s = HuffmanTable.extend(r, s); + zz[k] = s; + } + else + { + if (r != 15) + return (zz); + k += 15; + } + } + return zz; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java new file mode 100644 index 000000000..11d547f4d --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java @@ -0,0 +1,625 @@ +/* JPEGDecoder.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import java.nio.ByteOrder; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; +import javax.imageio.plugins.jpeg.JPEGQTable; +import javax.imageio.stream.ImageInputStream; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +public class JPEGDecoder +{ + byte majorVersion; + byte minorVersion; + byte units; + short Xdensity; + short Ydensity; + byte Xthumbnail; + byte Ythumbnail; + byte[] thumbnail; + BufferedImage image; + int width; + int height; + + byte marker; + + /** + * This decoder expects JFIF 1.02 encoding. + */ + public static final byte MAJOR_VERSION = (byte) 1; + public static final byte MINOR_VERSION = (byte) 2; + + /** + * The length of the JFIF field not including thumbnail data. + */ + public static final short JFIF_FIXED_LENGTH = 16; + + /** + * The length of the JFIF extension field not including extension + * data. + */ + public static final short JFXX_FIXED_LENGTH = 8; + + private JPEGImageInputStream jpegStream; + + ArrayList jpegFrames = new ArrayList(); + + JPEGHuffmanTable[] dcTables = new JPEGHuffmanTable[4]; + JPEGHuffmanTable[] acTables = new JPEGHuffmanTable[4]; + JPEGQTable[] qTables = new JPEGQTable[4]; + + public int getHeight() + { + return height; + } + + public int getWidth() + { + return width; + } + public JPEGDecoder(ImageInputStream in) + throws IOException, JPEGException + { + jpegStream = new JPEGImageInputStream(in); + jpegStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); + + if (jpegStream.findNextMarker() != JPEGMarker.SOI) + throw new JPEGException("Failed to find SOI marker."); + + if (jpegStream.findNextMarker() != JPEGMarker.APP0) + throw new JPEGException("Failed to find APP0 marker."); + + int length = jpegStream.readShort(); + if (!(length >= JFIF_FIXED_LENGTH)) + throw new JPEGException("Failed to find JFIF field."); + + byte[] identifier = new byte[5]; + jpegStream.read(identifier); + if (identifier[0] != JPEGMarker.JFIF_J + || identifier[1] != JPEGMarker.JFIF_F + || identifier[2] != JPEGMarker.JFIF_I + || identifier[3] != JPEGMarker.JFIF_F + || identifier[4] != JPEGMarker.X00) + throw new JPEGException("Failed to read JFIF identifier."); + + majorVersion = jpegStream.readByte(); + minorVersion = jpegStream.readByte(); + if (majorVersion != MAJOR_VERSION + || (majorVersion == MAJOR_VERSION + && minorVersion < MINOR_VERSION)) + throw new JPEGException("Unsupported JFIF version."); + + units = jpegStream.readByte(); + if (units > (byte) 2) + throw new JPEGException("Units field is out of range."); + + Xdensity = jpegStream.readShort(); + Ydensity = jpegStream.readShort(); + Xthumbnail = jpegStream.readByte(); + Ythumbnail = jpegStream.readByte(); + + // 3 * for RGB data + int thumbnailLength = 3 * Xthumbnail * Ythumbnail; + if (length > JFIF_FIXED_LENGTH + && thumbnailLength != length - JFIF_FIXED_LENGTH) + throw new JPEGException("Invalid length, Xthumbnail" + + " or Ythumbnail field."); + + if (thumbnailLength > 0) + { + thumbnail = new byte[thumbnailLength]; + if (jpegStream.read(thumbnail) != thumbnailLength) + throw new IOException("Failed to read thumbnail."); + } + } + + public void decode() + throws IOException + { + System.out.println ("DECODE!!!"); + // The frames in this jpeg are loaded into a list. There is + // usually just one frame except in heirarchial progression where + // there are multiple frames. + JPEGFrame frame = null; + + // The restart interval defines how many MCU's we should have + // between the 8-modulo restart marker. The restart markers allow + // us to tell whether or not our decoding process is working + // correctly, also if there is corruption in the image we can + // recover with these restart intervals. (See RSTm DRI). + int resetInterval = 0; + + // The JPEGDecoder constructor parses the JFIF field. At this + // point jpegStream points to the first byte after the JFIF field. + + // Find the first marker after the JFIF field. + byte marker = jpegStream.findNextMarker(); + + // Check for a JFIF extension field directly following the JFIF + // header and advance the current marker to the next marker in the + // stream, if necessary. + decodeJFIFExtension(); + + // Loop through until there are no more markers to read in, at + // that point everything is loaded into the jpegFrames array and + // can be processed. + while (true) + { + switch (marker) + { + // APPn Application Reserved Information - Just throw this + // information away because we wont be using it. + case JPEGMarker.APP0: + case JPEGMarker.APP1: + case JPEGMarker.APP2: + case JPEGMarker.APP3: + case JPEGMarker.APP4: + case JPEGMarker.APP5: + case JPEGMarker.APP6: + case JPEGMarker.APP7: + case JPEGMarker.APP8: + case JPEGMarker.APP9: + case JPEGMarker.APP10: + case JPEGMarker.APP11: + case JPEGMarker.APP12: + case JPEGMarker.APP13: + case JPEGMarker.APP14: + case JPEGMarker.APP15: + jpegStream.skipBytes(jpegStream.readShort() - 2); + break; + + case JPEGMarker.SOF0: + // SOFn Start of Frame Marker, Baseline DCT - This is the start + // of the frame header that defines certain variables that will + // be carried out through the rest of the encoding. Multiple + // frames are used in a heirarchiel system, however most JPEG's + // only contain a single frame. + jpegFrames.add(new JPEGFrame()); + frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1); + // Skip the frame length. + jpegStream.readShort(); + // Bits percision, either 8 or 12. + frame.setPrecision(jpegStream.readByte()); + // Scan lines = to the height of the frame. + frame.setScanLines(jpegStream.readShort()); + // Scan samples per line = to the width of the frame. + frame.setSamplesPerLine(jpegStream.readShort()); + // Number of Color Components (or channels). + frame.setComponentCount(jpegStream.readByte()); + + // Set the color mode for this frame, so far only 2 color + // modes are supported. + if (frame.getComponentCount() == 1) + frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY); + else + frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr); + // Add all of the necessary components to the frame. + for (int i = 0; i < frame.getComponentCount(); i++) + frame.addComponent(jpegStream.readByte(), jpegStream.readByte(), + jpegStream.readByte()); + break; + + case JPEGMarker.SOF2: + jpegFrames.add(new JPEGFrame()); + frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1); + // Skip the frame length. + jpegStream.readShort(); + // Bits percision, either 8 or 12. + frame.setPrecision(jpegStream.readByte()); + // Scan lines = to the height of the frame. + frame.setScanLines(jpegStream.readShort()); + // Scan samples per line = to the width of the frame. + frame.setSamplesPerLine(jpegStream.readShort()); + // Number of Color Components (or channels). + frame.setComponentCount(jpegStream.readByte()); + + // Set the color mode for this frame, so far only 2 color + // modes are supported. + if (frame.getComponentCount() == 1) + frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY); + else + frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr); + + // Add all of the necessary components to the frame. + for (int i = 0; i < frame.getComponentCount(); i++) + frame.addComponent(jpegStream.readByte(), jpegStream.readByte(), + jpegStream.readByte()); + break; + + case JPEGMarker.DHT: + // DHT non-SOF Marker - Huffman Table is required for decoding + // the JPEG stream, when we receive a marker we load in first + // the table length (16 bits), the table class (4 bits), table + // identifier (4 bits), then we load in 16 bytes and each byte + // represents the count of bytes to load in for each of the 16 + // bytes. We load this into an array to use later and move on 4 + // huffman tables can only be used in an image. + int huffmanLength = (jpegStream.readShort() - 2); + + // Keep looping until we are out of length. + int index = huffmanLength; + + // Multiple tables may be defined within a DHT marker. This + // will keep reading until there are no tables left, most + // of the time there are just one tables. + while (index > 0) + { + // Read the identifier information and class + // information about the Huffman table, then read the + // 16 byte codelength in and read in the Huffman values + // and put it into table info. + byte huffmanInfo = jpegStream.readByte(); + byte tableClass = (byte) (huffmanInfo >> 4); + byte huffmanIndex = (byte) (huffmanInfo & 0x0f); + short[] codeLength = new short[16]; + jpegStream.readFully(codeLength, 0, codeLength.length); + int huffmanValueLen = 0; + for (int i = 0; i < 16; i++) + huffmanValueLen += codeLength[i]; + index -= (huffmanValueLen + 17); + short[] huffmanVal = new short[huffmanValueLen]; + for (int i = 0; i < huffmanVal.length; i++) + huffmanVal[i] = jpegStream.readByte(); + // Assign DC Huffman Table. + if (tableClass == HuffmanTable.JPEG_DC_TABLE) + dcTables[(int) huffmanIndex] = new JPEGHuffmanTable(codeLength, + huffmanVal); + // Assign AC Huffman Table. + else if (tableClass == HuffmanTable.JPEG_AC_TABLE) + acTables[(int) huffmanIndex] = new JPEGHuffmanTable(codeLength, + huffmanVal); + } + break; + case JPEGMarker.DQT: + // DQT non-SOF Marker - This defines the quantization + // coeffecients, this allows us to figure out the quality of + // compression and unencode the data. The data is loaded and + // then stored in to an array. + short quantizationLength = (short) (jpegStream.readShort() - 2); + for (int j = 0; j < quantizationLength / 65; j++) + { + byte quantSpecs = jpegStream.readByte(); + int[] quantData = new int[64]; + if ((byte) (quantSpecs >> 4) == 0) + // Precision 8 bit. + { + for (int i = 0; i < 64; i++) + quantData[i] = jpegStream.readByte(); + + } + else if ((byte) (quantSpecs >> 4) == 1) + // Precision 16 bit. + { + for (int i = 0; i < 64; i++) + quantData[i] = jpegStream.readShort(); + } + qTables[(int) (quantSpecs & 0x0f)] = new JPEGQTable (quantData); + } + break; + case JPEGMarker.SOS: + // SOS non-SOF Marker - Start Of Scan Marker, this is where the + // actual data is stored in a interlaced or non-interlaced with + // from 1-4 components of color data, if three components most + // likely a YCrCb model, this is a fairly complex process. + + // Read in the scan length. + jpegStream.readShort(); + // Number of components in the scan. + byte numberOfComponents = jpegStream.readByte(); + byte[] componentSelector = new byte[numberOfComponents]; + for (int i = 0; i < numberOfComponents; i++) + { + // Component ID, packed byte containing the Id for the + // AC table and DC table. + byte componentID = jpegStream.readByte(); + byte tableInfo = jpegStream.readByte(); + frame.setHuffmanTables(componentID, + acTables[(byte) (tableInfo >> 4)], + dcTables[(byte) (tableInfo & 0x0f)]); + componentSelector[i] = componentID; + } + byte startSpectralSelection = jpegStream.readByte(); + byte endSpectralSelection = jpegStream.readByte(); + byte successiveApproximation = jpegStream.readByte(); + + int mcuIndex = 0; + int mcuTotalIndex = 0; + // This loops through until a MarkerTagFound exception is + // found, if the marker tag is a RST (Restart Marker) it + // simply skips it and moves on this system does not handle + // corrupt data streams very well, it could be improved by + // handling misplaced restart markers. + while (true) + { + try + { + // Loop though capturing MCU, instruct each + // component to read in its necessary count, for + // scaling factors the components automatically + // read in how much they need + for (int compIndex = 0; compIndex < numberOfComponents; compIndex++) + { + JPEGComponent comp = frame.components.getComponentByID(componentSelector[compIndex]); + comp.readComponentMCU(jpegStream); + } + mcuIndex++; + mcuTotalIndex++; + } + // We've found a marker, see if the marker is a restart + // marker or just the next marker in the stream. If + // it's the next marker in the stream break out of the + // while loop, if it's just a restart marker skip it + catch (JPEGMarkerFoundException bse) + { + // Handle JPEG Restart Markers, this is where the + // count of MCU's per interval is compared with + // the count actually obtained, if it's short then + // pad on some MCU's ONLY for components that are + // greater than one. Also restart the DC prediction + // to zero. + if (marker == JPEGMarker.RST0 + || marker == JPEGMarker.RST1 + || marker == JPEGMarker.RST2 + || marker == JPEGMarker.RST3 + || marker == JPEGMarker.RST4 + || marker == JPEGMarker.RST5 + || marker == JPEGMarker.RST6 + || marker == JPEGMarker.RST7) + { + for (int compIndex = 0; compIndex < numberOfComponents; compIndex++) + { + JPEGComponent comp = frame.components.getComponentByID(componentSelector[compIndex]); + if (compIndex > 1) + comp.padMCU(mcuTotalIndex, resetInterval - mcuIndex); + comp.resetInterval(); + } + mcuTotalIndex += (resetInterval - mcuIndex); + mcuIndex = 0; + } + else + { + // We're at the end of our scan, exit out. + break; + } + } + } + break; + case JPEGMarker.DRI: + // DRI - This defines the restart interval, if we have a + // restart interval when we reach our restart modulo calculate + // whether the count of MCU's specified in the restart + // interval have been reached, if they havent then pad with + // whatever MCU was last used, this is supposed to be a form of + // error recovery but it turns out that some JPEG encoders + // purposely cause missing MCU's on repeating MCU's to compress + // data even more (even though it adds an extra layer of + // complexity.. But since when is JPEG easy? + jpegStream.skipBytes(2); + resetInterval = jpegStream.readShort(); + break; + case JPEGMarker.COM: + // COM - This is a comment that was inserted into the JPEG, we + // simply skip over the comment because it's really of no + // importance, usually contains a verbal description of the + // application or author who created the JPEG. + jpegStream.skipBytes(jpegStream.readShort() - 2); + break; + case JPEGMarker.DNL: + // DNL - This sets the height of the image. This is the Define + // Number Lines for the image, I'm not sure exactly why we need + // this but, whatever we'll abide. + frame.setScanLines(jpegStream.readShort()); + break; + case JPEGMarker.EOI: + // EOI - End of Image, this processes the frames and turns the + // frames into a buffered image. + + if (jpegFrames.size() == 0) + { + return; + } + else if (jpegFrames.size() == 1) + { + // Only one frame, JPEG Non-Heirarchial Frame. + + DCT myDCT = new DCT(); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + frame.width, + frame.height, + frame.getComponentCount(), + new Point(0, 0)); + + // Unencode the data. + for (int i = 0; i < frame.getComponentCount(); i++) + { + JPEGComponent comp = frame.components.get(i); + comp.setQuantizationTable(qTables[comp.quant_id].getTable()); + comp.quantitizeData(); + comp.idctData(myDCT); + } + // Scale the image and write the data to the raster. + for (int i = 0; i < frame.getComponentCount(); i++) + { + JPEGComponent comp = frame.components.get(i); + comp.scaleByFactors(); + comp.writeData(raster, i); + // Ensure garbage collection. + comp = null; + } + // Grayscale Color Image (1 Component). + if (frame.getComponentCount() == 1) + { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + ComponentColorModel ccm = + new ComponentColorModel(cs, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + image = new BufferedImage(ccm, raster, false, + new Hashtable()); + } + // YCbCr Color Image (3 Components). + else if (frame.getComponentCount() == 3) + { + ComponentColorModel ccm = + new ComponentColorModel(new YCbCr_ColorSpace(), false, + false, Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + image = new BufferedImage(ccm, raster, false, + new Hashtable()); + } + // Possibly CMYK or RGBA ? + else + { + throw new JPEGException("Unsupported Color Mode: 4 " + + "Component Color Mode found."); + } + height = frame.height; + width = frame.width; + } + else + { + //JPEG Heirarchial Frame (progressive or baseline). + throw new JPEGException("Unsupported Codec Type:" + + " Hierarchial JPEG"); + } + break; + case JPEGMarker.SOF1: + // ERROR - If we encounter any of the following marker codes + // error out with a codec exception, progressive, heirarchial, + // differential, arithmetic, lossless JPEG's are not supported. + // This is where enhancements can be made for future versions. + // Thankfully 99% of all JPEG's are baseline DCT. + throw new JPEGException("Unsupported Codec Type: Extended " + + "Sequential DCT JPEG's Not-Supported"); + //case JPEGMarker.SOF2: + // throw new JPEGException("Unsupported Codec Type: Progressive DCT JPEG's Not-Supported"); + case JPEGMarker.SOF3: + throw new JPEGException("Unsupported Codec Type:" + + " Lossless (sequential)"); + case JPEGMarker.SOF5: + throw new JPEGException("Unsupported Codec Type:" + + " Differential sequential DCT"); + case JPEGMarker.SOF6: + throw new JPEGException("Unsupported Codec Type:" + + " Differential progressive DCT"); + case JPEGMarker.SOF7: + throw new JPEGException("Unsupported Codec Type:" + + " Differential lossless"); + case JPEGMarker.SOF9: + case JPEGMarker.SOF10: + case JPEGMarker.SOF11: + case JPEGMarker.SOF13: + case JPEGMarker.SOF14: + case JPEGMarker.SOF15: + throw new JPEGException("Unsupported Codec Type:" + + " Arithmetic Coding Frame"); + default: + // Unknown marker found, ignore it. + } + marker = jpegStream.findNextMarker(); + } + } + + // If the current marker is APP0, tries to decode a JFIF extension + // and advances the current marker to the next marker in the stream. + private void decodeJFIFExtension() throws IOException + { + if (marker == JPEGMarker.APP0) + { + int length = jpegStream.readShort(); + + if (length >= JFXX_FIXED_LENGTH) + { + byte[] identifier = new byte[5]; + jpegStream.read(identifier); + if (identifier[0] != JPEGMarker.JFIF_J + || identifier[1] != JPEGMarker.JFIF_F + || identifier[2] != JPEGMarker.JFIF_X + || identifier[3] != JPEGMarker.JFIF_X + || identifier[4] != JPEGMarker.X00) + // Not a JFXX field. Ignore it and continue. + jpegStream.skipBytes(length - 7); + else + { + byte extension_code = jpegStream.readByte(); + + switch (extension_code) + { + case JPEGMarker.JFXX_JPEG: + // FIXME: add support for JFIF Extension: + // Thumbnail coded using JPEG. + jpegStream.skipBytes(length - 8); + case JPEGMarker.JFXX_ONE_BPP: + // FIXME: add support for JFIF Extension: + // Thumbnail stored using 1 byte/pixel. + jpegStream.skipBytes(length - 8); + case JPEGMarker.JFXX_THREE_BPP: + // FIXME: add support for JFIF Extension: + // Thumbnail stored using 3 bytes/pixel. + jpegStream.skipBytes(length - 8); + } + } + } + else + { + // Unknown APP0 marker. Ignore it and continue. + jpegStream.skipBytes(length - 2); + } + marker = jpegStream.findNextMarker(); + } + } + + public BufferedImage getImage() + { + return image; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java new file mode 100644 index 000000000..a2c06e27e --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java @@ -0,0 +1,48 @@ +/* JPEGException.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import javax.imageio.*; + +public class JPEGException extends IIOException +{ + public JPEGException(String message) + { + super(message); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java new file mode 100644 index 000000000..35aed728a --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java @@ -0,0 +1,108 @@ +/* JPEGFrame.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + +public class JPEGFrame +{ + public final static byte JPEG_COLOR_GRAY = 1; + public final static byte JPEG_COLOR_RGB = 2; + public final static byte JPEG_COLOR_YCbCr = 3; + public final static byte JPEG_COLOR_CMYK = 4; + + public byte precision = 8; + public byte colorMode = JPEGFrame.JPEG_COLOR_YCbCr; + public byte componentCount = 0; + + public short width=0, height=0; + + public JPEGScan components; + + public JPEGFrame() + { + components = new JPEGScan(); + } + + public void addComponent(byte componentID, byte sampleFactors, + byte quantizationTableID) + { + byte sampleHorizontalFactor = (byte)(sampleFactors >> 4); + byte sampleVerticalFactor = (byte)(sampleFactors & 0x0f); + components.addComponent(componentID, sampleHorizontalFactor, + sampleVerticalFactor, quantizationTableID); + } + + public void setPrecision(byte data) + { + precision = data; + } + + public void setScanLines(short data) + { + height = data; + } + + public void setSamplesPerLine(short data) + { + width = data; + } + + public void setColorMode(byte data) + { + colorMode = data; + } + + public void setComponentCount(byte data) + { + componentCount = data; + } + + public byte getComponentCount() + { + return componentCount; + } + + public void setHuffmanTables(byte componentID, JPEGHuffmanTable ACTable, + JPEGHuffmanTable DCTable) + { + JPEGComponent comp = components.getComponentByID(componentID); + comp.setACTable(ACTable); + comp.setDCTable(DCTable); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java new file mode 100644 index 000000000..f2c26d9d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java @@ -0,0 +1,188 @@ +/* JPEGImageInputStream.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageInputStreamImpl; + +public class JPEGImageInputStream + extends ImageInputStreamImpl +{ + private ImageInputStream in; + + byte marker; + + public JPEGImageInputStream(ImageInputStream in) + { + super(); + + this.in = in; + } + + public int read() + throws IOException + { + setBitOffset(0); + return in.read(); + } + + public int read(byte[] data, int offset, int len) + throws IOException + { + setBitOffset(0); + return in.read(data, offset, len); + } + + /** + * Pull a byte from the stream, this checks to see if the byte is 0xff + * and if the next byte isn't 0x00 (stuffed byte) it errors out. If it's + * 0x00 then it simply ignores the byte. + * + * @return the next byte in the buffer + * + * @throws IOException TODO + * @throws BitStreamException TODO + */ + private byte pullByte() throws IOException, JPEGMarkerFoundException + { + byte mybyte = readByte(); + // FIXME: handle multiple 0xff in a row + if(mybyte==(byte)(0xff)) + { + byte secondbyte = readByte(); + if(secondbyte != (byte)(0x00)) + { + marker = secondbyte; + throw new JPEGMarkerFoundException(); + } + } + return mybyte; + } + + /** + * This returns the marker that was last encountered. This should only be + * used if removeBit() throws a MarkerTagFound exception. + * + * @return marker as byte + */ + public byte getMarker() + { + return marker; + } + + /** + * Removes a bit from the buffer. (Removes from the top of a queue). This + * also checks for markers and throws MarkerTagFound exception if it does. + * If MarkerTagFound is thrown you can use getMarker() method to get the + * marker that caused the throw. + * + * @param l specifies how many bits you want to remove and add to the + * integer + * @return the amount of bits specified by l as an integer + * + * @throws IOException TODO + * @throws JPEGMarkerFoundException + * @throws BitStreamException TODO + */ + public int readBit() + throws IOException, JPEGMarkerFoundException +{ + checkClosed(); + + // Calc new bit offset here, readByte resets it. + int newOffset = (bitOffset + 1) & 0x7; + + byte data = pullByte(); + + if (bitOffset != 0) + { + seek(getStreamPosition() - 1); + data = (byte) (data >> (8 - newOffset)); + } + + bitOffset = newOffset; + return data & 0x1; +} + + + /** + * This method skips over the the data and finds the next position + * in the bit sequence with a X'FF' X'??' sequence. Multiple X'FF + * bytes in sequence are considered padding and interpreted as one + * X'FF byte. + * + * @return the next marker byte in the stream + * @throws IOException if the end of the stream is reached + * unexpectedly + */ + public byte findNextMarker() + throws IOException + { + boolean marked0xff = false; + byte byteinfo = JPEGMarker.X00; + + setBitOffset(0); + while (true) + { + byteinfo = readByte(); + if (!marked0xff) + { + if (byteinfo == JPEGMarker.XFF) + marked0xff = true; + } + else + { + if (byteinfo == JPEGMarker.XFF) + // Ignore the value 0xff when it is immediately + // followed by another 0xff byte. + continue; + else if (byteinfo == JPEGMarker.X00) + // The sequence 0xff 0x00 is used to encode the + // actual value 0xff. So restart our search for a + // marker. + marked0xff = false; + else + // One or more 0xff values were follwed by a + // non-0x00, non-0xff value so return this as the + // marker byte. + return byteinfo; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java new file mode 100644 index 000000000..5ecbe0f8c --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java @@ -0,0 +1,141 @@ +/* JPEGImageReader.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import javax.imageio.*; +import javax.imageio.spi.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.ImageInputStream; +import java.util.Iterator; +import java.awt.image.BufferedImage; + +public class JPEGImageReader extends ImageReader +{ + JPEGDecoder decoder; + + protected JPEGImageReader(ImageReaderSpi originatingProvider) + { + super(originatingProvider); + System.out.println("JPEGIMAGEREADER!!!"); + } + + // Abstract ImageReader methods. + public int getHeight(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getHeight(); + } + + public IIOMetadata getImageMetadata(int imageIndex) + throws IOException + { + // FIXME: handle metadata + checkIndex(imageIndex); + return null; + } + + public Iterator getImageTypes(int imageIndex) + throws IOException + { + return null; + } + + public int getNumImages(boolean allowSearch) + throws IOException + { + return 1; + } + + public IIOMetadata getStreamMetadata() + throws IOException + { + // FIXME: handle metadata + return null; + } + + public int getWidth(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getWidth(); + } + + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getImage(); + } + + // private helper methods + private void checkIndex(int imageIndex) + throws IndexOutOfBoundsException + { + if (imageIndex != 0) + throw new IndexOutOfBoundsException(); + } + + private void checkStream() throws IOException + { + if (!(input instanceof ImageInputStream)) + throw new IllegalStateException("Input not an ImageInputStream."); + if(input == null) + throw new IllegalStateException("No input stream."); + } + + private void decodeStream() + throws IOException, IIOException + { + System.out.println("DECONDING 1"); + if (decoder != null) + return; + + System.out.println("DECONDING 2"); + checkStream(); + + System.out.println("DECONDING 3"); + decoder = new JPEGDecoder((ImageInputStream)input); + System.out.println("DECONDING 4"); + decoder.decode(); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java new file mode 100644 index 000000000..c45b818c7 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java @@ -0,0 +1,137 @@ +/* JPEGImageReaderSpi.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import java.util.Locale; +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.IIORegistry; +import javax.imageio.stream.ImageInputStream; + +public class JPEGImageReaderSpi extends ImageReaderSpi +{ + static final String vendorName = "GNU"; + static final String version = "0.1"; + static final String readerClassName = + "gnu.javax.imageio.jpeg.JPEGImageReader"; + static final String[] names = { "JPEG" }; + static final String[] suffixes = { ".jpeg", ".jpg", ".jpe" }; + static final String[] MIMETypes = { "image/jpeg" }; + static final String[] writerSpiNames = + { "gnu.javax.imageio.jpeg.JPEGImageWriterSpi" }; + + static final boolean supportsStandardStreamMetadataFormat = false; + static final String nativeStreamMetadataFormatName = null; + static final String nativeStreamMetadataFormatClassName = null; + static final String[] extraStreamMetadataFormatNames = null; + static final String[] extraStreamMetadataFormatClassNames = null; + static final boolean supportsStandardImageMetadataFormat = false; + static final String nativeImageMetadataFormatName = null; + static final String nativeImageMetadataFormatClassName = null; + static final String[] extraImageMetadataFormatNames = null; + static final String[] extraImageMetadataFormatClassNames = null; + + private static JPEGImageReaderSpi readerSpi; + + public JPEGImageReaderSpi() + { + super(vendorName, version, + names, suffixes, MIMETypes, + readerClassName, + STANDARD_INPUT_TYPE, // Accept ImageInputStreams + writerSpiNames, + supportsStandardStreamMetadataFormat, + nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, + extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames, + supportsStandardImageMetadataFormat, + nativeImageMetadataFormatName, + nativeImageMetadataFormatClassName, + extraImageMetadataFormatNames, + extraImageMetadataFormatClassNames); + System.out.println ("JPEGImageReaderSPI!!!"); + } + + public String getDescription(Locale locale) + { + return "JPEG ISO 10918-1, JFIF V1.02"; + } + + public boolean canDecodeInput(Object input) + throws IOException + { + if (!(input instanceof ImageInputStream)) + return false; + + ImageInputStream in = (ImageInputStream) input; + boolean retval; + + in.mark(); + try + { + new JPEGDecoder(in); + retval = true; + } + catch(JPEGException e) + { + retval = false; + } + in.reset(); + + return retval; + } + + public ImageReader createReaderInstance(Object extension) + { + return new JPEGImageReader(this); + } + + public static void registerSpis(IIORegistry reg) + { + reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class); + } + + public static synchronized JPEGImageReaderSpi getReaderSpi() + { + if (readerSpi == null) + readerSpi = new JPEGImageReaderSpi(); + return readerSpi; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java new file mode 100644 index 000000000..bc6350fbc --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java @@ -0,0 +1,205 @@ +/* JPEGMarker.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +public class JPEGMarker +{ + /** + * JFIF identifiers. + */ + public final static byte JFIF_J = (byte) 0x4a; + public final static byte JFIF_F = (byte) 0x46; + public final static byte JFIF_I = (byte) 0x49; + public final static byte JFIF_X = (byte) 0x46; + + /** + * JFIF extension codes. + */ + public final static byte JFXX_JPEG = (byte) 0x10; + public final static byte JFXX_ONE_BPP = (byte) 0x11; + public final static byte JFXX_THREE_BPP = (byte) 0x13; + + /** + * Marker prefix byte. + */ + public final static byte XFF = (byte) 0xff; + + /** + * Marker byte that represents a literal 0xff. + */ + public final static byte X00 = (byte) 0x00; + + /** + * Application Reserved Keyword. + */ + public final static byte APP0 = (byte) 0xe0; + + public final static byte APP1 = (byte) 0xe1; + public final static byte APP2 = (byte) 0xe2; + public final static byte APP3 = (byte) 0xe3; + public final static byte APP4 = (byte) 0xe4; + public final static byte APP5 = (byte) 0xe5; + public final static byte APP6 = (byte) 0xe6; + public final static byte APP7 = (byte) 0xe7; + public final static byte APP8 = (byte) 0xe8; + public final static byte APP9 = (byte) 0xe9; + public final static byte APP10 = (byte) 0xea; + public final static byte APP11 = (byte) 0xeb; + public final static byte APP12 = (byte) 0xec; + public final static byte APP13 = (byte) 0xed; + public final static byte APP14 = (byte) 0xee; + public final static byte APP15 = (byte) 0xef; + + /** + * Modulo Restart Interval. + */ + public final static byte RST0 = (byte) 0xd0; + + public final static byte RST1 = (byte) 0xd1; + public final static byte RST2 = (byte) 0xd2; + public final static byte RST3 = (byte) 0xd3; + public final static byte RST4 = (byte) 0xd4; + public final static byte RST5 = (byte) 0xd5; + public final static byte RST6 = (byte) 0xd6; + public final static byte RST7 = (byte) 0xd7; + + /** + * Nondifferential Huffman-coding frame (baseline dct). + */ + public final static byte SOF0 = (byte) 0xc0; + + /** + * Nondifferential Huffman-coding frame (extended dct). + */ + public final static byte SOF1 = (byte) 0xc1; + + /** + * Nondifferential Huffman-coding frame (progressive dct). + */ + public final static byte SOF2 = (byte) 0xc2; + + /** + * Nondifferential Huffman-coding frame Lossless (Sequential). + */ + public final static byte SOF3 = (byte) 0xc3; + + /** + * Differential Huffman-coding frame Sequential DCT. + */ + public final static byte SOF5 = (byte) 0xc5; + + /** + * Differential Huffman-coding frame Progressive DCT. + */ + public final static byte SOF6 = (byte) 0xc6; + + /** + * Differential Huffman-coding frame lossless. + */ + public final static byte SOF7 = (byte) 0xc7; + + /** + * Nondifferential Arithmetic-coding frame (extended dct). + */ + public final static byte SOF9 = (byte) 0xc9; + + /** + * Nondifferential Arithmetic-coding frame (progressive dct). + */ + public final static byte SOF10 = (byte) 0xca; + + /** + * Nondifferential Arithmetic-coding frame (lossless). + */ + public final static byte SOF11 = (byte) 0xcb; + + /** + * Differential Arithmetic-coding frame (sequential dct). + */ + public final static byte SOF13 = (byte) 0xcd; + + /** + * Differential Arithmetic-coding frame (progressive dct). + */ + public final static byte SOF14 = (byte) 0xce; + + /** + * Differential Arithmetic-coding frame (lossless). + */ + public final static byte SOF15 = (byte) 0xcf; + + /** + * Huffman Table. + */ + public final static byte DHT = (byte) 0xc4; + + /** + * Quantization Table. + */ + public final static byte DQT = (byte) 0xdb; + + /** + * Start of Scan. + */ + public final static byte SOS = (byte) 0xda; + + /** + * Defined Restart Interval. + */ + public final static byte DRI = (byte) 0xdd; + + /** + * Comment in JPEG. + */ + public final static byte COM = (byte) 0xfe; + + /** + * Start of Image. + */ + public final static byte SOI = (byte) 0xd8; + + /** + * End of Image. + */ + public final static byte EOI = (byte) 0xd9; + + /** + * Define Number of Lines. + */ + public final static byte DNL = (byte) 0xdc; +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java new file mode 100644 index 000000000..2e72d495b --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java @@ -0,0 +1,50 @@ +/* JPEGMarkerFoundException.java -- FIXME: briefly describe file purpose + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; + +public class JPEGMarkerFoundException + extends IOException +{ + public JPEGMarkerFoundException() + { + super(""); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java new file mode 100644 index 000000000..e07251021 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java @@ -0,0 +1,151 @@ +/* JPEGScan.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.util.ArrayList; + +public class JPEGScan +{ + private int maxHeight = 0, maxWidth = 0, maxV = 0, maxH = 0; + private int numOfComponents = 0, numOfComponentBlocks = 0; + private ArrayList components = new ArrayList(); + + public JPEGScan() + { + // Nothing to do here. + } + + public JPEGScan(int h, int w) + { + maxHeight=h; + maxWidth=w; + } + + private void recalculateDimensions() + { + JPEGComponent comp; + + // Compute the maximum H, maximum V factors defined in Annex A of the ISO + // DIS 10918-1. + for(int i=0; i < components.size() ; i++) + { + comp = (JPEGComponent)components.get(i); + if(comp.factorH > maxH) + maxH=comp.factorH; + if(comp.factorV > maxV) + maxV=comp.factorV; + } + + for(int i=0; i < components.size() ; i++) + { + comp = (JPEGComponent)components.get(i); + comp.maxH = maxH; + comp.maxV = maxV; + } + + } + + public void addComponent(byte id, byte factorHorizontal, byte factorVertical, + byte quantizationID) + { + JPEGComponent component = new JPEGComponent(id, factorHorizontal, factorVertical, quantizationID); + components.add((Object)component); + recalculateDimensions(); + numOfComponents++; + numOfComponentBlocks += factorHorizontal*factorVertical; + } + + public JPEGComponent getComponentByID(byte id) + { + JPEGComponent comp = (JPEGComponent)components.get(0); + for(int i=0; i < components.size() ; i++) + { + comp=(JPEGComponent)components.get(i); + if(comp.component_id==id) + break; + } + return(comp); + } + + public JPEGComponent get(int id) + { + return((JPEGComponent)components.get(id)); + } + + public int getX(byte id) + { + JPEGComponent comp = getComponentByID(id); + return(comp.width); + } + + public int getY(byte id) + { + JPEGComponent comp = getComponentByID(id); + return(comp.height); + } + + public int getMaxV() + { + return(maxV); + } + + public int getMaxH() + { + return(maxH); + } + + public void setWidth(int w) + { + maxWidth=w; + } + + public void setHeight(int h) + { + maxHeight=h; + } + + public int size() + { + return(numOfComponents); + } + + public int sizeComponentBlocks() + { + return(numOfComponentBlocks); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java b/libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java new file mode 100644 index 000000000..a3970b7fa --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java @@ -0,0 +1,113 @@ +/* YCbCr_ColorSpace.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.awt.color.ColorSpace; + +public class YCbCr_ColorSpace extends ColorSpace { + public YCbCr_ColorSpace() { + super(ColorSpace.TYPE_YCbCr, 3); + } + + public float[] fromCIEXYZ(float[] data) { + return(new float[data.length]); + } + + public float[] toCIEXYZ(float[] data) { + return(new float[data.length]); + } + + public float[] fromRGB(float[] data) { + return(new float[data.length]); + } + + /* YCbCr to RGB range 0 to 1 */ + public float[] toRGB(float[] data) { + float[] dest = new float[3]; + + data[0] *= 255; + data[1] *= 255; + data[2] *= 255; + + dest[0] = (float)data[0] + (float)1.402*((float)data[2]-(float)128); + dest[1] = (float)data[0] - (float)0.34414*((float)data[1]-(float)128) - (float)0.71414*((float)data[2]-(float)128); + dest[2] = (float)data[0] + (float)1.772*((float)data[1]-(float)128); + + dest[0] /= 255; + dest[1] /= 255; + dest[2] /= 255; + + //dest[0] = ((float)1.164*((float)data[0]*(float)255 - (float)16) + (float)1.596*((float)data[2]*(float)255 - (float)128))/(float)255; + //dest[1] = ((float)1.164*((float)data[0]*(float)255 - (float)16) - (float)0.813*((float)data[2]*(float)255 - (float)128) - (float)0.392*(data[1]*255 - 128))/(float)255; + //dest[2] = ((float)1.164*((float)data[0]*(float)255 - (float)16) + (float)2.017*((float)data[1]*(float)255 - (float)128))/(float)255; + + //System.err.println("toRGB values received: 0: "+data[0]+" 1: "+data[1]+" 2: "+data[2]+" sent: 0: "+dest[0]+" 1: "+dest[1]+" 2: "+dest[2]); + if(dest[0] < (float)0) + dest[0] = 0; + if(dest[1] < (float)0) + dest[1] = 0; + if(dest[2] < (float)0) + dest[2] = 0; + + if(dest[0] > (float)1) + dest[0] = 1; + if(dest[1] > (float)1) + dest[1] = 1; + if(dest[2] > (float)1) + dest[2] = 1; + + + return(dest); + } + + /* RGB to YCbCr range 0-255 */ + public static float[] toYCbCr(float[] data) { + float[] dest = new float[3]; + //dest[0] = (float)0.257*data[0] + (float)0.504*data[1] + (float)0.098*data[2] + 16; + //dest[1] = (float)-0.148*data[0] - (float)0.291*data[1] + (float)0.439*data[2] + 128; + //dest[2] = (float)0.439*data[0] - (float)0.368*data[1] - (float)0.071*data[2] + 128; + + dest[0] = (float)((0.299 * (float)data[0] + 0.587 * (float)data[1] + 0.114 * (float)data[2])); + dest[1] = 128 + (float)((-0.16874 * (float)data[0] - 0.33126 * (float)data[1] + 0.5 * (float)data[2])); + dest[2] = 128 + (float)((0.5 * (float)data[0] - 0.41869 * (float)data[1] - 0.08131 * (float)data[2])); + + + return(dest); + + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java b/libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java new file mode 100644 index 000000000..9aac0df40 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java @@ -0,0 +1,520 @@ +/* ZigZag.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +/** + * This class implements the Zig Zag Algorithm on any array with + * the same amount of rows and columns. It takes a matrix and in turn builds an + * encoded byte array (or double array) from it. The adverse is also true, this + * will take a byte or double array and build a matrix based on the zig zag + * algorithm. + * <p>This is used exclusively in the JPEG DCT encoding.</p> + */ +public class ZigZag +{ + public final static boolean ZIGZAG_FORWARD = true; + public final static boolean ZIGZAG_BACKWARD = false; + public final static int ZIGZAG_8X8_MAP[] = + { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 + }; + + /** + * Encodes a matrix of equal width and height to a byte array. + * + * @param matrix + * + * @return + */ + public static byte[] encode(byte[][] matrix) + { + byte[] buffer = new byte[matrix.length ^ 2]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a double array + * + * @param matrix + * + * @return + */ + public static double[] encode(double[][] matrix) + { + double[] buffer = new double[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a float array + * + * @param matrix + * + * @return + */ + public static float[] encode(float[][] matrix) + { + float[] buffer = new float[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a float array + * + * @param matrix + * + * @return + */ + public static short[] encode(short[][] matrix) + { + short[] buffer = new short[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Convert a double array into a matrix with the same amount of columns and + * rows with length sqrt(double array length) + * + * @param data + * + * @return + */ + public static double[][] decode(double[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + /** + * Convert a byte array into a matrix with the same amount of columns and + * rows with length sqrt(double array length) + * + * @param data + * + * @return + */ + public static byte[][] decode(byte[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + public static int[][] decode(int[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + public static byte[][] decode(byte[] data, int width, int height) + { + byte[][] buffer = new byte[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static double[][] decode(double[] data, int width, int height) + { + double[][] buffer = new double[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + System.err.println("Setting " + dataindex + " to row: " + yindex + + " column: " + xindex + " yourval:" + + (yindex*8+xindex)); + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static float[][] decode(float[] data, int width, int height) + { + float[][] buffer = new float[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static int[][] decode(int[] data, int width, int height) + { + int[][] buffer = new int[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static double[][] decode8x8_map(double input[]) + { + double[][] output = new double[8][8]; + for(int i=0; i < 64 ; i++) + output[ZIGZAG_8X8_MAP[i]/8][ZIGZAG_8X8_MAP[i]%8] = input[i]; + return (output); + } + +} |