3

I am trying to encode/decode arbitrary raw data (a byte[]) to be able to read GRIB files which use JPEG2000 (https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-40.shtml) in Java using OpenJpeg library (de.digitalcollections.imageio:imageio-openjpeg:0.3.0) but with no luck. Does any one have an idea how to achieve that? It does not have to be with the above library.

Jpeg2000 offers both, lossy and lossless compression. The library above and the ImageIO need an Image (BufferedImage) as an input/output. I was trying to use OpenJpeg().lib instance to access lower level API.

If I have an arbitrary data I can always say they are image data by saying that every 1st byte is R, 2nd is G and 3rd is B component of a RGB color. Maybe padding the end of the array to be dividable by 3. Therefore it should be possible to compress and then decompress any arbitrary byte[] using Jpeg2000 lossless compression. If my data are somewhat resembling an image/gradient and I do accept certain error after compression, even lossy compression may find its use-case.

The problem I am facing is that an image (BufferedImage more specifically) contains additionally some meta-data.

While compressing arbitrary data one can do by simply creating an image object and filling its bitmap with desired data, the challenge is to then extract only the part from the resulted compressed image which contains only the payload (not the image's meta-data)

On the other hand when wanting to decompress such payload it needs to look like a Jpeg2000 image (including image's meta-data, some wrappings, ...)

What I did till now was to explore the de.digitalcollections.openjpeg package in the above library trying to find out where the compression happens.

Did anyone had a similar issue or knows a direction here?

Update

As suggested in the comments I tried to read the JPEG 2000 code stream and decode it back into an image:

val width = 31
val height = 28

// Image data
val bytes = "FF 4F FF 51 00 29 00 00 00 00 01 70 00 00 00 01 00 00 00 00 00 00 00 00 00 00 01 70 00 00 00 01 00 00 00 00 00 00 00 00 00 01 0F 01 01 FF 64 00 23 00 01 43 72 65 61 74 6F 72 3A 20 4A 61 73 50 65 72 20 56 65 72 73 69 6F 6E 20 31 2E 39 30 30 2E 31 FF 52 00 0C 00 00 00 01 00 05 04 04 00 01 FF 5C 00 13 40 80 88 88 90 88 88 90 88 88 90 88 88 90 88 88 90 FF 90 00 0A 00 00 00 00 02 B9 00 01 FF 5D 00 14 00 40 80 88 00 00 88 00 00 88 00 00 88 00 00 88 00 00 FF 93 C7 FE 0C 2E 05 86 91 1F C4 06 14 1A 5C 03 F9 84 81 FB 90 FF 7C D2 3E AD E6 73 77 C1 FF 40 05 00 06 57 AA 30 E5 88 7C 4C F6 A1 31 5C 67 38 53 F7 29 AE 07 CC C3 FF 03 16 80 2E 54 0D 34 CA A5 48 53 3D 34 A2 8E E9 08 18 9B 86 07 B3 1E 8D C3 FF 46 B8 95 A3 A2 A8 C3 12 87 A7 DF 22 70 E3 51 80 49 13 87 FE B6 93 C7 FE 18 A8 07 B9 F0 EB 40 D1 36 1F 20 FF 70 96 73 5F 1B 93 E4 FE AB F7 79 6D B9 4C 5D 55 CB 00 CF D1 F2 D3 E1 25 79 B3 41 44 7F D6 39 0C D9 14 CD 57 B3 3A 14 5D E4 D0 ED 73 22 3A 39 F2 10 A8 E2 36 57 41 6A C7 03 87 0C 46 CA 15 4A B2 8A C3 67 9B 0D 23 9A 1F 2B DF E3 FF 43 1B BF F8 61 90 25 E8 E7 C9 13 AB 76 7A 8E B5 9A 9F F2 4A 66 DE 8B 20 59 1A 29 E1 A4 BB 7C 6C 8D F7 FB F7 D6 05 A3 FC 98 61 97 63 EC 05 C6 4A 86 B6 30 3E 3C 47 50 D7 6F C5 B0 CA 24 EF E6 36 8E E0 B3 BB AA 85 B2 05 38 5D B0 91 00 C3 99 F5 CF 65 65 29 1E E4 98 D4 A3 8E BC A6 A4 7E 12 2C B7 3C 4D A7 BA 33 4E DF D7 E6 6A 29 61 D8 A4 5B 56 7D 51 7F 12 95 72 F9 A4 73 58 32 E4 6A 66 95 0B 3B 80 8A 7F C5 82 C1 6F 96 25 6F 59 29 2A 86 4C 88 1A A8 85 F0 21 75 30 12 48 E4 7C A2 EC D2 62 60 27 D6 4F 12 F1 FF 70 C5 E9 FF 40 19 7F FE 18 C0 42 7B 05 78 6F 6C 22 51 5A 18 9D CA 4A 09 21 AD D3 D6 C8 1D 31 0A 5F 1B FC 73 6B 58 FF 38 0E C1 8D 5E DD 02 BA F9 23 4F C6 1D FF 1B CB 00 60 A7 ED 31 08 28 CD 97 D4 E0 A9 92 B9 F8 C4 63 4A F1 70 0B D2 9A D8 41 76 21 AD 4E 62 D2 80 D2 42 70 0B 52 3A 0E C7 DE 71 B4 10 4A 55 7B E6 C5 22 9C 09 B7 DE F7 28 F8 F4 F4 0A 05 D8 C1 12 6E BB 30 28 AE 34 C1 8D 93 3E D7 FF 0B C5 74 E8 AB EB F7 26 7E 30 28 30 D3 F1 C8 26 1E CA 31 B5 B1 FB 45 12 DF A9 98 B2 6C AF E9 8D D1 B0 17 25 54 72 25 3E 46 A9 BC 5A BA A3 9C 5A 24 D4 13 AD 14 B8 6A 15 C7 EE 70 8E E3 67 F7 64 1B A2 1C 14 94 6E 11 E5 62 67 06 2B BD D1 02 1F 2B 97 72 1D 09 54 76 65 65 41 31 E9 DC 1A 08 F1 40 D3 E8 60 6C D3 9E BA E9 12 37 76 53 EB 32 38 6B A1 F3 65 76 88 7A BF 9F 09 E5 B9 9E 0C 24 CB CF 87 B0 CA 6A FC D4 4E CE A5 2C 8F DB 4D 72 CA DA 81 F7 1F 9B D1 F2 23 FE DF 4D D0 D0 EC EC 21 86 65 3E E6 64 5F 3F 2B 2D E9 FF D9"
    .split(" ")
    .map { it.toInt(radix = 16).toByte() }
    .toByteArray()

val bis = ByteArrayInputStream(bytes)
val imageInputStream = ImageIO.createImageInputStream(bis)
val imageReaders = ImageIO.getImageReadersByFormatName("JPEG2000")
var bufferedImage: BufferedImage? = null
if (imageReaders.hasNext()) {
    val imageReader = imageReaders.next()
    imageReader.input = imageInputStream
    bufferedImage = imageReader.read(0) // Exception
}

But I get an exception:

java.lang.NullPointerException
    at de.digitalcollections.openjpeg.imageio.OpenJp2ImageReader.checkIndex(OpenJp2ImageReader.java:63)
    at de.digitalcollections.openjpeg.imageio.OpenJp2ImageReader.read(OpenJp2ImageReader.java:134)
    at java.desktop/javax.imageio.ImageReader.read(ImageReader.java:938)

The problem is that the OpenJpeg lib cannot find any header. If I understand it correctly, there is not any header in the JPEG2000 code stream.

Thanks!

Jan Kubovy
  • 421
  • 5
  • 11
  • 1
    Jpeg2000 is not suitable for encoding arbitrary raw data. It is for encoding images. Are you sure you have correctly described what you are trying to achieve? – Codo Mar 11 '21 at 07:08
  • JPEG is usually a loss format (you lose information, but in a way that it is visually not much relevant). For non image data, the compression is bad and possibly you get a larger file. JPEG also subsample R and B channels (this depends on the type of JPEG). In any case, you should show what you have done, so we may understand where it is the error. – Giacomo Catenazzi Mar 11 '21 at 09:23
  • Thanks for your comments! I updated my question and tried to clarify what is my goal. – Jan Kubovy Mar 11 '21 at 22:18
  • Sounds like an [xy problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) Can you describe what you're trying to achieve? If you're attempting steganography, this is clearly not the right approach because - viewing the image - it will be clear that it's not a real image. And if that's clear, what is the purpose at all of doing something for which the JPEG format is clearly not meant? You might as well write your binary data to a file directly and give it a ".jpeg" extension. – Erwin Bolwidt Mar 11 '21 at 22:28
  • I am trying to read/write grib2 data which are compressed using Jpeg2000: https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-40.shtml – Jan Kubovy Mar 11 '21 at 22:31
  • 1
    The standard clearly states that the data must be organized as a grid (and even says what to take for width and height) and should be encoded as a grayscale image. So no RGB, no division by 3. Therefore it should be straightforward to create a grayscale BufferedImage and have it JPEG 2000 compressed using the standard ImageIO API (and without digging into any low-level stuff). – Codo Mar 13 '21 at 12:15

0 Answers0