Difference between a TIFF file and Processing's TIFF file

What are the differences between a tiff file and one of Processing’s tiff files? I ask because I need to load tiff files into a sketch. I can do this with one of Processing’s tiff files but not with other tiff files.

I am familiar with GDAL and so, if I knew what I was aiming for, I could translate the normal tiff files into Processing tiff files and then be able to import them.

Error: Processing can only read its own TIFF files.

Hi @paulstgeorge – is this now a duplicate of Requirements that Processing has for loading TIFF files – can it be merged / deleted or do you need a separate question answered here?

Hi @jeremydouglass
Although we now have way to load TIFF files into a Processing sketch, (thank you), it would be very interesting and potentially useful to understand the difference between a proprietary TIFF and a TIFF that can be loaded into Processing.
I am guessing the difference is all in the metadata (headers) and in the image preview (embedded thumbnail image).
@behreajj pointed us towards https://github.com/processing/processing/blob/master/core/src/processing/core/PImage.java#L3012

If someone was clever enough to understand and communicate the requirements, I am sure I could work out how to translate a proprietary TIFF into a TIFF that can be loaded into Processing.

That’s a long answer. The short answer is can we see if anyone can answer?

Here the details of a TIF saved from GIMP which does not work in Processing:

Image: a.tif
  Format: TIFF (Tagged Image File Format)
  Mime type: image/tiff
  Class: DirectClass
  Geometry: 640x640+0+0
  Resolution: 72x72
  Print size: 8.88889x8.88889
  Units: PixelsPerInch
  Colorspace: sRGB
  Type: TrueColor
  Endianess: LSB
  Depth: 8-bit
  Channel depth:
    Red: 8-bit
    Green: 8-bit
    Blue: 8-bit
  Channel statistics:
    Pixels: 409600
    Red:
      min: 18  (0.0705882)
      max: 255 (1)
      mean: 155.674 (0.610484)
      standard deviation: 56.5443 (0.221742)
      kurtosis: -0.663911
      skewness: -0.437395
      entropy: 0.875267
    Green:
      min: 0  (0)
      max: 254 (0.996078)
      mean: 108.229 (0.424429)
      standard deviation: 59.5409 (0.233494)
      kurtosis: -0.771386
      skewness: 0.182195
      entropy: 0.85146
    Blue:
      min: 0  (0)
      max: 253 (0.992157)
      mean: 118.629 (0.465211)
      standard deviation: 61.0945 (0.239586)
      kurtosis: -0.778726
      skewness: -0.0462273
      entropy: 0.868692
  Image statistics:
    Overall:
      min: 0  (0)
      max: 255 (1)
      mean: 127.511 (0.500041)
      standard deviation: 59.0599 (0.231607)
      kurtosis: -0.88099
      skewness: -0.0970405
      entropy: 0.86514
  Rendering intent: Perceptual
  Gamma: 0.454545
  Chromaticity:
    red primary: (0.64,0.33)
    green primary: (0.3,0.6)
    blue primary: (0.15,0.06)
    white point: (0.3127,0.329)
  Matte color: grey74
  Background color: white
  Border color: srgb(223,223,223)
  Transparent color: none
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 640x640+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: None
  Orientation: TopLeft
  Convex hull: 0,0 639,0 639,502 587,583 583,589 580,593 570,603 566,606 563,608 558,611 552,614 483,639 0,639 0,0 
  Minimum bounding box: 639,0 639,639 0,639 -3.91275e-14,0 
  Properties:
    date:create: 2020-04-05T20:05:50+00:00
    date:modify: 2020-04-05T20:05:50+00:00
    label: Background
    minimum-bounding-box:angle: 0
    minimum-bounding-box:area: 408321
    minimum-bounding-box:height: 639
    minimum-bounding-box:unrotate: 0
    minimum-bounding-box:width: 639
    signature: c67f6dd5c6db58d2abcc06e43fb18f691bd8e01bf42e416f1732ff26696d0fee
    tiff:alpha: unspecified
    tiff:document: /tmp/a.tif
    tiff:endian: lsb
    tiff:photometric: RGB
    tiff:rows-per-strip: 128
  Artifacts:
    verbose: true
  Tainted: False
  Filesize: 1.17217MiB
  Number pixels: 409600
  Pixels per second: 103.579MP
  User time: 0.000u
  Elapsed time: 0:01.003
  Version: ImageMagick 7.0.10-4 Q16 x86_64 2020-04-05 https://imagemagick.org

And the details from a TIF saved from Processing:

