2

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.

Rigidity
  • 169
  • 10
talha06
  • 6,206
  • 21
  • 92
  • 147
  • Possible duplicate http://stackoverflow.com/questions/19281195/creating-images-with-a-java/19281350#19281350 – MadProgrammer Feb 05 '17 at 21:51
  • I have a size criteria too which is the key part of the question. – talha06 Feb 05 '17 at 22:00
  • Of course, I am aware of these parameters but I need to create images of various sizes. Also, I am asking **the most efficient way** of creating images in order to prevent any possible `heap size` exceptions. – talha06 Feb 05 '17 at 22:12
  • `BufferedImage` is still your best bet, I've managed sizes of over 2,000x2,000 pixels before, but your requirements are unclear and broad. The "most efficient way" is to ensure that you dispose of any unused resources when you're done with them – MadProgrammer Feb 05 '17 at 22:15
  • What are you doing with the images? Are you reading them and processing them in some manner? Are you drawing into them programmatically? How many images are you expecting to manage at once? Do you have any idea of the size ranges you might be expected to manage? Are you stuck using a single process or can you use multiple processes? You could simply store the image data in a byte array, which could allow you to devise your own disk cache, but it's manipulation becomes difficult and you lose the graphics support supplied by `BufferedImage` which would reduce your development time – MadProgrammer Feb 05 '17 at 22:26
  • Need to generate different images of various sizes (i.e. `10KB`, `100KB`, `1MB`, `10MB`, etc.) for an academic research.** The maximum file size** is expected to be `100MB`. No restrictions on the number of processes. **The number of images** needed to be generated is also part of the work - which is a number in the range of `1-1000` (i.e. `1`, `10`, `100`, `1000`). – talha06 Feb 05 '17 at 22:33
  • Is that uncompressed size? Memory and disk are different issues. If you can, generate some or all of images in different processes, each will get there memory space, might help – MadProgrammer Feb 05 '17 at 22:35
  • 1
    For your EDIT 2: width * height should be less than Integer.MAX_VALUE. @ http://stackoverflow.com/questions/9089675/creating-huge-bufferedimage – opensam Feb 05 '17 at 22:36
  • @opensam Could we use that as duplicate? – MadProgrammer Feb 05 '17 at 22:43
  • @MadProgrammer I am fairly new on this site. Sorry – opensam Feb 05 '17 at 22:44
  • @opensam No apologies required, it just sounds like that would answer the question as I've been able to ascertain it :P – MadProgrammer Feb 05 '17 at 22:46
  • @talha06 Care to comment on my answer, if it doesn't meet your requirements? – Harald K Feb 07 '17 at 15:43
  • see my comment below your answer @haraldK – talha06 Feb 08 '17 at 00:29

3 Answers3

2

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")));
opensam
  • 368
  • 1
  • 4
  • 10
  • All good except the size criteria which is the key part of the question. – talha06 Feb 05 '17 at 22:20
  • What specifically are you trying to do? Are you reading an image, doing some processing and then writing them back? or is it something else? – opensam Feb 05 '17 at 22:26
  • Need to generate different images of various sizes (i.e. 10KB, 100KB, 1MB, 10MB, etc.) for an academic research. – talha06 Feb 05 '17 at 22:28
  • I agree with MadProgrammer(see his comment under your question). BufferedImage is still you best best. I once used it to process an image in a thousand different ways. What I did was, before doing the different set of processing, I would write the image onto disk first and free up the resources. You can follow similar pattern. With the information you have provided, this is the best advice I can give you – opensam Feb 05 '17 at 22:33
  • Thanks @opensam, agree with you; it fits best for me but having some issues while creating images especially when the dimensions of images are getting larger as I mentioned in the original post. – talha06 Feb 05 '17 at 22:36
1

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.

Harald K
  • 26,314
  • 7
  • 65
  • 111
  • Really an efficient solution, works as expected, thanks for your contribution. What about generating well-known image formats such as `jpg`, `png`, etc.? – talha06 Feb 08 '17 at 00:28
  • 1
    @talha06 Added a section about this at the bottom of my answer. – Harald K Feb 08 '17 at 11:35
-3

For example

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366