-1

I have two services which trade binary data from an original heic/heif image via redis (binary safe). Since ImageIo does not support that image type I built a separate service in nodejs, which just converts heic/heif images to jpegs. After conversion on the nodejs service it saves the string encoded (latin1) image bytes again in Redis where the other service (javax.imagio) retrieves it, decodes the string back to bytes and tries to read from it. On that point I recveive the following exception:

java.lang.IllegalArgumentException: Empty region!
    at java.desktop/javax.imageio.ImageReader.computeRegions(ImageReader.java:2687)

I am no way an expert for image processing, so I would be happy if someone could explain what I am doing wrong. Below you can see my code:

My string serializer:

public static Optional<String> encodeBytesToString(byte[] data) {
        return Optional.ofNullable((data == null ? null : new String(data, StandardCharsets.ISO_8859_1)));
    }

    public static byte[] decodeStringToBinary(String string) {
        return (string == null ? null : string.getBytes(StandardCharsets.ISO_8859_1));
    }

Business logic

BufferedImage image = imageService.readImage(decodeStringToBinary(convertedImage.getData()));

Reader:

public BufferedImage readImage(byte[] data) throws IOException {
        return ImageIO.read(new ByteArrayInputStream(data));
    }

The docs of the computeRegions method (where the exception is thrown) states the following:

If either the source or destination regions end up having a width or height of 0, an IllegalArgumentException is thrown.

No idea why these properties are 0. I use the following lib for the nodejs service: https://github.com/catdad-experiments/heic-convert It works if you use the example in the readme, which saves the outputbuffer to disk. I wanted to skip that and just pass the bytes to redis directly. Am I doing something fundamentally wrong or whats going on here?

Below the code on nodejs:

const outputBuffer = await convert({
      buffer: inputBuffer,
      format: OutputFormatEnum.JPEG,
      quality: 1,
    });

const encodedBin: string = await this.encodeToStringBinary(
      Buffer.from(outputBuffer),
    );

this.redisCache.hset(fileId, encodedBin);
NightKnight
  • 1
  • 1
  • 3
  • 1
    It looks like you're using strings to hold binary (image) data, If so, that's not a legitimate use for strings. Use Base64 – g00se Apr 26 '22 at 17:02
  • Redis is binary safe, so that should not be the problem. I encoded it to latin1 because that has valid bytes and there was some issue with the spring redis implementation when just saving the plain bytes. – NightKnight Apr 26 '22 at 17:21
  • What does `this.encodeToStringBinary` in the js code do? Maybe you could include or link the data as found in redis too? Most likely something along the way corrupts the data, and I have to agree with @g00se, the string encoding seems the most likely culprit. – Harald K Apr 26 '22 at 18:14
  • 1
    Hi Harald, thanks for your input. The issue was the lib on nodejs which I broke with some changes and forgot to rollback. Big fail on me. I removed every encoding stuff and now storing the raw bytes on redis, which works fine now because its as it promises binary safe. There is a new issue now, where imageio.read() can't find a reader for the converted jpeg and returns image==null. It only works for originally very small heic files. Everything >500kb seems to fail. Except if I stop and wait with the debugger. After some waiting time it then loads the image in the BufferedImage. – NightKnight Apr 27 '22 at 12:41
  • It looks like not all bytes are "there" when it tries to write the image. Or am I missing something else? Might open a new issue. – NightKnight Apr 27 '22 at 12:43

1 Answers1

0

The issue was the lib on nodejs which I broke with some changes and forgot to rollback. Big fail on me. I removed every encoding stuff and now storing the raw bytes on redis, which works fine now because its as it promises binary safe.

NightKnight
  • 1
  • 1
  • 3