Skip to main content

Crop, Scale and reduce quality of TIF to JPEG

12 replies [Last post]
vinaypatil
Offline
Joined: 2006-06-28

Hi,

I am relatively new to JAI and ImageIO, so sorry if these questions have been asked before.

I am trying to convert a TIF image to JPEG format, but need to crop, scale and reduce the color of output JPEG image.
I went through many archives but didn't get a proper solution.

Will really appreciate help and suggestions of any kind

Following code throws
java.lang.IllegalArgumentException: Requested region cannot be represented by a single Raster.

public class TestCropScale
{

public static void main(String args[])

{
int cropStartX = 49;
int cropStartY = 0;
int cropscalesizeX = 902;
int cropscalesizeY = 1000;
int scalesizeX = 240;
int scalesizeY = 266;
int quality = 67;

try
{
String inFileName = "D:/jai-images/Doggy_Heart.tif";
String outputFileName = "D:/jai-images/output/D_H1.jpg";

PlanarImage pImage = JAI.create("fileload", inFileName);
System.out.println("File load the temp JPG file = " + pImage);

ParameterBlock pbCrop = new ParameterBlock();
pbCrop.addSource(pImage);
pbCrop.add((float)cropStartX);
pbCrop.add((float)cropStartY);
pbCrop.add((float)cropscalesizeX);
pbCrop.add((float)cropscalesizeY);
RenderedOp renderedOPCrop = JAI.create("crop", pbCrop, null);
System.out.println("Cropped Image=" +renderedOPCrop);

ParameterBlock pbScale = new ParameterBlock();
pbScale.addSource(pImage);
pbScale.add((float)scalesizeX);
pbScale.add((float)scalesizeY);
pbScale.add(0.0F);
pbScale.add(0.0F);
RenderedOp renderedOPScale = JAI.create("scale", pbScale, null);
System.out.println("Scaled Image=" +renderedOPScale);

JPEGEncodeParam jpgparam = new JPEGEncodeParam();
jpgparam.setQuality(quality);

FileOutputStream fs = new FileOutputStream(outputFileName);
ImageEncoder enc = ImageCodec.createImageEncoder("jpeg", fs, jpgparam);
enc.encode(renderedOPScale);
/*
JAI.create("filestore", renderedOPScale, outputFileName, "JPEG", null);
*/
}
catch(Exception e)
{
System.out.println("Exception = " +e);
}
}

}

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Brian Burkhalter

Vinay,

Hello. Would you please supply the entire test case which can be compiled
without editing?

Thanks,

Brian

On Thu, 29 Jun 2006, jai-imageio@javadesktop.org wrote:

> Hi,
>
> I am relatively new to JAI and ImageIO, so sorry if these questions have been asked before.
>
> I am trying to convert a TIF image to JPEG format, but need to crop, scale and reduce the color of output JPEG image.
> I went through many archives but didn't get a proper solution.
>
> Will really appreciate help and suggestions of any kind
>
> Following code throws
> java.lang.IllegalArgumentException: Requested region cannot be represented by a single Raster.
>
> public class TestCropScale
> {
>
> public static void main(String args[])
>
> {
> int cropStartX = 49;
> int cropStartY = 0;
> int cropscalesizeX = 902;
> int cropscalesizeY = 1000;
> int scalesizeX = 240;
> int scalesizeY = 266;
> int quality = 67;
>
> try
> {
> String inFileName = "D:/jai-images/Doggy_Heart.tif";
> String outputFileName = "D:/jai-images/output/D_H1.jpg";
>
> PlanarImage pImage = JAI.create("fileload", inFileName);
> System.out.println("File load the temp JPG file = " + pImage);
>
> ParameterBlock pbCrop = new ParameterBlock();
> pbCrop.addSource(pImage);
> pbCrop.add((float)cropStartX);
> pbCrop.add((float)cropStartY);
> pbCrop.add((float)cropscalesizeX);
> pbCrop.add((float)cropscalesizeY);
> RenderedOp renderedOPCrop = JAI.create("crop", pbCrop, null);
> System.out.println("Cropped Image=" +renderedOPCrop);
>
> ParameterBlock pbScale = new ParameterBlock();
> pbScale.addSource(pImage);
> pbScale.add((float)scalesizeX);
> pbScale.add((float)scalesizeY);
> pbScale.add(0.0F);
> pbScale.add(0.0F);
> RenderedOp renderedOPScale = JAI.create("scale", pbScale, null);
> System.out.println("Scaled Image=" +renderedOPScale);
>
> JPEGEncodeParam jpgparam = new JPEGEncodeParam();
> jpgparam.setQuality(quality);
>
> FileOutputStream fs = new FileOutputStream(outputFileName);
> ImageEncoder enc = ImageCodec.createImageEncoder("jpeg", fs, jpgparam);
> enc.encode(renderedOPScale);
> /*
> JAI.create("filestore", renderedOPScale, outputFileName, "JPEG", null);
> */
> }
> catch(Exception e)
> {
> System.out.println("Exception = " +e);
> }
> }
>
> }
> [Message sent by forum member 'vinaypatil' (vinaypatil)]
>
> http://forums.java.net/jive/thread.jspa?messageID=128332
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-imageio.dev.java.net
>
>

