Adjust brightness and contrast of BufferedImage in Java - java

I'm processing a bunch of images with some framework, and all I'm given is a bunch of BufferedImage objects. Unfortunately, these images are really dim, and I'd like to brighten them up and adjust the contrast a little.
Something like:
BufferedImage image = something.getImage();
image = new Brighten(image).brighten(0.3); // for 30%
image = new Contrast(image).contrast(0.3);
// ...
Any ideas?

That was easy, actually.
RescaleOp rescaleOp = new RescaleOp(1.2f, 15, null);
rescaleOp.filter(image, image); // Source and destination are the same.
A scaleFactor of 1.2 and offset of 15 seems to make the image about a stop brighter.
Yay!
Read more in the docs for RescaleOp.

Related

Putting multiple images together into one

I have bunch of photos sorted in a folder so that there is always one photo of type A and one photo of type B immediately after that.
Unfortunately, some of them needed to be rotated and I did so using standard Windows file explorer.
What I need is to combine each pair of photos A and B into new single photo so that the first source photo is displayed above the second. Both photos have same width.
Here is the code :
File first = ...;
File second = ...;
BufferedImage A = ImageIO.read(first);
BufferedImage B = ImageIO.read(second);
int resultHeight = A.getHeight() + B.getHeight();
int resultWidth = A.getWidth();
BufferedImage combined = new BufferedImage(resultWidth, resultHeight, BufferedImage.TYPE_INT_ARGB);
Graphics g = combined.getGraphics();
g.drawImage(A, 0, 0, null);
g.drawImage(B, 0, A.getHeight(), null);
g.dispose();
ImageIO.write(combined, "PNG", new File(destDirectory, destName));
Unfortunately, although all pictures seem to have same orientation when viewing with the Windows app, they are rotated differently in the result photos. I know there is some kind of flag that seems to be ignored by the BufferedImage.
How can I detect that flag and eventually rotate the photo as needed before combining? Thanks!
I suggest to use the MetadataExtractor to get the orientation of the images. See this question.

Java GUI image size

So I have an assignment where I need to create a catalog.
The catalog needs to have a list, an image and a description.
My entire code works, so I have no issue with the coding as such.
I do have an issue with the image size.
How do I take care of images on a java gui program to make them all into one size when it is running.
Please let me know :D
When you read in an image, create a new BufferedImage that is the exact size that you desire, get it's Graphics object via getGraphics(), draw the original image into the new image using Graphics#drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) where x and y are 0 and width and height are from the dimensions of the new image, dispose() of the Graphics object, and then display the new Image as an ImageIcon in a JLabel. Make sure though that the original image is the same size or larger than the new one, else your images will look gawd-awful.
For example, and note that this code may not be exactly correct since I don't have my IDE up:
BufferedImage originalImage = ImageIO.read(something); // read in original image
// create new empty image of desired size
BufferedImage newImage = new BufferedImage(desiredWidth, desiredHeight, BufferedImage.TYPE_INT_ARGB);
Graphics g = newImage.getGraphics(); // get its graphics object
// draw old image into new image
g.drawImage(originalImage, 0, 0, desiredWidth, desiredHeight, null);
g.dispose(); // get rid of Graphics object
// create ImageIcon and put in JLabel to display
Icon newIcon = new ImageIcon(newImage);
myJLabel.setIcon(newIcon);
I would propably create a JPanel to draw on one Image, and then work with the method:
myPanel.setSize(new Dimension(x,y))
or
myPanel.setPreferredSize(new Dimension....)
There is a method (image = imgobj.getScaledInstance(width, height, hints)) in awt.Image class which provides re-sizing capabilities very nicely, I always use this to re-size my images when I need. Please see here some examples :-), I hope it will work for you, it is the most convenient way to scale images I have ever seen. create a method pass the image to the method and size of the image you want and return the image back in return to reuse the code ;)

Android add a watermark logo to very large jpg file (say 10000 x 150000) [duplicate]

This question already has an answer here:
Load large picture from file and add watermark
(1 answer)
Closed 8 years ago.
I have a large jpeg file say 10000 x 150000 px. I want to add a small logo to the bottom of the image without re sizing.
I am able to do this If i down sample the original image and draw the logo using canvas.But when i finally save it to file, the image original size will be reduced as I am sampling it.
If i load the original image into bitmap without down sampling, it exceeds the VM.
Below code work for me :-
public static Bitmap mark(Bitmap src, String watermark, Point location, Color color, int alpha, int size, boolean underline) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
Paint paint = new Paint();
paint.setColor(color);
paint.setAlpha(alpha);
paint.setTextSize(size);
paint.setAntiAlias(true);
paint.setUnderlineText(underline);
canvas.drawText(watermark, location.x, location.y, paint);
return result;
}
For large image editing you'll need to use native tools like imagemagick. Because there seem to be a lack of advanced image processing libraries in android supported Java.
If you can compile Composite tool's binaries for android. Then you can use them with --limit option to work with limited memory.
Also, you can try OpenCV as an alternative.
You can use BitmapRegionDecoder when deal with large image file. From the official document.
BitmapRegionDecoder can be used to decode a rectangle region from an image. BitmapRegionDecoder is particularly useful when an original image is large and you only need parts of the image.
To create a BitmapRegionDecoder, call newInstance(...). Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly to get a decoded Bitmap of the specified region.
Just decode the part of your image that you need to add watermark, then use Canva to draw text on it.
try {
BitmapRegionDecoder regionDecoder = BitmapRegionDecoder.newInstance("/sdcard/test.png", true);
Bitmap bitmap = regionDecoder.decodeRegion(rect, options);
} catch (IOException e) {
e.printStackTrace();
}

