I want to dive in the low level of how a png file is represented on memory in java, so that i can iterate over its pixels, change them, create a modified png file using existing one, etc.
Where do i begin?
You could begin by reading it into a BufferedImage with ImageIO.read(file) .
The getRGB(...) methods can help you to obtain information about the individual pixels, and the corresponding setRGB(...) methods help you to change them.
The representation of an image in memory in Java, is essentially unrelated to the format of the file: be it PNG, JPEG, GIF or whatever, those are standards for encoding an image as a (language independent) stream of bytes. But when you are manipulating the pixels of an image in memory, you have already decoded it, and so you've "forgotten" from which format (PNG, JPEG...) it came from.
The most common way of manipulating an image in Java is using the BufferedImage class, included in the java.awt.image.* package. But that's not a requisite. For instance, I've worked on a low level PNG coder/encoder (PNGJ) that does not use BufferedImage, but instead gives you each image line as an int[] array.
Related
This is related to How to extract image bytes out of PDF efficiently, but I'll try to restate the problem differently so it's less about PDF parsing and more about image processing.
I'm using PDFBox to extract images out of PDF files. There's an class PDImageXObject that represents the image inside the PDF, which contains image metadata (height, width, etc), and exposes two APIs to pull out the image are: BufferedImage getImage() and BufferedImage getImage(Rectangle rect, int subsampling);.
The current code is straightforward:
BufferedImage image = pdImage.getImage();
ImageIO.write(image, "jpg", baos);
However, for a large image, I'm having an issue with memory usage, as BufferedImage is storing uncompressed image data in memory, which is a lot bigger than the compressed result.
Is there a way to avoid loading the whole image into memory by breaking it up into tiles (e.g. 1024x1024) and iterating over them using the getImage signature that takes Rectangle? I'm seeing some promising information about JAI being able to use Tiles to output a compressed image without loading the uncompressed content into memory at once, but I don't understand how to tie it together with what I have from PDImageXObject. Or is there another way to do it? Is JAI still an active project?
By the way, the purpose of extracting the image is to feed it into the next component in the pipeline that can handle multiple image formats. So, if some format other than jpg, is more suited for tiled processing, that should be ok.
I'm aware of one possibility using something like BigBufferedImage. But I was thinking processing a Tile at a time looked promising.
OK, I found a libray: Commons Imaging. Class Imaging maybe can help you.
I think you can try createInputStream() method, find out the size of real data(bytes length).
What I have is: for each of the colors r, g and b, a two-dimensional array of integers in the [0,255] range. What I want is: create a BMP out of this array and send it to the client. The problem is, I cannot use java.awt.Color, BufferedImage, etc., since these are off-limits in the App Engine. The App Engine does offer an image manipulation service which, however, is meant for images I already have, not for creating images from scratch.
I am considering teaching myself how to 'manually' create a BMP, but this does seem like a lot of work. Should I do this, or is there an easier way?
The BMP format is pretty simple compared to JPG or PNG for example.
It has lots of header fields and bits, but you don't need to calculate/fill all. Basically what you need to do is create/write the BMP header which is less than 100 bytes (~56 if I remember well). Only a few fields you need to set, e.g. image size in pixels, image type (e.g. bits/bytes per pixel) etc. You can use the image type which is identical to yours: 3 bytes per pixel (r, g and b components).
Once you have this, the image data follows which you can just write as you have, one thing to keep in mind is that BMP stores images upside-down, and it may have line padding to be a multiple of 4 bytes for example.
That's all! Note that I haven't mentioned java.awt.Image or java.awt.Color because they are not needed to create simple BMPs.
I consider posting full code out of "scope" as you haven't posted any.
Here's an example Java implementation, use it or modify/tweak it to your needs:
http://www.javaworld.com/article/2077561/learn-java/java-tip-60--saving-bitmap-files-in-java.html
There are also many other Java implementations, don't be afraid to search.
I am using the BufferedImage class to read in an image as pixels which I then use bit shifting to get their appropriate components into separate int arrays. This works OK.
I have used this reference site to manually perform DCT functions with the pixel arrays.
Methods used: forwardDCT(), quantitizeMatrix(), dequantitzeMatrax(), inverseDCT()
which then are fed back into a resultant image array to reconstruct the JPEG file, which I then use BufferedImage's write() method to write the pixel data back out as the image.
This works perfectly, and I can view the image. (Even better the value I use to compress visually works).
My question is, is there a way to write the quantitize coefficients as the compressed values as a JPEG?
Because the BufferedImage write() method is used to input pixel data, rather than coefficient data?
Hope this is clear.
Thanks
Ultimately the DCT calculation is just one step in the whole JPEG encoding process. A complete implementation also has to deal with quantization, Huffman encoding, and conforming with the JPEG standard.
Java effectively just gives you an interface to a JPEG encoder that lets you do useful things like save images.
The ImageWriter that ImageIO.write() uses for JPEG images depends on your system. The default ImageWriter for JPEGs will only let you change some settings that affect the quantization and encoding using the JPEGImageWriteParam class (http://docs.oracle.com/javase/6/docs/api/javax/imageio/ImageWriteParam.html).
Getting your hand-crafted DCT coefficients into a JPEG file could potentially involve writing an entire JPEG library. If you don't want to do all that work, then you could modify the source of an existing library so that it uses your DCT coefficients.
Before the DCT . . .
While JPEG has no knowledge of colors, it is normal for JPEG file formats to use the YCbCr color space. If you are thinking about writing a JPEG file, you would need to do this conversion first.
After the Quantization . . .
The coefficients are run length encoded. That's a step you'd have to add. That's the most complex part of JPEG encoding.
I have a specific object with image data. And I want read/write images (in BMP, JPEG and PNG formats) to this object.
Of course, I can read/write image into/from BufferedImage and then copy/paste pixels into/from my object. But, I want to do it more faster without intermediate objects!
How can I perform it over standard Java library or throw other Java library?
P.S.:
I know pngj library that allow read PNG images by lines. Maybe you know same libraries for BMP, JPEG (or for all of them: BMP, JPEG, PNG)?
Why don't you just have the BufferedImage in your Object? BufferedImage isn't all that bad. Otherwise, you will need to use something like BufferedImage to convert the image file into pixels, and then read the BufferedImage into something like an int[] array of pixels, but it still requires BufferedImage in the middle, and this would slow things down by adding an extra loop to read over and store the pixels.
Is there a reason why BufferedImage isn't suitable for your purpose?
If you want to do all the reading by yourself, you can just open the file with a stream and read it into an array, but you would need to work your way through the whole structure of the file (headers etc...) if you are working with compressed formats you'd have to work on that too.
Best would be to use imageio to load/write your files and I don't believe there is a lot of overhead coming from the read/write of your images.
Also if you expect to do some heavy work on the images, know that BufferedImages can be hardware accelerated which will improve performance a lot.
What is a Java type which can hold a PNG implement and provide access to it's pixel buffer?
BufferedImage img = ImageIO.read(new File("my.png"));
int color = img.getRGB(23,12);
I would take a look at Java Advanced Imaging, it handle multiple types of image files.
Take a look ImageIO and its numerous static helpers for reading and writing bytes/streams containing an image.
If you want to do pixel based operations on the entire image, I've found calling the getRGB() method every time to be fairly slow. In that case, you might want to try and get access to the actual pixel array holding the image data using something like:
byte[] pixel_array = ((DataBufferByte)img.getRaster().getDataBuffer()).getData()
There may be a more flexible way that doesn't make any presumptions on the array data type.