icc icon indicating copy to clipboard operation
icc copied to clipboard

Parsing Transform tags

Open fabulousduck opened this issue 5 years ago • 12 comments

Within the prtr ICC profile, a set of tags which I will list below define a set of color transform. The issue here is that these tags can regularly defy the size set for them in the tag in the tag table. A solution on how to parse them would be nice as I cannot figure this out myself.

Some info about these special tags can be found in this doc.

  • A2B0
  • A2B2
  • A2B1
  • B2A0
  • B2A1
  • B2A2

fabulousduck avatar Oct 04 '18 21:10 fabulousduck

Hello, at the moment this module only looks for tags with a tagType it knows about, namely desc and text - https://github.com/lovell/icc/blob/master/index.js#L83-L109

Perhaps it should provide a bit more data about the presence of other tags, including the 6 you list, exposing the raw data as a Buffer. In the case of the A2B and B2A tags, these would be look up tables (LUTs) with a tagType of mft1 (8 bit) or mft2 (16-bit).

Happy to accept a PR if you're able.

lovell avatar Oct 04 '18 21:10 lovell

I will try to implement this tag in my ICC implementation first. When I get that working i will port that tag implementation to you ICC parser.

fabulousduck avatar Oct 06 '18 16:10 fabulousduck

What is the status of this, I've looked through #3 and seems to meet the goals of this issue? I'd be interested in extending this so that functions could be derived from the A2Bx, B2Ax tables.

tristaaan avatar Jan 02 '20 21:01 tristaaan

I'd be very happy to accept a new PR if you're able, thank you. The work in #3 could be used as the basis with the addition of more unit tests to cover all the extra logic.

lovell avatar Jan 02 '20 21:01 lovell

I've added a few new tests and fixtures to the repo, including the ICC "probe" profiles that include sample transform tags. This should make testing a little easier should anyone like to work on a follow up to the original PR at #3.

lovell avatar Mar 27 '23 08:03 lovell

I am trying to work on a PR, do you have an idea how you would like the final json format to be ?

Would it be something like this ? with a major of upgrade since we put all previous answers in a key header

{
header: {
        version: '2.1',
        intent: 'Perceptual',
        cmm: 'Adobe',
        deviceClass: 'Printer',
        colorSpace: 'CMYK',
        connectionSpace: 'Lab',
        platform: 'Apple',
        manufacturer: 'Adobe',
        creator: 'Adobe',
        tagCount: 10,
    },
tables:
    {
        A2B0: [],
        A2B2: [],
        A2B1: [],
        B2A0: [],
        B2A1: [],
        B2A2: [],
        gamt: []
    }
}

or should we just have something like this

{
version: '2.1',
intent: 'Perceptual',
cmm: 'Adobe',
deviceClass: 'Printer',
colorSpace: 'CMYK',
connectionSpace: 'Lab',
platform: 'Apple',
manufacturer: 'Adobe',
creator: 'Adobe',
tagCount: 10,
tables:
    {
        A2B0: [],
        A2B2: [],
        A2B1: [],
        B2A0: [],
        B2A1: [],
        B2A2: [],
        gamt: []
    }
}

EDIT: I have written some code that looks ok and would need some refining,

EDIT2: I put the changes in a cloned repo here: https://github.com/Aminelahlou/icc/

Aminelahlou avatar Apr 28 '23 20:04 Aminelahlou

@Aminelahlou Thank you very much for picking this up and tackling it again.

I think I'd prefer not to alter the existing response structure and instead add to it.

Perhaps we can have A2B0, A2B1 and A2B2 as direct properties in the response? Or maybe an a2b property with perceptual, colorimetric and saturation as children might be easier to understand?

In terms of what lives under this, the structure in the closed-but-not-forgotten PR #3 looked pretty good to me.

https://github.com/lovell/icc/pull/3/files#diff-e727e4bdf3657fd1d798edcd6b099d6e092f8573cba266154583a746bba0f346R62

If the raw lookup table data could use the relevant TypedArray e.g. Uint8Array or Uint16Array then that would be great.

{
  version: '2.1',
  ...
  a2b: {
    perceptual: {
      inputChannels: ...
      matrix: ...
      ...
    },
    colorimetric: { ... }
    ...
  }
}

lovell avatar Apr 30 '23 13:04 lovell

I'm trying to achieve this at the moment. Is there anything wrong with what PR https://github.com/lovell/icc/pull/3 is doing at the moment? I see it needs more tests but the current state of parsing is useful (not sure returning a buffer instead of a processed array makes sense). I'm working on attaching functions for A2B/B2A/gamt but I'm struggling with the testing step.

I see the probe profile in the fixtures but I'm unsure about how to proceed to see if the extracted tables are correct or if the transform functions derived give the correct output.

MathieuLoutre avatar Sep 19 '23 08:09 MathieuLoutre

@MathieuLoutre Thanks for taking a look at this, always happy to accept/review a (partial) PR if you're able.

If you hadn't seen, the expected behaviour of the probe profile is documented at https://www.color.org/probeprofile.xalter

The rendering intent transforms (BToA tags) of the probe profile ignore the a* and b* components of incoming PCS colors, and map the L* components directly to monotone tints of process colorants. (L* = 0 is rendered as maximum colorant coverage, and L* = 100 is rendered as unmarked media.) The B2A0 tag (perceptual rendering intent transform) renders the L* values as tints of pure cyan. The B2A1 tag (relative colorimetric intent transform) renders them as tints of pure magenta, and the B2A2 tag (saturation intent transform) renders them as tints of pure yellow.

lovell avatar Sep 26 '23 11:09 lovell

Thanks @lovell! I had a look at this page but couldn't make sense of it at the time of my previous comment. Now that I've worked with ICC profiles for a few days, I think I understand it.

At the moment, the unit tests have something like this:

const B2A0Min = profile.B2A0.transform([0, 0.5, 0.5]);
assert.deepStrictEqual(B2A0Min, [1, 0, 0, 0])
const B2A0Max = profile.B2A0.transform([1, 0.5, 0.5]);
assert.deepStrictEqual(B2A0Max, [0, 0, 0, 0])

This passes successfully (transform is the function that takes the input and passes it through the various tables). However, it's maybe a little unclear from the above text whether a value of 0.5 in L* should yield a value of 0.5 in Cyan. That's what I understood from "monotone tints of process colorants" but at the moment, that returns 1 for C as well.

That being said, I'm. not sure how to approach the unit tests which currently verify the output with deepStrictEqual and as a result, we'd need a source of truth for each table. Would you be happy to exclude the tables from the equal check and use the transform functions as a way to verify that they're correct?

MathieuLoutre avatar Sep 27 '23 09:09 MathieuLoutre

...use the transform functions as a way to verify that they're correct?

That sounds sensible, yes please.

lovell avatar Oct 02 '23 20:10 lovell

Hi @lovell! I've made a new PR (#7) that picks up the work from #3. The A2B0 tests are failing (everything else seems fine). I can't pick out why. It returns 0.61 instead of a value between 0.7 and 1 as explained in https://www.color.org/probeprofile.xalter.

Any ideas?

MathieuLoutre avatar Oct 05 '23 19:10 MathieuLoutre