15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* vim: set ts=8 sw=8 noexpandtab: */ 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// qcms 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (C) 2009 Mozilla Foundation 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (C) 1998-2007 Marti Maria 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Permission is hereby granted, free of charge, to any person obtaining 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a copy of this software and associated documentation files (the "Software"), 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to deal in the Software without restriction, including without limitation 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the rights to use, copy, modify, merge, publish, distribute, sublicense, 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and/or sell copies of the Software, and to permit persons to whom the Software 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is furnished to do so, subject to the following conditions: 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The above copyright notice and this permission notice shall be included in 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// all copies or substantial portions of the Software. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <math.h> 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h> 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> //memset 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "qcmsint.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* It might be worth having a unified limit on content controlled 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * allocation per profile. This would remove the need for many 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * of the arbitrary limits that we used */ 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef uint32_t be32; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef uint16_t be16; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)not used yet 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* __builtin_bswap isn't available in older gccs 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * so open code it for now */ 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static be32 cpu_to_be32(int32_t v) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef IS_LITTLE_ENDIAN 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //return __builtin_bswap32(v); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return v; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uint32_t be32_to_cpu(be32 v) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef IS_LITTLE_ENDIAN 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //return __builtin_bswap32(v); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return v; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uint16_t be16_to_cpu(be16 v) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef IS_LITTLE_ENDIAN 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((v & 0xff) << 8) | ((v & 0xff00) >> 8); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return v; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* a wrapper around the memory that we are going to parse 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * into a qcms_profile */ 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct mem_source 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const unsigned char *buf; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_bool valid; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *invalid_reason; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void invalid_source(struct mem_source *mem, const char *reason) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mem->valid = false; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mem->invalid_reason = reason; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uint32_t read_u32(struct mem_source *mem, size_t offset) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Subtract from mem->size instead of the more intuitive adding to offset. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This avoids overflowing offset. The subtraction is safe because 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * mem->size is guaranteed to be > 4 */ 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset > mem->size - 4) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(mem, "Invalid offset"); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) be32 k; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&k, mem->buf + offset, sizeof(k)); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return be32_to_cpu(k); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uint16_t read_u16(struct mem_source *mem, size_t offset) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset > mem->size - 2) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(mem, "Invalid offset"); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) be16 k; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&k, mem->buf + offset, sizeof(k)); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return be16_to_cpu(k); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uint8_t read_u8(struct mem_source *mem, size_t offset) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (offset > mem->size - 1) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(mem, "Invalid offset"); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *(uint8_t*)(mem->buf + offset); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static s15Fixed16Number read_s15Fixed16Number(struct mem_source *mem, size_t offset) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return read_u32(mem, offset); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uInt8Number read_uInt8Number(struct mem_source *mem, size_t offset) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return read_u8(mem, offset); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uInt16Number read_uInt16Number(struct mem_source *mem, size_t offset) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return read_u16(mem, offset); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BAD_VALUE_PROFILE NULL 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INVALID_PROFILE NULL 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NO_MEM_PROFILE NULL 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* An arbitrary 4MB limit on profile size */ 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAX_PROFILE_SIZE 1024*1024*4 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAX_TAG_COUNT 1024 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void check_CMM_type_signature(struct mem_source *src) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //uint32_t CMM_type_signature = read_u32(src, 4); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //TODO: do the check? 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void check_profile_version(struct mem_source *src) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t major_revision = read_u8(src, 8 + 0); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t minor_revision = read_u8(src, 8 + 1); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t reserved1 = read_u8(src, 8 + 2); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t reserved2 = read_u8(src, 8 + 3); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Checking the version doesn't buy us anything 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (major_revision != 0x4) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (major_revision > 0x2) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "Unsupported major revision"); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (minor_revision > 0x40) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "Unsupported minor revision"); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reserved1 != 0 || reserved2 != 0) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "Invalid reserved bytes"); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INPUT_DEVICE_PROFILE 0x73636e72 // 'scnr' 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DISPLAY_DEVICE_PROFILE 0x6d6e7472 // 'mntr' 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define OUTPUT_DEVICE_PROFILE 0x70727472 // 'prtr' 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DEVICE_LINK_PROFILE 0x6c696e6b // 'link' 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define COLOR_SPACE_PROFILE 0x73706163 // 'spac' 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ABSTRACT_PROFILE 0x61627374 // 'abst' 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NAMED_COLOR_PROFILE 0x6e6d636c // 'nmcl' 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void read_class_signature(qcms_profile *profile, struct mem_source *mem) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->class = read_u32(mem, 12); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (profile->class) { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case DISPLAY_DEVICE_PROFILE: 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case INPUT_DEVICE_PROFILE: 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case OUTPUT_DEVICE_PROFILE: 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COLOR_SPACE_PROFILE: 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(mem, "Invalid Profile/Device Class signature"); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void read_color_space(qcms_profile *profile, struct mem_source *mem) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->color_space = read_u32(mem, 16); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (profile->color_space) { 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case RGB_SIGNATURE: 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GRAY_SIGNATURE: 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(mem, "Unsupported colorspace"); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void read_pcs(qcms_profile *profile, struct mem_source *mem) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->pcs = read_u32(mem, 20); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (profile->pcs) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case XYZ_SIGNATURE: 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case LAB_SIGNATURE: 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(mem, "Unsupported pcs"); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct tag 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t signature; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t offset; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t size; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct tag_index { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t count; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct tag *tags; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct tag_index read_tag_table(qcms_profile *profile, struct mem_source *mem) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct tag_index index = {0, NULL}; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index.count = read_u32(mem, 128); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index.count > MAX_TAG_COUNT) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(mem, "max number of tags exceeded"); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index.tags = malloc(sizeof(struct tag)*index.count); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index.tags) { 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < index.count; i++) { 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index.tags[i].signature = read_u32(mem, 128 + 4 + 4*i*3); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index.tags[i].offset = read_u32(mem, 128 + 4 + 4*i*3 + 4); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index.tags[i].size = read_u32(mem, 128 + 4 + 4*i*3 + 8); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks a profile for obvious inconsistencies and returns 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// true if the profile looks bogus and should probably be 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ignored. 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_bool qcms_profile_is_bogus(qcms_profile *profile) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float sum[3], target[3], tolerance[3]; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float rX, rY, rZ, gX, gY, gZ, bX, bY, bZ; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool negative; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned i; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We currently only check the bogosity of RGB profiles 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->color_space != RGB_SIGNATURE) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (qcms_supports_iccv4 && (profile->A2B0 || profile->B2A0)) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rX = s15Fixed16Number_to_float(profile->redColorant.X); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rY = s15Fixed16Number_to_float(profile->redColorant.Y); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rZ = s15Fixed16Number_to_float(profile->redColorant.Z); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gX = s15Fixed16Number_to_float(profile->greenColorant.X); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gY = s15Fixed16Number_to_float(profile->greenColorant.Y); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gZ = s15Fixed16Number_to_float(profile->greenColorant.Z); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bX = s15Fixed16Number_to_float(profile->blueColorant.X); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bY = s15Fixed16Number_to_float(profile->blueColorant.Y); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bZ = s15Fixed16Number_to_float(profile->blueColorant.Z); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if any of the XYZ values are negative (see mozilla bug 498245) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CIEXYZ tristimulus values cannot be negative according to the spec. 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) negative = 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (rX < 0) || (rY < 0) || (rZ < 0) || 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (gX < 0) || (gY < 0) || (gZ < 0) || 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (bX < 0) || (bY < 0) || (bZ < 0); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (negative) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sum the values; they should add up to something close to white 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum[0] = rX + gX + bX; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum[1] = rY + gY + bY; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum[2] = rZ + gZ + bZ; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined (_MSC_VER) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(push) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Disable double to float truncation warning 4305 */ 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(disable:4305) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Build our target vector (see mozilla bug 460629) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target[0] = 0.96420; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target[1] = 1.00000; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target[2] = 0.82491; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Our tolerance vector - Recommended by Chris Murphy based on 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // conversion from the LAB space criterion of no more than 3 in any one 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // channel. This is similar to, but slightly more tolerant than Adobe's 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // criterion. 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tolerance[0] = 0.02; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tolerance[1] = 0.02; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tolerance[2] = 0.04; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined (_MSC_VER) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Restore warnings */ 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(pop) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Compare with our tolerance 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < 3; ++i) { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!(((sum[i] - tolerance[i]) <= target[i]) && 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((sum[i] + tolerance[i]) >= target[i]))) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All Good 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_bXYZ 0x6258595a 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_gXYZ 0x6758595a 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_rXYZ 0x7258595a 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_rTRC 0x72545243 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_bTRC 0x62545243 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_gTRC 0x67545243 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_kTRC 0x6b545243 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_A2B0 0x41324230 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_B2A0 0x42324130 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TAG_CHAD 0x63686164 3436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#define TAG_desc 0x64657363 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct tag *find_tag(struct tag_index index, uint32_t tag_id) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct tag *tag = NULL; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < index.count; i++) { 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index.tags[i].signature == tag_id) { 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &index.tags[i]; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tag; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#define DESC_TYPE 0x64657363 // 'desc' 3586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#define MLUC_TYPE 0x6d6c7563 // 'mluc' 3596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)static bool read_tag_descType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id) 3616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles){ 3626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) struct tag *tag = find_tag(index, tag_id); 3636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (tag) { 3646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const uint32_t limit = sizeof profile->description; 3656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t offset = tag->offset; 3666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t type = read_u32(src, offset); 3676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t length = read_u32(src, offset+8); 3686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t i, description; 3696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (length && type == MLUC_TYPE) { 3706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) length = read_u32(src, offset+20); 3716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!length || (length & 1) || (read_u32(src, offset+12) != 12)) 3726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) goto invalid_desc_tag; 3736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) description = offset + read_u32(src, offset+24); 3746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!src->valid) 3756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) goto invalid_desc_tag; 3766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (length && type == DESC_TYPE) { 3776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) description = offset + 12; 3786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else { 3796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) goto invalid_desc_tag; 3806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 3816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (length >= limit) 3826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) length = limit - 1; 3836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (i = 0; i < length; ++i) 3846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) profile->description[i] = read_u8(src, description+i); 3856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) profile->description[length] = 0; 3866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else { 3876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) goto invalid_desc_tag; 3886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 3896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (src->valid) 3916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return true; 3926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)invalid_desc_tag: 3946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) invalid_source(src, "invalid description"); 3956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 3966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 3976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define XYZ_TYPE 0x58595a20 // 'XYZ ' 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CURVE_TYPE 0x63757276 // 'curv' 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PARAMETRIC_CURVE_TYPE 0x70617261 // 'para' 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define LUT16_TYPE 0x6d667432 // 'mft2' 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define LUT8_TYPE 0x6d667431 // 'mft1' 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define LUT_MAB_TYPE 0x6d414220 // 'mAB ' 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define LUT_MBA_TYPE 0x6d424120 // 'mBA ' 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHROMATIC_TYPE 0x73663332 // 'sf32' 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct matrix read_tag_s15Fixed16ArrayType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct tag *tag = find_tag(index, tag_id); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix matrix; 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag) { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t i; 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t offset = tag->offset; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t type = read_u32(src, offset); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check mandatory type signature for s16Fixed16ArrayType 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type != CHROMATIC_TYPE) { 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "unexpected type, expected 'sf32'"); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < 9; i++) { 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matrix.m[i/3][i%3] = s15Fixed16Number_to_float(read_s15Fixed16Number(src, offset+8+i*4)); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matrix.invalid = false; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matrix.invalid = true; 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "missing sf32tag"); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return matrix; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct XYZNumber read_tag_XYZType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct XYZNumber num = {0, 0, 0}; 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct tag *tag = find_tag(index, tag_id); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag) { 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t offset = tag->offset; 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t type = read_u32(src, offset); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type != XYZ_TYPE) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "unexpected type, expected XYZ"); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num.X = read_s15Fixed16Number(src, offset+8); 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num.Y = read_s15Fixed16Number(src, offset+12); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num.Z = read_s15Fixed16Number(src, offset+16); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "missing xyztag"); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return num; 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Read the tag at a given offset rather then the tag_index. 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method is used when reading mAB tags where nested curveType are 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// present that are not part of the tag_index. 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct curveType *read_curveType(struct mem_source *src, uint32_t offset, uint32_t *len) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7}; 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct curveType *curve = NULL; 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t type = read_u32(src, offset); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t count; 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type != CURVE_TYPE && type != PARAMETRIC_CURVE_TYPE) { 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "unexpected type, expected CURV or PARA"); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == CURVE_TYPE) { 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count = read_u32(src, offset+8); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAX_CURVE_ENTRIES 40000 //arbitrary 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count > MAX_CURVE_ENTRIES) { 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "curve size too large"); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*count); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!curve) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->count = count; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->type = type; 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i=0; i<count; i++) { 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->data[i] = read_u16(src, offset + 12 + i*2); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *len = 12 + count * 2; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { //PARAMETRIC_CURVE_TYPE 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count = read_u16(src, offset+8); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count > 4) { 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "parametric function type not supported."); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve = malloc(sizeof(struct curveType)); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!curve) 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->count = count; 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->type = type; 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i=0; i < COUNT_TO_LENGTH[count]; i++) { 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->parameter[i] = s15Fixed16Number_to_float(read_s15Fixed16Number(src, offset + 12 + i*4)); 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *len = 12 + COUNT_TO_LENGTH[count] * 4; 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((count == 1 || count == 2)) { 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* we have a type 1 or type 2 function that has a division by 'a' */ 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float a = curve->parameter[1]; 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (a == 0.f) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "parametricCurve definition causes division by zero."); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return curve; 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct curveType *read_tag_curveType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct tag *tag = find_tag(index, tag_id); 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct curveType *curve = NULL; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tag) { 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t len; 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return read_curveType(src, tag->offset, &len); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "missing curvetag"); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return curve; 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAX_CLUT_SIZE 500000 // arbitrary 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAX_CHANNELS 10 // arbitrary 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void read_nested_curveType(struct mem_source *src, struct curveType *(*curveArray)[MAX_CHANNELS], uint8_t num_channels, uint32_t curve_offset) 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t channel_offset = 0; 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < num_channels; i++) { 538116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch uint32_t tag_len = ~0; 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*curveArray)[i] = read_curveType(src, curve_offset + channel_offset, &tag_len); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!(*curveArray)[i]) { 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "invalid nested curveType curve"); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (tag_len == ~0) { 546116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch invalid_source(src, "invalid nested curveType tag length"); 547116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 548116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 549116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_offset += tag_len; 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 4 byte aligned 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((tag_len % 4) != 0) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_offset += 4 - (tag_len % 4); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void mAB_release(struct lutmABType *lut) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t i; 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < lut->num_in_channels; i++){ 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(lut->a_curves[i]); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < lut->num_out_channels; i++){ 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(lut->b_curves[i]); 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(lut->m_curves[i]); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(lut); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* See section 10.10 for specs */ 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct tag *tag = find_tag(index, tag_id); 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t offset = tag->offset; 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t a_curve_offset, b_curve_offset, m_curve_offset; 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t matrix_offset; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t clut_offset; 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t clut_size = 1; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t clut_precision; 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t type = read_u32(src, offset); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t num_in_channels, num_out_channels; 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct lutmABType *lut; 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type != LUT_MAB_TYPE && type != LUT_MBA_TYPE) { 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_in_channels = read_u8(src, offset + 8); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_out_channels = read_u8(src, offset + 8); 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_in_channels > MAX_CHANNELS || num_out_channels > MAX_CHANNELS) 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We require 3in/out channels since we only support RGB->XYZ (or RGB->LAB) 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // XXX: If we remove this restriction make sure that the number of channels 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is less or equal to the maximum number of mAB curves in qcmsint.h 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // also check for clut_size overflow. 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_in_channels != 3 || num_out_channels != 3) 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // some of this data is optional and is denoted by a zero offset 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we also use this to track their existance 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) a_curve_offset = read_u32(src, offset + 28); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_offset = read_u32(src, offset + 24); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) m_curve_offset = read_u32(src, offset + 20); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matrix_offset = read_u32(src, offset + 16); 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b_curve_offset = read_u32(src, offset + 12); 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convert offsets relative to the tag to relative to the profile 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // preserve zero for optional fields 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (a_curve_offset) 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) a_curve_offset += offset; 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clut_offset) 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_offset += offset; 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (m_curve_offset) 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) m_curve_offset += offset; 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (matrix_offset) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matrix_offset += offset; 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (b_curve_offset) 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b_curve_offset += offset; 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clut_offset) { 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert (num_in_channels == 3); 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // clut_size can not overflow since lg(256^num_in_channels) = 24 bits. 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < num_in_channels; i++) { 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_size *= read_u8(src, clut_offset + i); 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_size = 0; 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 24bits * 3 won't overflow either 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_size = clut_size * num_out_channels; 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clut_size > MAX_CLUT_SIZE) 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut = malloc(sizeof(struct lutmABType) + (clut_size) * sizeof(float)); 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!lut) 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we'll fill in the rest below 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(lut, 0, sizeof(struct lutmABType)); 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table = &lut->clut_table_data[0]; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < num_in_channels; i++) { 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->num_grid_points[i] = read_u8(src, clut_offset + i); 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reverse the processing of transformation elements for mBA type. 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->reversed = (type == LUT_MBA_TYPE); 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->num_in_channels = num_in_channels; 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->num_out_channels = num_out_channels; 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (matrix_offset) { 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // read the matrix if we have it 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e00 = read_s15Fixed16Number(src, matrix_offset+4*0); 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e01 = read_s15Fixed16Number(src, matrix_offset+4*1); 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e02 = read_s15Fixed16Number(src, matrix_offset+4*2); 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e10 = read_s15Fixed16Number(src, matrix_offset+4*3); 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e11 = read_s15Fixed16Number(src, matrix_offset+4*4); 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e12 = read_s15Fixed16Number(src, matrix_offset+4*5); 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e20 = read_s15Fixed16Number(src, matrix_offset+4*6); 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e21 = read_s15Fixed16Number(src, matrix_offset+4*7); 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e22 = read_s15Fixed16Number(src, matrix_offset+4*8); 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e03 = read_s15Fixed16Number(src, matrix_offset+4*9); 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e13 = read_s15Fixed16Number(src, matrix_offset+4*10); 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e23 = read_s15Fixed16Number(src, matrix_offset+4*11); 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (a_curve_offset) { 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_nested_curveType(src, &lut->a_curves, num_in_channels, a_curve_offset); 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (m_curve_offset) { 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_nested_curveType(src, &lut->m_curves, num_out_channels, m_curve_offset); 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (b_curve_offset) { 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_nested_curveType(src, &lut->b_curves, num_out_channels, b_curve_offset); 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "B curves required"); 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clut_offset) { 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_precision = read_u8(src, clut_offset + 16); 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clut_precision == 1) { 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < clut_size; i++) { 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table[i] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + 20 + i*1)); 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (clut_precision == 2) { 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < clut_size; i++) { 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table[i] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + 20 + i*2)); 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "Invalid clut precision"); 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!src->valid) { 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mAB_release(lut); 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return lut; 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct tag *tag = find_tag(index, tag_id); 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t offset = tag->offset; 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t type = read_u32(src, offset); 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t num_input_table_entries; 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t num_output_table_entries; 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t in_chan, grid_points, out_chan; 7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t clut_offset, output_offset; 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t clut_size; 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t entry_size; 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct lutType *lut; 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* I'm not sure why the spec specifies a fixed number of entries for LUT8 tables even though 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * they have room for the num_entries fields */ 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == LUT8_TYPE) { 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_input_table_entries = 256; 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_output_table_entries = 256; 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_size = 1; 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (type == LUT16_TYPE) { 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_input_table_entries = read_u16(src, offset + 48); 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_output_table_entries = read_u16(src, offset + 50); 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_size = 2; 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(0); // the caller checks that this doesn't happen 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "Unexpected lut type"); 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_chan = read_u8(src, offset + 8); 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_chan = read_u8(src, offset + 9); 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) grid_points = read_u8(src, offset + 10); 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_size = pow(grid_points, in_chan); 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clut_size > MAX_CLUT_SIZE) { 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_chan != 3 || out_chan != 3) { 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut = malloc(sizeof(struct lutType) + (num_input_table_entries * in_chan + clut_size*out_chan + num_output_table_entries * out_chan)*sizeof(float)); 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!lut) { 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* compute the offsets of tables */ 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->input_table = &lut->table_data[0]; 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table = &lut->table_data[in_chan*num_input_table_entries]; 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->output_table = &lut->table_data[in_chan*num_input_table_entries + clut_size*out_chan]; 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->num_input_table_entries = num_input_table_entries; 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->num_output_table_entries = num_output_table_entries; 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->num_input_channels = read_u8(src, offset + 8); 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->num_output_channels = read_u8(src, offset + 9); 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->num_clut_grid_points = read_u8(src, offset + 10); 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e00 = read_s15Fixed16Number(src, offset+12); 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e01 = read_s15Fixed16Number(src, offset+16); 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e02 = read_s15Fixed16Number(src, offset+20); 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e10 = read_s15Fixed16Number(src, offset+24); 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e11 = read_s15Fixed16Number(src, offset+28); 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e12 = read_s15Fixed16Number(src, offset+32); 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e20 = read_s15Fixed16Number(src, offset+36); 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e21 = read_s15Fixed16Number(src, offset+40); 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->e22 = read_s15Fixed16Number(src, offset+44); 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < lut->num_input_table_entries * in_chan; i++) { 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == LUT8_TYPE) { 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->input_table[i] = uInt8Number_to_float(read_uInt8Number(src, offset + 52 + i * entry_size)); 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->input_table[i] = uInt16Number_to_float(read_uInt16Number(src, offset + 52 + i * entry_size)); 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_offset = offset + 52 + lut->num_input_table_entries * in_chan * entry_size; 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < clut_size * out_chan; i+=3) { 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == LUT8_TYPE) { 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table[i+0] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + i*entry_size + 0)); 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table[i+1] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + i*entry_size + 1)); 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table[i+2] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + i*entry_size + 2)); 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table[i+0] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + i*entry_size + 0)); 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table[i+1] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + i*entry_size + 2)); 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->clut_table[i+2] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + i*entry_size + 4)); 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_offset = clut_offset + clut_size * out_chan * entry_size; 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < lut->num_output_table_entries * out_chan; i++) { 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == LUT8_TYPE) { 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->output_table[i] = uInt8Number_to_float(read_uInt8Number(src, output_offset + i*entry_size)); 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut->output_table[i] = uInt16Number_to_float(read_uInt16Number(src, output_offset + i*entry_size)); 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return lut; 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void read_rendering_intent(qcms_profile *profile, struct mem_source *src) 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->rendering_intent = read_u32(src, 64); 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (profile->rendering_intent) { 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case QCMS_INTENT_PERCEPTUAL: 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case QCMS_INTENT_SATURATION: 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case QCMS_INTENT_RELATIVE_COLORIMETRIC: 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case QCMS_INTENT_ABSOLUTE_COLORIMETRIC: 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_source(src, "unknown rendering intent"); 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_profile *qcms_profile_create(void) 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return calloc(sizeof(qcms_profile), 1); 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* build sRGB gamma table */ 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* based on cmsBuildParametricGamma() */ 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uint16_t *build_sRGB_gamma_table(int num_entries) 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* taken from lcms: Build_sRGBGamma() */ 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double gamma = 2.4; 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double a = 1./1.055; 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double b = 0.055/1.055; 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double c = 1./12.92; 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double d = 0.04045; 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t *table = malloc(sizeof(uint16_t) * num_entries); 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!table) 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i=0; i<num_entries; i++) { 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double x = (double)i / (num_entries-1); 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double y, output; 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IEC 61966-2.1 (sRGB) 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Y = (aX + b)^Gamma | X >= d 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Y = cX | X < d 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (x >= d) { 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double e = (a*x + b); 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (e > 0) 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) y = pow(e, gamma); 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) y = 0; 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) y = c*x; 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Saturate -- this could likely move to a separate function 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output = y * 65535. + .5; 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (output > 65535.) 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output = 65535; 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (output < 0) 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output = 0; 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table[i] = (uint16_t)floor(output); 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return table; 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct curveType *curve_from_table(uint16_t *table, int num_entries) 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct curveType *curve; 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*num_entries); 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!curve) 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->type = CURVE_TYPE; 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->count = num_entries; 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < num_entries; i++) { 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->data[i] = table[i]; 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return curve; 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static uint16_t float_to_u8Fixed8Number(float a) 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (a > (255.f + 255.f/256)) 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0xffff; 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (a < 0.f) 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return floor(a*256.f + .5f); 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct curveType *curve_from_gamma(float gamma) 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct curveType *curve; 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_entries = 1; 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*num_entries); 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!curve) 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->count = num_entries; 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) curve->data[0] = float_to_u8Fixed8Number(gamma); 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return curve; 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//XXX: it would be nice if we had a way of ensuring 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// everything in a profile was initialized regardless of how it was created 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//XXX: should this also be taking a black_point? 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* similar to CGColorSpaceCreateCalibratedRGB */ 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_profile* qcms_profile_create_rgb_with_gamma( 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_CIE_xyY white_point, 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_CIE_xyYTRIPLE primaries, 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float gamma) 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile* profile = qcms_profile_create(); 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile) 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_PROFILE; 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //XXX: should store the whitepoint 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!set_rgb_colorants(profile, white_point, primaries)) { 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile_release(profile); 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INVALID_PROFILE; 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->redTRC = curve_from_gamma(gamma); 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->blueTRC = curve_from_gamma(gamma); 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->greenTRC = curve_from_gamma(gamma); 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) { 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile_release(profile); 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_PROFILE; 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->class = DISPLAY_DEVICE_PROFILE; 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->rendering_intent = QCMS_INTENT_PERCEPTUAL; 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->color_space = RGB_SIGNATURE; 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile; 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_profile* qcms_profile_create_rgb_with_table( 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_CIE_xyY white_point, 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_CIE_xyYTRIPLE primaries, 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t *table, int num_entries) 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile* profile = qcms_profile_create(); 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile) 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_PROFILE; 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //XXX: should store the whitepoint 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!set_rgb_colorants(profile, white_point, primaries)) { 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile_release(profile); 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INVALID_PROFILE; 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->redTRC = curve_from_table(table, num_entries); 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->blueTRC = curve_from_table(table, num_entries); 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->greenTRC = curve_from_table(table, num_entries); 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) { 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile_release(profile); 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_PROFILE; 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->class = DISPLAY_DEVICE_PROFILE; 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->rendering_intent = QCMS_INTENT_PERCEPTUAL; 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->color_space = RGB_SIGNATURE; 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile; 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* from lcms: cmsWhitePointFromTemp */ 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* tempK must be >= 4000. and <= 25000. 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * similar to argyll: icx_DTEMP2XYZ() */ 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static qcms_CIE_xyY white_point_from_temp(int temp_K) 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_CIE_xyY white_point; 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double x, y; 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double T, T2, T3; 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // double M1, M2; 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No optimization provided. 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T = temp_K; 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T2 = T*T; // Square 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) T3 = T2*T; // Cube 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For correlated color temperature (T) between 4000K and 7000K: 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (T >= 4000. && T <= 7000.) { 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or for correlated color temperature (T) between 7000K and 25000K: 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (T > 7000.0 && T <= 25000.0) { 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(0 && "invalid temp"); 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Obtain y(x) 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) y = -3.000*(x*x) + 2.870*x - 0.275; 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // wave factors (not used, but here for futures extensions) 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fill white_point struct 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) white_point.x = x; 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) white_point.y = y; 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) white_point.Y = 1.0; 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return white_point; 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_profile* qcms_profile_sRGB(void) 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile *profile; 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t *table; 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_CIE_xyYTRIPLE Rec709Primaries = { 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {0.6400, 0.3300, 1.0}, 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {0.3000, 0.6000, 1.0}, 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {0.1500, 0.0600, 1.0} 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_CIE_xyY D65; 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D65 = white_point_from_temp(6504); 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table = build_sRGB_gamma_table(1024); 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!table) 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_PROFILE; 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table, 1024); 10376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (profile) 10386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) strcpy(profile->description, "sRGB IEC61966-2.1"); 10396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(table); 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile; 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* qcms_profile_from_memory does not hold a reference to the memory passed in */ 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_profile* qcms_profile_from_memory(const void *mem, size_t size) 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t length; 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mem_source source; 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mem_source *src = &source; 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct tag_index index; 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile *profile; 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source.buf = mem; 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source.size = size; 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source.valid = true; 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1058a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (size < 4) 1059a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return INVALID_PROFILE; 1060a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length = read_u32(src, 0); 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (length <= size) { 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // shrink the area that we can read if appropriate 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source.size = length; 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INVALID_PROFILE; 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* ensure that the profile size is sane so it's easier to reason about */ 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (source.size <= 64 || source.size >= MAX_PROFILE_SIZE) 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INVALID_PROFILE; 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile = qcms_profile_create(); 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile) 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_PROFILE; 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) check_CMM_type_signature(src); 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) check_profile_version(src); 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_class_signature(profile, src); 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_rendering_intent(profile, src); 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_color_space(profile, src); 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_pcs(profile, src); 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //TODO read rest of profile stuff 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!src->valid) 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto invalid_profile; 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index = read_tag_table(profile, src); 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!src->valid || !index.tags) 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto invalid_tag_table; 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!read_tag_descType(profile, src, index, TAG_desc)) 10936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) goto invalid_tag_table; 10946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (find_tag(index, TAG_CHAD)) { 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, index, TAG_CHAD); 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->chromaticAdaption.invalid = true; //Signal the data is not present 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->class == DISPLAY_DEVICE_PROFILE || profile->class == INPUT_DEVICE_PROFILE || 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->class == OUTPUT_DEVICE_PROFILE || profile->class == COLOR_SPACE_PROFILE) { 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->color_space == RGB_SIGNATURE) { 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (find_tag(index, TAG_A2B0)) { 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (read_u32(src, find_tag(index, TAG_A2B0)->offset) == LUT8_TYPE || 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_u32(src, find_tag(index, TAG_A2B0)->offset) == LUT16_TYPE) { 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->A2B0 = read_tag_lutType(src, index, TAG_A2B0); 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (read_u32(src, find_tag(index, TAG_A2B0)->offset) == LUT_MAB_TYPE) { 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->mAB = read_tag_lutmABType(src, index, TAG_A2B0); 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (find_tag(index, TAG_B2A0)) { 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (read_u32(src, find_tag(index, TAG_B2A0)->offset) == LUT8_TYPE || 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_u32(src, find_tag(index, TAG_B2A0)->offset) == LUT16_TYPE) { 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->B2A0 = read_tag_lutType(src, index, TAG_B2A0); 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (read_u32(src, find_tag(index, TAG_B2A0)->offset) == LUT_MBA_TYPE) { 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->mBA = read_tag_lutmABType(src, index, TAG_B2A0); 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (find_tag(index, TAG_rXYZ) || !qcms_supports_iccv4) { 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->redColorant = read_tag_XYZType(src, index, TAG_rXYZ); 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->greenColorant = read_tag_XYZType(src, index, TAG_gXYZ); 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->blueColorant = read_tag_XYZType(src, index, TAG_bXYZ); 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!src->valid) 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto invalid_tag_table; 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (find_tag(index, TAG_rTRC) || !qcms_supports_iccv4) { 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->redTRC = read_tag_curveType(src, index, TAG_rTRC); 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->greenTRC = read_tag_curveType(src, index, TAG_gTRC); 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->blueTRC = read_tag_curveType(src, index, TAG_bTRC); 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto invalid_tag_table; 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (profile->color_space == GRAY_SIGNATURE) { 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->grayTRC = read_tag_curveType(src, index, TAG_kTRC); 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile->grayTRC) 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto invalid_tag_table; 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(0 && "read_color_space protects against entering here"); 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto invalid_tag_table; 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto invalid_tag_table; 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!src->valid) 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto invalid_tag_table; 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(index.tags); 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile; 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)invalid_tag_table: 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(index.tags); 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)invalid_profile: 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile_release(profile); 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INVALID_PROFILE; 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2) 11666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles){ 11676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return memcmp(p1->description, p2->description, sizeof p1->description) == 0; 11686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 11696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile) 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile->rendering_intent; 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)icColorSpaceSignature 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_profile_get_color_space(qcms_profile *profile) 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile->color_space; 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void lut_release(struct lutType *lut) 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(lut); 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void qcms_profile_release(qcms_profile *profile) 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->output_table_r) 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache_release(profile->output_table_r); 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->output_table_g) 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache_release(profile->output_table_g); 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->output_table_b) 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache_release(profile->output_table_b); 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->A2B0) 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut_release(profile->A2B0); 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->B2A0) 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut_release(profile->B2A0); 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->mAB) 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mAB_release(profile->mAB); 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->mBA) 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mAB_release(profile->mBA); 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(profile->redTRC); 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(profile->blueTRC); 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(profile->greenTRC); 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(profile->grayTRC); 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(profile); 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_profile* qcms_profile_from_file(FILE *file) 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t length, remaining_length; 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile *profile; 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t read_length; 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) be32 length_be; 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *data; 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fread(&length_be, 1, sizeof(length_be), file) != sizeof(length_be)) 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return BAD_VALUE_PROFILE; 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length = be32_to_cpu(length_be); 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (length > MAX_PROFILE_SIZE || length < sizeof(length_be)) 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return BAD_VALUE_PROFILE; 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* allocate room for the entire profile */ 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = malloc(length); 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data) 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_PROFILE; 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* copy in length to the front so that the buffer will contain the entire profile */ 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *((be32*)data) = length_be; 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) remaining_length = length - sizeof(length_be); 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* read the rest profile */ 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_length = fread((unsigned char*)data + sizeof(length_be), 1, remaining_length, file); 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (read_length != remaining_length) { 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(data); 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return INVALID_PROFILE; 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile = qcms_profile_from_memory(data, length); 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(data); 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile; 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_profile* qcms_profile_from_path(const char *path) 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile *profile = NULL; 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *file = fopen(path, "rb"); 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file) { 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile = qcms_profile_from_file(file); 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fclose(file); 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile; 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef _WIN32 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Unicode path version */ 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path) 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile *profile = NULL; 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *file = _wfopen(path, L"rb"); 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file) { 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile = qcms_profile_from_file(file); 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fclose(file); 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile; 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1274