----------------
Brian Burkhalter
Java Media, Imaging, and Graphics
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-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

vinaypatil
Offline
Joined: 2006-06-28

Please find attached the test-case java class!
For some reason I get this message
Could not find mediaLib accelerator wrapper classes. Continuing in pure Java mode.
But the major problems are :-

1. There is a loss quality (smudged) of the JPEG image 2. The crop (or the scale) operation cause loss in some parts of the image

Could you please check whats wrong in the code.
I read the leptonica page and have included the SubsampleAverage.
(Thank you for that information)

Regards,
Vinay

import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;
import java.awt.RenderingHints;

public class TestLiveArgsCropScaleSubSample2
{

public static void main(String args[])
{
try
{
//Arguments List
int cropStartX = 125;
int cropStartY = 0;
int cropSizeX = 750;
int cropSizeY = 1000;
int sizeX = 240;
int sizeY = 320;

String inFileName = "D:/jai-images/OriginalTiff.tif";
String outputFileName = "D:/jai-images/output/JAI_output.jpg";

PlanarImage pImage = JAI.create("fileload", inFileName);
System.out.println("Fileload, TIF file = " + pImage);

ParameterBlock pbCrop = new ParameterBlock();
pbCrop.addSource(pImage);
pbCrop.add((float)cropStartX);
pbCrop.add((float)cropStartY);
pbCrop.add((float)cropSizeX);
pbCrop.add((float)cropSizeY);
RenderedOp renderedOPCrop = JAI.create("crop", pbCrop, null);
System.out.println("renderedOP.getWidth() = " + renderedOPCrop.getWidth());
System.out.println("renderedOP.getHeight() = " + renderedOPCrop.getHeight());
System.out.println("Cropped Image=" +renderedOPCrop);

// Specify the rendering hints
RenderingHints qualityHints =
new RenderingHints(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);

/*
* Create image with SubsampleAverage operation
*/
RenderedOp renderedOPScale = JAI.create("SubsampleAverage",
renderedOPCrop,
new Double((double)sizeX/renderedOPCrop.getWidth()),
new Double((double)sizeY/renderedOPCrop.getHeight()),
qualityHints);

System.out.println("renderedOPScale.getWidth() = " + renderedOPScale.getWidth());
System.out.println("renderedOPScale.getHeight() = " + renderedOPScale.getHeight());
System.out.println("Scaled Image=" +renderedOPScale);

JAI.create("filestore", renderedOPScale, outputFileName, "JPEG", null);
System.out.println("Done");

}
catch(Exception e)
{
System.out.println("Exception: " + e);
}
}
}

Brian Burkhalter

On Fri, 30 Jun 2006, jai-imageio@javadesktop.org wrote:

> Please find attached the test-case java class!

Which version of JAI is being used? Also, in the e-mail message which you sent
to me directly, I did not see the orignal source image file attached.

> For some reason I get this message
> Could not find mediaLib accelerator wrapper classes. Continuing in pure Java mode.

This is due to the mediaLib jar file and/or shared objects (.dll or .so files)
not being found. It is generally indicative of incorrect installation. Please
review your installation with respect to the installation instructions in
particular the list of files installed and there locations.

> But the major problems are :-
>
> 1. There is a loss quality (smudged) of the JPEG image

Similar artifacts are also visible in the "expected output" image that you
sent. There are three possible reasons for these artifacts:

* the filtering applied pre-subsampling;
* the subsampling itself;
* the JPEG compression parameters.

Unless each of these steps is identical to the equivalent step in both process
chains the results may differ. I would suggest saving the output in a lossless
format such as PNG to eliminate one degree of freedom from the comparison. If
there is still a significant difference I would suggest trying a
convolve-scale sequence with a more specifically tuned low pass kernel.

> 2. The crop (or the scale) operation cause loss in some parts of the image

I'm not sure what you mean here. Do you mean to say the results differ in
their area of overlap if the image is cropped versus when it is not?

> Could you please check whats wrong in the code.
> I read the leptonica page and have included the SubsampleAverage.
> (Thank you for that information)

