ref: 65b4913adc23dd0c5c63f43b9a67e07308834a89
author: sirjofri <sirjofri@sirjofri.de>
date: Mon Apr 6 16:07:02 EDT 2026
load metadata
--- /dev/null
+++ b/icc.h
@@ -1,0 +1,106 @@
+typedef enum {+ ICscnr,
+ ICmntr,
+ ICprtr,
+ IClink,
+ ICspac,
+ ICabst,
+ ICnmcl,
+ ICMAX
+} ICCclass;
+
+typedef enum {+ ICIEXYZ,
+ ICIELAB,
+ ICIELUV,
+ IYCbCr,
+ ICIEYxy,
+ IRGB,
+ IGray,
+ IHSV,
+ IHLS,
+ ICMYK,
+ ICMY,
+ I2CLR,
+ I3CLR,
+ I4CLR,
+ I5CLR,
+ I6CLR,
+ I7CLR,
+ I8CLR,
+ I9CLR,
+ IACLR,
+ IBCLR,
+ ICCLR,
+ IDCLR,
+ IECLR,
+ IFCLR,
+ ISPACEMAX,
+} ICCcolorspace;
+
+typedef struct ICCdate ICCdate;
+struct ICCdate {+ u16int year;
+ u16int month;
+ u16int day;
+ u16int hours;
+ u16int minutes;
+ u16int seconds;
+};
+
+typedef u32int s15f16;
+
+typedef struct XYZNumber XYZNumber;
+struct XYZNumber {+ s15f16 x;
+ s15f16 y;
+ s15f16 z;
+};
+
+typedef enum {+ IDTransparent = 0x1, /* or reflective */
+ IDMatte = 0x2, /* or glossy */
+ IDNegative = 0x4, /* or positive */
+ IDMono = 0x8, /* or color */
+} DevAttribute;
+
+typedef struct ICCprofile ICCprofile;
+struct ICCprofile
+{+ u32int size;
+ u32int cmm;
+ int vmajor;
+ int vminor;
+ int vbugfix;
+ ICCclass class;
+ ICCcolorspace dataspace;
+ ICCcolorspace pcs;
+ ICCdate creationdate;
+ char platform[5];
+ u32int flags;
+
+ u32int devmanufacturer;
+ u32int devmodel;
+ u64int devattrs; /* see DevAttribute enum */
+
+ /* rendering intent.
+ 0 - perceptual
+ 1 - media-relative colorimetric
+ 2 - saturation
+ 3 - ICC-absolute colorimetric
+ */
+ u32int rendintent;
+
+ XYZNumber illuminant; /* PCS illuminant, D50 */
+
+ u32int creator;
+ uchar id[16];
+};
+
+ICCprofile *iccload(int fd);
+char *iccgetclass(ICCprofile*);
+char *iccgetdataspace(ICCprofile*);
+char *iccgetpcs(ICCprofile*);
+
+double s15f16tod(s15f16);
+s15f16 dtos16f16(double);
\ No newline at end of file
--- /dev/null
+++ b/load.c
@@ -1,0 +1,223 @@
+#include <u.h>
+#include <libc.h>
+#include "icc.h"
+
+#define END16(A) (( (A) << 8 )&0xff00 | ( (A) >> 8 )&0x00ff)
+
+static char *classes[] = {+ [ICscnr] "scnr",
+ [ICmntr] "mntr",
+ [ICprtr] "prtr",
+ [IClink] "link",
+ [ICspac] "spac",
+ [ICabst] "abst",
+ [ICnmcl] "nmcl",
+};
+
+static char *spaces[] = {+ [ICIEXYZ] "XYZ ",
+ [ICIELAB] "Lab ",
+ [ICIELUV] "Luv ",
+ [IYCbCr] "YCbr",
+ [ICIEYxy] "Yxy ",
+ [IRGB] "RGB ",
+ [IGray] "GRAY",
+ [IHSV] "HSV ",
+ [IHLS] "HLS ",
+ [ICMYK] "CMYK",
+ [ICMY] "CMY ",
+ [I2CLR] "2CLR",
+ [I3CLR] "3CLR",
+ [I4CLR] "4CLR",
+ [I5CLR] "5CLR",
+ [I6CLR] "6CLR",
+ [I7CLR] "7CLR",
+ [I8CLR] "8CLR",
+ [I9CLR] "9CLR",
+ [IACLR] "ACLR",
+ [IBCLR] "BCLR",
+ [ICCLR] "CCLR",
+ [IDCLR] "DCLR",
+ [IECLR] "ECLR",
+ [IFCLR] "FCLR",
+};
+
+static u16int
+iread16(uchar *data)
+{+ u16int *d = (u16int*)data;
+ return ((*d)<<8)&0xff00 | ((*d)>>8)&0x00ff;
+}
+
+static u32int
+iread32(uchar *data)
+{+ u32int *d = (u32int*)data;
+ return (
+ ((*d)<<24)&0xff000000
+ | ((*d)<<8 )&0x00ff0000
+ | ((*d)>>8 )&0x0000ff00
+ | ((*d)>>24)&0x000000ff
+ );
+}
+
+static u64int
+iread64(uchar *data)
+{+ u64int *d = (u64int*)data;
+ return (
+ ((*d)<<56)&0xff00000000000000
+ | ((*d)<<40)&0x00ff000000000000
+ | ((*d)<<24)&0x0000ff0000000000
+ | ((*d)<<8 )&0x000000ff00000000
+ | ((*d)>>8 )&0x00000000ff000000
+ | ((*d)>>24)&0x0000000000ff0000
+ | ((*d)>>40)&0x000000000000ff00
+ | ((*d)>>56)&0x00000000000000ff
+ );
+}
+
+static ICCcolorspace
+iccs2colorspace(char *s)
+{+ int i;
+ for (i = 0; i < ISPACEMAX; i++)
+ if (strncmp(s, spaces[i], 4) == 0)
+ return i;
+ return -1;
+}
+
+static ICCclass
+iccs2class(char *s)
+{+ int i;
+ for (i = 0; i < ICMAX; i++) {+ if (strncmp(s, classes[i], 4) == 0)
+ return i;
+ }
+ return -1;
+}
+
+char*
+iccgetclass(ICCprofile *p)
+{+ if (p->class >= 0 && p->class < ICMAX)
+ return classes[p->class];
+ return nil;
+}
+
+char*
+iccgetdataspace(ICCprofile *p)
+{+ if (p->dataspace < 0 || p->dataspace >= ISPACEMAX)
+ return nil;
+ return spaces[p->dataspace];
+}
+
+char*
+iccgetpcs(ICCprofile *p)
+{+ if (p->pcs < 0 || p->pcs >= ISPACEMAX)
+ return nil;
+ return spaces[p->pcs];
+}
+
+ICCdate
+iccparsedate(uchar *data)
+{+ ICCdate d;
+ d.year = iread16(&data[0]);
+ d.month = iread16(&data[2]);
+ d.day = iread16(&data[4]);
+ d.hours = iread16(&data[6]);
+ d.minutes = iread16(&data[8]);
+ d.seconds = iread16(&data[10]);
+ return d;
+}
+
+ICCprofile*
+iccload(int fd)
+{+ uchar header[128];
+ ICCprofile *prof;
+ u8int vmajor;
+ u8int vminor;
+
+ prof = mallocz(sizeof(ICCprofile), 1);
+ if (!prof) {+ werrstr("malloc: %r");+ return nil;
+ }
+
+ /* header: ICC.1-2022-05.pdf!32 */
+ if (read(fd, header, 128) != 128) {+ free(prof);
+ werrstr("read header: %r");+ return nil;
+ }
+
+ if (strncmp((char*)&header[36], "acsp", 4) != 0) {+ free(prof);
+ werrstr("invalid file signature: missing acsp");+ return nil;
+ }
+
+ prof->size = iread32(&header[0]);
+ prof->cmm = iread32(&header[4]);
+
+ vmajor = header[8];
+ vminor = header[9];
+ prof->vmajor = vmajor;
+ prof->vminor = (vminor>>4)&0x0f;
+ prof->vbugfix = vminor&0x0f;
+
+ prof->class = iccs2class((char*)&header[12]);
+ prof->dataspace = iccs2colorspace((char*)&header[16]);
+ prof->pcs = iccs2colorspace((char*)&header[20]);
+
+ prof->creationdate = iccparsedate(&header[24]);
+
+ memcpy(prof->platform, &header[40], 4);
+ prof->platform[4] = 0;
+
+ /* 0x0003, 0x1 = embedded, 0x2 = no independent use */
+ prof->flags = iread32(&header[44]);
+
+ prof->devmanufacturer = iread32(&header[48]);
+ prof->devmodel = iread32(&header[52]);
+ prof->devattrs = iread64(&header[56]);
+
+ prof->rendintent = iread32(&header[64]);
+
+ prof->illuminant.x = iread32(&header[68]);
+ prof->illuminant.y = iread32(&header[72]);
+ prof->illuminant.z = iread32(&header[76]);
+
+ prof->creator = iread32(&header[80]);
+
+ memcpy(prof->id, &header[84], 16);
+
+ /* future 100 - 127 */
+
+ return prof;
+}
+
+double
+s15f16tod(s15f16 in)
+{+ int post;
+ s16int full;
+ double d;
+
+ full = (in&0xffff0000) >> 16;
+ post = in&0x0000ffff;
+ d = (double)post / 0xffff;
+ d += full;
+ return d;
+}
+
+s15f16
+dtos15f16(double in)
+{+ return 0;
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,7 @@
+</$objtype/mkfile
+
+LIB=icc.a$O
+OFILES=\
+ load.$O\
+
+</sys/src/cmd/mklib
--- /dev/null
+++ b/test/mkfile
@@ -1,0 +1,6 @@
+</$objtype/mkfile
+
+TEST=t
+LIB=../icc.a$O
+
+</sys/src/cmd/mktest
--- /dev/null
+++ b/test/t.c
@@ -1,0 +1,58 @@
+#include <u.h>
+#include <libc.h>
+#include "../icc.h"
+
+void
+readattrs(char *s, u64int attr)
+{+ s += sprint(s, "%s ", attr&IDTransparent ? "transparent" : "reflective");
+ s += sprint(s, "%s ", attr&IDMatte ? "matte" : "glossy");
+ s += sprint(s, "%s ", attr&IDNegative ? "negative" : "positive");
+ s += sprint(s, "%s", attr&IDMono ? "mono" : "color");
+}
+
+void
+main(void)
+{+ char buf[512];
+ double dx, dy, dz;
+ ICCprofile *prof;
+ ICCdate d;
+ int fd;
+ int n;
+
+ fd = open("sRGB_v4_ICC_preference.icc", OREAD);+ prof = iccload(fd);
+ close(fd);
+
+ fprint(2, "size: %d\n", prof->size);
+ fprint(2, "cmm: %d\n", prof->cmm);
+ fprint(2, "vers: %d.%d.%d\n", prof->vmajor, prof->vminor, prof->vbugfix);
+ fprint(2, "class: %s\n", iccgetclass(prof));
+ fprint(2, "data: %s\n", iccgetdataspace(prof));
+ fprint(2, "pcs: %s\n", iccgetpcs(prof));
+
+ d = prof->creationdate;
+ fprint(2, "cdate: %4d.%02d.%02d %02d:%02d:%02d\n", d.year, d.month, d.day, d.hours, d.minutes, d.seconds);
+
+ fprint(2, "plat: %s\n", prof->platform);
+ fprint(2, "dmanu: %d\n", prof->devmanufacturer);
+ fprint(2, "dmodel: %d\n", prof->devmodel);
+
+ readattrs(buf, prof->devattrs);
+ fprint(2, "dattrs: %s\n", buf);
+
+ fprint(2, "intent: %d\n", prof->rendintent);
+
+ dx = s15f16tod(prof->illuminant.x);
+ dy = s15f16tod(prof->illuminant.y);
+ dz = s15f16tod(prof->illuminant.z);
+ fprint(2, "illum: %f %f %f\n", dx, dy, dz);
+
+ fprint(2, "creatr: %d\n", prof->creator);
+
+ n = enc64(buf, sizeof buf, prof->id, sizeof prof->id);
+ fprint(2, "id: %*s\n", n, buf);
+
+ exits(nil);
+}
--
⑨