talha06
talha06

Reputation: 6466

How do you generate an image of a specific size in Java?

I need to generate images (the format of images does not matter) of a given size (For example, 10KB, 100KB, 1MB, 10MB, etc), using Java. The image can be any shape which is filled a background color, no restrictions for the content of images.

Edit #1: The sizes of the images which are going to be created are changeable, so I am looking for an efficient way in terms of memory usage in order to be safe from the Java heap space exception while creating images.

Edit #2: I am getting the java.lang.IllegalArgumentException: Dimensions (width=48000 height=48000) are too large exception when I try to generate an image with the dimensions 48000x48000 using the Graphics2D library, which is necessary in order to generate images with large file sizes.

Edit #3: When the dimensions get bigger, I experience the java.lang.OutOfMemoryError: Java heap space exception even though I have manually configured the -Xmx parameter of the Java program that does this.

Upvotes: 2

Views: 5030

Answers (3)

Harald K
Harald K

Reputation: 27054

Here's some very simple sample code that should match your requirements as far as I can understand. The program should work very efficiently with almost no memory at all, but will still create image files of sizes up to (roughly) 2GB (you can also easily adapt it to create much larger images, if you like).

Assumptions:

  • The image format does not matter, so we'll choose the PGM format (in binary 'P5' mode)
  • The image can be any shape/color, so we'll just do the simplest thing and write one line of all black.
  • The size that matters is the image file size (the code below doesn't write to the byte this size, but could easily be modified by subtracting the size of the minimal file header before writing to be exact).

Input is file size, followed by file name (you want to use .pgm as extension). As an example:

$ java -cp ... WritePGM 2147483640 foo.pnm

The above will create the largest possible image my JVM permits to read back, which is roughly 2 GB.

Code:

public class WritePGM {
    public static void main(String[] args) throws IOException {

        int size = Integer.parseInt(args[0]);
        File file = new File(args[1]);

        try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
            // Format P5/binary gray
            out.write("P5\n".getBytes(StandardCharsets.UTF_8));
            // Dimensions (width/height)
            out.write(String.format("%s 1\n", size).getBytes(StandardCharsets.UTF_8));
            // MaxSample
            out.write("255\n".getBytes(StandardCharsets.UTF_8));

            // Just write a single line of 0-bytes
            for (int i = 0; i < size; i++) {
                out.write(0);
            }
        }
    }
}

PS: If you need an ImageIO plugin to read the generated file using Java, you can use JAI ImageIO or my own PNM plugin, but you will of course experience the same memory issues as when you tried to generate such images using Java2D (BufferedImage).


In theory, you could also use similar techniques for creating files in formats like JPEG or PNG, but these formats are much harder to implement. Also, they are compressed, so predicting the file size is hard.

Perhaps you could pad a minimal JPEG with extra non-image data, like XMP or so. PNG does allow writing Deflate blocks with no compression, which might be an option. Or use extra chunks for padding.

An uncompressed format like BMP will be simpler. You could use the same technique as above, just write a fixed, minimal BMP header, set the correct width and write the image data almost as above. BMP does need row padding, and doesn't support gray data, so you need to do some extra work. But certainly doable.

Upvotes: 1

opensam
opensam

Reputation: 368

One way to generate a Gray Scale image(of width : width and height : height) :-

1) Create a BufferedImage object :-

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);

2) Populate your BufferedImage object (here I am assuming that you have proper input to the image stored in a 2-d array of int called img):-

for (int y = 0; y < image.getHeight(); y++) 
    {
      for (int x = 0; x < image.getWidth(); x++) 
      {

          image.setRGB(x, y, img[y][x]<<16 | img[y][x] << 8 | img[y][x]);
      }

    }

3) Write the BufferedImage object to disk :-

ImageIO.write(image, "jpg", new FileOutputStream(new File("SomePath/Name-of-Image.jpg")));

Upvotes: 2

Related Questions