Resize image without loss of information - java

I was trying to do really the same functionality of resizing images like in MS Word.
I want to resize BufferedImage but I’m losing some information during process of resizing.
I tried to implement two approaches, but both produced same result.
Before any resizing:
Picture after few resize actions in my application:
First approach:
image = Thumbnails.of(image).size(w,h).asBufferedImage();
Second approach:
image = toBufferedImage(image.getScaledInstance(w, h, Image.SCALE_SMOOTH));
image is instance of BufferedImage, w is new width of image and h is new hight of image
Any idea, what I’m doing wrong?

You're constantly losing information from your image after each resizing attempt. If you want solution (like in MS Word) you have to keep somewhere original image but show only resized copy.
The best solution would be creating an object to store original image and making resized copy on demand. You can improve quality of this solution adding simple cache so you don't actually generate another resized copy of your image for every request but only if your application demands image with different height or width than last time.
I hope I helped you a bit.

Related

WorldWind complicated updating 2D interface

I use using WorldWind to plot data, and I also require a 2D interface as an overlay. I have been creating a new BufferedImage a few times per second to update the data, but this requires a lot of overhead. I'd like to redraw on an existing image to decrease the overall usage, both in terms of CPU and memory. I'm using this code before redrawing:
BufferedImage img = TrackingService.img.get(width).get(height);
g = img.createGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
g.fillRect(0,0,img.getWidth(),img.getHeight());
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
image = img;
ach element which can add to the UI returns a HashMap of BufferedImage to Point. Each BufferedImage and point is transformed into a ButtonAnnotation and added to an AnnotationLayer. Each x milliseconds, the system will:
layer.removeAllAnnotations();
layer.addAnnotations(buttonAnnotations);
redraw()
on the AWT Event queue. This works fine for markers, etc. but these images will never change from the first image I use. I've tried replacing the layer, disposing it, etc. I've tried writing the images to a debug file and noted that the BufferedImage is changing as expected. The problem is that WorldWind must be caching the images at some level. Since I am providing the same instance of BufferedImage to each new ButtonAnnotation, with a few modifications made using Graphics2D, it appears to be assuming that no changes have been made, when, in fact, there have been. This works perfectly fine if I use a new BufferedImage each time I want the data to change.
I have also tried the suggestions in This Question, and they did not work for me.

Image Resize UpScale lost Quality

I want to try up scale image up to 3 times.
For example,
Up Scaled Image
I am using this library for Image Resizing.
The following code snipped does the trick,
public static BufferedImage getScaledSampledImage(BufferedImage img,
int targetWidth, int targetHeight, boolean higherQuality) {
ResampleOp resampleOp = new ResampleOp(targetWidth, targetHeight);
resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.Normal);
BufferedImage rescaledImage = resampleOp.filter(img, null);
return rescaledImage;
}
You can see there a resized images are lower quality. I want that I can up scale images at least 3 times than the original image without quality lost.
Is it Pposible? Should I need to change existing library ?
Thanks
The fact is that when you scale an image up, it has to create data where there was none. (Roughly speaking). To do this, you have to interpolate between the existing pixels to fill in the new ones. You may be able to get better results by trying different kinds of interpolation - but the best method will be different for different kinds of images.
Since your sample image is just squares, nearest-neighbour interpolation will likely give you the best results. If you are scaling up an image of scenery or maybe a portrait you'll need a more clever algorithm.
The result will rarely look perfect, and it's best to start with a larger image if possible!
Take a look here to get an understanding of the problem. http://en.wikipedia.org/wiki/Image_scaling#Scaling_methods

Image Resizing, Java

