cantaloupe icon indicating copy to clipboard operation
cantaloupe copied to clipboard

Stream JPEG-compressed tiles from tiled TIFFs

Open jbarth-ubhd opened this issue 3 years ago • 5 comments

Requesting 512×512 tiles with 16 client processes in parallel from pyramidal jpeg tiff with 512×512 tile size from our dual Xeon Gold 6246 server we're getting approx. 140 MPixel/s.

Now did some trace:

Responded to GET … 30 msec (median)

e.i.l.c.r.ImageRepresentation [ImageRepresentation.java:207] …
  Java2dProcessor processed in 20 msec (median)

But… the tiff already has jpeg tiles of the size wanted and we're requesting those with no overhang. So why Java2dProcessor? Couldn't cantaloupe just pass through the data with minimal modification to the client → 0 msec?

Otherwise the performance is limited to 512²px/0,02s = 13.1 MPixel/s per core.

With .jpg tile files (extracted from ptif) we're getting approx. 3 GPixel/s (https). Is there a Javascript wrapper to simulate IIIF (for scaling, cropping, etc) on the browser?

jbarth-ubhd avatar Jul 09 '21 11:07 jbarth-ubhd

Is there a Javascript wrapper to simulate IIIF (for scaling, cropping, etc) on the browser?

You could take a look at https://github.com/samvera-labs/serverless-iiif and https://www.npmjs.com/package/iiif-processor, and see if either of those is helpful.

bcail avatar Jul 09 '21 12:07 bcail

I don't think it's possible using the Image I/O API to read the JPEG tile data without decompressing it, but it's a neat idea. I will keep it in mind as a potential enhancement.

adolski avatar Jul 12 '21 15:07 adolski

My way (with a lot assumptions) to extract jpeg tiles in c:

    uint32 jpegtables_len;
    void *jpegtables;
    if(TIFFGetField(tif, TIFFTAG_JPEGTABLES, &jpegtables_len, &jpegtables)==1) {
      FILE *fw=fopen("x.jpg", "w");
      FIF(!fw);
      FIF(fwrite(jpegtables, 1, 2, fw)!=2); // nur SOI
      uint8 jfif[]={0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x00};
      FIF(fwrite(jfif, 1, sizeof(jfif), fw)!=sizeof(jfif));
      FIF(fwrite(jpegtables+2, 1, jpegtables_len-2-2, fw)!=jpegtables_len-2-2); // without EOI

      tsize_t ts = TIFFTileSize(tif);
      tdata_t tile = malloc(ts);
      FIF(tile==NULL);
      tsize_t bytecount = TIFFReadRawTile(tif, TIFFComputeTile(tif, x, y, 0, 0), tile, ts);
      FIF(bytecount > ts);
      printf("tables:%d tile:%ld\n", jpegtables_len, bytecount);

      FIF(fwrite(tile+2, 1, bytecount-2, fw)!=bytecount-2); // tile starts with SOI = ff d8 — skip.
      free(tile);
      FIF(fwrite(jpegtables+jpegtables_len-2, 1, 2, fw)!=2); // EOI;
      TIFFClose(tif);
      fclose(fw);

jbarth-ubhd avatar Jul 13 '21 07:07 jbarth-ubhd

Would be cool if ptif generaters (like vips) would arrange tiles in Hilbert or Z space filling curve for disk locality.

vips issue

jbarth-ubhd avatar Jul 13 '21 10:07 jbarth-ubhd

tiff-java has List<Long> getTileOffsets() and List<Number> getTileByteCounts() in Class FileDirectory

jbarth-ubhd avatar Jul 14 '21 14:07 jbarth-ubhd