diff options
author | FRIGN <dev@frign.de> | 2016-01-17 01:39:36 +0100 |
---|---|---|
committer | FRIGN <dev@frign.de> | 2016-01-17 02:11:54 +0100 |
commit | 3bc6c69ae8ff25377848b76a25494aa4a0055544 (patch) | |
tree | f100a868b831c1dcf190446657a7a5851d511ff7 /ff2png.c | |
parent | a0767dd0ba8c9c5f04616ff5dc8d82b2591cf2d8 (diff) |
Mandate "ProPhoto RGB" color space for farbfeld and handle ICC profiles
I've literally been thinking about this for quite a while now. The
initial motivation behind defaulting to sRGB was the idea that most data
on the web was in sRGB anyway.
However, my assumption was weakened in the sense that the development
is clearly moving towards images with supplied ICC profiles and software
slowly catching up to handle this. My tests have shown that more and
more people even do that on the web, even though it's been a "tradition"
that Photoshop users "Save for Web" and convert the gamut lossy into
sRGB to bring a consistent color-"experience" even to those clients not
supporting ICC profiles and which always assume sRGB.
What made this decision so difficult is that converting to "ProPhoto
RGB" requires some advanced knowledge on this topic, however, I came to
the conclusion to implement it given the *2ff- and ff2*-tools handle it
silently and well in the background, and given the little cms library is
actually quite okay to use.
When converting from ff to png, a proper "Pro Photo RGB" ICC V4-profile is
automatically included in the exported png by ff2png. V4 is not as
widespread as V2, but in the worst case (no V4 support somewhere) the
colors will just be a little off.
As an added bonus, any input files for png2ff which include ICC profiles
are also correctly handled and the color space conversions are executed
as expected.
Accordingly, the FORMAT-specification has been changed. While at it,
I added the note on alpha-multiplication. Now the format is very exact
and shouldn't leave any ambiguities.
jpeg supports ICC profiles as well, but I hadn't had the chance to look
into it (not as trivial as PNG probably, help appreciated :)), so I'm
always assuming sRGB here.
Rationale
---------
It is not obvious why one would go through the lenghts of supporting
this big-gamut colorspace and not just stick with sRGB. In 99% of the
cases, there's no reason to do that, but with even more extreme
developments in the OLED-sector and other advances display hardware is
slowly getting more powerful than sRGB, asking for color information
which is suitable for the task and actually uses the full potential.
The decision in this regard was not difficult in farbfeld because we
always use 16-Bit anyway and won't have to fear posterization in a big-
gamut color-space.
Diffstat (limited to 'ff2png.c')
-rw-r--r-- | ff2png.c | 47 |
1 files changed, 46 insertions, 1 deletions
@@ -7,12 +7,21 @@ #include <stdlib.h> #include <string.h> +#include <lcms2.h> #include <png.h> #define HEADER "farbfeld########" static char *argv0; +/* ProPhoto RGB */ +static cmsCIExyYTRIPLE primaries = { + /* x, y, Y */ + { 0.7347, 0.2653, 0.288040 }, /* red */ + { 0.1596, 0.8404, 0.711874 }, /* green */ + { 0.0366, 0.0001, 0.000086 }, /* blue */ +}; + void pngerr(png_structp png_struct_p, png_const_charp msg) { @@ -23,12 +32,17 @@ pngerr(png_structp png_struct_p, png_const_charp msg) int main(int argc, char *argv[]) { + cmsContext icc_context; + cmsHPROFILE out_profile; + cmsMLU *mlu1, *mlu2; + cmsToneCurve *gamma18, *out_curves[3]; png_structp png_struct_p; png_infop png_info_p; png_size_t png_row_len, j; png_uint_32 width, height, i; + uint32_t icclen; uint16_t tmp16, *png_row; - uint8_t hdr[16]; + uint8_t hdr[16], *icc; argv0 = argv[0], argc--, argv++; @@ -49,6 +63,32 @@ main(int argc, char *argv[]) width = ntohl(*((uint32_t *)(hdr + 8))); height = ntohl(*((uint32_t *)(hdr + 12))); + /* icc profile (ProPhoto RGB) */ + if (!(icc_context = cmsCreateContext(NULL, NULL))) + goto lcmserr; + if (!(gamma18 = cmsBuildGamma(icc_context, 1.8))) + goto lcmserr; + out_curves[0] = out_curves[1] = out_curves[2] = gamma18; + if (!(out_profile = cmsCreateRGBProfileTHR(icc_context, cmsD50_xyY(), + &primaries, out_curves))) + goto lcmserr; + cmsSetHeaderFlags(out_profile, cmsEmbeddedProfileTrue | cmsUseAnywhere); + cmsSetHeaderRenderingIntent(out_profile, INTENT_RELATIVE_COLORIMETRIC); + cmsSetDeviceClass(out_profile, cmsSigColorSpaceClass); + if (!(mlu1 = cmsMLUalloc(NULL, 1)) || !(mlu2 = cmsMLUalloc(NULL, 1))) + goto lcmserr; + cmsMLUsetASCII(mlu1, "en", "US", "Public Domain"); + cmsWriteTag(out_profile, cmsSigCopyrightTag, mlu1); + cmsMLUsetASCII(mlu2, "en", "US", "ProPhoto RGB"); + cmsWriteTag(out_profile, cmsSigProfileDescriptionTag, mlu2); + cmsWriteTag(out_profile, cmsSigDeviceModelDescTag, mlu2); + cmsSaveProfileToMem(out_profile, NULL, &icclen); + if (!(icc = malloc(icclen))) { + fprintf(stderr, "%s: malloc: out of memory\n", argv0); + return 1; + } + cmsSaveProfileToMem(out_profile, icc, &icclen); + /* load png */ png_struct_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, pngerr, NULL); @@ -62,6 +102,7 @@ main(int argc, char *argv[]) png_set_IHDR(png_struct_p, png_info_p, width, height, 16, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_set_iCCP(png_struct_p, png_info_p, "ProPhoto RGB", 0, icc, icclen); png_write_info(png_struct_p, png_info_p); /* write rows */ @@ -84,4 +125,8 @@ main(int argc, char *argv[]) png_destroy_write_struct(&png_struct_p, NULL); return 0; +lcmserr: + fprintf(stderr, "%s: lcms error\n", argv0); + + return 1; } |