3 // Copyright (C) 1998-2007 Marti Maria
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the Software
10 // is furnished to do so, subject to the following conditions:
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
17 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 // Generic I/O, tag dictionary management, profile struct
31 // Memory-based stream ---------------------------------------------------
34 LPBYTE Block
; // Points to allocated memory
35 size_t Size
; // Size of allocated memory
36 int Pointer
; // Points to current location
37 int FreeBlockOnClose
; // As title
42 LPVOID
MemoryOpen(LPBYTE Block
, size_t Size
, char Mode
)
44 FILEMEM
* fm
= (FILEMEM
*) _cmsMalloc(sizeof(FILEMEM
));
45 if (fm
== NULL
) return NULL
;
47 ZeroMemory(fm
, sizeof(FILEMEM
));
51 fm
->Block
= (LPBYTE
) _cmsMalloc(Size
);
52 if (fm
->Block
== NULL
) {
57 CopyMemory(fm
->Block
, Block
, Size
);
58 fm
->FreeBlockOnClose
= TRUE
;
62 fm
->FreeBlockOnClose
= FALSE
;
73 size_t MemoryRead(LPVOID buffer
, size_t size
, size_t count
, struct _lcms_iccprofile_struct
* Icc
)
75 FILEMEM
* ResData
= (FILEMEM
*) Icc
->stream
;
77 size_t len
= size
* count
;
80 if (ResData
-> Pointer
+ len
> ResData
-> Size
){
82 len
= (ResData
-> Size
- ResData
-> Pointer
);
83 cmsSignalError(LCMS_ERRC_ABORTED
, "Read from memory error. Got %d bytes, block should be of %d bytes", len
* size
, count
* size
);
87 Ptr
= ResData
-> Block
;
88 Ptr
+= ResData
-> Pointer
;
89 CopyMemory(buffer
, Ptr
, len
);
90 ResData
-> Pointer
+= (int) len
;
95 // SEEK_CUR is assumed
98 LCMSBOOL
MemorySeek(struct _lcms_iccprofile_struct
* Icc
, size_t offset
)
100 FILEMEM
* ResData
= (FILEMEM
*) Icc
->stream
;
102 if (offset
> ResData
->Size
) {
103 cmsSignalError(LCMS_ERRC_ABORTED
, "Pointer error; probably corrupted file");
107 ResData
->Pointer
= (DWORD
) offset
;
114 size_t MemoryTell(struct _lcms_iccprofile_struct
* Icc
)
116 FILEMEM
* ResData
= (FILEMEM
*) Icc
->stream
;
118 return ResData
-> Pointer
;
122 // Writes data to memory, also keeps used space for further reference. NO CHECK IS PERFORMED
125 LCMSBOOL
MemoryWrite(struct _lcms_iccprofile_struct
* Icc
, size_t size
, void *Ptr
)
127 FILEMEM
* ResData
= (FILEMEM
*) Icc
->stream
;
129 if (size
== 0) return TRUE
;
132 CopyMemory(ResData
->Block
+ Icc
->UsedSpace
, Ptr
, size
);
134 Icc
->UsedSpace
+= size
;
141 LCMSBOOL
MemoryClose(struct _lcms_iccprofile_struct
* Icc
)
143 FILEMEM
* ResData
= (FILEMEM
*) Icc
->stream
;
145 if (ResData
->FreeBlockOnClose
) {
147 if (ResData
->Block
) _cmsFree(ResData
->Block
);
154 // File-based stream -------------------------------------------------------
157 LPVOID
FileOpen(const char* filename
)
159 return (void*) fopen(filename
, "rb");
163 size_t FileRead(void *buffer
, size_t size
, size_t count
, struct _lcms_iccprofile_struct
* Icc
)
165 size_t nReaded
= fread(buffer
, size
, count
, (FILE*) Icc
->stream
);
166 if (nReaded
!= count
) {
167 cmsSignalError(LCMS_ERRC_ABORTED
, "Read error. Got %d bytes, block should be of %d bytes", nReaded
* size
, count
* size
);
176 LCMSBOOL
FileSeek(struct _lcms_iccprofile_struct
* Icc
, size_t offset
)
178 if (fseek((FILE*) Icc
->stream
, (long) offset
, SEEK_SET
) != 0) {
180 cmsSignalError(LCMS_ERRC_ABORTED
, "Seek error; probably corrupted file");
189 size_t FileTell(struct _lcms_iccprofile_struct
* Icc
)
191 return ftell((FILE*) Icc
->stream
);
194 // Writes data to stream, also keeps used space for further reference
198 LCMSBOOL
FileWrite(struct _lcms_iccprofile_struct
* Icc
, size_t size
, LPVOID Ptr
)
200 if (size
== 0) return TRUE
;
202 Icc
->UsedSpace
+= size
;
204 if (Icc
->stream
== NULL
) {
209 return (fwrite(Ptr
, size
, 1, (FILE*) Icc
->stream
) == 1);
214 LCMSBOOL
FileClose(struct _lcms_iccprofile_struct
* Icc
)
216 return fclose((FILE*) Icc
->stream
);
219 // ----------------------------------------------------------------------------------------------------
222 // Creates an empty structure holding all required parameters
224 cmsHPROFILE
_cmsCreateProfilePlaceholder(void)
227 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) _cmsMalloc(sizeof(LCMSICCPROFILE
));
228 if (Icc
== NULL
) return NULL
;
231 ZeroMemory(Icc
, sizeof(LCMSICCPROFILE
));
233 // Make sure illuminant is correct
234 Icc
->Illuminant
= *cmsD50_XYZ();
240 return (cmsHPROFILE
) Icc
;
244 // Return the number of tags
245 icInt32Number LCMSEXPORT
cmsGetTagCount(cmsHPROFILE hProfile
)
247 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
248 return Icc
->TagCount
;
251 // Return the tag signature of a given tag number
252 icTagSignature LCMSEXPORT
cmsGetTagSignature(cmsHPROFILE hProfile
, icInt32Number n
)
254 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
256 if (n
< 0 || n
> Icc
->TagCount
) return (icTagSignature
) 0; // Mark as not available
258 return Icc
->TagNames
[n
];
262 // Search for a specific tag in tag dictionary
263 // Returns position or -1 if tag not found
265 icInt32Number
_cmsSearchTag(LPLCMSICCPROFILE Profile
, icTagSignature sig
, LCMSBOOL lSignalError
)
269 if (sig
== 0) return -1; // 0 identifies a special tag holding raw memory.
271 for (i
=0; i
< Profile
-> TagCount
; i
++) {
273 if (sig
== Profile
-> TagNames
[i
])
278 cmsSignalError(LCMS_ERRC_ABORTED
, "Tag '%lx' not found", sig
);
286 LCMSBOOL LCMSEXPORT
cmsIsTag(cmsHPROFILE hProfile
, icTagSignature sig
)
288 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
289 return _cmsSearchTag(Icc
, sig
, FALSE
) >= 0;
294 // Search for a particular tag, replace if found or add new one else
296 LPVOID
_cmsInitTag(LPLCMSICCPROFILE Icc
, icTagSignature sig
, size_t size
, const void* Init
)
301 i
= _cmsSearchTag(Icc
, sig
, FALSE
);
305 if (Icc
-> TagPtrs
[i
]) _cmsFree(Icc
-> TagPtrs
[i
]);
312 if (Icc
->TagCount
>= MAX_TABLE_TAG
) {
314 cmsSignalError(LCMS_ERRC_ABORTED
, "Too many tags (%d)", MAX_TABLE_TAG
);
315 Icc
->TagCount
= MAX_TABLE_TAG
-1;
321 Ptr
= _cmsMalloc(size
);
322 if (Ptr
== NULL
) return NULL
;
324 CopyMemory(Ptr
, Init
, size
);
326 Icc
->TagNames
[i
] = sig
;
327 Icc
->TagSizes
[i
] = size
;
328 Icc
->TagPtrs
[i
] = Ptr
;
337 // Creates a profile from file read placeholder
339 LPLCMSICCPROFILE
_cmsCreateProfileFromFilePlaceholder(const char* FileName
)
341 LPLCMSICCPROFILE NewIcc
;
342 LPVOID ICCfile
= FileOpen(FileName
);
344 if (ICCfile
== NULL
) {
346 cmsSignalError(LCMS_ERRC_ABORTED
, "File '%s' not found", FileName
);
350 NewIcc
= (LPLCMSICCPROFILE
) _cmsCreateProfilePlaceholder();
351 if (NewIcc
== NULL
) return NULL
;
353 strncpy(NewIcc
-> PhysicalFile
, FileName
, MAX_PATH
-1);
354 NewIcc
-> PhysicalFile
[MAX_PATH
-1] = 0;
356 NewIcc
->stream
= ICCfile
;
358 NewIcc
->Read
= FileRead
;
359 NewIcc
->Seek
= FileSeek
;
360 NewIcc
->Tell
= FileTell
;
361 NewIcc
->Close
= FileClose
;
362 NewIcc
->Write
= NULL
;
364 NewIcc
->IsWrite
= FALSE
;
373 // Creates a profile from memory read placeholder
375 LPLCMSICCPROFILE
_cmsCreateProfileFromMemPlaceholder(LPVOID MemPtr
, DWORD dwSize
)
378 LPLCMSICCPROFILE NewIcc
;
379 LPVOID ICCfile
= MemoryOpen((LPBYTE
) MemPtr
, (size_t) dwSize
, 'r');
382 if (ICCfile
== NULL
) {
384 cmsSignalError(LCMS_ERRC_ABORTED
, "Couldn't allocate %ld bytes for profile", dwSize
);
389 NewIcc
= (LPLCMSICCPROFILE
) _cmsCreateProfilePlaceholder();
390 if (NewIcc
== NULL
) return NULL
;
392 NewIcc
-> PhysicalFile
[0] = 0;
393 NewIcc
->stream
= ICCfile
;
395 NewIcc
->Read
= MemoryRead
;
396 NewIcc
->Seek
= MemorySeek
;
397 NewIcc
->Tell
= MemoryTell
;
398 NewIcc
->Close
= MemoryClose
;
399 NewIcc
->Write
= NULL
;
401 NewIcc
->IsWrite
= FALSE
;
408 // Turn a placeholder into file writter
410 void _cmsSetSaveToDisk(LPLCMSICCPROFILE Icc
, const char* FileName
)
413 if (FileName
== NULL
) {
419 Icc
->stream
= fopen(FileName
, "wb");
420 if (Icc
->stream
== NULL
)
421 cmsSignalError(LCMS_ERRC_ABORTED
, "Couldn't write to file '%s'", FileName
);
424 Icc
->Write
= FileWrite
; // Save to disk
425 Icc
->Close
= FileClose
;
430 // Turn a placeholder into memory writter
432 void _cmsSetSaveToMemory(LPLCMSICCPROFILE Icc
, LPVOID MemPtr
, size_t dwSize
)
435 if (MemPtr
== NULL
) {
441 Icc
->stream
= (FILEMEM
*) MemoryOpen((LPBYTE
) MemPtr
, dwSize
, 'w');
442 if (Icc
->stream
== NULL
)
443 cmsSignalError(LCMS_ERRC_ABORTED
, "Couldn't write to memory");
446 Icc
->Write
= MemoryWrite
;
447 Icc
->Close
= MemoryClose
;
451 // ----------------------------------------------------------------------- Set/Get several struct members
456 LCMSBOOL LCMSEXPORT
cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest
, cmsHPROFILE hProfile
)
458 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
459 *Dest
= Icc
-> MediaWhitePoint
;
464 LCMSBOOL LCMSEXPORT
cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest
, cmsHPROFILE hProfile
)
466 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
467 *Dest
= Icc
-> MediaBlackPoint
;
471 LCMSBOOL LCMSEXPORT
cmsTakeIluminant(LPcmsCIEXYZ Dest
, cmsHPROFILE hProfile
)
473 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
474 *Dest
= Icc
-> Illuminant
;
478 int LCMSEXPORT
cmsTakeRenderingIntent(cmsHPROFILE hProfile
)
480 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
481 return (int) Icc
-> RenderingIntent
;
484 void LCMSEXPORT
cmsSetRenderingIntent(cmsHPROFILE hProfile
, int RenderingIntent
)
486 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
487 Icc
-> RenderingIntent
= (icRenderingIntent
) RenderingIntent
;
491 DWORD LCMSEXPORT
cmsTakeHeaderFlags(cmsHPROFILE hProfile
)
493 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
494 return (DWORD
) Icc
-> flags
;
497 void LCMSEXPORT
cmsSetHeaderFlags(cmsHPROFILE hProfile
, DWORD Flags
)
499 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
500 Icc
-> flags
= (icUInt32Number
) Flags
;
503 DWORD LCMSEXPORT
cmsTakeHeaderAttributes(cmsHPROFILE hProfile
)
505 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
506 return (DWORD
) Icc
-> attributes
;
509 void LCMSEXPORT
cmsSetHeaderAttributes(cmsHPROFILE hProfile
, DWORD Flags
)
511 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
512 Icc
-> attributes
= (icUInt32Number
) Flags
;
516 const BYTE
* LCMSEXPORT
cmsTakeProfileID(cmsHPROFILE hProfile
)
518 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
519 return Icc
->ProfileID
;
522 void LCMSEXPORT
cmsSetProfileID(cmsHPROFILE hProfile
, LPBYTE ProfileID
)
524 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
525 CopyMemory(Icc
-> ProfileID
, ProfileID
, 16);
529 LCMSBOOL LCMSEXPORT
cmsTakeCreationDateTime(struct tm
*Dest
, cmsHPROFILE hProfile
)
531 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
532 CopyMemory(Dest
, &Icc
->Created
, sizeof(struct tm
));
537 icColorSpaceSignature LCMSEXPORT
cmsGetPCS(cmsHPROFILE hProfile
)
539 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
544 void LCMSEXPORT
cmsSetPCS(cmsHPROFILE hProfile
, icColorSpaceSignature pcs
)
546 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
550 icColorSpaceSignature LCMSEXPORT
cmsGetColorSpace(cmsHPROFILE hProfile
)
552 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
553 return Icc
-> ColorSpace
;
556 void LCMSEXPORT
cmsSetColorSpace(cmsHPROFILE hProfile
, icColorSpaceSignature sig
)
558 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
559 Icc
-> ColorSpace
= sig
;
562 icProfileClassSignature LCMSEXPORT
cmsGetDeviceClass(cmsHPROFILE hProfile
)
564 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
565 return Icc
-> DeviceClass
;
568 DWORD LCMSEXPORT
cmsGetProfileICCversion(cmsHPROFILE hProfile
)
570 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
571 return (DWORD
) Icc
-> Version
;
574 void LCMSEXPORT
cmsSetProfileICCversion(cmsHPROFILE hProfile
, DWORD Version
)
576 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
577 Icc
-> Version
= Version
;
581 void LCMSEXPORT
cmsSetDeviceClass(cmsHPROFILE hProfile
, icProfileClassSignature sig
)
583 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) hProfile
;
584 Icc
-> DeviceClass
= sig
;
588 // --------------------------------------------------------------------------------------------------------------
592 int SizeOfGammaTab(LPGAMMATABLE In
)
594 return sizeof(GAMMATABLE
) + (In
-> nEntries
- 1)*sizeof(WORD
);
598 // Creates a phantom tag holding a memory block
601 LPVOID
DupBlock(LPLCMSICCPROFILE Icc
, LPVOID Block
, size_t size
)
603 if (Block
!= NULL
&& size
> 0)
604 return _cmsInitTag(Icc
, (icTagSignature
) 0, size
, Block
);
610 // This is tricky, since LUT structs does have pointers
612 LCMSBOOL LCMSEXPORT
_cmsAddLUTTag(cmsHPROFILE hProfile
, icTagSignature sig
, const void* lut
)
614 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
621 Stored
= (LPLUT
) _cmsInitTag(Icc
, (icTagSignature
) sig
, sizeof(LUT
), lut
);
623 // dup' the memory blocks
624 for (i
=0; i
< Orig
->InputChan
; i
++)
625 Stored
-> L1
[i
] = (LPWORD
) DupBlock(Icc
, (LPWORD
) Orig
->L1
[i
],
626 sizeof(WORD
) * Orig
->In16params
.nSamples
);
628 for (i
=0; i
< Orig
->OutputChan
; i
++)
629 Stored
-> L2
[i
] = (LPWORD
) DupBlock(Icc
, (LPWORD
) Orig
->L2
[i
],
630 sizeof(WORD
) * Orig
->Out16params
.nSamples
);
632 Stored
-> T
= (LPWORD
) DupBlock(Icc
, (LPWORD
) Orig
->T
, Orig
-> Tsize
);
634 // Zero any additional pointer
635 Stored
->CLut16params
.p8
= NULL
;
640 LCMSBOOL LCMSEXPORT
_cmsAddXYZTag(cmsHPROFILE hProfile
, icTagSignature sig
, const cmsCIEXYZ
* XYZ
)
642 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
644 _cmsInitTag(Icc
, sig
, sizeof(cmsCIEXYZ
), XYZ
);
649 LCMSBOOL LCMSEXPORT
_cmsAddTextTag(cmsHPROFILE hProfile
, icTagSignature sig
, const char* Text
)
651 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
653 _cmsInitTag(Icc
, sig
, strlen(Text
)+1, (LPVOID
) Text
);
657 LCMSBOOL LCMSEXPORT
_cmsAddGammaTag(cmsHPROFILE hProfile
, icTagSignature sig
, LPGAMMATABLE TransferFunction
)
659 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
661 _cmsInitTag(Icc
, sig
, SizeOfGammaTab(TransferFunction
), TransferFunction
);
666 LCMSBOOL LCMSEXPORT
_cmsAddChromaticityTag(cmsHPROFILE hProfile
, icTagSignature sig
, LPcmsCIExyYTRIPLE Chrm
)
668 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
670 _cmsInitTag(Icc
, sig
, sizeof(cmsCIExyYTRIPLE
), Chrm
);
675 LCMSBOOL LCMSEXPORT
_cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile
, icTagSignature sig
, LPcmsSEQ pseq
)
677 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
679 _cmsInitTag(Icc
, sig
, sizeof(int) + pseq
-> n
* sizeof(cmsPSEQDESC
), pseq
);
685 LCMSBOOL LCMSEXPORT
_cmsAddNamedColorTag(cmsHPROFILE hProfile
, icTagSignature sig
, LPcmsNAMEDCOLORLIST nc
)
687 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
689 _cmsInitTag(Icc
, sig
, sizeof(cmsNAMEDCOLORLIST
) + (nc
->nColors
- 1) * sizeof(cmsNAMEDCOLOR
), nc
);
694 LCMSBOOL LCMSEXPORT
_cmsAddDateTimeTag(cmsHPROFILE hProfile
, icTagSignature sig
, struct tm
*DateTime
)
696 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
698 _cmsInitTag(Icc
, sig
, sizeof(struct tm
), DateTime
);
703 LCMSBOOL LCMSEXPORT
_cmsAddColorantTableTag(cmsHPROFILE hProfile
, icTagSignature sig
, LPcmsNAMEDCOLORLIST nc
)
705 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
707 _cmsInitTag(Icc
, sig
, sizeof(cmsNAMEDCOLORLIST
) + (nc
->nColors
- 1) * sizeof(cmsNAMEDCOLOR
), nc
);
712 LCMSBOOL LCMSEXPORT
_cmsAddChromaticAdaptationTag(cmsHPROFILE hProfile
, icTagSignature sig
, const cmsCIEXYZ
* mat
)
714 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
716 _cmsInitTag(Icc
, sig
, 3*sizeof(cmsCIEXYZ
), mat
);