shithub: libicc

Download patch

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);
+}
--