summaryrefslogtreecommitdiff
path: root/jpg2ff.c
diff options
context:
space:
mode:
authorFRIGN <dev@frign.de>2016-01-17 01:39:36 +0100
committerFRIGN <dev@frign.de>2016-01-17 02:11:54 +0100
commit3bc6c69ae8ff25377848b76a25494aa4a0055544 (patch)
treef100a868b831c1dcf190446657a7a5851d511ff7 /jpg2ff.c
parenta0767dd0ba8c9c5f04616ff5dc8d82b2591cf2d8 (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 'jpg2ff.c')
-rw-r--r--jpg2ff.c58
1 files changed, 50 insertions, 8 deletions
diff --git a/jpg2ff.c b/jpg2ff.c
index eaed74b..aec6dd0 100644
--- a/jpg2ff.c
+++ b/jpg2ff.c
@@ -8,9 +8,19 @@
#include <string.h>
#include <jpeglib.h>
+#include <lcms2.h>
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 */
+};
+
+
METHODDEF(void)
jpeg_error(j_common_ptr cinfo)
{
@@ -22,6 +32,9 @@ jpeg_error(j_common_ptr cinfo)
int
main(int argc, char *argv[])
{
+ cmsHPROFILE in_profile, out_profile;
+ cmsHTRANSFORM transform;
+ cmsToneCurve *gamma18, *out_curves[3];
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
uint32_t width, height, val_be;
@@ -57,12 +70,26 @@ main(int argc, char *argv[])
/* create output buffers */
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,
JPOOL_IMAGE, jpeg_row_len, 1);
- ff_row_len = strlen("RGBA") * sizeof(uint16_t) * width;
- if(!(ff_row = malloc(ff_row_len))) {
+ ff_row_len = strlen("RGBA") * width;
+ if(!(ff_row = malloc(ff_row_len * sizeof(uint16_t)))) {
fprintf(stderr, "%s: malloc: out of memory\n", argv0);
return 1;
}
+ /* icc profile (output ProPhoto RGB) */
+ if (!(in_profile = cmsCreate_sRGBProfile()))
+ goto lcmserr;
+ if (!(gamma18 = cmsBuildGamma(NULL, 1.8)))
+ goto lcmserr;
+ out_curves[0] = out_curves[1] = out_curves[2] = gamma18;
+ if (!(out_profile = cmsCreateRGBProfile(cmsD50_xyY(), &primaries,
+ out_curves)))
+ goto lcmserr;
+ if (!(transform = cmsCreateTransform(in_profile, TYPE_RGBA_16,
+ out_profile, TYPE_RGBA_16,
+ INTENT_RELATIVE_COLORIMETRIC, 0)))
+ goto lcmserr;
+
/* write header */
fprintf(stdout, "farbfeld");
val_be = htonl(width);
@@ -78,15 +105,25 @@ main(int argc, char *argv[])
* more than one scanline at a time if that's more convenient. */
jpeg_read_scanlines(&cinfo, buffer, 1);
- for(i = 0, dx = 0, sx = 0; i < width; i++, sx += 3, dx += 4) {
- ff_row[dx] = htons(buffer[0][sx] * 257);
- ff_row[dx+1] = htons(buffer[0][sx+1] * 257);
- ff_row[dx+2] = htons(buffer[0][sx+2] * 257);
- ff_row[dx+3] = htons(65535);
+ for (i = 0, dx = 0, sx = 0; i < width; i++, sx += 3, dx += 4) {
+ ff_row[dx] = buffer[0][sx] * 257;
+ ff_row[dx+1] = buffer[0][sx+1] * 257;
+ ff_row[dx+2] = buffer[0][sx+2] * 257;
+ ff_row[dx+3] = 65535;
+ }
+
+ cmsDoTransform(transform, ff_row, ff_row, ff_row_len);
+
+ for (i = 0; i < ff_row_len; i++) {
+ /* re-add alpha */
+ if (i >= 3 && (i - 3) % 4 == 0)
+ ff_row[i] = 65535;
+ /* swap endianness to BE */
+ ff_row[i] = htons(ff_row[i]);
}
/* write data */
- if (fwrite(ff_row, 1, ff_row_len, stdout) != ff_row_len)
+ if (fwrite(ff_row, 2, ff_row_len, stdout) != ff_row_len)
goto writerr;
}
jpeg_finish_decompress(&cinfo);
@@ -96,5 +133,10 @@ main(int argc, char *argv[])
writerr:
fprintf(stderr, "%s: fwrite: ", argv0);
perror(NULL);
+
+ return 1;
+lcmserr:
+ fprintf(stderr, "%s: lcms error\n", argv0);
+
return 1;
}