Image: b.tif
  Format: TIFF (Tagged Image File Format)
  Mime type: image/tiff
  Class: DirectClass
  Geometry: 640x640+0+0
  Units: PixelsPerInch
  Colorspace: sRGB
  Type: TrueColor
  Endianess: MSB
  Depth: 8-bit
  Channel depth:
    Red: 8-bit
    Green: 8-bit
    Blue: 8-bit
  Channel statistics:
    Pixels: 409600
    Red:
      min: 0  (0)
      max: 252 (0.988235)
      mean: 133.718 (0.524383)
      standard deviation: 72.9768 (0.286184)
      kurtosis: -1.19089
      skewness: -0.303666
      entropy: 0.751271
    Green:
      min: 0  (0)
      max: 251 (0.984314)
      mean: 134.909 (0.529054)
      standard deviation: 73.1623 (0.286911)
      kurtosis: -1.21699
      skewness: -0.270766
      entropy: 0.754885
    Blue:
      min: 0  (0)
      max: 251 (0.984314)
      mean: 149.573 (0.586562)
      standard deviation: 70.6641 (0.277114)
      kurtosis: -1.02109
      skewness: -0.464986
      entropy: 0.748687
  Image statistics:
    Overall:
      min: 0  (0)
      max: 252 (0.988235)
      mean: 139.4 (0.546666)
      standard deviation: 72.2677 (0.283403)
      kurtosis: -1.15051
      skewness: -0.346065
      entropy: 0.751614
  Rendering intent: Perceptual
  Gamma: 0.454545
  Chromaticity:
    red primary: (0.64,0.33)
    green primary: (0.3,0.6)
    blue primary: (0.15,0.06)
    white point: (0.3127,0.329)
  Matte color: grey74
  Background color: white
  Border color: srgb(223,223,223)
  Transparent color: none
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 640x640+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: None
  Orientation: TopLeft
  Convex hull: 54,0 566,0 567,1 639,92 639,487 638,624 637,628 635,634 633,638 632,639 0,639 0,70 3,66 52,2 54,0 
  Minimum bounding box: 639,0 639,639 0,639 -3.91275e-14,0 
  Properties:
    date:create: 2020-04-05T20:12:29+00:00
    date:modify: 2020-04-05T20:12:29+00:00
    minimum-bounding-box:angle: 0
    minimum-bounding-box:area: 408321
    minimum-bounding-box:height: 639
    minimum-bounding-box:unrotate: 0
    minimum-bounding-box:width: 639
    signature: 6c9e8585dbc79cdce6b186461fa06eb841ede13cb1fea78d137e383289ac6306
    tiff:alpha: unspecified
    tiff:endian: msb
    tiff:photometric: RGB
    tiff:rows-per-strip: 4
  Artifacts:
    verbose: true
  Tainted: False
  Filesize: 1.17261MiB
  Number pixels: 409600
  Pixels per second: 98.1911MP
  User time: 0.000u
  Elapsed time: 0:01.004
  Version: ImageMagick 7.0.10-4 Q16 x86_64 2020-04-05 https://imagemagick.org

I generated this with $identify -verbose image.tif

I tried changing the endiannes with imagemagick and didn’t help (from LSB to MSB). Is it the resolution? the signature?

Update: Here you can see the different reasons for that error: https://github.com/processing/processing-android/blob/master/core/src/processing/core/PImage.java#L2535

Very interesting function. It compares the header and it must match exactly the expected header byte by byte, except for bytes 30, 31, 42, 43, 102, 103, 114 ~ 117. It should be doable to put those bytes on a tiff file, but first it should have the same header length I guess.

Comparing the two files with an hex editor I seed that the first bytes are already different. Instead of 77, 77, 0, 42 it starts with 73, 73, 42, 0.

@hamoid We’ll get there!
I have also been using GIMP to investigate. That reference to Endianess might be slang for Big-endian or little-Endian. LSB: least significant bit first. MSB: most significant bit first. I think Endianess might not be the thing because the TIFF that loads OK is Big-endian (Motorola, MM) and my TIFF that does not load is also Big-endian.
I have compared the files that work against the files that don’t work at https://www.metadata2go.com/ and the major difference seems to be that the files that do not work have so much more meta data (including an embedded thumbnail image). Is there a way to delete all the meta data?
The other difference seems to be Strip Offsets. 768 works. 29792 doesn’t work.

I suspect that Processing is being very restrictive about what it loads because it doesn’t support most of the many features from the TIFF format TIFF - Wikipedia

– and it doesn’t even want to try to check for them all. It isn’t trying to determine “could I load this TIFF” but “is this one specific simple type of tiff, probably one that I made?”

The blame also looks like that code block hasn’t been touched since 2009. Possibly earlier.

edit …BTW: just noticed that link is to the Android code. Why that repo, not the main Processing one?

Hi :slight_smile: Android code because I didn’t notice. I was searching for the error and found that without noticing.

This is the Processing version, I assume equal: https://github.com/processing/processing/blob/master/core/src/processing/core/PImage.java#L2951

