/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.imaging.formats.jpeg; import java.io.IOException; import java.io.InputStream; import org.apache.commons.imaging.ImageReadException; import org.apache.commons.imaging.common.BinaryFileParser; import org.apache.commons.imaging.common.ByteOrder; import org.apache.commons.imaging.common.bytesource.ByteSource; import org.apache.commons.imaging.util.Debug; public class JpegUtils extends BinaryFileParser implements JpegConstants { public JpegUtils() { setByteOrder(ByteOrder.NETWORK); } public static interface Visitor { // return false to exit before reading image data. public boolean beginSOS(); public void visitSOS(int marker, byte markerBytes[], byte imageData[]); // return false to exit traversal. public boolean visitSegment(int marker, byte markerBytes[], int segmentLength, byte segmentLengthBytes[], byte segmentData[]) throws ImageReadException, IOException; } public void traverseJFIF(final ByteSource byteSource, final Visitor visitor) throws ImageReadException, IOException { InputStream is = null; try { is = byteSource.getInputStream(); readAndVerifyBytes(is, SOI, "Not a Valid JPEG File: doesn't begin with 0xffd8"); int markerCount; for (markerCount = 0; true; markerCount++) { final byte[] markerBytes = new byte[2]; do { markerBytes[0] = markerBytes[1]; markerBytes[1] = readByte("marker", is, "Could not read marker"); } while ((0xff & markerBytes[0]) != 0xff || (0xff & markerBytes[1]) == 0xff); final int marker = ((0xff & markerBytes[0]) << 8) | (0xff & markerBytes[1]); if (marker == EOIMarker || marker == SOS_Marker) { if (!visitor.beginSOS()) { return; } final byte imageData[] = getStreamBytes(is); visitor.visitSOS(marker, markerBytes, imageData); break; } final byte segmentLengthBytes[] = readBytes("segmentLengthBytes", is, 2, "segmentLengthBytes"); final int segmentLength = toUInt16(segmentLengthBytes); final byte segmentData[] = readBytes("Segment Data", is, segmentLength - 2, "Invalid Segment: insufficient data"); if (!visitor.visitSegment(marker, markerBytes, segmentLength, segmentLengthBytes, segmentData)) { return; } } Debug.debug("" + markerCount + " markers"); } finally { try { if (is != null) { is.close(); } } catch (final Exception e) { Debug.debug(e); } } } public static String getMarkerName(final int marker) { switch (marker) { case SOS_Marker: return "SOS_Marker"; // case JPEG_APP0 : // return "JPEG_APP0"; // case JPEG_APP0_Marker : // return "JPEG_APP0_Marker"; case JPEG_APP1_Marker: return "JPEG_APP1_Marker"; case JPEG_APP2_Marker: return "JPEG_APP2_Marker"; case JPEG_APP13_Marker: return "JPEG_APP13_Marker"; case JPEG_APP14_Marker: return "JPEG_APP14_Marker"; case JPEG_APP15_Marker: return "JPEG_APP15_Marker"; case JFIFMarker: return "JFIFMarker"; case SOF0Marker: return "SOF0Marker"; case SOF1Marker: return "SOF1Marker"; case SOF2Marker: return "SOF2Marker"; case SOF3Marker: return "SOF3Marker"; case DHTMarker: return "SOF4Marker"; case SOF5Marker: return "SOF5Marker"; case SOF6Marker: return "SOF6Marker"; case SOF7Marker: return "SOF7Marker"; case SOF8Marker: return "SOF8Marker"; case SOF9Marker: return "SOF9Marker"; case SOF10Marker: return "SOF10Marker"; case SOF11Marker: return "SOF11Marker"; case DACMarker: return "DACMarker"; case SOF13Marker: return "SOF13Marker"; case SOF14Marker: return "SOF14Marker"; case SOF15Marker: return "SOF15Marker"; case DQTMarker: return "DQTMarker"; default: return "Unknown"; } } public void dumpJFIF(final ByteSource byteSource) throws ImageReadException, IOException { final Visitor visitor = new Visitor() { // return false to exit before reading image data. public boolean beginSOS() { return true; } public void visitSOS(final int marker, final byte markerBytes[], final byte imageData[]) { Debug.debug("SOS marker. " + imageData.length + " bytes of image data."); Debug.debug(""); } // return false to exit traversal. public boolean visitSegment(final int marker, final byte markerBytes[], final int segmentLength, final byte segmentLengthBytes[], final byte segmentData[]) { Debug.debug("Segment marker: " + Integer.toHexString(marker) + " (" + getMarkerName(marker) + "), " + segmentData.length + " bytes of segment data."); return true; } }; traverseJFIF(byteSource, visitor); } }