How to save a huge bmp file in java? - java

I am working a project involves visualizing a star catalog and create a printable bmp file. If I want to print a 24 by 24 picture with 1200 dpi resolution, it would be 28800*28800 and roughly 2.32 Gb.
Generally when create a bmp file, one would make a BufferedImage, graph something with the setRGB method, and save it as a bmp file with ImageIO.write.
But as I try to distribute my program, the end user may not have sufficient free RAM, and it will cause an OutOfMemoryError.
Is there a way to avoid saving every pixel of the image on RAM? If I can horizontally cut the image into several bands, and save them one by one to a single bmp file, it would be great (since I can get ride of the saved buffers).
Something similar would be:
Before I find the imageIO and awt package, I wrote a Bitmap class that saves a bitmap as a csv file and use an external software to render it. It has a toString method, and I use the method to save the content of the csv as a string instead of actually save it on the disk. When I want to make a large image, I create a fileWriter and a printWriter. I buffer a horizontal band of the image, and write it to the disk with the printWriter. Then I buffer the next band and replace the old band, and write it with the printWriter again. When it is finished, I close the writers and have the complete bitmap as a csv file on my disk.

What you need is code that directly creates an image file without loading the data completely into memory (usually this is called tiled image processing). I don't know a Java library that allows to do so, therefore my recommendation would be to look at the BMP file format and just write the file manually. AFAIR the BMP file format is pretty simple.
Some time ago I have seen something similar for PNG output: PngXxlWriter.java

Related

Change the format of an Image in java without saving

I would like to read an image and then change its format but without saving it.
For example I can read the image like this
BufferedImage img=ImageIO.read(new File(fileName));
Then I want to change the format of img, for example from jpeg to png.
The only way I found is to use ImageIO.read to write and then read the new image, but it does seem to be an efficient way to do it.
When you "read" the image via
BufferedImage img=ImageIO.read(new File('myimage.png'));
you are not only reading but also decoding it, i.e., transforming the raw bytes in the (say) PNG format to some "RAW" format that your aplication or API can manipulate (or display) - in this case, a BufferedImage. Once this is done, the fact that this image came from a PNG file is forgotten. To read it as PNG and save it as JPEG you need to decode it (as PNG) and then code it (as JPG).
I would like to read an image and then change its format but without saving it.
The "format" of the image (in the PNG/JPEG sense) gives you a way of packing an image in a sequence of bits. So, your desire makes little sense. At most, you could store those bits in memory (what for?), but that would be the same as "saving it" (to memory instead of disk).

Java: How do I create a movie from an array of images?

I basically have an matrix of bytes. Each row (meaning byte[]) represents an image. How do I create a movie out of that (any format - avi, mpeg, whatever), and save it as a file?
Each image can be one of the following:
int JPEG Encoded formats.
int NV16 YCbCr format, used for video.
int NV21 YCrCb format used for images, which uses the NV21 encoding format.
int RGB_565 RGB format used for pictures encoded as RGB_565.
int YUY2 YCbCr format used for images, which uses YUYV (YUY2) encoding format.
int YV12 Android YUV format: This format is exposed to software decoders and applications.
I can choose the format to whatever I like, as long as I get to create the movie.
public void createMovie(byte[][] images) {
// and ideas on what to write here?
}
I don't need the actual implementation, just let me know the idea and what external libraries I need (if I need any).
I also need to edit some of the images (the byte stream) before I create the movie (to add some text). How can I do that?
The solution needs to be "Java only"! No external programs, no external commands (but I can use external jars).
Thanks!
The solution seems to be to use Mencoder (or at least, that seems to be a semi-popular choice).
Here's a link that specifically addresses images-to-movies capabilities in Mencoder.
As for rendering text onto the frames before encoding them as part of the video, you can use Java2D's image manipulation libraries to simply draw text on top of the images beforehand For example:
Load up the images into BufferedImage objects via the ImageIO library's .read method
Use Graphics2D's .drawString method to render the text
That's one way to do it, and this FAQ should get you started in that direction with Java2D, font rendering, etc., and offer pointers to further resources.
The ImageIO library also allows you to read/write a number of image formats, effectively allowing you to transcode images from, say, .jpg -> BufferedImage -> .png, or any which way you need to do it, if you want to store the image files temporarily during the conversion process, and/or convert all the images to a single format when importing them for the conversion project, etc.
Depending on how many output formats you want to support, you'll probably do something like
public void createMovie(BufferedImage[] frames, String destinationFormat)
...where "destinationFormat" is something like "m4v", "mpeg2", "h.264", "gif", etc.
Have you heard about JMF (Java Media Framework), from the sample you can find this example : Generating a Movie File from a List of (JPEG) Images
You can try making a gif with this gif encoder.
I wrote an MJPEG reader and writer for playing videos inside of Java applets. MJPEG is not the most advanced video format but it is very easy to manipulate. The code is part of my computer vision library BoofCV, but you could just rip out this one class for your own purposes.
Download this file: CreateMJpeg.java
Look at main function. Where it reads in jpeg images put your byte[] data, but you will need to convert it to jpeg's first.
You can convert it into a jpeg using the standard java library
Run modified code and enjoy your movie
Sorry its not in a more user friendly format, but at least you don't need to mess with JNI like some other solutions.

