ref: 6727b8912f34a00c4a8a83b0795f9bbf96c06fe9
dir: /load.c/
#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;
}
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)
{
return 0;
}