summaryrefslogtreecommitdiff
path: root/png2ff.c
diff options
context:
space:
mode:
Diffstat (limited to 'png2ff.c')
-rw-r--r--png2ff.c96
1 files changed, 80 insertions, 16 deletions
diff --git a/png2ff.c b/png2ff.c
index 4963e86..aea7a50 100644
--- a/png2ff.c
+++ b/png2ff.c
@@ -5,11 +5,21 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <lcms2.h>
#include <png.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 */
+};
+
void
pngerr(png_structp png_struct_p, png_const_charp msg)
{
@@ -20,11 +30,16 @@ pngerr(png_structp png_struct_p, png_const_charp msg)
int
main(int argc, char *argv[])
{
+ cmsHPROFILE in_profile, out_profile;
+ cmsHTRANSFORM transform;
+ cmsToneCurve *gamma18, *out_curves[3];
png_structp png_struct_p;
png_infop png_info_p;
- png_bytepp png_row_p;
- uint32_t width, height, png_row_len, tmp32, r, i;
- uint16_t tmp16;
+ png_bytepp png_row_p, icc_data = NULL;
+ png_charpp icc_name = NULL;
+ uint32_t width, height, icc_len, outrowlen, tmp32, r, i;
+ uint16_t *inrow, *outrow;
+ int icc_compression;
argv0 = argv[0], argc--, argv++;
@@ -53,9 +68,33 @@ main(int argc, char *argv[])
PNG_TRANSFORM_EXPAND, NULL);
width = png_get_image_width(png_struct_p, png_info_p);
height = png_get_image_height(png_struct_p, png_info_p);
- png_row_len = png_get_rowbytes(png_struct_p, png_info_p);
png_row_p = png_get_rows(png_struct_p, png_info_p);
+ /* icc profile (output ProPhoto RGB) */
+ if (png_get_valid(png_struct_p, png_info_p, PNG_INFO_iCCP)) {
+ png_get_iCCP(png_struct_p, png_info_p, icc_name,
+ &icc_compression, icc_data, &icc_len);
+ if (!(in_profile = cmsOpenProfileFromMem(icc_data,
+ icc_len)))
+ goto lcmserr;
+ } else {
+ 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;
+
+ /* allocate row buffer */
+ outrowlen = width * strlen("RGBA");
+ if (!(outrow = malloc(outrowlen * sizeof(uint16_t)))) {
+ fprintf(stderr, "%s: malloc: out of memory\n", argv0);
+ return 1;
+ }
+
/* write header */
fputs("farbfeld", stdout);
tmp32 = htonl(width);
@@ -68,25 +107,46 @@ main(int argc, char *argv[])
/* write data */
switch(png_get_bit_depth(png_struct_p, png_info_p)) {
case 8:
+ if (!(transform = cmsCreateTransform(in_profile,
+ TYPE_RGBA_8, out_profile, TYPE_RGBA_16,
+ INTENT_RELATIVE_COLORIMETRIC, 0)))
+ goto lcmserr;
for (r = 0; r < height; ++r) {
- for (i = 0; i < png_row_len; i++) {
- /* ((2^16-1) / 255) == 257 */
- tmp16 = htons(257 * png_row_p[r][i]);
- if (fwrite(&tmp16, sizeof(uint16_t), 1,
- stdout) != 1)
- goto writerr;
+ cmsDoTransform(transform, png_row_p[r], outrow, width);
+ for (i = 0; i < outrowlen; i++) {
+ /* re-add alpha */
+ if (i >= 3 && (i - 3) % 4 == 0)
+ outrow[i] = 257 * png_row_p[r][i];
+ /* swap endiannes to BE */
+ outrow[i] = htons(outrow[i]);
}
+ if (fwrite(outrow, sizeof(uint16_t), outrowlen,
+ stdout) != outrowlen)
+ goto writerr;
}
break;
case 16:
+ if (!(transform = cmsCreateTransform(in_profile,
+ TYPE_RGBA_16, out_profile, TYPE_RGBA_16,
+ INTENT_RELATIVE_COLORIMETRIC, 0)))
+ goto lcmserr;
for (r = 0; r < height; ++r) {
- for (i = 0; i < png_row_len / 2; i++) {
- tmp16 = *((uint16_t *)(png_row_p[r] +
- 2 * i));
- if (fwrite(&tmp16, sizeof(uint16_t), 1,
- stdout) != 1)
- goto writerr;
+ inrow = (uint16_t *)png_row_p[r];
+ for (i = 0; i < outrowlen; i++) {
+ /* swap endianness to LE */
+ inrow[i] = ntohs(inrow[i]);
+ }
+ cmsDoTransform(transform, png_row_p[r], outrow, width);
+ for (i = 0; i < outrowlen; ++i) {
+ /* re-add alpha */
+ if (i >= 3 && (i - 3) % 4 == 0)
+ outrow[i] = inrow[i];
+ /* swap endianness to BE */
+ outrow[i] = htons(outrow[i]);
}
+ if (fwrite(outrow, sizeof(uint16_t), outrowlen,
+ stdout) != outrowlen)
+ goto writerr;
}
break;
default:
@@ -102,4 +162,8 @@ writerr:
perror(NULL);
return 1;
+lcmserr:
+ fprintf(stderr, "%s: lcms error\n", argv0);
+
+ return 1;
}