Crop Bitmap without reading entire Bitmap first

I have a very large image and I only want to display a section the size of the display (no scaling), and the section should just be the center of the image. Because the image is very large I cannot read the entire image into memory and then crop it. This is what I have so far but it will give OutOfMemory for large images. Also I don't think inSampleSize applies because I want to crop the image, not lower the resolution.
Uri data = getIntent().getData();
InputStream is = getContentResolver().openInputStream(data);
Bitmap bitmap = BitmapFactory.decodeStream(is, null, null);
Any help would be great?
You can do this in 2 steps:
get the size of the bitmap, by using inJustDecodeBounds=true .
use BitmapRegionDecoder to decode just the part you want to .
The downside ? it works only from API 10 (but it's already the majority...).
I agree that the easiest way is to break the image up into many smaller tiled images and to just load the appropriate ones to make the image you are after.
However, if you do not want to do that, you may be forced to look into the encoding of the jpeg itself.
What you could do is something along the lines of copying the header from the file into a new file, and then extracting just the pixels you want in order to create a new file. Then reloading the new file will allow you to have just the subset of the image you are looking to work with, and all the regular java functionality and classes will be equally available for you to use.
I know it isn't necessarily an elegant or simple solution, however it does guarantee that you will be able to use the original java functionality which you expect to be able to use.
I think you're approaching the problem from the wrong direction.
If the bitmap is already so large it can't be loaded as a single continuous image, why store it as a single image? Slice it into tiles then load the center tile/tiles and act upon those.

How to save optimized png images with java's ImageIO?

I am generating lots of images in java and saving them through the ImageIO.write method like this:
final BufferedImage img = createSomeImage();
ImageIO.write( img, "png", new File( "/some/file.png" );
I was happy with the results until Google's firefox addon 'Page Speed' told me that i can save up to 60% of the size if i optimize the images. The images are QR codes, their size is around 900B each and the firefox-plugin optimized versions are around 300B.
I'd like to save such optimized 300B Images directly from java.
So here my question again: How to save optimized png images with java's ImageIO?
Use PngEncoderB to convert your BufferedImage into a PNG encoded byte array.
You can apply a filter to it, which helps prepare the image for better optimization. This is what OptiPNG does, only OptiPNG calculates which filter will get you the best compression.
You might have to try applying each filter to see which one is consistently better for you. With 2 bit color, I think the only filter that might help is "up", so I'm guessing that's the one to use.
Once you get the image to a PNG encoded byte array, you can write that directly to a file.

How to make a thumb from a big image file in J2ME?

I'm trying to display a big image file in a J2ME application. But I found that when the image file is too big I can not even create the Image instance and get a OutOfMemory exception.
I suppose I can read the image file in small chunks and create a thumbnail to show to the user?
Is there a way to do this? Or is there any other method to display the image file in the application?
Thanks.
There are a number of things to try, depending on exactly what you are trying to do and what handset you want your application to run on.
If your image is packaged inside your MIDlet JAR file, You have less control over what the MIDP runtime does because the data needs to be unzipped before it can be loaded as an Image. In that case, I would suggest simply packaging a smaller image. Either reduce the number of pixels or the number of bytes used to encode each pixel.
If you can read the image bytes from a GCF-based InputStream (file, network...), You need to understand the image format (BMP is straightforward, JPEG less so...) so you can scale it down into a mutable Image object that would take less memory, one chunk at a time.
In that case, you also need to decide what your scaling algorithm should be. Turning 32 bits pixels in a file into 8 bits pixels in memory might not actually work as expected if the LCDUI implementation on your mobile phone was badly written.
Depending on the content of the image, simply removing half of the pixel columns and half of the pixel lines may be either exactly what you need or way too naive an approach. You may want to look at existing image scaling algorithms and write one into your application.
Remember that basic LCDUI may not be the only way to display an image on the screen. JSR-184, JSR-239, JSR-226 and eSWT could all allow you to do that in a way that may be totally independant from your handset LCDUI implementation.
Finally, let's face it, if your phone MIDP runtime doesn't allow you to create at least 2 images the size of your screen at full color depth at the same time, then it might be time to decide to not support that specific handset.

Categories

Resources