I’ll include here the relevant code:

  static byte[] TIFF_HEADER = {
    77, 77, 0, 42, 0, 0, 0, 8, 0, 9, 0, -2, 0, 4, 0, 0, 0, 1, 0, 0,
    0, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 3, 0, 0, 0, 1,
    0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 3, 0, 0, 0, 122, 1, 6, 0, 3, 0,
    0, 0, 1, 0, 2, 0, 0, 1, 17, 0, 4, 0, 0, 0, 1, 0, 0, 3, 0, 1, 21,
    0, 3, 0, 0, 0, 1, 0, 3, 0, 0, 1, 22, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0,
    1, 23, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8
  };


  static final String TIFF_ERROR =
    "Error: Processing can only read its own TIFF files.";

  static protected PImage loadTIFF(byte[] tiff) {
    if ((tiff[42] != tiff[102]) ||  // width/height in both places
        (tiff[43] != tiff[103])) {
      System.err.println(TIFF_ERROR);
      return null;
    }

    int width =
      ((tiff[30] & 0xff) << 8) | (tiff[31] & 0xff);
    int height =
      ((tiff[42] & 0xff) << 8) | (tiff[43] & 0xff);

    int count =
      ((tiff[114] & 0xff) << 24) |
      ((tiff[115] & 0xff) << 16) |
      ((tiff[116] & 0xff) << 8) |
      (tiff[117] & 0xff);
    if (count != width * height * 3) {
      System.err.println(TIFF_ERROR + " (" + width + ", " + height +")");
      return null;
    }

    // check the rest of the header
    for (int i = 0; i < TIFF_HEADER.length; i++) {
      if ((i == 30) || (i == 31) || (i == 42) || (i == 43) ||
          (i == 102) || (i == 103) ||
          (i == 114) || (i == 115) || (i == 116) || (i == 117)) continue;

      if (tiff[i] != TIFF_HEADER[i]) {
        System.err.println(TIFF_ERROR + " (" + i + ")");
        return null;
      }
    }

So one can see there 3 reasons for the error:

  • byte 42 must be equal to 102, byte 43 must be equal to 103.
  • count must be equal width * height * 3
  • most header bytes must match

A different approach: I found this:

Which would easily load lots of image types.
In my sketch I create a code folder and drop these inside:

common-image-3.5.jar
common-io-3.5.jar
common-lang-3.5.jar
imageio-core-3.5.jar
imageio-metadata-3.5.jar
imageio-tiff-3.5.jar

This program loads and shows the tiff:

import java.awt.image.*;
import javax.imageio.ImageIO;

PImage img;

void setup() { 
  size(640, 400);

  try {
    BufferedImage tiff = ImageIO.read(new File("/tmp/a.tif"));
    byte[] px = ((DataBufferByte) tiff.getRaster().getDataBuffer()).getData();
    img = createImage(tiff.getWidth(), tiff.getHeight(), RGB);
    img.loadPixels();
    for(int i=0; i<px.length; i+=4) {
      img.pixels[i/4] = (px[i+3] << 16) + (px[i+2] << 8) + px[i+1];
    }
    img.updatePixels();    
  } 
  catch(Exception e) {
    e.printStackTrace();
  }
}

void draw() {
  image(img, 0, 0);
}

But I’m doing something wrong. Most of the image looks fine, but the pure bright colors don’t. Left gimp, right Processing.

I’ll let others finish the job :slight_smile:

3 Likes

@hamoid @jeremydouglass

So,

  1. Processing > Tools > Movie Maker to convert a folder of proprietary TIFFs into a movie.

  2. Import said movie into a Processing sketch
    https://www.processing.org/reference/libraries/video/Movie.html

  3. Export frames as Processing’s TIFFs
    saveFrame(“frames/####.tif);

Done

What do you think?

I would never convert images to movie and back, that would destroy their quality.

I don’t know what’s your goal. But if the goal is just to get those images loaded in any way, I would

  • use a command line program like image magick to convert them all in advance (if the image set does not grow)
  • or execute convert (an image magick command line application) from Processing to convert the image to TGA or BMP (which is lossless) then load that, then delete the converted image to not occupy space on disk.
  • or finish the approach I mentioned above with those twelve monkeys, which would allow not only tiff but jpg2000 and others.
2 Likes

An approach that I mentioned in another thread was to use JAI:

I didn’t test it much, though – not sure if it has color palette problems. I wonder how it compares with TwelveMonkeys.

@hamoid

The goal was to increase understanding and resolve a mystery. Both now achieved.

@jeremydouglass found a way to import the TIFF like this:

  1. create a /code subfolder in your sketch, and add jai_imageio-1.1.jar
  2. add a TIFF file to the sketch folder: test.tif
  3. run a sketch that uses the protected undocumented loadImageIO method of Processing’s PApplet:
PImage img;
 
void setup() {
  size(484, 480);
  background(128);
  img = this.loadImageIO("test.tif");
  image(img, 0, 0);
}

Your TIFF is loaded as a PImage and displayed.

But I also found your excellent work, (colorjoy)!

3 Likes