001 /* 002 * TIFFDecoderLogLuv 003 * 004 * Copyright (c) 2002, 2003 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.codecs.tiff; 009 010 import java.io.DataInput; 011 import java.io.IOException; 012 import net.sourceforge.jiu.codecs.tiff.TIFFConstants; 013 import net.sourceforge.jiu.codecs.tiff.TIFFDecoder; 014 import net.sourceforge.jiu.codecs.InvalidFileStructureException; 015 import net.sourceforge.jiu.ops.MissingParameterException; 016 017 /** 018 * A TIFF decoder for files compressed with the <em>LogLuv RLE</em> method. 019 * This compression algorithm has the value <code>34676</code> 020 * ({@link TIFFConstants#COMPRESSION_SGI_LOG_RLE}) 021 * in the compression tag of an image file directory. 022 * Only image data with a photometric interpretation value of 023 * {@link TIFFConstants#PHOTOMETRIC_TRUECOLOR_LOGLUV} can be compressed with this method. 024 * <p> 025 * This implementation is based on the file <code>tif_luv.c</code> which 026 * is part of the TIFF library <a target="_top" href="http://www.libtiff.org">libtiff</a>. 027 * The original implementation was written by Greg W. Larson. 028 * <p> 029 * Learn more about the color type and its encoding on Greg's page 030 * <a target="_top" href="http://positron.cs.berkeley.edu/~gwlarson/pixformat/tiffluv.html">LogLuv 031 * Encoding for TIFF Images</a>. 032 * You will also find numerous sample image files there. 033 * @author Marco Schmidt 034 * @since 0.10.0 035 */ 036 public class TIFFDecoderLogLuv extends TIFFDecoder 037 { 038 private DataInput in; 039 private int compressedSize; 040 private int tileWidth; 041 private boolean rle; 042 043 public void decode() throws 044 InvalidFileStructureException, 045 IOException 046 { 047 byte[] row = new byte[getBytesPerRow()]; 048 rle = getImageFileDirectory().getCompression() == TIFFConstants.COMPRESSION_SGI_LOG_RLE; 049 for (int y = getY1(); y <= getY2(); y++) 050 { 051 decodeRow(row); 052 putBytes(row, 0, row.length); 053 } 054 } 055 056 private void decodeRow(byte[] row) throws 057 InvalidFileStructureException, 058 IOException 059 { 060 if (rle) 061 { 062 decodeRowRLE(row); 063 } 064 else 065 { 066 decodeRowPacked24(row); 067 } 068 } 069 070 private void decodeRowPacked24(byte[] row) throws 071 InvalidFileStructureException, 072 IOException 073 { 074 int num = getImageFileDirectory().getTileWidth() * 3; 075 in.readFully(row, 0, num); 076 } 077 078 private void decodeRowRLE(byte[] row) throws 079 InvalidFileStructureException, 080 IOException 081 { 082 final int BYTES_PER_PIXEL; 083 if (getImageFileDirectory().getPhotometricInterpretation() == TIFFConstants.PHOTOMETRIC_LOGL) 084 { 085 BYTES_PER_PIXEL = 2; // LogL 086 } 087 else 088 { 089 BYTES_PER_PIXEL = 4; // LogLuv 090 } 091 for (int initialOffset = 0; initialOffset < BYTES_PER_PIXEL; initialOffset++) 092 { 093 int offset = initialOffset; 094 int numPixels = tileWidth; 095 do 096 { 097 int v1 = in.readUnsignedByte(); 098 if ((v1 & 128) != 0) 099 { 100 // run 101 int runCount = v1 + (2 - 128); 102 numPixels -= runCount; 103 compressedSize -= 2; 104 byte v2 = in.readByte(); 105 while (runCount-- != 0) 106 { 107 row[offset] = v2; 108 offset += BYTES_PER_PIXEL; 109 } 110 } 111 else 112 { 113 // non-run, copy data 114 int runCount = v1; 115 numPixels -= runCount; 116 compressedSize = compressedSize - runCount - 1; 117 while (runCount-- != 0) 118 { 119 row[offset] = in.readByte(); 120 offset += BYTES_PER_PIXEL; 121 } 122 } 123 if (compressedSize < 0) 124 { 125 throw new InvalidFileStructureException("Ran out of compressed input bytes before completing the decoding process."); 126 } 127 } 128 while (numPixels > 0); 129 } 130 } 131 132 public Integer[] getCompressionTypes() 133 { 134 return new Integer[] {new Integer(TIFFConstants.COMPRESSION_SGI_LOG_RLE), new Integer(TIFFConstants.COMPRESSION_SGI_LOG_24_PACKED)}; 135 } 136 137 public void initialize() throws 138 IOException, 139 MissingParameterException 140 { 141 super.initialize(); 142 in = getInput(); 143 compressedSize = getImageFileDirectory().getByteCount(getTileIndex()); 144 tileWidth = getImageFileDirectory().getTileWidth(); 145 } 146 }