shithub: libicc

ref: 4514f7351d135f29d3f322c1512cf348c656a022
dir: /load.c/

View raw version
#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",
};

u16int
iread16(uchar *data)
{
	u16int *d = (u16int*)data;
	return ((*d)<<8)&0xff00 | ((*d)>>8)&0x00ff;
}

u32int
iread32(uchar *data)
{
	u32int *d = (u32int*)data;
	return (
		  ((*d)<<24)&0xff000000
		| ((*d)<<8 )&0x00ff0000
		| ((*d)>>8 )&0x0000ff00
		| ((*d)>>24)&0x000000ff
	);
}

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];
	uchar *td;
	ICCprofile *prof;
	ICCTag *tag;
	u8int vmajor;
	u8int vminor;
	ulong n;
	int hasdesc;
	int hascprt;
	int haswtpt;
	int haschad;
	
	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 */
	
	/* load tags */
	prof->tagdata = mallocz(prof->size - 128, 1);
	if (!prof->tagdata) {
		werrstr("malloc tagdata: %r");
		free(prof);
		return nil;
	}
	if (read(fd, prof->tagdata, prof->size-128) != prof->size-128) {
		werrstr("read tagdata: %r");
		free(prof->tagdata);
		free(prof);
		return nil;
	}
	prof->ntags = iread32(&prof->tagdata[0]);
	
	prof->tags = mallocz(prof->ntags * sizeof(ICCTag), 1);
	if (!prof->tags) {
		werrstr("malloc tag table: %r");
		free(prof->tags);
		free(prof->tagdata);
		free(prof);
		return nil;
	}
	
	hasdesc = haschad = hascprt = haswtpt = 0;
	for (n = 0; n < prof->ntags; n++) {
		tag = &prof->tags[n];
		td = &prof->tagdata[n*12] + 4;
		tag->signature = iread32(td + 0);
		tag->offset = iread32(td + 4);
		tag->size = iread32(td + 8);
		
		if (tag->signature == 0x64657363)
			hasdesc++;
		if (tag->signature == 0x63686164)
			haschad++;
		if (tag->signature == 0x63707274)
			hascprt++;
		if (tag->signature == 0x77747074)
			haswtpt++;
	}
	
	if (!hasdesc) {
		werrstr("missing desc tag");
		free(prof->tags);
		free(prof->tagdata);
		free(prof);
		return nil;
	}
	if (!hascprt) {
		werrstr("missing cprt tag");
		free(prof->tags);
		free(prof->tagdata);
		free(prof);
		return nil;
	}
	
	return prof;
}

void
iccfree(ICCprofile *prof)
{
	free(prof->tagdata);
	free(prof->tags);
	free(prof);
}

ICCTagPtr
iccfindtag(ICCprofile *prof, u32int signature)
{
	ICCTagPtr p;
	int i;
	
	for (i = 0; i < prof->ntags; i++) {
		if (prof->tags[i].signature != signature)
			continue;
		p.ptr = prof->tagdata + prof->tags[i].offset - 128;
		p.size = prof->tags[i].size;
		p.type = iread32(p.ptr);
		return p;
	}
	
	p.ptr = nil;
	p.type = 0;
	p.size = 0;
	return p;
}

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)
{
	fprint(2, "not implemented yet!\n");
	return 0;
}