Can I save a huge PNG without the whole thing being in memory?

I'm saving a very large PNG (25 MB or so) with Java. The problem is that while it's being generated, it's using 3+ gigabytes of memory, which is not ideal since it severely slows down systems with low memory.
The code I'm working with needs to combine a set of tiled images into a single image; in other words, I have nine images (PNG):
A1 A2 A3
B1 B2 B3
C1 C2 C3
which need to be combined into a single image.
The code I'm using is this:
image = new BufferedImage(width, height, height, BufferedImage.TYPE_INT_ARGB_PRE);
g2d = image.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
// draw the 9 images on here at their proper positions...
// save image
g2d.dispose();
File file = getOutputFile();
ImageIO.write(image, "png", file);
Is there a way to make and save an image without having the entire image in memory?
Edit:
To draw the images, I'm doing this in a loop:
BufferedImage tile = ImageIO.read(new File("file.png"));
g2d.drawImage(tile, x, y, w, h);
This is being repeated many times (it's usually about 25x25, but sometimes more), so if there is even a small memory leak here, that could be causing the problem.
You can also take a look at this PNGJ library (disclaimer: I coded it), it allows to save a PNG image line by line.
ImageIO.write(image, "png", file); is internally using com.sun.imageio.plugins.png.PNGImageWriter. That method and that writer expect image to be a rendered image but PNG writting is done by 'bands' so you can make a subclass of RenderedImage that generates the requested bands of the composed large image as the writer ask for that bands to the image.
From PNGImageWriter class:
private void encodePass(ImageOutputStream os,
RenderedImage image,
int xOffset, int yOffset,
int xSkip, int ySkip) throws IOException {
// (...)
for (int row = minY + yOffset; row < minY + height; row += ySkip) {
Rectangle rect = new Rectangle(minX, row, width, 1); // <--- *1
Raster ras = image.getData(rect); // <--- *2
*2 I think this is the only place where the writer reads pixels from you image. You should make a getData(rect) method that computes that rect joining 3 bands from 3 images into one.
*1 As you see it reads bands with a height of 1 pixel.
If the things are as I think you should only need to compose 3 images at a time. There would be no need for the other 6 to be in memory.
I know it is not an easy solution but it might help you if you don't find anything easier.
Would using an external tool be an option? I remember using ImageMagick for similar purpose, you would need to save your smaller images first.

BufferedImage colour change

I have working on an application which captures screen shots and create video from captured images. But the problem is that when video is generated, colours in generated video is very pinkish. I think this is because I am manipulating captured images to show cursor using BufferedImage.TYPE_3BYTE_BGR type. Could someone tell me how to resolve this issue, I want to have the colour of video same as actual colour of screen.
For capturing screen image I am doing as follows:
Robot robot = new Robot();
Rectangle captureSize = new Rectangle(screenBounds);
return robot.createScreenCapture(captureSize);
For manipulating images I am doing as follows:
image = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
if (true) {
int x = MouseInfo.getPointerInfo().getLocation().x - 25;
int y = MouseInfo.getPointerInfo().getLocation().y - 37;
Graphics2D graphics2D = sourceImage.createGraphics();`enter code here`
graphics2D.drawImage(SimpleWebBrowserExample.m_MouseIcon, x, y, 48, 48, null);
}
image.getGraphics().drawImage(sourceImage, 0, 0, null);
return image;
please tell me how to get the images with colour same as actual colour on screen.
Thanks.
Use BufferedImage.TYPE_INT_ARGB or BufferedImage.TYPE_INT_RGB, as shown in this example. If you need to change the colors, you can use a LookupOp with a four-component LookupTable that adjusts the alpha component as required for BufferedImage.TYPE_3BYTE_BGR: "When data with non-opaque alpha is stored in an image of this type, the color data must be adjusted to a non-premultiplied form and the alpha discarded." Examples may be found in Using the Java 2D LookupOp Filter Class to Process Images and Image processing with Java 2D.
See the the "pinkish" explanation here
Basically the image is saved as a ARGB and most viewers interpret it as a CMYK. Alpha is preserved when opening it back in Java, though.

Categories

Resources