You are viewing a plain text version of this content. The canonical link for it is here.
Posted to sanselan-commits@incubator.apache.org by cm...@apache.org on 2007/11/29 02:27:15 UTC
svn commit: r599250 [6/15] - in /incubator/sanselan/trunk/src/main/java/org:
apache/sanselan/ apache/sanselan/color/ apache/sanselan/common/
apache/sanselan/common/byteSources/ apache/sanselan/common/mylzw/
apache/sanselan/formats/bmp/ apache/sanselan/...
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,727 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.text.NumberFormat;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.sanselan.ImageFormat;
+import org.apache.sanselan.ImageInfo;
+import org.apache.sanselan.ImageParser;
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.common.IImageMetadata;
+import org.apache.sanselan.common.byteSources.ByteSource;
+import org.apache.sanselan.formats.jpeg.segments.App13Segment;
+import org.apache.sanselan.formats.jpeg.segments.App2Segment;
+import org.apache.sanselan.formats.jpeg.segments.GenericSegment;
+import org.apache.sanselan.formats.jpeg.segments.JFIFSegment;
+import org.apache.sanselan.formats.jpeg.segments.SOFNSegment;
+import org.apache.sanselan.formats.jpeg.segments.Segment;
+import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;
+import org.apache.sanselan.formats.tiff.TiffField;
+import org.apache.sanselan.formats.tiff.TiffImageMetadata;
+import org.apache.sanselan.formats.tiff.TiffImageParser;
+import org.apache.sanselan.util.Debug;
+
+public class JpegImageParser extends ImageParser implements JpegConstants
+{
+ public JpegImageParser()
+ {
+ setByteOrder(BYTE_ORDER_NETWORK);
+ // setDebug(true);
+ }
+
+ protected ImageFormat[] getAcceptedTypes()
+ {
+ return new ImageFormat[]{
+ ImageFormat.IMAGE_FORMAT_JPEG, //
+ };
+ }
+
+ public String getName()
+ {
+ return "Jpeg-Custom";
+ }
+
+ public String getDefaultExtension()
+ {
+ return DEFAULT_EXTENSION;
+ }
+
+ private static final String DEFAULT_EXTENSION = ".jpg";
+
+ public static final String AcceptedExtensions[] = {
+ ".jpg", ".jpeg",
+ };
+
+ protected String[] getAcceptedExtensions()
+ {
+ return AcceptedExtensions;
+ }
+
+ public final BufferedImage getBufferedImage(ByteSource byteSource,
+ Map params) throws ImageReadException, IOException
+ {
+ throw new ImageReadException(
+ "Sanselan cannot read or write JPEG images.");
+ }
+
+ private boolean keepMarker(int marker, int markers[])
+ {
+ if (markers == null)
+ return true;
+
+ for (int i = 0; i < markers.length; i++)
+ {
+ if (markers[i] == marker)
+ return true;
+ }
+
+ return false;
+ }
+
+ private Vector readMarkers(InputStream is, int markers[],
+ boolean return_after_first, boolean readEverything)
+ throws ImageReadException, IOException
+ {
+ Vector result = new Vector();
+
+ for (int markerCount = 0; true; markerCount++)
+ {
+ int marker = read2Bytes("marker", is, "Not a Valid JPEG File");
+
+ if (marker == 0xffd9)
+ break;
+ else
+ {
+
+ int markerLength = read2Bytes("markerLength", is,
+ "Not a Valid JPEG File");
+
+ if (keepMarker(marker, markers))
+ {
+ if (marker == JPEG_APP13_Marker)
+ {
+ result.add(new App13Segment(this, marker,
+ markerLength - 2, is));
+ }
+ else if (marker == JPEG_APP2_Marker)
+ {
+ result
+ .add(new App2Segment(marker, markerLength - 2,
+ is));
+ }
+ // else if (marker == JPEG_APP14_Marker)
+ // {
+ // result.add(new Segment(markerLength - 2, is));
+ // }
+ else if (marker == JFIFMarker)
+ {
+ result
+ .add(new JFIFSegment(marker, markerLength - 2,
+ is));
+ }
+ else if ((marker >= SOF0Marker) && (marker <= SOF15Marker))
+ {
+ result
+ .add(new SOFNSegment(marker, markerLength - 2,
+ is));
+ }
+ else if ((marker >= JPEG_APP1_Marker)
+ && (marker <= JPEG_APP15_Marker))
+ {
+ result.add(new UnknownSegment(marker, markerLength - 2,
+ is));
+ }
+ else if (marker == SOS_Marker)
+ {
+ result.add(new UnknownSegment(marker, markerLength - 2,
+ is));
+
+ return result;
+ }
+ else
+ {
+ skipBytes(is, markerLength - 2,
+ "Not a Valid JPEG File: missing marker data");
+ }
+
+ if (debug)
+ {
+ System.out
+ .println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ System.out
+ .println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ System.out
+ .println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ System.out
+ .println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+
+ if (return_after_first)
+ return result;
+ }
+ else
+ {
+ skipBytes(is, markerLength - 2,
+ "Not a Valid JPEG File: missing marker data");
+ }
+
+ if (marker == SOS_Marker)
+ {
+ // Debug.debug("SOS");
+ return result;
+ }
+
+ }
+ if (debug)
+ System.out.println("");
+ }
+
+ return result;
+ }
+
+ public static final boolean permissive = true;
+
+ private byte[] assembleSegments(Vector v) throws ImageReadException,
+ IOException
+ {
+ try
+ {
+ return assembleSegments(v, false);
+ }
+ catch (ImageReadException e)
+ {
+ return assembleSegments(v, true);
+ }
+ }
+
+ private byte[] assembleSegments(Vector v, boolean start_with_zero)
+ throws ImageReadException, IOException
+ {
+ if (v.size() < 1)
+ throw new ImageReadException("No App2 Segments Found.");
+
+ int markerCount = ((App2Segment) v.get(0)).num_markers;
+
+ // if (permissive && (markerCount == 0))
+ // markerCount = v.size();
+
+ if (v.size() != markerCount)
+ throw new ImageReadException("App2 Segments Missing. Found: "
+ + v.size() + ", Expected: " + markerCount + ".");
+
+ Collections.sort(v);
+
+ int offset = start_with_zero ? 0 : 1;
+
+ int total = 0;
+ for (int i = 0; i < v.size(); i++)
+ {
+ App2Segment segment = (App2Segment) v.get(i);
+
+ if ((i + offset) != segment.cur_marker)
+ {
+ dumpSegments(v);
+ throw new ImageReadException(
+ "Incoherent App2 Segment Ordering. i: " + i
+ + ", segment[" + i + "].cur_marker: "
+ + segment.cur_marker + ".");
+ }
+
+ if (markerCount != segment.num_markers)
+ {
+ dumpSegments(v);
+ throw new ImageReadException(
+ "Inconsistent App2 Segment Count info. markerCount: "
+ + markerCount + ", segment[" + i
+ + "].num_markers: " + segment.num_markers + ".");
+ }
+
+ total += segment.icc_bytes.length;
+ }
+
+ byte result[] = new byte[total];
+ int progress = 0;
+
+ for (int i = 0; i < v.size(); i++)
+ {
+ App2Segment segment = (App2Segment) v.get(i);
+
+ System.arraycopy(segment.icc_bytes, 0, result, progress,
+ segment.icc_bytes.length);
+ progress += segment.icc_bytes.length;
+ }
+
+ return result;
+ }
+
+ private void dumpSegments(Vector v)
+ {
+ Debug.debug();
+ Debug.debug("dumpSegments", v.size());
+
+ for (int i = 0; i < v.size(); i++)
+ {
+ App2Segment segment = (App2Segment) v.get(i);
+
+ Debug.debug((i) + ": " + segment.cur_marker + " / "
+ + segment.num_markers);
+ }
+ Debug.debug();
+ }
+
+ public Vector readSegments(ByteSource byteSource, int markers[],
+ boolean return_after_first) throws ImageReadException, IOException
+ {
+ return readSegments(byteSource, markers, return_after_first, false);
+ }
+
+ public Vector readSegments(ByteSource byteSource, int markers[],
+ boolean return_after_first, boolean readEverything)
+ throws ImageReadException, IOException
+ {
+ InputStream is = null;
+
+ try
+ {
+ is = byteSource.getInputStream();
+
+ readAndVerifyBytes(is, SOI,
+ "Not a Valid JPEG File: doesn't begin with 0xffd8");
+
+ return readMarkers(is, markers, return_after_first, readEverything);
+ }
+ finally
+ {
+ try
+ {
+ is.close();
+ }
+ catch (Exception e)
+ {
+ Debug.debug(e);
+ }
+ }
+ }
+
+ public byte[] getICCProfileBytes(ByteSource byteSource)
+ throws ImageReadException, IOException
+ {
+ Vector segments = readSegments(byteSource, new int[]{
+ JPEG_APP2_Marker,
+ }, false);
+
+ if (segments != null)
+ {
+ // throw away non-icc profile app2 segments.
+ Vector filtered = new Vector();
+ for (int i = 0; i < segments.size(); i++)
+ {
+ App2Segment segment = (App2Segment) segments.get(i);
+ if (segment.icc_bytes != null)
+ filtered.add(segment);
+ }
+ segments = filtered;
+ }
+
+ if ((segments == null) || (segments.size() < 1))
+ return null;
+
+ byte bytes[] = assembleSegments(segments);
+
+ if (debug)
+ System.out.println("bytes" + ": "
+ + ((bytes == null) ? null : "" + bytes.length));
+
+ if (debug)
+ System.out.println("");
+
+ return (bytes);
+ }
+
+ public IImageMetadata getMetadata(ByteSource byteSource, Map params)
+ throws ImageReadException, IOException
+ {
+ TiffImageMetadata exif = getExifMetadata(byteSource, params);
+
+ JpegImageMetadata.Photoshop photoshop = getPhotoshopMetadata(byteSource);
+
+ if (null == exif && null == photoshop)
+ return null;
+
+ JpegImageMetadata result = new JpegImageMetadata(photoshop, exif);
+
+ return result;
+ }
+
+ public static boolean isExifAPP1Segment(GenericSegment segment)
+ {
+ byte bytes[] = segment.bytes;
+
+ if ((bytes == null) || (bytes.length < 4))
+ return false;
+
+ for (int i = 0; i < 4 && i < bytes.length; i++)
+ if (bytes[i] != ExifIdentifierCode[i])
+ return false;
+
+ return true;
+ }
+
+ private Vector filterAPP1Segments(Vector v)
+ {
+ Vector result = new Vector();
+
+ for (int i = 0; i < v.size(); i++)
+ {
+ GenericSegment segment = (GenericSegment) v.get(i);
+ if (isExifAPP1Segment(segment))
+ result.add(segment);
+ }
+
+ return result;
+ }
+
+ public TiffImageMetadata getExifMetadata(ByteSource byteSource, Map params)
+ throws ImageReadException, IOException
+ {
+ byte bytes[] = getExifRawData(byteSource);
+ if (null == bytes)
+ return null;
+
+ return (TiffImageMetadata) new TiffImageParser().getMetadata(bytes,
+ params);
+ }
+
+ public byte[] getExifRawData(ByteSource byteSource)
+ throws ImageReadException, IOException
+ {
+ Vector segments = readSegments(byteSource, new int[]{
+ JPEG_APP1_Marker,
+ }, false);
+
+ if ((segments == null) || (segments.size() < 1))
+ return null;
+
+ Vector exifSegments = filterAPP1Segments(segments);
+ if (debug)
+ System.out.println("exif_segments.size" + ": "
+ + exifSegments.size());
+
+ // TODO: concatenate if multiple segments, need example.
+ if (exifSegments.size() > 1)
+ throw new ImageReadException(
+ "Sanselan currently can't parse EXIF metadata split across multiple APP1 segments. "
+ + "Please send this image to the Sanselan project.");
+
+ GenericSegment segment = (GenericSegment) exifSegments.get(0);
+ byte bytes[] = segment.bytes;
+
+ // byte head[] = readBytearray("exif head", bytes, 0, 6);
+ //
+ // Debug.debug("head", head);
+
+ return getBytearrayTail("trimmed exif bytes", bytes, 6);
+ }
+
+ private JpegImageMetadata.Photoshop getPhotoshopMetadata(
+ ByteSource byteSource) throws ImageReadException, IOException
+ {
+ Vector segments = readSegments(byteSource, new int[]{
+ JPEG_APP13_Marker,
+ }, false);
+
+ if ((segments == null) || (segments.size() < 1))
+ return null;
+
+ JpegImageMetadata.Photoshop result = new JpegImageMetadata.Photoshop();
+
+ for (int i = 0; i < segments.size(); i++)
+ {
+ App13Segment segment = (App13Segment) segments.get(i);
+
+ Vector elements = segment.elements;
+
+ for (int j = 0; j < elements.size(); j++)
+ {
+ IptcElement element = (IptcElement) elements.get(j);
+ result.add(element.getIptcTypeName(), element.getValue());
+ }
+ }
+
+ return result;
+ }
+
+ public Dimension getImageSize(ByteSource byteSource)
+ throws ImageReadException, IOException
+ {
+ Vector segments = readSegments(byteSource, new int[]{
+ // kJFIFMarker,
+ SOF0Marker,
+
+ SOF1Marker, SOF2Marker, SOF3Marker, SOF5Marker, SOF6Marker,
+ SOF7Marker, SOF9Marker, SOF10Marker, SOF11Marker, SOF13Marker,
+ SOF14Marker, SOF15Marker,
+
+ }, true);
+
+ if ((segments == null) || (segments.size() < 1))
+ throw new ImageReadException("No JFIF Data Found.");
+
+ if (segments.size() > 1)
+ throw new ImageReadException("Redundant JFIF Data Found.");
+
+ SOFNSegment fSOFNSegment = (SOFNSegment) segments.get(0);
+
+ return new Dimension(fSOFNSegment.width, fSOFNSegment.height);
+ }
+
+ public byte[] embedICCProfile(byte image[], byte profile[])
+ {
+ return null;
+ }
+
+ public boolean embedICCProfile(File src, File dst, byte profile[])
+ {
+ return false;
+ }
+
+ public ImageInfo getImageInfo(ByteSource byteSource)
+ throws ImageReadException, IOException
+ {
+
+ Vector SOF_segments = readSegments(byteSource, new int[]{
+ // kJFIFMarker,
+
+ SOF0Marker, SOF1Marker, SOF2Marker, SOF3Marker, SOF5Marker,
+ SOF6Marker, SOF7Marker, SOF9Marker, SOF10Marker, SOF11Marker,
+ SOF13Marker, SOF14Marker, SOF15Marker,
+
+ }, false);
+
+ if (SOF_segments == null)
+ throw new ImageReadException("No SOFN Data Found.");
+
+ // if (SOF_segments.size() != 1)
+ // System.out.println("Incoherent SOFN Data Found: "
+ // + SOF_segments.size());
+
+ Vector JFIF_segments = readSegments(byteSource, new int[]{
+ JFIFMarker,
+ }, true);
+
+ SOFNSegment fSOFNSegment = (SOFNSegment) SOF_segments.get(0);
+ // SOFNSegment fSOFNSegment = (SOFNSegment) findSegment(segments, SOFNmarkers);
+
+ if (fSOFNSegment == null)
+ throw new ImageReadException("No SOFN Data Found.");
+
+ int Width = fSOFNSegment.width;
+ int Height = fSOFNSegment.height;
+
+ JFIFSegment fTheJFIFSegment = null;
+
+ if ((JFIF_segments != null) && (JFIF_segments.size() > 0))
+ fTheJFIFSegment = (JFIFSegment) JFIF_segments.get(0);
+
+ // JFIFSegment fTheJFIFSegment = (JFIFSegment) findSegment(segments,
+ // kJFIFMarker);
+
+ double x_density = -1.0;
+ double y_density = -1.0;
+ double units_per_inch = -1.0;
+ // int JFIF_major_version;
+ // int JFIF_minor_version;
+ String FormatDetails;
+
+ if (fTheJFIFSegment != null)
+ {
+ x_density = fTheJFIFSegment.xDensity;
+ y_density = fTheJFIFSegment.yDensity;
+ int density_units = fTheJFIFSegment.density_units;
+ // JFIF_major_version = fTheJFIFSegment.JFIF_major_version;
+ // JFIF_minor_version = fTheJFIFSegment.JFIF_minor_version;
+
+ FormatDetails = "Jpeg/JFIF v." + fTheJFIFSegment.JFIF_major_version
+ + "." + fTheJFIFSegment.JFIF_minor_version;
+
+ switch (density_units)
+ {
+ case 0 :
+ break;
+ case 1 : // inches
+ units_per_inch = 1.0;
+ break;
+ case 2 : // cms
+ units_per_inch = 2.54;
+ break;
+ default :
+ break;
+ }
+ }
+ else
+ {
+ JpegImageMetadata metadata = (JpegImageMetadata) getMetadata(byteSource);
+
+ {
+ TiffField field = metadata
+ .findEXIFValue(TiffField.TIFF_TAG_XResolution);
+ if (field == null)
+ throw new ImageReadException("No XResolution");
+
+ x_density = ((Number) field.getValue()).doubleValue();
+ }
+ {
+ TiffField field = metadata
+ .findEXIFValue(TiffField.TIFF_TAG_YResolution);
+ if (field == null)
+ throw new ImageReadException("No YResolution");
+
+ y_density = ((Number) field.getValue()).doubleValue();
+ }
+ {
+ TiffField field = metadata
+ .findEXIFValue(TiffField.TIFF_TAG_ResolutionUnit);
+ if (field == null)
+ throw new ImageReadException("No ResolutionUnits");
+
+ int density_units = ((Number) field.getValue()).intValue();
+
+ switch (density_units)
+ {
+ case 1 :
+ break;
+ case 2 : // inches
+ units_per_inch = 1.0;
+ break;
+ case 3 : // cms
+ units_per_inch = 2.54;
+ break;
+ default :
+ break;
+ }
+
+ }
+
+ FormatDetails = "Jpeg/DCM";
+
+ }
+
+ int PhysicalHeightDpi = -1;
+ float PhysicalHeightInch = -1;
+ int PhysicalWidthDpi = -1;
+ float PhysicalWidthInch = -1;
+
+ if (units_per_inch > 0)
+ {
+ PhysicalWidthDpi = (int) Math.round((double) x_density
+ / units_per_inch);
+ PhysicalWidthInch = (float) ((double) Width / (x_density * units_per_inch));
+ PhysicalHeightDpi = (int) Math.round((double) y_density
+ * units_per_inch);
+ PhysicalHeightInch = (float) ((double) Height / (y_density * units_per_inch));
+ }
+
+ Vector Comments = new Vector();
+ // TODO: comments...
+
+ int Number_of_components = fSOFNSegment.Number_of_components;
+ int Precision = fSOFNSegment.Precision;
+
+ int BitsPerPixel = Number_of_components * Precision;
+ ImageFormat Format = ImageFormat.IMAGE_FORMAT_JPEG;
+ String FormatName = "JPEG (Joint Photographic Experts Group) Format";
+ String MimeType = "image/jpeg";
+ // we ought to count images, but don't yet.
+ int NumberOfImages = -1;
+ // not accurate ... only reflects first
+ boolean isProgressive = fSOFNSegment.marker == SOF2Marker;
+
+ boolean isTransparent = false; // TODO: inaccurate.
+ boolean usesPalette = false; // TODO: inaccurate.
+ int ColorType;
+ if (Number_of_components == 1)
+ ColorType = ImageInfo.COLOR_TYPE_BW;
+ else if (Number_of_components == 3)
+ ColorType = ImageInfo.COLOR_TYPE_RGB;
+ else if (Number_of_components == 4)
+ ColorType = ImageInfo.COLOR_TYPE_CMYK;
+ else
+ ColorType = ImageInfo.COLOR_TYPE_UNKNOWN;
+
+ String compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_JPEG;
+
+ ImageInfo result = new ImageInfo(FormatDetails, BitsPerPixel, Comments,
+ Format, FormatName, Height, MimeType, NumberOfImages,
+ PhysicalHeightDpi, PhysicalHeightInch, PhysicalWidthDpi,
+ PhysicalWidthInch, Width, isProgressive, isTransparent,
+ usesPalette, ColorType, compressionAlgorithm);
+
+ return result;
+ }
+
+ public boolean dumpImageFile(PrintWriter pw, ByteSource byteSource)
+ throws ImageReadException, IOException
+ {
+ pw.println("tiff.dumpImageFile");
+
+ {
+ ImageInfo imageInfo = getImageInfo(byteSource);
+ if (imageInfo == null)
+ return false;
+
+ imageInfo.toString(pw, "");
+ }
+
+ pw.println("");
+
+ {
+ Vector segments = readSegments(byteSource, null, false);
+
+ if (segments == null)
+ throw new ImageReadException("No Segments Found.");
+
+ for (int d = 0; d < segments.size(); d++)
+ {
+
+ Segment segment = (Segment) segments.get(d);
+
+ NumberFormat nf = NumberFormat.getIntegerInstance();
+ // this.debugNumber("found, marker: ", marker, 4);
+ pw.println(d + ": marker: "
+ + Integer.toHexString(segment.marker) + ", "
+ + segment.getDescription() + " (length: "
+ + nf.format(segment.length) + ")");
+ segment.dump(pw);
+ }
+
+ pw.println("");
+ }
+
+ return true;
+ }
+
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.exifRewrite;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.common.BinaryFileParser;
+import org.apache.sanselan.common.byteSources.ByteSource;
+import org.apache.sanselan.formats.jpeg.JpegConstants;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+import org.apache.sanselan.formats.jpeg.segments.GenericSegment;
+import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;
+import org.apache.sanselan.formats.tiff.TagInfo;
+import org.apache.sanselan.formats.tiff.TiffField;
+import org.apache.sanselan.formats.tiff.TiffImageMetadata;
+import org.apache.sanselan.formats.tiff.TiffImageParser;
+import org.apache.sanselan.formats.tiff.fieldtypes.FieldType;
+import org.apache.sanselan.formats.tiff.write.TiffImageWriter;
+import org.apache.sanselan.formats.tiff.write.WriteField;
+import org.apache.sanselan.util.Debug;
+
+public class ExifRewriter extends BinaryFileParser implements JpegConstants
+{
+ public ExifRewriter()
+ {
+ setByteOrder(BYTE_ORDER_NETWORK);
+ }
+
+ public void rewriteEXIFMetadata(ByteSource byteSource, OutputStream os,
+ Map params) throws ImageReadException, IOException,
+ ImageWriteException
+ {
+ Vector pieces = new Vector();
+ InputStream is = null;
+ GenericSegment exifSegment = null;
+
+ try
+ {
+ is = byteSource.getInputStream();
+
+ readAndVerifyBytes(is, SOI,
+ "Not a Valid JPEG File: doesn't begin with 0xffd8");
+
+ int byteOrder = getByteOrder();
+
+ for (int markerCount = 0; true; markerCount++)
+ {
+ byte markerBytes[] = readByteArray("markerBytes", 2, is,
+ "markerBytes");
+ int marker = convertByteArrayToShort("marker", markerBytes,
+ byteOrder);
+
+ // private boolean isExifAPP1Segment(GenericSegment segment)
+
+ if (marker == 0xffd9 || marker == SOS_Marker)
+ {
+ pieces.add(markerBytes);
+ pieces.add(getStreamBytes(is));
+ break;
+ }
+
+ byte markerLengthBytes[] = readByteArray("markerLengthBytes",
+ 2, is, "markerLengthBytes");
+ int markerLength = convertByteArrayToShort("markerLength",
+ markerLengthBytes, byteOrder);
+
+ UnknownSegment segment = new UnknownSegment(marker,
+ markerLength - 2, is);
+
+ if (marker != JPEG_APP1_Marker)
+ {
+ pieces.add(markerBytes);
+ pieces.add(markerLengthBytes);
+ pieces.add(segment.bytes);
+ continue;
+ }
+
+ if (!JpegImageParser.isExifAPP1Segment(segment))
+ {
+ pieces.add(markerBytes);
+ pieces.add(markerLengthBytes);
+ pieces.add(segment.bytes);
+ continue;
+ }
+
+ if (exifSegment != null)
+ {
+ // TODO: add support for multiple segments
+ throw new ImageWriteException(
+ "More than one APP1 EXIF segment.");
+ }
+
+ exifSegment = segment;
+ pieces.add(segment);
+ }
+
+ }
+ finally
+ {
+ try
+ {
+ is.close();
+ }
+ catch (Exception e)
+ {
+ Debug.debug(e);
+ }
+ }
+
+ if (exifSegment == null)
+ {
+ // TODO: add support for adding, not just replacing.
+ throw new ImageWriteException("No APP1 EXIF segment found.");
+ }
+
+ byte exifBytes[] = exifSegment.bytes;
+ exifBytes = getBytearrayTail("trimmed exif bytes", exifBytes, 6);
+
+ TiffImageMetadata exifMetadata = (TiffImageMetadata) new TiffImageParser()
+ .getMetadata(exifBytes, params);
+
+ byte newBytes[] = rewriteExif(exifMetadata, true);
+ // exifSegment.bytes = newBytes;
+
+ // Vector segments = readSegments(byteSource, null, false, true);
+
+ // TiffImageMetadata exif = getExifMetadata(byteSource, params);
+
+ writeSegments(os, pieces, newBytes);
+ }
+
+ private void writeSegments(OutputStream os, Vector segments,
+ byte newBytes[]) throws ImageWriteException, IOException
+ {
+ int byteOrder = getByteOrder();
+
+ try
+ {
+ os.write(SOI);
+
+ for (int i = 0; i < segments.size(); i++)
+ {
+ Object o = segments.get(i);
+ if (o instanceof byte[])
+ {
+ byte bytes[] = (byte[]) o;
+ os.write(bytes);
+ }
+ else if (o instanceof GenericSegment)
+ {
+ // byte markerBytes[] = readByteArray("markerBytes", 2, is,
+ // "markerBytes");
+ // int marker = convertByteArrayToShort("marker", markerBytes,
+ // byteOrder);
+ byte markerBytes[] = convertShortToByteArray(
+ JPEG_APP1_Marker, byteOrder);
+ os.write(markerBytes);
+
+ int markerLength = newBytes.length + 2;
+ byte markerLengthBytes[] = convertShortToByteArray(
+ markerLength, byteOrder);
+ os.write(markerLengthBytes);
+
+ //
+ // pieces.add(markerBytes);
+ // pieces.add(markerLengthBytes);
+
+ os.write(newBytes);
+ // GenericSegment segment = (GenericSegment) o;
+ // os.write(segment.bytes);
+ }
+ else
+ throw new ImageWriteException("Unknown data: " + o);
+ }
+ // readAndVerifyBytes(is, SOI,
+ // "Not a Valid JPEG File: doesn't begin with 0xffd8");
+ //
+ // return readMarkers(is, markers, return_after_first);
+ }
+ finally
+ {
+ try
+ {
+ os.close();
+ }
+ catch (Exception e)
+ {
+ Debug.debug(e);
+ }
+ }
+ }
+
+ public byte[] rewriteExif(TiffImageMetadata exif, boolean includeEXIFPrefix)
+ throws IOException, ImageWriteException
+ {
+ if (exif == null)
+ return null;
+
+ int byteOrder = exif.contents.header.byteOrder;
+
+ Vector dstDirs = new Vector();
+ Vector srcDirs = exif.getDirectories();
+ for (int i = 0; i < srcDirs.size(); i++)
+ {
+ TiffImageMetadata.Directory srcDir = (TiffImageMetadata.Directory) srcDirs
+ .get(i);
+ // Debug.debug("srcDir", srcDir);
+
+ TiffImageWriter.Directory dstDir = translate(srcDir, byteOrder);
+ dstDirs.add(dstDir);
+ }
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ if (includeEXIFPrefix)
+ {
+ os.write(ExifIdentifierCode);
+ os.write(0);
+ os.write(0);
+ }
+
+ new TiffImageWriter(byteOrder).writeDirectories(os, dstDirs);
+
+ return os.toByteArray();
+ }
+
+ private TiffImageWriter.Directory translate(
+ TiffImageMetadata.Directory srcDir, int byteOrder)
+ throws ImageWriteException
+ {
+ TiffImageWriter.Directory dstDir = new TiffImageWriter.Directory(
+ srcDir.type);
+
+ Vector entries = srcDir.getItems();
+ for (int i = 0; i < entries.size(); i++)
+ {
+ TiffImageMetadata.Item item = (TiffImageMetadata.Item) entries
+ .get(i);
+ TiffField srcField = item.getTiffField();
+
+ TagInfo tag = srcField.tagInfo;
+ FieldType tagtype = srcField.fieldType;
+ int count = srcField.length;
+ byte bytes[] = srcField.fieldType.getRawBytes(srcField);
+
+ // Debug.debug("\t" + "srcField", srcField);
+ // Debug.debug("\t" + "bytes", bytes);
+
+ Object value = srcField.getValue();
+ byte bytes2[];
+ if (tag.isDate)
+ bytes2 = tagtype.getRawBytes(srcField);
+ else
+ bytes2 = tagtype.writeData(value, byteOrder);
+ // Debug.debug("\t" + "bytes2", bytes2);
+
+ WriteField dstField = new WriteField(tag, tagtype, count, bytes2);
+ dstDir.add(dstField);
+ }
+
+ dstDir.setRawTiffImageData(srcDir.getRawTiffImageData());
+ dstDir.setRawJpegImageData(srcDir.getRawJpegImageData());
+
+ return dstDir;
+ }
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/APPNSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/APPNSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/APPNSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/APPNSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+
+public class APPNSegment extends GenericSegment
+{
+ public APPNSegment(int marker, int marker_length, InputStream is)
+ throws ImageReadException, IOException
+ {
+ super(marker, marker_length, is);
+ }
+
+ public String getDescription()
+ {
+ return "APPN (APP" + (marker - JpegImageParser.JPEG_APP0_Marker)
+ + ") (" + getSegmentType() + ")";
+ }
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/APPNSegment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App13Segment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App13Segment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App13Segment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App13Segment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.formats.jpeg.IptcElement;
+import org.apache.sanselan.formats.jpeg.IptcType;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+
+public class App13Segment extends APPNSegment
+{
+ protected final JpegImageParser parser;
+ public final Vector elements = new Vector();
+
+ public App13Segment(JpegImageParser parser, int marker, int marker_length,
+ InputStream is2) throws ImageReadException, IOException
+ {
+ super(marker, marker_length, is2);
+ this.parser = parser;
+
+ // InputStream bais = new ByteArrayInputStream(bytes);
+ // dump();
+
+ // Debug.debug("bytes", bytes);
+ boolean verbose = false;
+
+ if (!compareByteArrays(bytes, 0,
+ JpegImageParser.PhotoshopIdentificationString, 0,
+ JpegImageParser.PhotoshopIdentificationString.length))
+ throw new ImageReadException("Invalid App13 Segment");
+ // readAndVerifyBytes("Photoshop Identification String", bais,
+ // kPhotoshopIdentificationString, "Invalid App13 Segment");
+
+ int index = JpegImageParser.PhotoshopIdentificationString.length;
+ while (index < bytes.length)
+ {
+ if (!compareByteArrays(bytes, index, JpegImageParser.CONST_8BIM, 0,
+ JpegImageParser.CONST_8BIM.length))
+ {
+ // dump(index);
+ throw new ImageReadException("Invalid .CONST_8BIM Segment");
+ }
+ index += JpegImageParser.CONST_8BIM.length;
+
+ int segmentType = convertByteArrayToShort("SegmentType", index,
+ bytes);
+ if (verbose)
+ debugNumber("SegmentType", segmentType, 2);
+ index += 2;
+
+ // padding
+ index += 4;
+
+ int segmentSize = convertByteArrayToShort("SegmentSize", index,
+ bytes);
+ if (verbose)
+ debugNumber("fSegmentSize", segmentSize, 2);
+ index += 2;
+
+ int index2 = index;
+
+ index += segmentSize;
+ if ((segmentSize % 2) != 0)
+ index++;
+
+ while (index2 < index)
+ {
+ int iptcPrefix = convertByteArrayToShort("IPTCPrefix", index2,
+ bytes);
+ if (verbose)
+ debugNumber("fIPTCPrefix", iptcPrefix, 2);
+ index2 += 2;
+
+ if (iptcPrefix == 0x1c02)
+ {
+ // System.out.println(" TEXTBLOCK: "
+ // + fSegmentType);
+ }
+ else
+ {
+ // System.out.println(" !TEXTBLOCK: " + fSegmentType);
+ break;
+ }
+
+ byte iptcSegmentType = bytes[index2];
+ // debugNumber("fIPTCSegmentType", fIPTCSegmentType);
+ index2++;
+
+ int iptcSegmentSize = convertByteArrayToShort(
+ "IPTCSegmentSize", index2, bytes);
+ // debugNumber("fIPTCegmentSize", fIPTCegmentSize, 2);
+ index2 += 2;
+
+ byte iptcData[] = readBytearray("iptc_data", bytes, index2,
+ iptcSegmentSize);
+ index2 += iptcSegmentSize;
+
+ String value = new String(iptcData);
+ // System.out.println("iptc_data: '" + value + "' ("
+ // + fIPTCegmentSize + ")");
+
+ IptcType iptcType = IptcType.getIptcType(iptcSegmentType);
+ IptcElement element = new IptcElement(iptcType, value);
+ elements.add(element);
+ }
+
+ }
+ // System.out.println(" zimbabwe legit");
+
+ //
+ // {
+ // int i = read_byte("zero", is, "Invalid App13 Segment");
+ // if (i != 0)
+ // throw new ImageReadException("Invalid App13 Segment");
+ // }
+
+ // while (true)
+ // {
+ // readAndVerifyBytes(.CONST_8BIM", bais, .CONST_8BIM, "Invalid.CONST_8BIM Segment");
+ // System.out.println();
+ // }
+
+ }
+
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App13Segment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App2Segment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App2Segment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App2Segment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App2Segment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.segments;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+
+public class App2Segment extends APPNSegment implements Comparable
+{
+ public final byte icc_bytes[];
+ public final int cur_marker, num_markers;
+
+ public App2Segment(int marker, int marker_length, InputStream is2)
+ throws ImageReadException, IOException
+ {
+ super(marker, marker_length, is2);
+
+ if (startsWith(bytes, JpegImageParser.icc_profile_label))
+ {
+ InputStream is = new ByteArrayInputStream(bytes);
+
+ readAndVerifyBytes(is, JpegImageParser.icc_profile_label,
+ "Not a Valid App2 Segment: missing ICC Profile label");
+
+ cur_marker = readByte("cur_marker", is, "Not a valid App2 Marker");
+ num_markers = readByte("num_markers", is, "Not a valid App2 Marker");
+
+ marker_length -= JpegImageParser.icc_profile_label.length;
+ marker_length -= (1 + 1);
+
+ icc_bytes = readByteArray("App2 Data", marker_length, is,
+ "Invalid App2 Segment: insufficient data");
+ }
+ else
+ {
+ debugByteArray("Unknown APP2 Segment Type", bytes);
+ cur_marker = -1;
+ num_markers = -1;
+ icc_bytes = null;
+ }
+ }
+
+ public int compareTo(Object o)
+ {
+ App2Segment other = (App2Segment) o;
+ return cur_marker - other.cur_marker;
+ }
+
+ // public String getDescription()
+ // {
+ // return "APPN (APP"
+ // + (marker - JpegImageParser.JPEG_APP0)
+ // + ") (" + getDescription() + ")";
+ // }
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App2Segment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/GenericSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/GenericSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/GenericSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/GenericSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+
+import org.apache.sanselan.ImageReadException;
+
+public abstract class GenericSegment extends Segment
+{
+ public final byte bytes[];
+
+ public GenericSegment(int marker, int marker_length, InputStream is)
+ throws ImageReadException, IOException
+ {
+ super(marker, marker_length);
+
+ bytes = readByteArray("Segment Data", marker_length, is,
+ "Invalid Segment: insufficient data");
+ }
+
+ public void dump(PrintWriter pw)
+ {
+ dump(pw, 0);
+ }
+
+ public void dump(PrintWriter pw, int start)
+ {
+ for (int i = 0; (i < 50) && ((i + start) < bytes.length); i++)
+ {
+ debugNumber(pw, "\t" + (i + start), bytes[i + start]);
+ }
+ }
+
+ // public String getDescription()
+ // {
+ // return "Unknown";
+ // }
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/GenericSegment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/JFIFSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/JFIFSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/JFIFSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/JFIFSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+
+public class JFIFSegment extends Segment
+{
+ public final int JFIF_major_version;
+ public final int JFIF_minor_version;
+ public final int density_units;
+ public final int xDensity;
+ public final int yDensity;
+
+ public final int xThumbnail;
+ public final int yThumbnail;
+ public final int thumbnailSize;
+
+ public String getDescription()
+ {
+ return "JFIF (" + getSegmentType() + ")";
+ }
+
+ private static final byte JFIF0_SIGNATURE[] = new byte[]{
+ (byte) 'J', (byte) 'F', (byte) 'I', (byte) 'F', (byte) 0,
+ };
+
+ public JFIFSegment(int marker, int marker_length, InputStream is)
+ throws ImageReadException, IOException
+ {
+ super(marker, marker_length);
+
+ {
+ readAndVerifyBytes(is, JFIF0_SIGNATURE,
+ "Not a Valid JPEG File: missing JFIF string");
+
+ JFIF_major_version = readByte("JFIF_major_version", is,
+ "Not a Valid JPEG File");
+ JFIF_minor_version = readByte("JFIF_minor_version", is,
+ "Not a Valid JPEG File");
+ density_units = readByte("density_units", is,
+ "Not a Valid JPEG File");
+ xDensity = read2Bytes("x_density", is, "Not a Valid JPEG File");
+ yDensity = read2Bytes("y_density", is, "Not a Valid JPEG File");
+
+ xThumbnail = readByte("x_thumbnail", is, "Not a Valid JPEG File");
+ yThumbnail = readByte("y_thumbnail", is, "Not a Valid JPEG File");
+ thumbnailSize = xThumbnail * yThumbnail;
+ if (thumbnailSize > 0)
+ {
+ skipBytes(is, thumbnailSize,
+ "Not a Valid JPEG File: missing thumbnail");
+
+ }
+ }
+
+ if (getDebug())
+ System.out.println("");
+ }
+
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/JFIFSegment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOFNSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOFNSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOFNSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOFNSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+
+public class SOFNSegment extends Segment
+{
+ public final int width, height;
+ public final int Number_of_components;
+ public final int Precision;
+
+ // public final byte bytes[];
+ // public final int cur_marker, num_markers;
+
+ public SOFNSegment(int marker, int marker_length, InputStream is)
+ throws ImageReadException, IOException
+ {
+ super(marker, marker_length);
+
+ if (getDebug())
+ System.out.println("SOF0Segment marker_length: " + marker_length);
+
+ {
+ Precision = readByte("Data_precision", is, "Not a Valid JPEG File");
+ height = read2Bytes("Image_height", is, "Not a Valid JPEG File");
+ width = read2Bytes("Image_Width", is, "Not a Valid JPEG File");
+ Number_of_components = readByte("Number_of_components", is,
+ "Not a Valid JPEG File");
+
+ // ignore the rest of the segment for now...
+ skipBytes(is, marker_length - 6,
+ "Not a Valid JPEG File: SOF0 Segment");
+
+ // int Each_component1 = read_byte("Each_component1", is,
+ // "Not a Valid JPEG File");
+ // int Each_component2 = read_byte("Each_component2", is,
+ // "Not a Valid JPEG File");
+ // int Each_component3 = read_byte("Each_component3", is,
+ // "Not a Valid JPEG File");
+ }
+
+ if (getDebug())
+ System.out.println("");
+ }
+
+ public String getDescription()
+ {
+ return "SOFN (SOF" + (marker - JpegImageParser.SOF0Marker) + ") ("
+ + getSegmentType() + ")";
+ }
+
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOFNSegment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOSSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOSSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOSSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOSSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.util.Debug;
+
+public class SOSSegment extends Segment
+{
+ // public final int width, height;
+ // public final int Number_of_components;
+ // public final int Precision;
+
+ // public final byte bytes[];
+ // public final int cur_marker, num_markers;
+
+ public SOSSegment(int marker, int marker_length, InputStream is)
+ throws ImageReadException, IOException
+ {
+ super(marker, marker_length);
+
+ if (getDebug())
+ System.out.println("SOSSegment marker_length: " + marker_length);
+
+ Debug.debug("SOS", marker_length);
+ // {
+ int number_of_components_in_scan = readByte(
+ "number_of_components_in_scan", is, "Not a Valid JPEG File");
+ Debug.debug("number_of_components_in_scan",
+ number_of_components_in_scan);
+
+ for (int i = 0; i < number_of_components_in_scan; i++)
+ {
+ int scan_component_selector = readByte("scan_component_selector",
+ is, "Not a Valid JPEG File");
+ Debug.debug("scan_component_selector", scan_component_selector);
+
+ int ac_dc_entrooy_coding_table_selector = readByte(
+ "ac_dc_entrooy_coding_table_selector", is,
+ "Not a Valid JPEG File");
+ Debug.debug("ac_dc_entrooy_coding_table_selector",
+ ac_dc_entrooy_coding_table_selector);
+ }
+
+ int start_of_spectral_selection = readByte(
+ "start_of_spectral_selection", is, "Not a Valid JPEG File");
+ Debug.debug("start_of_spectral_selection", start_of_spectral_selection);
+ int end_of_spectral_selection = readByte("end_of_spectral_selection",
+ is, "Not a Valid JPEG File");
+ Debug.debug("end_of_spectral_selection", end_of_spectral_selection);
+ int successive_approximation_bit_position = readByte(
+ "successive_approximation_bit_position", is,
+ "Not a Valid JPEG File");
+ Debug.debug("successive_approximation_bit_position",
+ successive_approximation_bit_position);
+
+ // height = read2Bytes("Image_height", is, "Not a Valid JPEG File");
+ // width = read2Bytes("Image_Width", is, "Not a Valid JPEG File");
+ // Number_of_components = read_byte("Number_of_components", is,
+ // "Not a Valid JPEG File");
+ //
+ // // ignore the rest of the segment for now...
+ // skipBytes(is, marker_length - 6,
+ // "Not a Valid JPEG File: SOF0 Segment");
+ //
+ // // int Each_component1 = read_byte("Each_component1", is,
+ // // "Not a Valid JPEG File");
+ // // int Each_component2 = read_byte("Each_component2", is,
+ // // "Not a Valid JPEG File");
+ // // int Each_component3 = read_byte("Each_component3", is,
+ // // "Not a Valid JPEG File");
+ // }
+
+ if (getDebug())
+ System.out.println("");
+ }
+
+ public String getDescription()
+ {
+ return "SOS (" + getSegmentType() + ")";
+ }
+
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOSSegment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/Segment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/Segment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/Segment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/Segment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.segments;
+
+import java.io.PrintWriter;
+
+import org.apache.sanselan.common.BinaryFileParser;
+
+public abstract class Segment extends BinaryFileParser
+{
+ public final int marker;
+ public final int length;
+
+ public Segment(int marker, int length)
+ {
+ // super();
+
+ this.marker = marker;
+ this.length = length;
+ }
+
+ public void dump(PrintWriter pw)
+ {
+ }
+
+ public abstract String getDescription();
+
+ public String getSegmentType()
+ {
+
+ switch (marker)
+ {
+ case 0xffc0 :
+ return "Start Of Frame, Baseline DCT, Huffman coding";
+ case 0xffc1 :
+ return "Start Of Frame, Extended sequential DCT, Huffman coding";
+ case 0xffc2 :
+ return "Start Of Frame, Progressive DCT, Huffman coding";
+ case 0xffc3 :
+ return "Start Of Frame, Lossless (sequential), Huffman coding";
+
+ case 0xffc5 :
+ return "Start Of Frame, Differential sequential DCT, Huffman coding";
+ case 0xffc6 :
+ return "Start Of Frame, Differential progressive DCT, Huffman coding";
+ case 0xffc7 :
+ return "Start Of Frame, Differential lossless (sequential), Huffman coding";
+
+ case 0xffc8 :
+ return "Start Of Frame, Reserved for JPEG extensions, arithmetic coding";
+ case 0xffc9 :
+ return "Start Of Frame, Extended sequential DCT, arithmetic coding";
+ case 0xffca :
+ return "Start Of Frame, Progressive DCT, arithmetic coding";
+ case 0xffcb :
+ return "Start Of Frame, Lossless (sequential), arithmetic coding";
+
+ case 0xffcd :
+ return "Start Of Frame, Differential sequential DCT, arithmetic coding";
+ case 0xffce :
+ return "Start Of Frame, Differential progressive DCT, arithmetic coding";
+ case 0xffcf :
+ return "Start Of Frame, Differential lossless (sequential), arithmetic coding";
+
+ case 0xffc4 :
+ return "Define Huffman table(s)";
+ case 0xffcc :
+ return "Define arithmetic coding conditioning(s)";
+
+ case 0xffd0 :
+ return "Restart with modulo 8 count 0";
+ case 0xffd1 :
+ return "Restart with modulo 8 count 1";
+ case 0xffd2 :
+ return "Restart with modulo 8 count 2";
+ case 0xffd3 :
+ return "Restart with modulo 8 count 3";
+ case 0xffd4 :
+ return "Restart with modulo 8 count 4";
+ case 0xffd5 :
+ return "Restart with modulo 8 count 5";
+ case 0xffd6 :
+ return "Restart with modulo 8 count 6";
+ case 0xffd7 :
+ return "Restart with modulo 8 count 7";
+
+ case 0xffd8 :
+ return "Start of image";
+ case 0xffd9 :
+ return "End of image";
+ case 0xffda :
+ return "Start of scan";
+ case 0xffdb :
+ return "Define quantization table(s)";
+ case 0xffdc :
+ return "Define number of lines";
+ case 0xffdd :
+ return "Define restart interval";
+ case 0xffde :
+ return "Define hierarchical progression";
+ case 0xffdf :
+ return "Expand reference component(s)";
+ // case 0xffd8 :
+ // return "Reserved for application segments";
+ // case 0xffd8 :
+ // return "Reserved for JPEG extensions";
+ case 0xfffe :
+ return "Comment";
+ case 0xff01 :
+ return "For temporary private use in arithmetic coding";
+ // case 0xffd8 :
+ // return "Reserved";
+
+ default :
+ }
+
+ if ((marker >= 0xff02) && (marker <= 0xffbf))
+ return "Reserved";
+ if ((marker >= 0xffe0) && (marker <= 0xffef))
+ return "APP" + (marker - 0xffe0);
+ if ((marker >= 0xfff0) && (marker <= 0xfffd))
+ return "JPG" + (marker - 0xffe0);
+
+ return "Unknown";
+
+ }
+
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/Segment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/UnknownSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/UnknownSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/UnknownSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/UnknownSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.jpeg.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+
+public class UnknownSegment extends GenericSegment
+{
+ public UnknownSegment(int marker, int marker_length, InputStream is)
+ throws ImageReadException, IOException
+ {
+ super(marker, marker_length, is);
+ }
+
+ public String getDescription()
+ {
+ return "Unknown (" + getSegmentType() + ")";
+ }
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/UnknownSegment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.png;
+
+import java.io.IOException;
+
+import org.apache.sanselan.ImageReadException;
+
+public class BitParser
+{
+ private final byte bytes[];
+ private final int BitsPerPixel;
+ private final int BitDepth;
+
+ public BitParser(byte bytes[], int BitsPerPixel, int BitDepth)
+ {
+ this.bytes = bytes;
+ this.BitsPerPixel = BitsPerPixel;
+ this.BitDepth = BitDepth;
+ }
+
+ public int getSample(int pixel_index_in_scanline, int SampleIndex)
+ throws ImageReadException, IOException
+ {
+ int pixel_index_bits = BitsPerPixel * pixel_index_in_scanline;
+ int sample_index_bits = pixel_index_bits + (SampleIndex * BitDepth);
+ // int sample_index_bytes = sample_index_bits / 8;
+ int sample_index_bytes = sample_index_bits >> 3;
+ // int sample_index_bytes = pixel_index_bits / 8;
+
+ // System.out.println("sample_index_bytes: " + sample_index_bytes);
+
+ if (BitDepth == 8)
+ return 0xff & bytes[sample_index_bytes];
+ else if (BitDepth < 8)
+ {
+ int b = 0xff & bytes[sample_index_bytes];
+ // int bits_to_shift = 8 - ((pixel_index_bits % 8) + BitsPerPixel);
+ int bits_to_shift = 8 - ((pixel_index_bits & 7) + BitDepth);
+ // int bits_to_shift = 8 - ((pixel_index_bits % 8) + BitDepth);
+ b >>= bits_to_shift;
+
+ int bitmask = (1 << BitDepth) - 1;
+ return b & bitmask;
+ // switch (BitDepth)
+ // {
+ // case 1 :
+ // return b & 1;
+ // case 2 :
+ // return b & 3;
+ // case 4 :
+ // return b & 15;
+ // }
+ }
+ else if (BitDepth == 16)
+ {
+ return ((0xff & (bytes[sample_index_bytes] << 8)) | (0xff & bytes[sample_index_bytes + 1]));
+ }
+
+ throw new ImageReadException("PNG: bad BitDepth: " + BitDepth);
+ }
+
+ public int getSampleAsByte(int pixel_index_in_scanline, int SampleIndex)
+ throws ImageReadException, IOException
+ {
+ int sample = getSample(pixel_index_in_scanline, SampleIndex);
+ int rot = 8 - BitDepth;
+ if (rot > 0)
+ sample <<= rot;
+ else if (rot < 0)
+ sample >>= -rot;
+ return 0xff & sample;
+ }
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.png;
+
+public class GammaCorrection
+{
+ // private final double src_gamma, dst_gamma;
+ private final int lookup_table[];
+
+ public GammaCorrection(double src_gamma, double dst_gamma)
+ {
+ // this.src_gamma = src_gamma;
+ // this.dst_gamma = dst_gamma;
+ System.out.println("src_gamma: " + src_gamma);
+ System.out.println("dst_gamma: " + dst_gamma);
+
+ lookup_table = new int[256];
+ for (int i = 0; i < 256; i++)
+ {
+ lookup_table[i] = correctSample(i, src_gamma, dst_gamma);
+ System.out.println("lookup_table[" + i + "]: " + lookup_table[i]);
+ }
+ }
+
+ public int correctSample(int sample)
+ {
+ return lookup_table[sample];
+ }
+
+ public int correctARGB(int pixel)
+ {
+ int alpha = (0xff000000) & pixel;
+ int red = (pixel & 0xff) >> 16;
+ int green = (pixel & 0xff) >> 8;
+ int blue = (pixel & 0xff) >> 0;
+
+ red = correctSample(red);
+ green = correctSample(green);
+ blue = correctSample(blue);
+
+ int rgb = alpha | ((0xff & red) << 16) | ((0xff & green) << 8)
+ | ((0xff & blue) << 0);
+
+ return rgb;
+ }
+
+ private int correctSample(int sample, double src_gamma, double dst_gamma)
+ {
+ // if (kUseAdobeGammaMethod && val <= 32)
+ // {
+ // double slope = Math.round(255.0d * Math.pow((32.0 / 255.0d),
+ // src_gamma / dst_gamma)) / 32.d;
+ // return (int) (sample * slope);
+ // }
+
+ return (int) Math.round(255.0d * Math.pow((sample / 255.0d), src_gamma
+ / dst_gamma));
+ }
+
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.png;
+
+import org.apache.sanselan.SanselanConstants;
+
+public interface PngConstants extends SanselanConstants
+{
+
+ public static final int COMPRESSION_DEFLATE_INFLATE = 0;
+
+ public final static byte[] IHDR_CHUNK_TYPE = new byte[]{
+ 73, 72, 68, 82
+ };
+ public final static byte[] PLTE_CHUNK_TYPE = new byte[]{
+ 80, 76, 84, 69
+ };
+ public final static byte[] IEND_CHUNK_TYPE = new byte[]{
+ 73, 69, 78, 68
+ };
+ public final static byte[] IDAT_CHUNK_TYPE = new byte[]{
+ 73, 68, 65, 84
+ };
+
+ public final static int IEND = PngImageParser.CharsToQuad('I', 'E', 'N',
+ 'D');
+ public final static int IHDR = PngImageParser.CharsToQuad('I', 'H', 'D',
+ 'R');
+ public final static int iCCP = PngImageParser.CharsToQuad('i', 'C', 'C',
+ 'P');
+ public final static int tEXt = PngImageParser.CharsToQuad('t', 'E', 'X',
+ 't');
+ public final static int zTXt = PngImageParser.CharsToQuad('z', 'T', 'X',
+ 't');
+ public final static int pHYs = PngImageParser.CharsToQuad('p', 'H', 'Y',
+ 's');
+ public final static int PLTE = PngImageParser.CharsToQuad('P', 'L', 'T',
+ 'E');
+ public final static int IDAT = PngImageParser.CharsToQuad('I', 'D', 'A',
+ 'T');
+ public final static int tRNS = PngImageParser.CharsToQuad('t', 'R', 'N',
+ 'S');
+ public final static int gAMA = PngImageParser.CharsToQuad('g', 'A', 'M',
+ 'A');
+ public final static int sRGB = PngImageParser.CharsToQuad('s', 'R', 'G',
+ 'B');
+
+ public static final byte PNG_Signature[] = {
+ (byte) 137, 80, 78, 71, 13, 10, 26, 10,
+ };
+
+ public static final String PARAM_KEY_PNG_BIT_DEPTH = "PNG_BIT_DEPTH";
+ public static final String PARAM_KEY_PNG_FORCE_INDEXED_COLOR = "PNG_FORCE_INDEXED_COLOR";
+ public static final String PARAM_KEY_PNG_FORCE_TRUE_COLOR = "PNG_FORCE_TRUE_COLOR";
+
+ // public static final Object PARAM_KEY_PNG_BIT_DEPTH_YES = "YES";
+ // public static final Object PARAM_KEY_PNG_BIT_DEPTH_NO = "NO";
+
+ public static final int COLOR_TYPE_GREYSCALE = 0;
+ public static final int COLOR_TYPE_TRUE_COLOR = 2;
+ public static final int COLOR_TYPE_INDEXED_COLOR = 3;
+ public static final int COLOR_TYPE_GREYSCALE_WITH_ALPHA = 4;
+ public static final int COLOR_TYPE_TRUE_COLOR_WITH_ALPHA = 6;
+
+ public static final byte COMPRESSION_TYPE_INFLATE_DEFLATE = 0;
+ public static final byte FILTER_METHOD_ADAPTIVE = 0;
+
+ public static final byte INTERLACE_METHOD_NONE = 0;
+ public static final byte INTERLACE_METHOD_ADAM7 = 1;
+
+ public static final byte FILTER_TYPE_NONE = 0;
+ public static final byte FILTER_TYPE_SUB = 1;
+ public static final byte FILTER_TYPE_UP = 2;
+ public static final byte FILTER_TYPE_AVERAGE = 3;
+ public static final byte FILTER_TYPE_PAETH = 4;
+
+ /*
+ Background colour Solid background colour to be used when presenting the image if no better option is available.
+ Gamma and chromaticity Gamma characteristic of the image with respect to the desired output intensity, and chromaticity characteristics of the RGB values used in the image.
+ ICC profile Description of the colour space (in the form of an International Color Consortium (ICC) profile) to which the samples in the image conform.
+ Image histogram Estimates of how frequently the image uses each palette entry.
+ Physical pixel dimensions Intended pixel size and aspect ratio to be used in presenting the PNG image.
+ Significant bits The number of bits that are significant in the samples.
+ sRGB colour space A rendering intent (as defined by the International Color Consortium) and an indication that the image samples conform to this colour space.
+ Suggested palette A reduced palette that may be used when the display device is not capable of displaying the full range of colours in the image.
+ Textual data Textual information (which may be compressed) associated with the image.
+ Time The time when the PNG image was last modified.
+ Transparency Alpha information that allows the reference image to be reconstructed when the alpha channel is not retained in the PNG image.
+ */
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.formats.png;
+
+// should just use ints, not longs
+public class PngCrc
+{
+ /* Table of CRCs of all 8-bit messages. */
+ private final long crc_table[] = new long[256];
+
+ /* Flag: has the table been computed? Initially false. */
+ private boolean crc_table_computed = false;
+
+ /* Make the table for a fast CRC. */
+ private void make_crc_table()
+ {
+ long c;
+ int n, k;
+
+ for (n = 0; n < 256; n++)
+ {
+ c = n;
+ for (k = 0; k < 8; k++)
+ {
+ if ((c & 1) != 0)
+
+ c = 0xedb88320L ^ (c >> 1);
+ else
+ c = c >> 1;
+ }
+ crc_table[n] = c;
+ }
+ crc_table_computed = true;
+ }
+
+ /* Update a running CRC with the bytes buf[0..len-1]--the CRC
+ should be initialized to all 1's, and the transmitted value
+ is the 1's complement of the final running CRC (see the
+ crc() routine below)). */
+
+ private final long update_crc(long crc, byte buf[])
+ {
+ long c = crc;
+ int n;
+
+ if (!crc_table_computed)
+ make_crc_table();
+ for (n = 0; n < buf.length; n++)
+ {
+ // Debug.debug("crc[" + n + "]", c + " (" + Long.toHexString(c) + ")");
+
+ c = crc_table[(int) ((c ^ buf[n]) & 0xff)] ^ (c >> 8);
+ }
+ return c;
+ }
+
+ /* Return the CRC of the bytes buf[0..len-1]. */
+ public final int crc(byte buf[], int len)
+ {
+ return (int) (update_crc(0xffffffffL, buf) ^ 0xffffffffL);
+ }
+
+ public final long start_partial_crc(byte buf[], int len)
+ {
+ return update_crc(0xffffffffL, buf);
+ }
+
+ public final long continue_partial_crc(long old_crc, byte buf[], int len)
+ {
+ return update_crc(old_crc, buf);
+ }
+
+ public final long finish_partial_crc(long old_crc)
+ {
+ return (old_crc ^ 0xffffffffL);
+ }
+}
\ No newline at end of file
Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java
------------------------------------------------------------------------------
svn:eol-style = native