Skip to main content

Bad efficiency for Tiff encoding

7 replies [Last post]
calarandir
Offline
Joined: 2008-03-27
Points: 0

Hello,

I am encoding binary tiff images and writing them to the disk. The images are fully prepared together with the header tag information and the encoding/writing to disk takes around 1-2 seconds for a 500kb image. For me this is unacceptable and I do not understand why it takes so long to write some data to the disk. Am I doing anything wrong? Here is the code for encoding:

public boolean saveImage(Image img, int index) throws IOException {
OutputStream os = null;
String filename = "someFileName.tif";
try {
os = new FileOutputStream(filename);
ParameterBlock pb = new ParameterBlock();
pb.add(img);
PlanarImage op = (PlanarImage) JAI.create("awtImage", pb);
PlanarImage monoOp = convertRGBtoBilevel(op);
TIFFEncodeParam param = new TIFFEncodeParam();
param.setLittleEndian(true);
param.setCompression(TIFFEncodeParam.COMPRESSION_NONE);
param.setWriteTiled(false);
TIFFField[] extraFields = new TIFFField[3];
extraFields[0] = new TIFFField(262, TIFFField.TIFF_SHORT, 1, (Object) new char[] { 0 });
extraFields[1] = new TIFFField(282, TIFFField.TIFF_RATIONAL, 1, (Object) createXResolution());
extraFields[2] = new TIFFField(283, TIFFField.TIFF_RATIONAL, 1, (Object) createYResolution());
param.setExtraFields(extraFields);
ImageEncoder enc = ImageCodec.createImageEncoder("TIFF", os, param);

enc.encode(monoOp);//This one takes 2 seconds for 500kb binary image

} finally {
if (os != null)
try {
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

Thanks for your help,

Oliver

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
calarandir
Offline
Joined: 2008-03-27
Points: 0

Ok, I replaced the FileOutputStream with

ByteArrayOutputStream os = new ByteArrayOutputStream(722);
//722 is my actual image size in bytes for the moment

and skipped writing to disk.
Still the call

enc.encode(monoOp);

takes forever to finish. My profiler says that

javax.media.jai.LookupTableJAI.findNearestEntry()

is taking most of the time and is called once per image pixel. To be honest I have no idea what is happening so deep inside of JAI. But I tried to use encode with raster and colormodel as parameters and found out that the encode is a lot faster. Now the slow part is

Raster raster = monoOp.getData();

Maybe that is a better hint to my problem? Could it have anything to do with the fact that it is a binary image? Any other ideas how to improve the performance?

Oliver

Message was edited by: calarandir

Message was edited by: calarandir

calarandir
Offline
Joined: 2008-03-27
Points: 0

Ok, I have investigated a little more and it seems that the conversion from my RGB image to the binary one I want to save as tiff is not done when I thought but when the image is encoded to tiff format. The errordiffusion is, what takes all the time here. Still I do not understand why. Is it such a big deal to convert an image?

Here is the code for the color conversion I use:

private PlanarImage convertRGBtoBilevel(PlanarImage src) {
ParameterBlock pb = new ParameterBlock();
pb.addSource(src);

LookupTableJAI lut = new LookupTableJAI(new byte[][] {
{ (byte) 0xff, (byte) 0x00 },
{ (byte) 0xff, (byte) 0x00 },
{ (byte) 0xff, (byte) 0x00 } });
pb.add(lut);
pb.add(KernelJAI.ERROR_FILTER_FLOYD_STEINBERG);

ImageLayout layout = new ImageLayout();
byte[] map = new byte[] { (byte) 0xff, (byte) 0x00 };
ColorModel cm = new IndexColorModel(1, 2, map, map, map);
layout.setColorModel(cm);
SampleModel sm = new MultiPixelPackedSampleModel(
DataBuffer.TYPE_BYTE,
src.getWidth(),
src.getHeight(),
1);
layout.setSampleModel(sm);

RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);

final PlanarImage dst = JAI.create("errordiffusion", pb, hints);
return dst;
}

I've tried ordered dither as well, but ran into several problems with color cube compatibility and gave up. In case this information is important, my images are monochrome all the time, just not represented as binary data. Maybe there is an easier and faster way to convert?

Thanks for any help,

Oliver

tg@cs.york.ac.uk

Hi Oliver,

I'm not sure if this is precisely what you're looking for, but you can
create a binary bufferedimage with

new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);

and draw any image into its graphics object. I've used this as a rough
method of binarising colour images, so it should work fine for the
monochrome images you describe.

> I've tried ordered dither as well, but ran into several problems with
> color cube compatibility and gave up. In case this information is
> important, my images are monochrome all the time, just not represented as
> binary data. Maybe there is an easier and faster way to convert?
>
>
> Thanks for any help,
>
> Oliver
> [Message sent by forum member 'calarandir' (calarandir)]
>
> http://forums.java.net/jive/thread.jspa?messageID=266430
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
> For additional commands, e-mail: interest-help@jai.dev.java.net
>
>

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

bpb
Offline
Joined: 2004-06-23
Points: 0

If you have the same value in all three channels you should just be able to do a BandSelect (which does no copying) followed by Binarize with the appropriate threshold.

Brian

> Hi Oliver,
>
> I'm not sure if this is precisely what you're looking
> for, but you can
> create a binary bufferedimage with
>
> new BufferedImage(width, height,
> BufferedImage.TYPE_BYTE_BINARY);
>
> and draw any image into its graphics object. I've
> used this as a rough
> method of binarising colour images, so it should work
> fine for the
> monochrome images you describe.
>
>
> > I've tried ordered dither as well, but ran into
> several problems with
> > color cube compatibility and gave up. In case this
> information is
> > important, my images are monochrome all the time,
> just not represented as
> > binary data. Maybe there is an easier and faster
> way to convert?
> >
> >
> > Thanks for any help,
> >
> > Oliver
> > [Message sent by forum member 'calarandir'
> (calarandir)]
> >
> >
> http://forums.java.net/jive/thread.jspa?messageID=2664
> 30
> >
> >
> ------------------------------------------------------
> ---------------
> > To unsubscribe, e-mail:
> interest-unsubscribe@jai.dev.java.net
> > For additional commands, e-mail:
> interest-help@jai.dev.java.net
> >
> >
>
>
>
> ------------------------------------------------------
> ---------------
> To unsubscribe, e-mail:
> interest-unsubscribe@jai.dev.java.net
> For additional commands, e-mail:
> interest-help@jai.dev.java.net

calarandir
Offline
Joined: 2008-03-27
Points: 0

I have decided to choose the suggestion to draw directly to a Binary BufferedImage graphics context. This works very fast and leads me to a binary tiff image as required.
There is one problem left, I need to set the PhotometricInterpretation tag in the TIFF header. I am doing this with

...
TIFFField[] extraFields = new TIFFField[10];
extraFields[0] = new TIFFField(262, TIFFField.TIFF_SHORT, 1, (Object) new char[] {0} );
...
param.setExtraFields(extraFields);

Which worked fine before. Now this tag is simply ignored and always set to 1 (BlackIsZero). But I need WhiteIsZero. Any idea?

Thanks for the good help so far.

Oliver

bpb
Offline
Joined: 2004-06-23
Points: 0

Using the approach that you are I don't think that you can get WhiteIsZero. The encoder always sets BlackIsZero for this case. If you have an index color image with 1-bit per pixel and the color map is {{255,255,255},{0,0,0}} then the encoder will set WhiteIsZero.

Brian

> I have decided to choose the suggestion to draw
> directly to a Binary BufferedImage graphics context.
> This works very fast and leads me to a binary tiff
> image as required.
> There is one problem left, I need to set the
> PhotometricInterpretation tag in the TIFF header. I
> am doing this with
>
> ...
> TIFFField[] extraFields = new TIFFField[10];
> extraFields[0] = new TIFFField(262,
> TIFFField.TIFF_SHORT, 1, (Object) new char[] {0} );
> ...
> param.setExtraFields(extraFields);
>
> Which worked fine before. Now this tag is simply
> ignored and always set to 1 (BlackIsZero). But I need
> WhiteIsZero. Any idea?
>
> Thanks for the good help so far.
>
> Oliver

Burwinkel, Scott

I have a couple of suggestions for you:
First, exchange the FileOutputStream with a ByteArrayOutputStream and
run your timing exercise again. I think you'll find that there's a lot
more happening in the encode() call thatn you might think at first. Just
calling the JAI.create("op_name") doesn't do the actual execution, it's
just setting up a chain of events. It's not until something like
getTiles() or encode() is called that the actual execution occurs.
Second, for actual file writing, you might try wrapping your new
FileOutputStream() with a BufferedOutputStream. Not sure it will make a
huge difference, but worth a shot.

-----Original Message-----
From: jai-interest@javadesktop.org [mailto:jai-interest@javadesktop.org]

Sent: Thursday, March 27, 2008 10:23 AM
To: interest@jai.dev.java.net
Subject: [JAI] Efficiency of Tiff encoding

Hello,

I am encoding binary tiff images and writing them to the disk. The
images are fully prepared together with the header tag information and
the encoding/writing to disk takes around 1-2 seconds for a 500kb image.
For me this is unacceptable and I do not understand why it takes so long
to write some data to the disk. Am I doing anything wrong? Here is the
code for encoding:

public boolean saveImage(Image img, int index) throws IOException {
OutputStream os = null;
String filename = "someFileName.tif";
try {
os = new FileOutputStream(filename);
ParameterBlock pb = new ParameterBlock();
pb.add(img);
PlanarImage op = (PlanarImage) JAI.create("awtImage", pb);
PlanarImage monoOp = convertRGBtoBilevel(op);
TIFFEncodeParam param = new TIFFEncodeParam();
param.setLittleEndian(true);
param.setCompression(TIFFEncodeParam.COMPRESSION_NONE);
param.setWriteTiled(false);
TIFFField[] extraFields = new TIFFField[3];
extraFields[0] = new TIFFField(262, TIFFField.TIFF_SHORT, 1,
(Object) new char[] { 0 });
extraFields[1] = new TIFFField(282, TIFFField.TIFF_RATIONAL, 1,
(Object) createXResolution());
extraFields[2] = new TIFFField(283, TIFFField.TIFF_RATIONAL, 1,
(Object) createYResolution());
param.setExtraFields(extraFields);
ImageEncoder enc = ImageCodec.createImageEncoder("TIFF", os,
param);

enc.encode(monoOp);//This one takes 2 seconds for 500kb binary
image

} finally {
if (os != null)
try {
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

Thanks for your help,

Oliver
[Message sent by forum member 'calarandir' (calarandir)]

http://forums.java.net/jive/thread.jspa?messageID=266210

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

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