Small quiet zone with Zxing when specified 0 - java

I'm currently using the ZXing Library to decode QR Codes. Additional I'm displaying the created QR Code on the screen with JavaFx. I'd like to create QR Codes without quiet zone, so I set the margin to zero. However I realized that when I create a QR Code with Error Correction Level L there is still a small quiet zone. Here is a picture displaying the result.
Picture1
Now the strange thing is the same QR Code with Error Correction Level H has no quiet zone.
Here is my code for creating the QR Codes.
private BufferedImage QRCodeGenerator(String content, int height, int width) {
Map<EncodeHintType, Object> hintMap = new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
hintMap.put(EncodeHintType.MARGIN, 0);
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BufferedImage bufferedImage = null;
try {
BitMatrix byteMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hintMap);
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
bufferedImage.createGraphics();
Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
graphics.setColor(Color.BLACK);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (byteMatrix.get(i, j)) {
graphics.fillRect(i, j, 1, 1);
}
}
}
} catch (WriterException e) {
}
return bufferedImage;
}
Can someone explain this behavior?

Related

Antialiasing on JButton Icon [duplicate]

I made this code to resize images with two factors. It works, but the quality of image is very bad after it is resized! Can you help me?
This is the code
public class ImageTest {
private static final int factor1 = 3;
private static final int factor2 = 4;
public static void main(String [] args){
JFileChooser cs = new JFileChooser();
cs.setFileSelectionMode(cs.DIRECTORIES_ONLY);
int i = cs.showOpenDialog(null);
if(i==cs.APPROVE_OPTION){
File f = cs.getSelectedFile();
File[] ff = f.listFiles();
for(int j=0;j<ff.length;j++){
String end = ff[j].getName().substring(ff[j].getName().indexOf(".")+1);
System.out.println(end);
try{
BufferedImage originalImage = ImageIO.read(ff[j]);
int type = originalImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizeImageJpg = resizeImageWithHint(originalImage, type);
ImageIO.write(resizeImageJpg, end, new File("pr/"+ff[j].getName()));
}catch(IOException e){
e.printStackTrace();
}
}
}
}
private static BufferedImage resizeImageWithHint(BufferedImage originalImage, int type){
int IMG_WIDTH = (originalImage.getWidth()*factor1)/factor2;
int IMG_HEIGHT = (originalImage.getHeight()*factor1)/factor2;
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
return resizedImage;
}
}
I saw on web that resizeImageWithHint is done within the scope so as not to lose quality.. but it does! why? can you help me with this?
The best article I have ever read on this topic is The Perils of Image.getScaledInstance() (web archive).
In short: You need to use several resizing steps in order to get a good image. Helper method from the article:
public BufferedImage getScaledInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality)
{
int type = (img.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage)img;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
return ret;
}
The following code produced me highest quality resize with aspect ratio preserved.
Tried few things and read several entries presented here in other answers. Lost two days and in the end I got the best result with plain Java method (tried also ImageMagick and java-image-scaling libraries):
public static boolean resizeUsingJavaAlgo(String source, File dest, int width, int height) throws IOException {
BufferedImage sourceImage = ImageIO.read(new FileInputStream(source));
double ratio = (double) sourceImage.getWidth()/sourceImage.getHeight();
if (width < 1) {
width = (int) (height * ratio + 0.4);
} else if (height < 1) {
height = (int) (width /ratio + 0.4);
}
Image scaled = sourceImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedScaled.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.drawImage(scaled, 0, 0, width, height, null);
dest.createNewFile();
writeJpeg(bufferedScaled, dest.getCanonicalPath(), 1.0f);
return true;
}
/**
* Write a JPEG file setting the compression quality.
*
* #param image a BufferedImage to be saved
* #param destFile destination file (absolute or relative path)
* #param quality a float between 0 and 1, where 1 means uncompressed.
* #throws IOException in case of problems writing the file
*/
private static void writeJpeg(BufferedImage image, String destFile, float quality)
throws IOException {
ImageWriter writer = null;
FileImageOutputStream output = null;
try {
writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
output = new FileImageOutputStream(new File(destFile));
writer.setOutput(output);
IIOImage iioImage = new IIOImage(image, null, null);
writer.write(null, iioImage, param);
} catch (IOException ex) {
throw ex;
} finally {
if (writer != null) {
writer.dispose();
}
if (output != null) {
output.close();
}
}
}
Know question is old... I've tried different solutions surfing then web, I got the best result using getScaledInstance(), supplying Image.SCALE_SMOOTH as argument. In fact the resulting image quality was really better.
My code below:
final int THUMB_SIDE = 140;
try {
BufferedImage masterImage = ImageIO.read(startingImage);
BufferedImage thumbImage = new BufferedImage(THUMB_SIDE, THUMB_SIDE, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = thumbImage.createGraphics();
g2d.drawImage(masterImage.getScaledInstance(THUMB_SIDE, THUMB_SIDE, Image.SCALE_SMOOTH), 0, 0, THUMB_SIDE, THUMB_SIDE, null);
g2d.dispose();
String thumb_path = path.substring(0, path.indexOf(".png")) + "_thumb.png";
ImageIO.write(thumbImage, "png", new File(thumb_path));
} catch (IOException e) {
e.printStackTrace();
}
If your image source is a png then use like this:
Image imgSmall = imgBig.getScaledInstance(
targetWidth, targetHeight, Image.SCALE_SMOOTH);
If you want to resize jpeg or gif without loose too much quality, I made a library in 2010 for this: beautylib on github that uses internally this other library: java-image-scaling. You can see directly the source code to find something useful: https://github.com/felipelalli/beautylib/blob/master/src/br/eti/fml/beautylib/ResizeImage.java
None of the answers will help you to get real quality you desire. Include thumbailator.jar in your project (download it form here):
https://code.google.com/p/thumbnailator/
https://code.google.com/p/thumbnailator/wiki/Downloads?tm=2
Then upload the image first (as file, without Thumbnailator - it's use is to create thumbs, but you can create large images with it of course), and resize it to every dimensions you want (with Thumbnailator 800x600 for example). Quality will be very good. I was searching for this long time, this .jar helped me to achieve what i want.
Yes, I had the same problems and solved them, please read my question (answer is embedded in the question). I tried imgscalr and java-image-scaling libraries and found the second much better quality. Get close to the monitor to appreciate the difference between the thumbnail examples.
Despite my initial thoughts, resizing an image seems a very complicate thing, you don't want to do it yourself. For example I tell java-image-scaling to use ResampleFilters.getLanczos3Filter() to have better result.
It also addresses how to save a JPG with a quality higher than the standard 75, which produces a bad result especially for a thumbnail.
I also wrote a small class, called MyImage to help with common tasks, such as reading an image from a byte array, from a file, scaling by specifying only width or only height, scaling by specifying a bounding box, scaling by specifying width and height and adding a white band to make the image not distorted and writing to JPG file.
Answer: Remove the hints VALUE_INTERPOLATION_BILINEAR, and VALUE_RENDERING_QUALITY.
Example:
public static BufferedImage resizeImage(BufferedImage image, int width, int height) {
// Temporary image
BufferedImage tmp = image;
// Result image
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Graphics object
Graphics2D graphics = (Graphics2D)result.createGraphics();
// Add rendering hints
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
// Draw tmp
graphics.drawImage(tmp, 0, 0, width, height, null);
// Dispose of graphics object
graphics.dispose();
// Return image result
return result;
}
Note: For some reason, the hints VALUE_INTERPOLATION_BILINEAR and VALUE_RENDERING_QUALITY blur the image being resized.
All the methods posted does'nt work for me i have to reduce QrCode size, but with above methods the quality is poor and scanner doesn't work , if i take original picture and resize it in paint the scanner is working.
The do while loop used in The Perils of Image.getScaledInstance() will run into an infinite loop, given those values,
w = 606; h = 505, targetWidth = 677, targetHeight = 505
Here is a simplied testing code, you can try it.
public class LoopTest {
public static void main(String[] args) {
new LoopTest(true, 606, 505, 677, 505);
}
public LoopTest(boolean higherQuality, int w, int h, int targetWidth, int targetHeight) {
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
} while (w != targetWidth || h != targetHeight); // TODO Auto-generated constructor stub
}
}
A quick work around: define an index for loop count. If the index is >=10, break out of loop.

How to find out that the Barcode has been scanned?

I have this method to generate a Barcode bitmap:
public static Bitmap encodeToQrCode(String text, int width, int height) {
QRCodeWriter writer = new QRCodeWriter();
BitMatrix matrix = null;
try {
matrix = writer.encode(text, BarcodeFormat.QR_CODE, 400, 400);
} catch (WriterException ex) {
ex.printStackTrace();
}
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height - 1; y++) {
bmp.setPixel(x, y, matrix.get(x, y) ? Color.BLACK : Color.WHITE);
}
}
return bmp;
}
Is there any way to find out that the Barcode has been scanned? I'm using zxing.
If I understand you correctly you're looking for a way to
Create a bitmap that contains a QR code
Display that bitmap on your device
Detect when a different device that doesn't use your software scans that code
This is not possible. The QR code bitmap is just that: A bitmap your app displays. And a barcode scanner app simply takes a photo of your display and tries to find patterns in that bitmap.