You're welcome!

Brian

> import java.awt.image.renderable.ParameterBlock;
> import javax.media.jai.JAI;
> import javax.media.jai.PlanarImage;
> import javax.media.jai.RenderedOp;
> import java.awt.RenderingHints;
>
> public class TestLiveArgsCropScaleSubSample2
> {
>
> public static void main(String args[])
> {
> try
> {
> //Arguments List
> int cropStartX = 125;
> int cropStartY = 0;
> int cropSizeX = 750;
> int cropSizeY = 1000;
> int sizeX = 240;
> int sizeY = 320;
>
> String inFileName = "D:/jai-images/OriginalTiff.tif";
> String outputFileName = "D:/jai-images/output/JAI_output.jpg";
>
> PlanarImage pImage = JAI.create("fileload", inFileName);
> System.out.println("Fileload, TIF file = " + pImage);
>
> ParameterBlock pbCrop = new ParameterBlock();
> pbCrop.addSource(pImage);
> pbCrop.add((float)cropStartX);
> pbCrop.add((float)cropStartY);
> pbCrop.add((float)cropSizeX);
> pbCrop.add((float)cropSizeY);
> RenderedOp renderedOPCrop = JAI.create("crop", pbCrop, null);
> System.out.println("renderedOP.getWidth() = " + renderedOPCrop.getWidth());
> System.out.println("renderedOP.getHeight() = " + renderedOPCrop.getHeight());
> System.out.println("Cropped Image=" +renderedOPCrop);
>
> // Specify the rendering hints
> RenderingHints qualityHints =
> new RenderingHints(RenderingHints.KEY_RENDERING,
> RenderingHints.VALUE_RENDER_QUALITY);
>
> /*
> * Create image with SubsampleAverage operation
> */
> RenderedOp renderedOPScale = JAI.create("SubsampleAverage",
> renderedOPCrop,
> new Double((double)sizeX/renderedOPCrop.getWidth()),
> new Double((double)sizeY/renderedOPCrop.getHeight()),
> qualityHints);
>
> System.out.println("renderedOPScale.getWidth() = " + renderedOPScale.getWidth());
> System.out.println("renderedOPScale.getHeight() = " + renderedOPScale.getHeight());
> System.out.println("Scaled Image=" +renderedOPScale);
>
> JAI.create("filestore", renderedOPScale, outputFileName, "JPEG", null);
> System.out.println("Done");
>
>
> }
> catch(Exception e)
> {
> System.out.println("Exception: " + e);
> }
> }
> }
> [Message sent by forum member 'vinaypatil' (vinaypatil)]
>
> http://forums.java.net/jive/thread.jspa?messageID=128759
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-imageio.dev.java.net
>
>

----------------
Brian Burkhalter
Java Media, Imaging, and Graphics
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-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

vinaypatil
Offline
Joined: 2006-06-28

Hi,

I've sent the original tiff image on interest@jai.dev.java.net

The old software used JMagick(+Image Magick) for processing images, I do agree that the expected output also had small amount of smudges, but as per James Hagen(our Content/Art Director) the images with JAI had extreme loss of quality.
[Brian, the green circles were his remarks].

Since these images are delivered to the customers/partners, we have to be precise with format, quality and size.
For JPEG images we reduce the quality and for GIF we reduce the colors till the required file size is achieved.
This image can attain a max file size of 20kb, but as I said in the mail, if I try to reduce the quality using

JPEGEncodeParam jpgparam = new JPEGEncodeParam();
jpgparam.setQuality(100);
The file-size is doubled, so obviously I am not using the correct technique for controlling quality!

I tried with 'SubsampleAverage' and also 'INTERP_BICUBIC' filter, still the image quality has not improved.

Regarding the crop problem, I meant even with the same arguments[rectangle], the cropped area looks different than the one made with JMagick, but as you said both need not produce the same result!
But once I scale the image, the quality is compromised!

Any suggestions, hints, samples are greatly appreciated!
Thanks in advance!

Regards,
Vinay

vinaypatil
Offline
Joined: 2006-06-28

Hi Brian,

After some research, I found the problem with the JPEG file-size growth.
The JPEGEncodeParam.setQuality(quality) is a factor in %, the amount to which the image needs to be reduced/modified.

Please check the attached code with modifications!
But
1. I see the distortion/smudges are reduced to great extented but the edges are still jagged(not smooth)

2. I also want to put a png watermark on the jpeg images.
I tried the excample in the archieve
http://archives.java.sun.com/cgi-bin/wa?A2=ind0503&L=jai-interest&D=1&T=...
and it worked fine.
Is it the best way to watermark images?

