[Java] [Kotlin] I wanted to create a png with a large capacity per area [Java]

1 minute read

What i wanted to do

In a certain project, a large amount of heavy png image samples were needed. On the other hand, when the image was created by simply filling the squares, it would be compressed to a few KB at most, and the capacity could not be secured. Since the required image format was already decided, it was difficult to simply increase the area to increase the capacity.

Policy

Generally, compression works strongly when the following two points are met.

  • Same pattern continues
  • The same color is continuous

Therefore, I did it by saying that “it will be difficult to compress if you draw a lot of random lines of random colors”.

The goal is 1940 x 500 and 2MB per sheet. It does not matter if you have achieved that, so do not worry about further capacity increase and processing time.

Implementation

This is a sample to generate 2000 images in the ${project root}/build/generated directory. If lines is 100000, it has stably exceeded 2MB.

The reason why parallelStream() is is that it will be a little faster, but I have not confirmed whether it is actually faster.

import java.awt.Color
import java.awt.Graphics2D
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
import kotlin.random.Random

const val width = 1940
const val height = 500
const val lines = 100000 // number of lines
const val count = 2000

fun main() {
    val generateTarget = System.getProperty("user.dir") + "/build/generated/"

    List(count) {it }.parallelStream().forEach {index ->
        val img = BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR)
        (img.graphics as Graphics2D).apply {
            repeat(lines) {
                //Specify the transparency to increase the color capacity
                this.color = Random.nextBytes(4).let {
                    Color(it[0] + 128, it[1] + 128, it[2] + 128, it[3] + 128)
                }
                this.drawLine(Random.nextInt(width), Random.nextInt(height), Random.nextInt(width), Random.nextInt(height))
            }
            dispose()
        }
        ImageIO.write(img, "png", File("$generateTarget${index}.png"))
    }
}

Execution result

The 2000 number was 4.81GB, and the average was 2.4MB. Since the load is high and the execution time took some time, I think it’s best to turn it around in your free time.

An image like this will be generated. 0.png