Reduce the size of an image in java - java

I want to make sure that an image in my application is not more than 200x200 px and the image size is not more than 150 kB. For example, if the file size of image is more than 150 kB i need to make it 150 kB. The image can be of type jpeg,png etc.
I have the following code for resizing an image to a given width and height
private BufferedImage resize(BufferedImage img, int newW, int newH) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage dimg = new BufferedImage(newW, newH, img.getType());
Graphics2D g = dimg.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);
g.dispose();
return dimg;
}
But im not sure how to go about reducing the file size to 150 kB. How to do that in java ?.Some example would be really appreciated.
Thank You

Just as an option - image magic - it also has some convenience wrappers for Java, so you can easily use it.

Does your question have any practical relevance or is it just theoretical?
A 200x200 pixel image with a colour depth of 24 bit will uncompressed require 117kB. If you use any reasonable JPEG encoder, it will also never exceed 150kB for such an image.

You can only rezise the image multiple times, to get below the determined file size.

Related

Scaling BufferedImage and writing to file [duplicate]

I have viewed this question, but it does not seem to actually answer the question that I have. I have a, image file, that may be any resolution. I need to load that image into a BufferedImage Object at a specific resolution (say, for this example, 800x800). I know the Image class can use getScaledInstance() to scale the image to a new size, but I then cannot figure out how to get it back to a BufferedImage. Is there a simple way to scale a Buffered Image to a specific size?
NOTE I I do not want to scale the image by a specific factor, I want to take an image and make is a specific size.
Something like this? :
/**
* Resizes an image using a Graphics2D object backed by a BufferedImage.
* #param srcImg - source image to scale
* #param w - desired width
* #param h - desired height
* #return - the new resized image
*/
private BufferedImage getScaledImage(Image srcImg, int w, int h){
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TRANSLUCENT);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}
You can create a new BufferedImage of the size you want and then perform a scaled paint of the original image into the new one:
BufferedImage resizedImage = new BufferedImage(new_width, new_height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(image, 0, 0, new_width, new_height, null);
g.dispose();
see this website Link1
Or
This Link2

Is there a way to scale an image down to a specific size?

I am currently trying to get some kind of 2D dungeoncrawler (think: roguelike) running. Now I want to work with square tiles (32x32) but I wonder if there's a way to make my textures in a higher resolution, say 64x64, and scale them down onto a 32x32 square?
I imagine there has to be since almost all games do this in one way or another but all I can seem to find online is about 3D stuff.
Yeah. When you draw an image, you can add the new width and height to it to resize it.
public static BufferedImage resizeImage(BufferedImage image, int newwidth, int newheight) {
BufferedImage image2 = new BufferedImage(newwidth, newheight, BufferedImage.TYPE_INT_ARGB);
Graphics g = image2.getGraphics();
g.drawImage(image, 0, 0, newwidth, newheight, null);
g.dispose();
return image2;
}
Refer to here for more info.

JavaFX: Fastest way to write pixels to PixelWriter

I'm looking for the fastest way to write pixels on javafx.scene.image.Image. Writing to BufferedImage's backing array is much faster. At least on the test image I made it took only ~20ms for BufferedImage, WritableImage on the other hand took ~100ms. I already tried SwingFXUtils but no luck.
Code for BufferedImage (faster):
BufferedImage bi = createCompatibleImage( width, height );
WritableRaster raster = bi.getRaster();
DataBufferInt dataBuffer = (DataBufferInt) raster.getDataBuffer();
System.arraycopy( pixels, 0, dataBuffer.getData(), 0, pixels.length );
Code for WritableImage (slower):
WritableImage wi = new WritableImage( width, height );
PixelWriter pw = wi.getPixelWriter();
WritablePixelFormat<IntBuffer> pf = WritablePixelFormat.getIntArgbInstance();
pw.setPixels( 0, 0, width, height, pf, pixels, 0, width );
Maybe there's a way to write to WritableImage's backing array too?
For the performance of the pixel writer it is absolutely crucial that you pick the right pixel format. You can check what the native pixel format is via
pw.getPixelFormat().getType()
On my Mac this is PixelFormat.Type.BYTE_BGRA_PRE. If your raw data conforms to this pixel format, then the transfer to the image should be pretty fast. Otherwise the pixel data has to be converted and that takes some time.

Whats the best way to lower the bitdepth of a PNG

I have a PNG image in an BufferedImage and I would like to lower the bitdepth in order to make it smaller. Below is a function that saves a small portion of an image to "disk." The writeImage function is the function that writes it to disk. Any ideas?
private BufferedImage createSubImage(Avatar avatar, int[] srcRect, Dimension size, BufferedImage image, String name) throws IOException {
Graphics2D graphics;
BufferedImage thumb = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
graphics = (Graphics2D) thumb.getGraphics();
//lower PNG bitdepth here
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.drawImage(image, 0, 0, size.width, size.height, srcRect[0], srcRect[1],
srcRect[2], srcRect[3], null);
writeImage(DataAccess.APP_DATA_BUCKET, thumb, "avatars/" + avatar.getId() + "/" + name);
thumb.flush();
return thumb;
}
png supports greyscale, indexed or truecolor with 8 or 16 bits per channel. if you reduce the bit depth yourself by rounding each value in all channels to a multiple of 4 for example the resulting png will be smaller because compression will be better. it will use only 6 instead of 8 bits so it should be around 6/8 the size of the original but can be much better (depending on the image) because most of the noisy, hard to compress information is in the 2 removed bits.

How to scale JPEG images with a non-standard sampling factor in Java?

I am using Java AWT for scaling a JPEG image, to create thumbnails. The code works fine when the image has a normal sampling factor ( 2x2,1x1,1x1 )
However, an image which has this sampling factor ( 1x1, 1x1, 1x1 ) creates problem when scaled. The colors get corrupted though the features are recognizable.
The original and the thumbnail:
alt text http://otherplace.in/thumb1.jpg
The code I am using is roughly equivalent to:
static BufferedImage awtScaleImage(BufferedImage image,
int maxSize, int hint) {
// We use AWT Image scaling because it has far superior quality
// compared to JAI scaling. It also performs better (speed)!
System.out.println("AWT Scaling image to: " + maxSize);
int w = image.getWidth();
int h = image.getHeight();
float scaleFactor = 1.0f;
if (w > h)
scaleFactor = ((float) maxSize / (float) w);
else
scaleFactor = ((float) maxSize / (float) h);
w = (int)(w * scaleFactor);
h = (int)(h * scaleFactor);
// since this code can run both headless and in a graphics context
// we will just create a standard rgb image here and take the
// performance hit in a non-compatible image format if any
Image i = image.getScaledInstance(w, h, hint);
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
g.drawImage(i, null, null);
g.dispose();
i.flush();
return image;
}
(Code courtesy of this page )
Is there a better way to do this?
Here's a test image with sampling factor of [ 1x1, 1x1, 1x1 ].
I believe the problem is not the scaling, but your use of an incompatible color model ("image type") when constructing your BufferedImage.
Creating decent thumbnails in Java is surprisingly hard. Here's a detailed discussion.

Categories

Resources