1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "icc_profile_info.h"
16 
17 #include <algorithm>
18 #include <cstdio>
19 #include <cstddef>
20 #include <unistd.h>
21 
22 #include "image_log.h"
23 #include "securec.h"
24 #include "jerror.h"
25 
26 #undef LOG_DOMAIN
27 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
28 
29 #undef LOG_TAG
30 #define LOG_TAG "IccProfile"
31 
32 namespace OHOS {
33 namespace ImagePlugin {
34 namespace {
35     static constexpr uint32_t ICC_MARKER = JPEG_APP0 + 2;
36     static constexpr uint32_t ICC_MARKER_HEADER_SIZE = 14;
37     static constexpr uint8_t ICC_SIGNATURE[] = {
38         'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0',
39     }; // Corresponding hexadecimal: { 0x49, 0x43, 0x43, 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x45, 0x00 }
40 }
41 
ICCProfileInfo()42 ICCProfileInfo::ICCProfileInfo(): isSupportICCProfile_(false)
43 {
44 }
45 
~ICCProfileInfo()46 ICCProfileInfo::~ICCProfileInfo()
47 {
48 }
49 #ifdef IMAGE_COLORSPACE_FLAG
GetICCData(j_decompress_ptr cinfo)50 sk_sp<SkData> ICCProfileInfo::GetICCData(j_decompress_ptr cinfo)
51 {
52     IMAGE_LOGI("%{public}s begin", __func__);
53     unsigned char *icc_profile = NULL;
54     unsigned int icc_data_len = 0;
55     bool isReadIccProfile = false;
56     sk_sp<SkData> data;
57     isReadIccProfile = jpeg_read_icc_profile(cinfo, &icc_profile, &icc_data_len);
58     if (isReadIccProfile) {
59         // copy ICC profile data
60         data = SkData::MakeWithCopy(icc_profile, icc_data_len);
61     } else {
62         IMAGE_LOGE("ERROR: jpeg_read_icc_profile failed!");
63     }
64 
65     // clean up
66     free(icc_profile);
67     return data;
68 }
69 
ParsingICCProfile(j_decompress_ptr cinfo)70 uint32_t ICCProfileInfo::ParsingICCProfile(j_decompress_ptr cinfo)
71 {
72     IMAGE_LOGI("%{public}s begin", __func__);
73 
74     // read icc data to skdata
75     sk_sp<SkData> profile = GetICCData(cinfo);
76     skcms_ICCProfile parsed;
77     uint32_t parseResult = OHOS::Media::ERR_IMAGE_DENCODE_ICC_FAILED;
78     sk_sp<SkColorSpace> skColorSpace = nullptr;
79     if (profile != nullptr && skcms_Parse(profile->data(), profile->size(), &parsed)) {
80         skColorSpace = SkColorSpace::Make(parsed);
81         if (skColorSpace != nullptr) {
82             isSupportICCProfile_ = true;
83         }
84     } else {
85         skColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB);
86         isSupportICCProfile_ = false;
87     }
88     if (skColorSpace != nullptr) {
89         parseResult = OHOS::Media::SUCCESS;
90     } else {
91         IMAGE_LOGE("ERROR: ParsingICCProfile skColorSpace is Null!");
92     }
93     grColorSpace_ = OHOS::ColorManager::ColorSpace(skColorSpace);
94     return parseResult;
95 }
96 
getGrColorSpace()97 OHOS::ColorManager::ColorSpace ICCProfileInfo::getGrColorSpace()
98 {
99     return grColorSpace_;
100 }
101 
IsSupportICCProfile()102 bool ICCProfileInfo::IsSupportICCProfile()
103 {
104     return isSupportICCProfile_;
105 }
106 
PackingICCProfile(j_compress_ptr cinfo,const SkImageInfo & info)107 uint32_t ICCProfileInfo::PackingICCProfile(j_compress_ptr cinfo, const SkImageInfo& info)
108 {
109     IMAGE_LOGI("%{public}s begin", __func__);
110     uint32_t packingResult = OHOS::Media::ERR_IMAGE_ENCODE_ICC_FAILED;
111 
112     // write colorspace to SKData
113     sk_sp<SkData> icc = icc_from_color_space(info);
114 
115     if (icc) {
116         // get a contiguous block of profile memory with the icc signature
117         sk_sp<SkData> jpegMarkerData =
118                 SkData::MakeUninitialized(ICC_MARKER_HEADER_SIZE + icc->size());
119         uint8_t* ptrMaker = static_cast<uint8_t*>(jpegMarkerData->writable_data());
120         (void)memcpy_s(ptrMaker, sizeof(*ptrMaker), ICC_SIGNATURE, sizeof(ICC_SIGNATURE));
121         ptrMaker += sizeof(ICC_SIGNATURE);
122         // first marker
123         *ptrMaker++ = 1;
124          // total markers
125         *ptrMaker++ = 1;
126         (void)memcpy_s(ptrMaker, sizeof(*ptrMaker), icc->data(), icc->size());
127         jpeg_write_marker(cinfo, ICC_MARKER, jpegMarkerData->bytes(), jpegMarkerData->size());
128         packingResult = OHOS::Media::SUCCESS;
129     } else {
130         IMAGE_LOGE("ERROR: PackingICCProfile icc profile is Null!");
131     }
132     return packingResult;
133 }
134 #endif
135 } // namespace ImagePlugin
136 } // namespace OHOS
137