1 /* 2 * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.imageio.plugins.tiff; 26 27 import java.io.IOException; 28 import java.io.ByteArrayInputStream; 29 import java.util.Iterator; 30 import javax.imageio.ImageIO; 31 import javax.imageio.ImageReader; 32 import javax.imageio.ImageReadParam; 33 import javax.imageio.stream.MemoryCacheImageInputStream; 34 import javax.imageio.stream.ImageInputStream; 35 import javax.imageio.plugins.tiff.BaselineTIFFTagSet; 36 import javax.imageio.plugins.tiff.TIFFField; 37 38 public class TIFFJPEGDecompressor extends TIFFDecompressor { 39 // Start of Image 40 protected static final int SOI = 0xD8; 41 42 // End of Image 43 protected static final int EOI = 0xD9; 44 45 protected ImageReader JPEGReader = null; 46 protected ImageReadParam JPEGParam; 47 48 protected boolean hasJPEGTables = false; 49 protected byte[] tables = null; 50 51 private byte[] data = new byte[0]; 52 TIFFJPEGDecompressor()53 public TIFFJPEGDecompressor() {} 54 beginDecoding()55 public void beginDecoding() { 56 // Initialize the JPEG reader if needed. 57 if(this.JPEGReader == null) { 58 // Get all JPEG readers. 59 Iterator<ImageReader> iter = ImageIO.getImageReadersByFormatName("jpeg"); 60 61 if(!iter.hasNext()) { 62 throw new IllegalStateException("No JPEG readers found!"); 63 } 64 65 // Initialize reader to the first one. 66 this.JPEGReader = iter.next(); 67 68 this.JPEGParam = JPEGReader.getDefaultReadParam(); 69 } 70 71 // Get the JPEGTables field. 72 TIFFImageMetadata tmetadata = (TIFFImageMetadata)metadata; 73 TIFFField f = 74 tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_TABLES); 75 76 if (f != null) { 77 this.hasJPEGTables = true; 78 this.tables = f.getAsBytes(); 79 } else { 80 this.hasJPEGTables = false; 81 } 82 } 83 decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, int scanlineStride)84 public void decodeRaw(byte[] b, 85 int dstOffset, 86 int bitsPerPixel, 87 int scanlineStride) throws IOException { 88 // Seek to the data position for this segment. 89 stream.seek(offset); 90 91 // Set the stream variable depending on presence of JPEGTables. 92 ImageInputStream is; 93 if(this.hasJPEGTables) { 94 // The current strip or tile is an abbreviated JPEG stream. 95 96 // Reallocate memory if there is not enough already. 97 int dataLength = tables.length + byteCount; 98 if(data.length < dataLength) { 99 data = new byte[dataLength]; 100 } 101 102 // Copy the tables ignoring any EOI and subsequent bytes. 103 int dataOffset = tables.length; 104 for(int i = tables.length - 2; i > 0; i--) { 105 if((tables[i] & 0xff) == 0xff && 106 (tables[i+1] & 0xff) == EOI) { 107 dataOffset = i; 108 break; 109 } 110 } 111 System.arraycopy(tables, 0, data, 0, dataOffset); 112 113 // Check for SOI and skip it if present. 114 byte byte1 = (byte)stream.read(); 115 byte byte2 = (byte)stream.read(); 116 if(!((byte1 & 0xff) == 0xff && (byte2 & 0xff) == SOI)) { 117 data[dataOffset++] = byte1; 118 data[dataOffset++] = byte2; 119 } 120 121 // Read remaining data. 122 stream.readFully(data, dataOffset, byteCount - 2); 123 124 // Create ImageInputStream. 125 ByteArrayInputStream bais = new ByteArrayInputStream(data); 126 is = new MemoryCacheImageInputStream(bais); 127 } else { 128 // The current strip or tile is a complete JPEG stream. 129 is = stream; 130 } 131 132 // Set the stream on the reader. 133 JPEGReader.setInput(is, false, true); 134 135 // Set the destination to the raw image ignoring the parameters. 136 JPEGParam.setDestination(rawImage); 137 138 // Read the strip or tile. 139 JPEGReader.read(0, JPEGParam); 140 } 141 142 @SuppressWarnings("deprecation") finalize()143 protected void finalize() throws Throwable { 144 super.finalize(); 145 JPEGReader.dispose(); 146 } 147 } 148