1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkICC_DEFINED
9 #define SkICC_DEFINED
10 
11 #include "SkData.h"
12 #include "SkRefCnt.h"
13 
14 struct SkColorSpaceTransferFn;
15 class SkColorSpace;
16 class SkData;
17 class SkMatrix44;
18 
19 class SK_API SkICC : public SkRefCnt {
20 public:
21 
22     /**
23      *  Parse an ICC profile.
24      *
25      *  Returns nullptr if the data is not a valid ICC profile or if the profile
26      *  input space is not RGB.
27      */
28     static sk_sp<SkICC> Make(const void*, size_t);
29 
30     /**
31      *  If the gamut can be represented as transformation into XYZ D50, returns
32      *  true and sets the proper values in |toXYZD50|.
33      *
34      *  If not, returns false.  This indicates that the ICC data is too complex
35      *  to isolate a simple gamut transformation.
36      */
37     bool toXYZD50(SkMatrix44* toXYZD50) const;
38 
39     /**
40      *  If the transfer function can be represented as coefficients to the standard
41      *  equation, returns true and sets |fn| to the proper values.
42      *
43      *  If not, returns false.  This indicates one of the following:
44      *  (1) The R, G, and B transfer functions are not the same.
45      *  (2) The transfer function is represented as a table that we have not managed
46      *      to match to a standard curve.
47      *  (3) The ICC data is too complex to isolate a single transfer function.
48      */
49     bool isNumericalTransferFn(SkColorSpaceTransferFn* fn) const;
50 
51     /**
52      *  Please do not call this unless isNumericalTransferFn() has been called and it
53      *  fails.  SkColorSpaceTransferFn is the preferred representation.
54      *
55      *  If it is not possible to represent the R, G, and B transfer functions numerically
56      *  and it is still necessary to get the transfer function, this will return the
57      *  transfer functions as three tables (R, G, and B).
58      *
59      *  If possible, this will return tables of the same length as they were specified in
60      *  the ICC profile.  This means that the lengths of the three tables are not
61      *  guaranteed to be the same.  If the ICC representation was not a table, the length
62      *  will be chosen arbitrarily.
63      *
64      *  The lengths of the tables are all guaranteed to be at least 2.  Entries in the
65      *  tables are guaranteed to be in [0, 1].
66      *
67      *  This API may be deleted in favor of a numerical approximation of the raw data.
68      *
69      *  This function may fail, indicating that the ICC profile does not have transfer
70      *  functions.
71      */
72     struct Channel {
73         // Byte offset of the start of the table in |fStorage|
74         size_t fOffset;
75         int    fCount;
76     };
77     struct Tables {
78         Channel fRed;
79         Channel fGreen;
80         Channel fBlue;
81 
redTables82         const float* red() {
83             return (const float*) (fStorage->bytes() + fRed.fOffset);
84         }
greenTables85         const float* green() {
86             return (const float*) (fStorage->bytes() + fGreen.fOffset);
87         }
blueTables88         const float* blue() {
89             return (const float*) (fStorage->bytes() + fBlue.fOffset);
90         }
91 
92         sk_sp<SkData> fStorage;
93     };
94     bool rawTransferFnData(Tables* tables) const;
95 
96     /**
97      *  Write an ICC profile with transfer function |fn| and gamut |toXYZD50|.
98      */
99     static sk_sp<SkData> WriteToICC(const SkColorSpaceTransferFn& fn, const SkMatrix44& toXYZD50);
100 
101 private:
102     SkICC(sk_sp<SkColorSpace> colorSpace);
103 
104     sk_sp<SkColorSpace> fColorSpace;
105 
106     friend class ICCTest;
107 };
108 
109 #endif
110