Skip to main content

[JAI] Converting CCITT stream into TIFF

2 replies [Last post]
Anonymous

Hi,

I am trying to convert a CCITT stream from a PDF into a TIFF. I have
saved out a sample image to identify the required TIFF tags and am
trying to replicate this, merely replacing the data and altering the
required values. My code is not producing valid tiff files :-(

Any suggestions where I am going wrong.

Regards,

MArk

writeWord, writeDWord and WriteTag write a Word (2 bytes), Dword (4
bytes) or tag (12 bytes) to my stream

This code creates the stream (I have K and data from the PDF.

/**
* build the image
*/
ByteArrayOutputStream bos=new ByteArrayOutputStream();

/**
* tiff header (id, version, offset)
* */
String[] headerValues={"4d","4d","00","2a","00","00","00","08"};
for(int i=0;i 0)
writeTag("259", "03", "01", "00030000", bos); /**compression 259 */
else if (k < 0)
writeTag("259", "03", "01", "00040000", bos); /**compression 259 */

if(isBlack)
writeTag("262", "03", "01", "00000000", bos);
/**photometricInterpretation 262 */
else
writeTag("262", "03", "01", "00010000", bos);
/**photometricInterpretation 262 */

writeTag("273", "04", "01", "7Ah", bos); /**stripOffsets 273 */
writeTag("277", "03", "01", "00010000", bos); /**samplesPerPixel
277 */
writeTag("278", "04", "01", "01", bos); /**rowsPerStrip 278 */
writeTag("279", "04", "01", ""+((w | 8 )>>3), bos);
/**stripByteCount 279 */

/** write next IOD offset */
writeDWord("0",bos);

try {

bos.close();

java.io.FileOutputStream fos=new
java.io.FileOutputStream("test.tiff");
fos.write(bos.toByteArray());
fos.close();

} catch (Exception e1) {
e1.printStackTrace();
}

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mark.stephens@ukonline.co.uk

I've been writing some code to decode a CCITT stream from a PDF by
adding a tiff header and using the JAI decoding routines (which seem
to be more uptodate than the class TiffFaxDecoder.java which Sun
released some years ago). This is being used in our Java PDF renderer
(www.jpedal.org) if you wish to see it in action.

Here is the code, if anyone else is interested.

I have found it appears to fail on some CCITT streams which the old
version handled correctly (mainly type3 fonts) so I still use the old
code for this. I will keep investigating this and post some more
details.

Please feel free to use the code for any purpose.

Hope it is of use. Please let me know any enhancements or fixes so I
can update.

Regards,

MArk

/**
*
* This code is distributed as an example of how to create
* a tiff from a CCITT stream as is with no warranty or guarantee
*
* Please feel free to use any or all of this code
*
* ---------------
* TiffDecoder.java
* ---------------
*
* @author: mark@idrsolutions.com
*
* --------------------------
*/
package org.jpedal.io;

import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;

import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;

import org.jpedal.gui.ShowGUIMessage;
import org.jpedal.utils.LogWriter;

import com.sun.media.jai.codec.ByteArraySeekableStream;

/**
* converts CCITT stream into either an image of bytestream
*
* Many thanks to Brian Burkhalter for all his help
*/
public class TiffDecoder {

byte[] bytes;

/**
* called with values from PDF
* Map contains values from PDF as stream pair
*/
public TiffDecoder(int w, int h,Map values,byte[] data){

//return value
bytes=null;

/**
* get values from stream
*/
//flag to show if default is black or white
boolean isBlack = false;
//int columns = 1728; //in PDF spec
int k = 0;
//boolean isByteAligned=false; //in PDF spec

//get k (type of encoding)
String value = (String) values.get("K");
if (value != null)
k = Integer.parseInt(value);

/**
//get flag for white/black as default
value = (String) values.get("EncodedByteAlign");
if (value != null)
isByteAligned =
Boolean.valueOf(value).booleanValue();*/

//get flag for white/black as default
value = (String) values.get("BlackIs1");
if (value != null){
isBlack = Boolean.valueOf(value).booleanValue();

}

/**not used but in Map from PDF
value = (String) values.get("Rows");
if (value != null)
rows = Integer.parseInt(value);

value = (String) values.get("Columns");
if (value != null)
columns= Integer.parseInt(value); */

/**
* build the image
*/
ByteArrayOutputStream bos=new ByteArrayOutputStream();

/**
* tiff header (id, version, offset)
* */
final String[] headerValues={"4d","4d","00","2a","00","00",
"00","08"};
for(int i=0;i bos.write(Integer.parseInt(headerValues[i],16));

int tagCount=9; //appears to be minimum needed
int stripCount=1; //1 strip with all CCITT data

/**
* write IFD image file directory
*/
writeWord(""+tagCount,bos); //num of directory entries
writeTag("256", "04", "01", ""+w, bos); /**image
width*/
writeTag("257", "04", "01", ""+h, bos); /**image
length*/
writeTag("258", "03", "01", "00010000h", bos);
/**BitsPerSample 258 - b&w 1 bit image*/

if (k == 0){
writeTag("259", "03", "01", "00030000h", bos);
/**compression 259 */
}else if (k > 0)
writeTag("259", "03", "01", "00020000h", bos);
/**compression 259 */
else if (k < 0)
writeTag("259", "03", "01", "00040000h", bos);
/**compression 259 */

if(!isBlack)
writeTag("262", "03", "01", "00000000h", bos);
/**photometricInterpretation 262 */
else
writeTag("262", "03", "01", "00010000h", bos);
/**photometricInterpretation 262 */

writeTag("273", "04", "1","122", bos); /**stripOffsets
273 -start of data after tables */
writeTag("277", "03", "01", "00010000h", bos);
/**samplesPerPixel 277 */
writeTag("278", "04", "01", ""+h, bos); /**rowsPerStrip
278 - uses height */
writeTag("279", "04", "1", ""+data.length,bos);
/**stripByteCount 279 - 1 strip so all data */
writeDWord("0",bos); /** write next IOD offset zero as
no other table*/

/**
* write the CCITT image data at the end
*/
try{

bos.write(data);
bos.close();

} catch (IOException e) {
e.printStackTrace();
}

/**setup image */
try {

/**write out to debug*
java.io.FileOutputStream fos=new
java.io.FileOutputStream("macX2test.tiff");
fos.write(bos.toByteArray());
fos.close();
/***/

ByteArraySeekableStream fss=new
ByteArraySeekableStream(bos.toByteArray());//.wrapInputStrea
m(bis,true);

RenderedOp op = (JAI.create("stream",fss));

Raster raster=op.getData();

//Raster raster = img2.getData();
DataBuffer db = raster.getDataBuffer();

DataBufferByte dbb = (DataBufferByte) db;

bytes=dbb.getData();

if(!isBlack){ //invert if needed
int bcount=bytes.length;
for(int i=0;i bytes[i]= (byte) (255-(bytes[i]));
}
}

} catch (Error err) {
LogWriter.writeLog("[PDF] Tiff error "+err);
//
// System.exit(1);
//
} catch (Exception e1) {
e1.printStackTrace();
//
// System.exit(1);
//
}
}

/**return raw bytes from image*/
public byte[] getRawBytes(){

return bytes;

}

/**write word (2 bytes to stream) */
private void writeWord(String i, ByteArrayOutputStream bos)
{

int value=0;

//allow decimal,octal or hex
if(i.endsWith("h"))
value=Integer.parseInt(i.substring(0,i.length()-1),16);
else if(i.endsWith("o"))
value=Integer.parseInt(i.substring(0,i.length()-1),8);
else
value=Integer.parseInt(i);

bos.write((value>>8)); //high byte
bos.write(value & 0xFF); //low byte

}

/**write Dword (4 bytes to stream) */
private void writeDWord(String i, ByteArrayOutputStream bos)
{

int value=0;

//allow decimal,octal or hex
if(i.endsWith("h"))
value=Integer.parseInt(i.substring(0,i.length()-1),16);
else if(i.endsWith("o"))
value=Integer.parseInt(i.substring(0,i.length()-1),8);
else
value=Integer.parseInt(i);

bos.write((value>>24) & 0xff); //high byte
bos.write((value>>16) & 0xff);
bos.write((value>>8) & 0xff);
bos.write(value & 0xFF); //low byte

}

/**write a tag to stream*/
private void writeTag(String TagId, String dataType, String
DataCount, String DataOffset, ByteArrayOutputStream bos) {

writeWord(TagId,bos);
writeWord(dataType,bos);
writeDWord(DataCount,bos);
writeDWord(DataOffset,bos);

}

}

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

Brian Burkhalter

Please note that this thread has been resolved via discussion outside the
mailing list. The solution was to construct the TIFF header and IFD with the
expected contents for a Group 4-compressed bilevel data set.

One thing to note concerns the group 4 stream. This stream was available as a
single byte array. As no information was defined in terms of how the stream
might be split into strips (a TIFF concept as opposed to a CCITT/ITU concept)
it had to be assumed that the stream represented the embedded image as a
single group 4 block. Without prior knowledge as to how the stream might be
split it would be very difficult to detect strips in any case as with group 4
only the first row is 1D-encoded.

Brian

On Wed, 25 May 2005 mark.stephens@ukonline.co.uk wrote:

> Hi,
>
> I am trying to convert a CCITT stream from a PDF into a TIFF. I have
> saved out a sample image to identify the required TIFF tags and am
> trying to replicate this, merely replacing the data and altering the
> required values. My code is not producing valid tiff files :-(
>
> Any suggestions where I am going wrong.
>
> Regards,
>
> MArk
>
> writeWord, writeDWord and WriteTag write a Word (2 bytes), Dword (4
> bytes) or tag (12 bytes) to my stream
>
>
> This code creates the stream (I have K and data from the PDF.
>
> /**
> * build the image
> */
> ByteArrayOutputStream bos=new ByteArrayOutputStream();
>
> /**
> * tiff header (id, version, offset)
> * */
> String[] headerValues={"4d","4d","00","2a","00","00","00","08"};
> for(int i=0;i > bos.write(Integer.parseInt(headerValues[i],16));
>
> //write the CCITT image data
> try{
> bos.write(data);
>
>
> } catch (IOException e) {
> e.printStackTrace();
> }
>
> /**
> * write IFD image file directory
> */
> writeWord("9",bos); //num of directory entries
> writeTag("256", "04", "01", ""+w, bos); /**image width*/
> writeTag("257", "04", "01", ""+h, bos); /**image length*/
> writeTag("258", "03", "01", "00010000h", bos); /**BitsPerSample
> 258 */
>
> if (k == 0)
> writeTag("259", "03", "01", "00020000", bos); /**compression 259
> */
> else if (k > 0)
> writeTag("259", "03", "01", "00030000", bos); /**compression 259 */
> else if (k < 0)
> writeTag("259", "03", "01", "00040000", bos); /**compression 259 */
>
> if(isBlack)
> writeTag("262", "03", "01", "00000000", bos);
> /**photometricInterpretation 262 */
> else
> writeTag("262", "03", "01", "00010000", bos);
> /**photometricInterpretation 262 */
>
> writeTag("273", "04", "01", "7Ah", bos); /**stripOffsets 273 */
> writeTag("277", "03", "01", "00010000", bos); /**samplesPerPixel
> 277 */
> writeTag("278", "04", "01", "01", bos); /**rowsPerStrip 278 */
> writeTag("279", "04", "01", ""+((w | 8 )>>3), bos);
> /**stripByteCount 279 */
>
> /** write next IOD offset */
> writeDWord("0",bos);
>
> try {
>
> bos.close();
>
> java.io.FileOutputStream fos=new
> java.io.FileOutputStream("test.tiff");
> fos.write(bos.toByteArray());
> fos.close();
>
> } catch (Exception e1) {
> e1.printStackTrace();
> }
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
> For additional commands, e-mail: interest-help@jai.dev.java.net
>
>

----------------
Brian Burkhalter
Advanced Development, Graphics and Media
Software Chief Technology Office
Sun Microsystems, Inc.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This email message is for the sole use of the intended recipient(s)
and may contain confidential and privileged information. Any
unauthorized review, use, disclosure or distribution is prohibited.
If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net