Is there the better way to resize the Buffered image without losing of quality? [duplicate]

I made this code to resize images with two factors. It works, but the quality of image is very bad after it is resized! Can you help me?
This is the code
public class ImageTest {
private static final int factor1 = 3;
private static final int factor2 = 4;
public static void main(String [] args){
JFileChooser cs = new JFileChooser();
cs.setFileSelectionMode(cs.DIRECTORIES_ONLY);
int i = cs.showOpenDialog(null);
if(i==cs.APPROVE_OPTION){
File f = cs.getSelectedFile();
File[] ff = f.listFiles();
for(int j=0;j<ff.length;j++){
String end = ff[j].getName().substring(ff[j].getName().indexOf(".")+1);
System.out.println(end);
try{
BufferedImage originalImage = ImageIO.read(ff[j]);
int type = originalImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizeImageJpg = resizeImageWithHint(originalImage, type);
ImageIO.write(resizeImageJpg, end, new File("pr/"+ff[j].getName()));
}catch(IOException e){
e.printStackTrace();
}
}
}
}
private static BufferedImage resizeImageWithHint(BufferedImage originalImage, int type){
int IMG_WIDTH = (originalImage.getWidth()*factor1)/factor2;
int IMG_HEIGHT = (originalImage.getHeight()*factor1)/factor2;
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
return resizedImage;
}
}
I saw on web that resizeImageWithHint is done within the scope so as not to lose quality.. but it does! why? can you help me with this?
The best article I have ever read on this topic is The Perils of Image.getScaledInstance() (web archive).
In short: You need to use several resizing steps in order to get a good image. Helper method from the article:
public BufferedImage getScaledInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality)
{
int type = (img.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage)img;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
return ret;
}
The following code produced me highest quality resize with aspect ratio preserved.
Tried few things and read several entries presented here in other answers. Lost two days and in the end I got the best result with plain Java method (tried also ImageMagick and java-image-scaling libraries):
public static boolean resizeUsingJavaAlgo(String source, File dest, int width, int height) throws IOException {
BufferedImage sourceImage = ImageIO.read(new FileInputStream(source));
double ratio = (double) sourceImage.getWidth()/sourceImage.getHeight();
if (width < 1) {
width = (int) (height * ratio + 0.4);
} else if (height < 1) {
height = (int) (width /ratio + 0.4);
}
Image scaled = sourceImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedScaled.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.drawImage(scaled, 0, 0, width, height, null);
dest.createNewFile();
writeJpeg(bufferedScaled, dest.getCanonicalPath(), 1.0f);
return true;
}
/**
* Write a JPEG file setting the compression quality.
*
* #param image a BufferedImage to be saved
* #param destFile destination file (absolute or relative path)
* #param quality a float between 0 and 1, where 1 means uncompressed.
* #throws IOException in case of problems writing the file
*/
private static void writeJpeg(BufferedImage image, String destFile, float quality)
throws IOException {
ImageWriter writer = null;
FileImageOutputStream output = null;
try {
writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
output = new FileImageOutputStream(new File(destFile));
writer.setOutput(output);
IIOImage iioImage = new IIOImage(image, null, null);
writer.write(null, iioImage, param);
} catch (IOException ex) {
throw ex;
} finally {
if (writer != null) {
writer.dispose();
}
if (output != null) {
output.close();
}
}
}
Know question is old... I've tried different solutions surfing then web, I got the best result using getScaledInstance(), supplying Image.SCALE_SMOOTH as argument. In fact the resulting image quality was really better.
My code below:
final int THUMB_SIDE = 140;
try {
BufferedImage masterImage = ImageIO.read(startingImage);
BufferedImage thumbImage = new BufferedImage(THUMB_SIDE, THUMB_SIDE, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = thumbImage.createGraphics();
g2d.drawImage(masterImage.getScaledInstance(THUMB_SIDE, THUMB_SIDE, Image.SCALE_SMOOTH), 0, 0, THUMB_SIDE, THUMB_SIDE, null);
g2d.dispose();
String thumb_path = path.substring(0, path.indexOf(".png")) + "_thumb.png";
ImageIO.write(thumbImage, "png", new File(thumb_path));
} catch (IOException e) {
e.printStackTrace();
}
If your image source is a png then use like this:
Image imgSmall = imgBig.getScaledInstance(
targetWidth, targetHeight, Image.SCALE_SMOOTH);
If you want to resize jpeg or gif without loose too much quality, I made a library in 2010 for this: beautylib on github that uses internally this other library: java-image-scaling. You can see directly the source code to find something useful: https://github.com/felipelalli/beautylib/blob/master/src/br/eti/fml/beautylib/ResizeImage.java
None of the answers will help you to get real quality you desire. Include thumbailator.jar in your project (download it form here):
https://code.google.com/p/thumbnailator/
https://code.google.com/p/thumbnailator/wiki/Downloads?tm=2
Then upload the image first (as file, without Thumbnailator - it's use is to create thumbs, but you can create large images with it of course), and resize it to every dimensions you want (with Thumbnailator 800x600 for example). Quality will be very good. I was searching for this long time, this .jar helped me to achieve what i want.
Yes, I had the same problems and solved them, please read my question (answer is embedded in the question). I tried imgscalr and java-image-scaling libraries and found the second much better quality. Get close to the monitor to appreciate the difference between the thumbnail examples.
Despite my initial thoughts, resizing an image seems a very complicate thing, you don't want to do it yourself. For example I tell java-image-scaling to use ResampleFilters.getLanczos3Filter() to have better result.
It also addresses how to save a JPG with a quality higher than the standard 75, which produces a bad result especially for a thumbnail.
I also wrote a small class, called MyImage to help with common tasks, such as reading an image from a byte array, from a file, scaling by specifying only width or only height, scaling by specifying a bounding box, scaling by specifying width and height and adding a white band to make the image not distorted and writing to JPG file.
Answer: Remove the hints VALUE_INTERPOLATION_BILINEAR, and VALUE_RENDERING_QUALITY.
Example:
public static BufferedImage resizeImage(BufferedImage image, int width, int height) {
// Temporary image
BufferedImage tmp = image;
// Result image
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Graphics object
Graphics2D graphics = (Graphics2D)result.createGraphics();
// Add rendering hints
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
// Draw tmp
graphics.drawImage(tmp, 0, 0, width, height, null);
// Dispose of graphics object
graphics.dispose();
// Return image result
return result;
}
Note: For some reason, the hints VALUE_INTERPOLATION_BILINEAR and VALUE_RENDERING_QUALITY blur the image being resized.
All the methods posted does'nt work for me i have to reduce QrCode size, but with above methods the quality is poor and scanner doesn't work , if i take original picture and resize it in paint the scanner is working.
The do while loop used in The Perils of Image.getScaledInstance() will run into an infinite loop, given those values,
w = 606; h = 505, targetWidth = 677, targetHeight = 505
Here is a simplied testing code, you can try it.
public class LoopTest {
public static void main(String[] args) {
new LoopTest(true, 606, 505, 677, 505);
}
public LoopTest(boolean higherQuality, int w, int h, int targetWidth, int targetHeight) {
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
} while (w != targetWidth || h != targetHeight); // TODO Auto-generated constructor stub
}
}
A quick work around: define an index for loop count. If the index is >=10, break out of loop.

Resizing an image in swing

I have snippet of code that I am using for the purpose of resizing an image to a curtain size (I want to change the resolution to something like 200 dpi). Basically the reason I need it is because I want to display the image that the user have picked (somewhat large) and then if the user approves I want to display the same image in a different place but using a smaller resolution. Unfortunately, if I give it a large image nothing appears on the screen. Also, if I change
imageLabel.setIcon(newIcon);
to
imageLabel.setIcon(icon);
I get the image to display but not in the correct resolution that's how I know that I have a problem inside this snipper of code and not somewhere else.
Image img = icon.getImage();
BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
BufferedImage bi = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
boolean myBool = g.drawImage(img, 0, 0, 100, 100, null);
System.out.println(myBool);
ImageIcon newIcon = new ImageIcon(bi);
imageLabel.setIcon(newIcon);
submitText.setText(currentImagePath);
imageThirdPanel.add(imageLabel);
You don't really have to care about the details of scaling images. The Image class has already a method getScaledInstance(int width, int height, int hints) designed for this purpose.
Java documentation says:
Creates a scaled version of this image. A new Image object is returned
which will render the image at the specified width and height by
default. The new Image object may be loaded asynchronously even if the
original source image has already been loaded completely. If either
the width or height is a negative number then a value is substituted
to maintain the aspect ratio of the original image dimensions.
And you can use it like this:
// Scale Down the original image fast
Image scaledImage = imageToScale.getScaledInstance(newWidth, newHighth, Image.SCALE_FAST);
// Repaint this component
repaint();
Check this for a complete example.
Here is my solution:
private BufferedImage resizeImage(BufferedImage originalImage, int width, int height, int type) throws IOException {
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
Try this CODE to resize image :
public static Image scaleImage(Image original, int newWidth, int newHeight) {
//do nothing if new and old resolutions are same
if (original.getWidth() == newWidth && original.getHeight() == newHeight) {
return original;
}
int[] rawInput = new int[original.getHeight() * original.getWidth()];
original.getRGB(rawInput, 0, original.getWidth(), 0, 0, original.getWidth(), original.getHeight());
int[] rawOutput = new int[newWidth * newHeight];
// YD compensates for the x loop by subtracting the width back out
int YD = (original.getHeight() / newHeight) * original.getWidth() - original.getWidth();
int YR = original.getHeight() % newHeight;
int XD = original.getWidth() / newWidth;
int XR = original.getWidth() % newWidth;
int outOffset = 0;
int inOffset = 0;
for (int y = newHeight, YE = 0; y > 0; y--) {
for (int x = newWidth, XE = 0; x > 0; x--) {
rawOutput[outOffset++] = rawInput[inOffset];
inOffset += XD;
XE += XR;
if (XE >= newWidth) {
XE -= newWidth;
inOffset++;
}
}
inOffset += YD;
YE += YR;
if (YE >= newHeight) {
YE -= newHeight;
inOffset += original.getWidth();
}
}
return Image.createRGBImage(rawOutput, newWidth, newHeight, false);
}
Another example is given here :
2D-Graphics/LoadImageandscaleit.htm">http://www.java2s.com/Tutorial/Java/0261_2D-Graphics/LoadImageandscaleit.htm
http://www.java2s.com/Code/JavaAPI/java.awt/ImagegetScaledInstanceintwidthintheightinthints.htm

Re-sizing an image without losing quality

I made this code to resize images with two factors. It works, but the quality of image is very bad after it is resized! Can you help me?
This is the code
public class ImageTest {
private static final int factor1 = 3;
private static final int factor2 = 4;
public static void main(String [] args){
JFileChooser cs = new JFileChooser();
cs.setFileSelectionMode(cs.DIRECTORIES_ONLY);
int i = cs.showOpenDialog(null);
if(i==cs.APPROVE_OPTION){
File f = cs.getSelectedFile();
File[] ff = f.listFiles();
for(int j=0;j<ff.length;j++){
String end = ff[j].getName().substring(ff[j].getName().indexOf(".")+1);
System.out.println(end);
try{
BufferedImage originalImage = ImageIO.read(ff[j]);
int type = originalImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizeImageJpg = resizeImageWithHint(originalImage, type);
ImageIO.write(resizeImageJpg, end, new File("pr/"+ff[j].getName()));
}catch(IOException e){
e.printStackTrace();
}
}
}
}
private static BufferedImage resizeImageWithHint(BufferedImage originalImage, int type){
int IMG_WIDTH = (originalImage.getWidth()*factor1)/factor2;
int IMG_HEIGHT = (originalImage.getHeight()*factor1)/factor2;
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
return resizedImage;
}
}
I saw on web that resizeImageWithHint is done within the scope so as not to lose quality.. but it does! why? can you help me with this?
The best article I have ever read on this topic is The Perils of Image.getScaledInstance() (web archive).
In short: You need to use several resizing steps in order to get a good image. Helper method from the article:
public BufferedImage getScaledInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality)
{
int type = (img.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage)img;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
return ret;
}
The following code produced me highest quality resize with aspect ratio preserved.
Tried few things and read several entries presented here in other answers. Lost two days and in the end I got the best result with plain Java method (tried also ImageMagick and java-image-scaling libraries):
public static boolean resizeUsingJavaAlgo(String source, File dest, int width, int height) throws IOException {
BufferedImage sourceImage = ImageIO.read(new FileInputStream(source));
double ratio = (double) sourceImage.getWidth()/sourceImage.getHeight();
if (width < 1) {
width = (int) (height * ratio + 0.4);
} else if (height < 1) {
height = (int) (width /ratio + 0.4);
}
Image scaled = sourceImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedScaled.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.drawImage(scaled, 0, 0, width, height, null);
dest.createNewFile();
writeJpeg(bufferedScaled, dest.getCanonicalPath(), 1.0f);
return true;
}
/**
* Write a JPEG file setting the compression quality.
*
* #param image a BufferedImage to be saved
* #param destFile destination file (absolute or relative path)
* #param quality a float between 0 and 1, where 1 means uncompressed.
* #throws IOException in case of problems writing the file
*/
private static void writeJpeg(BufferedImage image, String destFile, float quality)
throws IOException {
ImageWriter writer = null;
FileImageOutputStream output = null;
try {
writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
output = new FileImageOutputStream(new File(destFile));
writer.setOutput(output);
IIOImage iioImage = new IIOImage(image, null, null);
writer.write(null, iioImage, param);
} catch (IOException ex) {
throw ex;
} finally {
if (writer != null) {
writer.dispose();
}
if (output != null) {
output.close();
}
}
}
Know question is old... I've tried different solutions surfing then web, I got the best result using getScaledInstance(), supplying Image.SCALE_SMOOTH as argument. In fact the resulting image quality was really better.
My code below:
final int THUMB_SIDE = 140;
try {
BufferedImage masterImage = ImageIO.read(startingImage);
BufferedImage thumbImage = new BufferedImage(THUMB_SIDE, THUMB_SIDE, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = thumbImage.createGraphics();
g2d.drawImage(masterImage.getScaledInstance(THUMB_SIDE, THUMB_SIDE, Image.SCALE_SMOOTH), 0, 0, THUMB_SIDE, THUMB_SIDE, null);
g2d.dispose();
String thumb_path = path.substring(0, path.indexOf(".png")) + "_thumb.png";
ImageIO.write(thumbImage, "png", new File(thumb_path));
} catch (IOException e) {
e.printStackTrace();
}
If your image source is a png then use like this:
Image imgSmall = imgBig.getScaledInstance(
targetWidth, targetHeight, Image.SCALE_SMOOTH);
If you want to resize jpeg or gif without loose too much quality, I made a library in 2010 for this: beautylib on github that uses internally this other library: java-image-scaling. You can see directly the source code to find something useful: https://github.com/felipelalli/beautylib/blob/master/src/br/eti/fml/beautylib/ResizeImage.java
None of the answers will help you to get real quality you desire. Include thumbailator.jar in your project (download it form here):
https://code.google.com/p/thumbnailator/
https://code.google.com/p/thumbnailator/wiki/Downloads?tm=2
Then upload the image first (as file, without Thumbnailator - it's use is to create thumbs, but you can create large images with it of course), and resize it to every dimensions you want (with Thumbnailator 800x600 for example). Quality will be very good. I was searching for this long time, this .jar helped me to achieve what i want.
Yes, I had the same problems and solved them, please read my question (answer is embedded in the question). I tried imgscalr and java-image-scaling libraries and found the second much better quality. Get close to the monitor to appreciate the difference between the thumbnail examples.
Despite my initial thoughts, resizing an image seems a very complicate thing, you don't want to do it yourself. For example I tell java-image-scaling to use ResampleFilters.getLanczos3Filter() to have better result.
It also addresses how to save a JPG with a quality higher than the standard 75, which produces a bad result especially for a thumbnail.
I also wrote a small class, called MyImage to help with common tasks, such as reading an image from a byte array, from a file, scaling by specifying only width or only height, scaling by specifying a bounding box, scaling by specifying width and height and adding a white band to make the image not distorted and writing to JPG file.
Answer: Remove the hints VALUE_INTERPOLATION_BILINEAR, and VALUE_RENDERING_QUALITY.
Example:
public static BufferedImage resizeImage(BufferedImage image, int width, int height) {
// Temporary image
BufferedImage tmp = image;
// Result image
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Graphics object
Graphics2D graphics = (Graphics2D)result.createGraphics();
// Add rendering hints
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
// Draw tmp
graphics.drawImage(tmp, 0, 0, width, height, null);
// Dispose of graphics object
graphics.dispose();
// Return image result
return result;
}
Note: For some reason, the hints VALUE_INTERPOLATION_BILINEAR and VALUE_RENDERING_QUALITY blur the image being resized.
All the methods posted does'nt work for me i have to reduce QrCode size, but with above methods the quality is poor and scanner doesn't work , if i take original picture and resize it in paint the scanner is working.
The do while loop used in The Perils of Image.getScaledInstance() will run into an infinite loop, given those values,
w = 606; h = 505, targetWidth = 677, targetHeight = 505
Here is a simplied testing code, you can try it.
public class LoopTest {
public static void main(String[] args) {
new LoopTest(true, 606, 505, 677, 505);
}
public LoopTest(boolean higherQuality, int w, int h, int targetWidth, int targetHeight) {
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
} while (w != targetWidth || h != targetHeight); // TODO Auto-generated constructor stub
}
}
A quick work around: define an index for loop count. If the index is >=10, break out of loop.

Categories

Resources