Could someone explain why this line of code isn't working. No errors are given. It simply doesn't resize the image.
image = ImageIO.read(file);
image.getScaledInstance(ImageDisplayBox.getWidth(), ImageDisplayBox.getHeight());
ImageDisplayBox.setIcon(new ImageIcon(image));
I've looked at the other answers on Stackoverflow and noticed a lot of people using the .getScaledInstance method.
I (think) it might be the fact that I have it as .setIcon - Although I'm not the best with Java.
The image is printed but displays only the top left of the image due to size.
You're ignoring the returned value. You want:
image = image.getScaledInstance(ImageDisplayBox.getWidth(),
ImageDisplayBox.getHeight(), 5);
Or maybe to make things clearer:
Image scaled = image.getScaledInstance(ImageDisplayBox.getWidth(),
ImageDisplayBox.getHeight(), 5);
ImageDisplayBox.setIcon(new ImageIcon(scaled));
From the docs:
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.
Note that that doesn't say anything about changing the existing image. It just creates a new image with the given size.
Yes
This should work
Image scaled =image.getScaledInstance(ImageDisplayBox.getWidth(),
ImageDisplayBox.getHeight(), 5);
ImageDisplayBox.setIcon(new ImageIcon(scaled));

Image manipulation using java

i'm trying to create a program that generates images for use as multi-screen backgrounds, i'm doing this targeted at windows (in my case, 7 so that basically i can get images to change without seeing the same image on two different screens)
in my program, i read multiple image input files and compile them into a single output image that is the total size of the desktop (including black areas not seen on screens)
my question is, what class/methods are good for cropping/resizing/pasting into a new image in java because i'm coming across so many image manipulation classes and they all seem to do one tiny thing.
i will not be modifying any of the images beyond resize or crop and putting it into a certain position in the new (initially blank) image.
code can be made available as i plan to release it at some later point for whoever may like/need it.
thank you in advance, if this question has been answered, my apologies but i DID have a look around.
I do not know if this is the best method, but it is quite easy:
// load an image
Image image = javax.imageio.ImageIO.read(new File("someimage.png");
// resize it
image = image.getScaledInstance(100, 100, Image.SCALE_SMOOTH);
// create a new image to render to
BufferedImage newimg = new BufferedImage(200,100,BufferedImage.TYPE_INT_ARGB);
// get graphics to draw..
Graphics2D graphics =newimg.createGraphics();
//draw the other image on it
graphics.drawImage(image,0,0,null);
graphics.drawImage(image,100,0,null);
graphics.fillOval(20,20,40,40); //making it a bit ugly ;)
//export the new image
ImageIO.write(newimg,"png",new File("output.png"));
//done!
For simplicity I dropped all checks, exception handling, etc.

SWT Image concatenation or tiling / mosaic

I have an Eclipse RCP application that displays a lot (10k+) of small images next to each other, like a film strip. For each image, I am using a SWT Image object. This uses an excessive amount of memory and resources. I am looking for a more efficient way. I thought of taking all of these images and concatenating them by creating an ImageData object of the proper total, concatenated width (with a constant height) and using setPixel() for the rest of the pixels. However, the Palette used in the ImageData constructor I can't figure out.
I also searched for SWT tiling or mosaic functionality to create one image from a group of images, but found nothing.
Any ideas how I can display thousands of small images next to each other efficiently? Please note that once the images are displayed, they are not manipulated, so this is a one-time cost.
You can draw directly on the GC (graphics context) of a new (big) image. Having one big Image should result in much less resource usage than thousands of smaller images (each image in SWT keeps some OS graphics object handle)
What you can try is something like this:
final List<Image> images;
final Image bigImage = new Image(Display.getCurrent(), combinedWidth, height);
final GC gc = new GC(bigImage);
//loop thru all the images while increasing x as necessary:
int x = 0;
int y = 0;
for (Image curImage : images) {
gc.drawImage(curImage, x, y);
x += curImage.getBounds().width;
}
//very important to dispose GC!!!
gc.dispose();
//now you can use bigImage
Presumably not every image is visible on screen at any one time? Perhaps a better solution would be to only load the images when they become (or are about to become) visible, disposing of them when they have been scrolled off the screen. Obviously you'd want to keep a few in memory on either side of the current viewport in order to make a smooth transition for the user.
I previously worked with a Java application to create photomosaics, and found it very difficult to achieve adequate performance and memory usage using the java imaging (JAI) libraries and SWT. Although we weren't using nearly as many images as you mention, one route was to rely on a utilities outside of java. In particular, you could use ImageMagick command-line utilities to stitch together your mosaic, and the load the completed memory from disk. If you want to get fancy, there is also a C++ API for ImageMagick, which is very efficient in memory.

Categories

Resources