Hopefully following code works well at your end. Most images look pretty ok except those having edges and curves.
I tried to search the forums, but didn't find a similar case.
You also mentioned the 'convolve-scale sequence' in your previous post, how does it work, do you have a example or some archive.

Thanks.
Regards,
Vinay

import java.awt.image.renderable.ParameterBlock;

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

import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageEncoder;
import com.sun.media.jai.codec.JPEGEncodeParam;

import java.awt.RenderingHints;
import java.io.FileOutputStream;

public class TestLiveArgsCropScaleSubSample2
{

public static void main(String args[])
{
try
{
//Arguments List
int cropStartX = 125;
int cropStartY = 0;
int cropSizeX = 750;
int cropSizeY = 1000;
int sizeX = 240;
int sizeY = 320;

float quality = 0.85F;

String inFileName = "D:/jai-images/OriginalTiff.tif";
//String inFileName = "D:/jai-images/output/DHTemp.jpg";
String outputFileName = "D:/jai-images/output/TiffInSubsample2_qlty085.jpg";

PlanarImage pImage = JAI.create("fileload", inFileName);
System.out.println("Fileload, TIF file = " + pImage);

ParameterBlock pbCrop = new ParameterBlock();
pbCrop.addSource(pImage);
pbCrop.add((float)cropStartX);
pbCrop.add((float)cropStartY);
pbCrop.add((float)cropSizeX);
pbCrop.add((float)cropSizeY);
//added new
pbCrop.add(Interpolation.getInstance(Interpolation.INTERP_BILINEAR));
//INTERP_BILINEAR and INTERP_BICUBIC produce same results
//pbCrop.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));

RenderedOp renderedOPCrop = JAI.create("crop", pbCrop, null);
System.out.println("renderedOP.getWidth() = " + renderedOPCrop.getWidth());
System.out.println("renderedOP.getHeight() = " + renderedOPCrop.getHeight());
System.out.println("Cropped Image=" +renderedOPCrop);

// Specify the rendering hints
RenderingHints qualityHints =
new RenderingHints(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);

/*
* Create image with SubsampleAverage operation
*/
RenderedOp renderedOPScale = JAI.create("SubsampleAverage",
renderedOPCrop,
new Double((double)sizeX/renderedOPCrop.getWidth()),
new Double((double)sizeY/renderedOPCrop.getHeight()),
qualityHints);

System.out.println("renderedOPScale.getWidth() = " + renderedOPScale.getWidth());
System.out.println("renderedOPScale.getHeight() = " + renderedOPScale.getHeight());
System.out.println("Scaled Image =" +renderedOPScale);

JPEGEncodeParam jpgparam = new JPEGEncodeParam();
jpgparam.setQuality(quality);

FileOutputStream fs = new FileOutputStream(outputFileName);
ImageEncoder enc = ImageCodec.createImageEncoder("jpeg", fs, jpgparam);
enc.encode(renderedOPScale);
}
catch(Exception e)
{
System.out.println("Exception: " + e);
}
}
}

Brian Burkhalter

> After some research, I found the problem with the JPEG file-size growth.
> The JPEGEncodeParam.setQuality(quality) is a factor in %, the amount to which the image needs to be reduced/modified.
>
> Please check the attached code with modifications!

I don't see any obvious problems.

> But
> 1. I see the distortion/smudges are reduced to great extented but the edges are still jagged(not smooth)

Please check out this note:

http://www.htmlhelp.com/design/imageuse.htm#jpgvsgif

> 2. I also want to put a png watermark on the jpeg images.
> I tried the excample in the archieve
> http://archives.java.sun.com/cgi-bin/wa?A2=ind0503&L=jai-interest&D=1&T=...
> and it worked fine.
> Is it the best way to watermark images?

I am afraid I am not an expert on watermarking. Perhaps someone else can
comment (or you can post something with "watermark" in the subject to
interest@jai.dev.java.net).

> Hopefully following code works well at your end. Most images look pretty ok except those having edges and curves.
> I tried to search the forums, but didn't find a similar case.
> You also mentioned the 'convolve-scale sequence' in your previous post, how does it work, do you have a example or some archive.

In effect you do a "Convolve" operation with a low pass kernel, e.g., all 1s,
followed by a "Scale" operation. The size of the kernel should be a function
od the scaling factor, i.e., the more the downscaling the larger the kernel. A
better low pass filter is the guassian kernel.

Brian

----------------
Brian Burkhalter
Java Media, Imaging, and Graphics
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-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

vinaypatil
Offline
Joined: 2006-06-28

Hi Brian,

Sorry I was badly involved in some other issues, hence couldn't write back.

There are two issues which I couldn't resolve with JAI/Image.IO.
1. The images cropped by JAI are slightly different.
(Our QA team did a crop and scale of a tif image(to .jpg) and compared it with JAI output and found the crop area made by JAI was slightly different!
2. The quality of JPEG image at edges and curves were not sharp but jagged!

Regarding the 1st problem, I am pasting the code-snippet and the images.
Please have a look.

import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;

import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageEncoder;
import com.sun.media.jai.codec.JPEGEncodeParam;

import java.awt.RenderingHints;
import java.io.FileOutputStream;

public class TestJAICropArgs
{
public static void main(String args[])
{
int quality = 96;
String inFileName = "D:/jai-images/flower.tif";
String outputFileName = "D:/jai-images/output/flowerQuality96.jpg";
try
{
//Arguments List
int cropStartX = 115;//74;//122; //0;//
int cropStartY = 122;//164;//122;//160;
int cropSizeX = 794;//851;//756;//1024;
int cropSizeY = 780;//672;//756;//704;
int sizeX = 176;//101;//128;//320;
int sizeY = 173;//80;//128;//220;

float qualityF = (float)quality/100;

PlanarImage pImage = JAI.create("fileload", inFileName);
//System.out.println("Fileload, TIF file = " + pImage);

ParameterBlock pbCrop = new ParameterBlock();
pbCrop.addSource(pImage);
pbCrop.add((float)cropStartX);
pbCrop.add((float)cropStartY);
pbCrop.add((float)cropSizeX);
pbCrop.add((float)cropSizeY);
//added new
pbCrop.add(Interpolation.getInstance(Interpolation.INTERP_BILINEAR));
//INTERP_BILINEAR and INTERP_BICUBIC produce same results
//pbCrop.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));

RenderedOp renderedOPCrop = JAI.create("crop", pbCrop, null);

// Specify the rendering hints
RenderingHints qualityHints =
new RenderingHints(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);

/*
* Create image with SubsampleAverage operation
*/
RenderedOp renderedOPScale = JAI.create("SubsampleAverage",
renderedOPCrop,
new Double((double)sizeX/renderedOPCrop.getWidth()),
new Double((double)sizeY/renderedOPCrop.getHeight()),
qualityHints);

JPEGEncodeParam jpgparam = new JPEGEncodeParam();
jpgparam.setQuality(qualityF);

FileOutputStream fs = new FileOutputStream(outputFileName);
ImageEncoder enc = ImageCodec.createImageEncoder("jpeg", fs, jpgparam);
enc.encode(renderedOPScale);

fs.flush();
fs.close();
/*
File file = null;
file = new File(outputFileName);
System.out.println("No media Generated FILE ==" + file.length()+ " BYTES ("+quality+".)");
*/
}
catch(Exception e)
{
System.out.println("Exception: " + e);
}
quality = quality - 5;
}//main
}

Brian Burkhalter

Vinay,

On Mon, 31 Jul 2006, jai-imageio@javadesktop.org wrote:

> Sorry I was badly involved in some other issues, hence couldn't write back.
>
> There are two issues which I couldn't resolve with JAI/Image.IO.
> 1. The images cropped by JAI are slightly different.
> (Our QA team did a crop and scale of a tif image(to .jpg) and compared it with JAI output and found the crop area made by JAI was slightly different!

I tested this myself and verified by two different approaches that the cropped
image created by JAI is in fact correct. Firstly I added this code to your
test case after the "Crop" operation:

// BEGIN - crop test
{
ParameterBlock pbXlate = new ParameterBlock();
pbXlate.addSource(renderedOPCrop);
pbCrop.add((float)-cropStartX);
pbCrop.add((float)-cropStartY);
RenderedOp xlate = JAI.create("Translate",
pbXlate);
JAI.create("FileStore", xlate, "xlate.tif");
RenderedOp diff = JAI.create("subtract",
pImage,
xlate);
RenderedOp diffExtrema = JAI.create("Extrema", diff);
double[][] extrema =
(double[][])diffExtrema.getProperty("Extrema");
for(int i = 0; i < extrema.length; i++) {
for(int j = 0; j < extrema[i].length; j++) {
System.out.print(extrema[i][j]+" ");
}
System.out.println("");
}
}
// END

The first result is that the extrema of the difference between the original
and cropped image in their overlap region are calculated and are all zero
which means that the cropped image is the same as the original image in the
region of overlap.

The second result is that an image called "xlate.tif" is saved and consists of
the cropped image. I took the original image, converted it to PPM, cropped
that using 'pamquant' to the same bounds as specified to "Crop" and used
'tiffcmp' to compare these two. Outcome: they are identical.

> 2. The quality of JPEG image at edges and curves were not sharp but jagged!

This discrepancy has nothing to do with JPEG but appears to be due to a
difference in the scaling algorithms. AFAIK Photoshop reduction scaling
automatically incorporates a low pass filtering step. In JAI this is not the
case as we want the developer to have full control over the operation. When
you use SubsampleAverage you are actually getting the equivalent of box
filtering (with kernel dimensions determined by the subsampling factors)
followed by a nearest neigbor downscaling. If this approach is not yielding
the desired quality for your images then you should probably swith to
FilteredSubsample or, if that is not amenable, to "Convolve" followed by
"Scale". The latter approach will allow you tune the computation to whatever
quality criteria you must meet. If your convolution kernel is designed
properly you might even be able to use nearest neighbor interpolation in the
"Scale" operation as the aliasing will already have been prevented by
pre-filtering.

Brian

> Regarding the 1st problem, I am pasting the code-snippet and the images.
> Please have a look.
>
> import java.awt.image.renderable.ParameterBlock;
> import javax.media.jai.Interpolation;
> import javax.media.jai.JAI;
> import javax.media.jai.PlanarImage;
> import javax.media.jai.RenderedOp;
>
> import com.sun.media.jai.codec.ImageCodec;
> import com.sun.media.jai.codec.ImageEncoder;
> import com.sun.media.jai.codec.JPEGEncodeParam;
>
> import java.awt.RenderingHints;
> import java.io.FileOutputStream;
>
> public class TestJAICropArgs
> {
> public static void main(String args[])
> {
> int quality = 96;
> String inFileName = "D:/jai-images/flower.tif";
> String outputFileName = "D:/jai-images/output/flowerQuality96.jpg";
> try
> {
> //Arguments List
> int cropStartX = 115;//74;//122; //0;//
> int cropStartY = 122;//164;//122;//160;
> int cropSizeX = 794;//851;//756;//1024;
> int cropSizeY = 780;//672;//756;//704;
> int sizeX = 176;//101;//128;//320;
> int sizeY = 173;//80;//128;//220;
>
> float qualityF = (float)quality/100;
>
> PlanarImage pImage = JAI.create("fileload", inFileName);
> //System.out.println("Fileload, TIF file = " + pImage);
>
> ParameterBlock pbCrop = new ParameterBlock();
> pbCrop.addSource(pImage);
> pbCrop.add((float)cropStartX);
> pbCrop.add((float)cropStartY);
> pbCrop.add((float)cropSizeX);
> pbCrop.add((float)cropSizeY);
> //added new
> pbCrop.add(Interpolation.getInstance(Interpolation.INTERP_BILINEAR));
> //INTERP_BILINEAR and INTERP_BICUBIC produce same results
> //pbCrop.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));
>
> RenderedOp renderedOPCrop = JAI.create("crop", pbCrop, null);
>
> // Specify the rendering hints
> RenderingHints qualityHints =
> new RenderingHints(RenderingHints.KEY_RENDERING,
> RenderingHints.VALUE_RENDER_QUALITY);
>
> /*
> * Create image with SubsampleAverage operation
> */
> RenderedOp renderedOPScale = JAI.create("SubsampleAverage",
> renderedOPCrop,
> new Double((double)sizeX/renderedOPCrop.getWidth()),
> new Double((double)sizeY/renderedOPCrop.getHeight()),
> qualityHints);
>
> JPEGEncodeParam jpgparam = new JPEGEncodeParam();
> jpgparam.setQuality(qualityF);
>
> FileOutputStream fs = new FileOutputStream(outputFileName);
> ImageEncoder enc = ImageCodec.createImageEncoder("jpeg", fs, jpgparam);
> enc.encode(renderedOPScale);
>
> fs.flush();
> fs.close();
> /*
> File file = null;
> file = new File(outputFileName);
> System.out.println("No media Generated FILE ==" + file.length()+ " BYTES ("+quality+".)");
> */
> }
> catch(Exception e)
> {
> System.out.println("Exception: " + e);
> }
> quality = quality - 5;
> }//main
> }
> [Message sent by forum member 'vinaypatil' (vinaypatil)]
>
> http://forums.java.net/jive/thread.jspa?messageID=138356
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-imageio.dev.java.net
>
>

----------------
Brian Burkhalter
Java Media, Imaging, and Graphics
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-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

Brian Burkhalter

> The second result is that an image called "xlate.tif" is saved and consists
> of the cropped image. I took the original image, converted it to PPM, cropped
> that using 'pamquant' to the same bounds as specified to "Crop" and used
> 'tiffcmp' to compare these two. Outcome: they are identical.

In the section above I intended to write "pamcut".

Brian

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

vinaypatil
Offline
Joined: 2006-06-28

Thanks a lot Brian.
The Translate takes care that the area is cropped properly.
But on performing a scale or subsampleAverage operation, the image shows a black border on the left side.
(Since the cropped image has black-borders on both sides, they are expected after resizing too)

As you would have seen, if the input image has no black-frame with 1024x1024, the scaling is perfect.
When I test with a image having black-frame around the motif, the scaled image has non-proportionate borders.

Do I have to pass a convolve filter before scaling, filteredSubsample gave me strange result.
If there is a post or some example how to do this, would be a great help for me.

Thanks.
-Vinay

vinaypatil
Offline
Joined: 2006-06-28

I tried to convolve using a low pass filter(Gaussian) after the image was translated.
//Low pass filter
KernelJAI gausKernel ;
float[] kernelData = {
0.0625f, 0.125f, 0.0625f,
0.125f, 0.25f, 0.125f,
0.0625f, 0.125f , 0.0625f
};

gausKernel = new KernelJAI(3, 3, 1, 1, kernelData);
RenderedOp convolved = JAI.create("convolve", xlate, gausKernel);

And then performed a subSampleAverage, but still I get a black-border on the left, but not on the right.
Instead, if I perform a scale operation, the result image is not as I expect.

Whats is the solution, how can I overcome this problem?
Please find below the complete code:

import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.KernelJAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageEncoder;
import com.sun.media.jai.codec.JPEGEncodeParam;

import java.awt.RenderingHints;
import java.io.FileOutputStream;

public class TestJAI_1_1_3stab
{
public static void main(String args[])
{
int quality = 96;
String inFileName = "D:/jai-images/woman3.tif";
String outputFileName = "D:/jai-images/result_1_1_3stable_bb/tif_in_SSA_woman3.jpg";
try
{
//Arguments List
int cropStartX = 115;
int cropStartY = 122;
int cropSizeX = 794;
int cropSizeY = 780;
int sizeX = 176;
int sizeY = 173;
float qualityF = (float)quality/100;
System.out.println("Using JAI build version: " + JAI.getBuildVersion());

PlanarImage pImage = JAI.create("fileload", inFileName);

ParameterBlock pbCrop = new ParameterBlock();
pbCrop.addSource(pImage);
pbCrop.add((float)cropStartX);
pbCrop.add((float)cropStartY);
pbCrop.add((float)cropSizeX);
pbCrop.add((float)cropSizeY);
//added new
pbCrop.add(Interpolation.getInstance(Interpolation.INTERP_BILINEAR));
//INTERP_BILINEAR and INTERP_BICUBIC produce same results
pbCrop.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));
RenderedOp renderedOPCrop = JAI.create("crop", pbCrop, null);
//Intermediate crop test
//JAI.create("filestore", renderedOPCrop,"D:/jai-images/result_1_1_3stable_bb/SSA_interCROP-woman3.jpeg" ,"JPEG", null);

ParameterBlock pbXlate = new ParameterBlock();
pbXlate.addSource(renderedOPCrop);
pbCrop.add((float)-cropStartX);
pbCrop.add((float)-cropStartY);
RenderedOp xlate = JAI.create("Translate", pbXlate);
/* Cross-verfied by BB@SUN
JAI.create("FileStore", xlate, "D:/jai-images/result_1_1_3stable_bb/xlate.tif");
RenderedOp diff = JAI.create("subtract", pImage, xlate);
JAI.create("FileStore", diff, "D:/jai-images/result_1_1_3stable_bb/diff.tif");
RenderedOp diffExtrema = JAI.create("Extrema", diff);
JAI.create("FileStore", diffExtrema, "D:/jai-images/result_1_1_3stable_bb/diffExtrema.tif");
double[][] extrema =
(double[][])diffExtrema.getProperty("Extrema");
for(int i = 0; i < extrema.length; i++)
{
for(int j = 0; j < extrema.length; j++)
{
System.out.print(extrema[j]+" ");
}
System.out.println("");
}
*/

//Low pass filter
KernelJAI gausKernel ;
float[] kernelData = {
0.0625f, 0.125f, 0.0625f,
0.125f, 0.25f, 0.125f,
0.0625f, 0.125f , 0.0625f
};

gausKernel = new KernelJAI(3, 3, 1, 1, kernelData);
RenderedOp convolved = JAI.create("convolve", xlate, gausKernel);
// Specify the rendering hints
RenderingHints qualityHints =
new RenderingHints(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);

System.out.println("width="+renderedOPCrop.getWidth());
System.out.println("height="+renderedOPCrop.getHeight());

//System.out.println("scale factor x ="+(float)sizeX/renderedOPCrop.getWidth());
//System.out.println("scale factor y ="+(float)sizeY/renderedOPCrop.getHeight());

/*
* Create image with SubsampleAverage operation
*/

RenderedOp renderedOPScale = JAI.create("SubsampleAverage",
convolved,
new Double((double)sizeX/renderedOPCrop.getWidth()),
new Double((double)sizeY/renderedOPCrop.getHeight()),
qualityHints);
/*
Scale operation, instead of SubsampleAverage[Image quality is not good]
Interpolation interp = Interpolation.getInstance(Interpolation.INTERP_BILINEAR);
ParameterBlock pbScale = new ParameterBlock();
pbScale.addSource(convolved);
pbScale.add((float)sizeX/renderedOPCrop.getWidth());
pbScale.add((float)sizeY/renderedOPCrop.getHeight());
pbScale.add(0.0F);
pbScale.add(0.0F);
//pbScale.add(interp);
RenderedOp renderedOPScale = JAI.create("scale", pbScale, null);
*/
//Intermediate scale test
JAI.create("filestore", renderedOPScale,"D:/jai-images/result_1_1_3stable_bb/c_ssa_xlate_woman3.jpeg" ,"JPEG", null);

JPEGEncodeParam jpgparam = new JPEGEncodeParam();
jpgparam.setQuality(qualityF);

FileOutputStream fs = new FileOutputStream(outputFileName);
ImageEncoder enc = ImageCodec.createImageEncoder("jpeg", fs, jpgparam);
System.out.println("Finish");
enc.encode(renderedOPScale);
fs.flush();
fs.close();
}
catch(Exception e)
{
System.out.println("Exception: " + e);
}
}
}

Brian Burkhalter

Vinay,

Hello. Would you please supply the entire test case which can be compiled
without editing?

Thanks,

Brian

On Thu, 29 Jun 2006, jai-imageio@javadesktop.org wrote:

> Hi,
>
> I am relatively new to JAI and ImageIO, so sorry if these questions have been asked before.
>
> I am trying to convert a TIF image to JPEG format, but need to crop, scale and reduce the color of output JPEG image.
> I went through many archives but didn't get a proper solution.
>
> Will really appreciate help and suggestions of any kind
>
> Following code throws
> java.lang.IllegalArgumentException: Requested region cannot be represented by a single Raster.
>
> public class TestCropScale
> {
>
> public static void main(String args[])
>
> {
> int cropStartX = 49;
> int cropStartY = 0;
> int cropscalesizeX = 902;
> int cropscalesizeY = 1000;
> int scalesizeX = 240;
> int scalesizeY = 266;
> int quality = 67;
>
> try
> {
> String inFileName = "D:/jai-images/Doggy_Heart.tif";
> String outputFileName = "D:/jai-images/output/D_H1.jpg";
>
> PlanarImage pImage = JAI.create("fileload", inFileName);
> System.out.println("File load the temp JPG file = " + pImage);
>
> ParameterBlock pbCrop = new ParameterBlock();
> pbCrop.addSource(pImage);
> pbCrop.add((float)cropStartX);
> pbCrop.add((float)cropStartY);
> pbCrop.add((float)cropscalesizeX);
> pbCrop.add((float)cropscalesizeY);
> RenderedOp renderedOPCrop = JAI.create("crop", pbCrop, null);
> System.out.println("Cropped Image=" +renderedOPCrop);
>
> ParameterBlock pbScale = new ParameterBlock();
> pbScale.addSource(pImage);
> pbScale.add((float)scalesizeX);
> pbScale.add((float)scalesizeY);
> pbScale.add(0.0F);
> pbScale.add(0.0F);
> RenderedOp renderedOPScale = JAI.create("scale", pbScale, null);
> System.out.println("Scaled Image=" +renderedOPScale);
>
> JPEGEncodeParam jpgparam = new JPEGEncodeParam();
> jpgparam.setQuality(quality);
>
> FileOutputStream fs = new FileOutputStream(outputFileName);
> ImageEncoder enc = ImageCodec.createImageEncoder("jpeg", fs, jpgparam);
> enc.encode(renderedOPScale);
> /*
> JAI.create("filestore", renderedOPScale, outputFileName, "JPEG", null);
> */
> }
> catch(Exception e)
> {
> System.out.println("Exception = " +e);
> }
> }
>
> }
> [Message sent by forum member 'vinaypatil' (vinaypatil)]
>
> http://forums.java.net/jive/thread.jspa?messageID=128332
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-imageio.dev.java.net
>
>

----------------
Brian Burkhalter
Java Media, Imaging, and Graphics
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-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net