OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkCodec.h" | 8 #include "SkCodec.h" |
9 #include "SkMSAN.h" | 9 #include "SkMSAN.h" |
10 #include "SkJpegCodec.h" | 10 #include "SkJpegCodec.h" |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 static const uint8_t kICCSig[] { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I'
, 'L', 'E', '\0' }; | 113 static const uint8_t kICCSig[] { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I'
, 'L', 'E', '\0' }; |
114 return !memcmp(marker->data, kICCSig, sizeof(kICCSig)); | 114 return !memcmp(marker->data, kICCSig, sizeof(kICCSig)); |
115 } | 115 } |
116 | 116 |
117 /* | 117 /* |
118 * ICC profiles may be stored using a sequence of multiple markers. We obtain t
he ICC profile | 118 * ICC profiles may be stored using a sequence of multiple markers. We obtain t
he ICC profile |
119 * in two steps: | 119 * in two steps: |
120 * (1) Discover all ICC profile markers and verify that they are numbered pr
operly. | 120 * (1) Discover all ICC profile markers and verify that they are numbered pr
operly. |
121 * (2) Copy the data from each marker into a contiguous ICC profile. | 121 * (2) Copy the data from each marker into a contiguous ICC profile. |
122 */ | 122 */ |
123 static sk_sp<SkData> get_icc_profile(jpeg_decompress_struct* dinfo) { | 123 static sk_sp<SkColorSpace> get_icc_profile(jpeg_decompress_struct* dinfo) { |
124 // Note that 256 will be enough storage space since each markerIndex is stor
ed in 8-bits. | 124 // Note that 256 will be enough storage space since each markerIndex is stor
ed in 8-bits. |
125 jpeg_marker_struct* markerSequence[256]; | 125 jpeg_marker_struct* markerSequence[256]; |
126 memset(markerSequence, 0, sizeof(markerSequence)); | 126 memset(markerSequence, 0, sizeof(markerSequence)); |
127 uint8_t numMarkers = 0; | 127 uint8_t numMarkers = 0; |
128 size_t totalBytes = 0; | 128 size_t totalBytes = 0; |
129 | 129 |
130 // Discover any ICC markers and verify that they are numbered properly. | 130 // Discover any ICC markers and verify that they are numbered properly. |
131 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marke
r->next) { | 131 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marke
r->next) { |
132 if (is_icc_marker(marker)) { | 132 if (is_icc_marker(marker)) { |
133 // Verify that numMarkers is valid and consistent. | 133 // Verify that numMarkers is valid and consistent. |
(...skipping 24 matching lines...) Expand all Loading... |
158 totalBytes += marker->data_length - kICCHeaderSize; | 158 totalBytes += marker->data_length - kICCHeaderSize; |
159 } | 159 } |
160 } | 160 } |
161 | 161 |
162 if (0 == totalBytes) { | 162 if (0 == totalBytes) { |
163 // No non-empty ICC profile markers were found. | 163 // No non-empty ICC profile markers were found. |
164 return nullptr; | 164 return nullptr; |
165 } | 165 } |
166 | 166 |
167 // Combine the ICC marker data into a contiguous profile. | 167 // Combine the ICC marker data into a contiguous profile. |
168 sk_sp<SkData> iccData = SkData::MakeUninitialized(totalBytes); | 168 SkAutoMalloc iccData(totalBytes); |
169 void* dst = iccData->writable_data(); | 169 void* dst = iccData.get(); |
170 for (uint32_t i = 1; i <= numMarkers; i++) { | 170 for (uint32_t i = 1; i <= numMarkers; i++) { |
171 jpeg_marker_struct* marker = markerSequence[i]; | 171 jpeg_marker_struct* marker = markerSequence[i]; |
172 if (!marker) { | 172 if (!marker) { |
173 SkCodecPrintf("ICC Profile Error: Missing marker %d of %d.\n", i, nu
mMarkers); | 173 SkCodecPrintf("ICC Profile Error: Missing marker %d of %d.\n", i, nu
mMarkers); |
174 return nullptr; | 174 return nullptr; |
175 } | 175 } |
176 | 176 |
177 void* src = SkTAddOffset<void>(marker->data, kICCHeaderSize); | 177 void* src = SkTAddOffset<void>(marker->data, kICCHeaderSize); |
178 size_t bytes = marker->data_length - kICCHeaderSize; | 178 size_t bytes = marker->data_length - kICCHeaderSize; |
179 memcpy(dst, src, bytes); | 179 memcpy(dst, src, bytes); |
180 dst = SkTAddOffset<void>(dst, bytes); | 180 dst = SkTAddOffset<void>(dst, bytes); |
181 } | 181 } |
182 | 182 |
183 return iccData; | 183 return SkColorSpace::NewICC(iccData.get(), totalBytes); |
184 } | 184 } |
185 | 185 |
186 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, | 186 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, |
187 JpegDecoderMgr** decoderMgrOut) { | 187 JpegDecoderMgr** decoderMgrOut) { |
188 | 188 |
189 // Create a JpegDecoderMgr to own all of the decompress information | 189 // Create a JpegDecoderMgr to own all of the decompress information |
190 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream)); | 190 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream)); |
191 | 191 |
192 // libjpeg errors will be caught and reported here | 192 // libjpeg errors will be caught and reported here |
193 if (setjmp(decoderMgr->getJmpBuf())) { | 193 if (setjmp(decoderMgr->getJmpBuf())) { |
(...skipping 20 matching lines...) Expand all Loading... |
214 // Get the encoded color type | 214 // Get the encoded color type |
215 SkEncodedInfo::Color color; | 215 SkEncodedInfo::Color color; |
216 if (!decoderMgr->getEncodedColor(&color)) { | 216 if (!decoderMgr->getEncodedColor(&color)) { |
217 return false; | 217 return false; |
218 } | 218 } |
219 | 219 |
220 // Create image info object and the codec | 220 // Create image info object and the codec |
221 SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_A
lpha, 8); | 221 SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_A
lpha, 8); |
222 | 222 |
223 Origin orientation = get_exif_orientation(decoderMgr->dinfo()); | 223 Origin orientation = get_exif_orientation(decoderMgr->dinfo()); |
224 sk_sp<SkData> iccData = get_icc_profile(decoderMgr->dinfo()); | 224 sk_sp<SkColorSpace> colorSpace = get_icc_profile(decoderMgr->dinfo()); |
225 sk_sp<SkColorSpace> colorSpace = nullptr; | |
226 if (iccData) { | |
227 colorSpace = SkColorSpace::NewICC(iccData->data(), iccData->size()); | |
228 if (!colorSpace) { | |
229 SkCodecPrintf("Could not create SkColorSpace from ICC data.\n"); | |
230 } | |
231 } | |
232 if (!colorSpace) { | 225 if (!colorSpace) { |
233 // Treat unmarked jpegs as sRGB. | 226 // Treat unmarked jpegs as sRGB. |
234 colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); | 227 colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); |
235 } | 228 } |
236 | 229 |
237 const int width = decoderMgr->dinfo()->image_width; | 230 const int width = decoderMgr->dinfo()->image_width; |
238 const int height = decoderMgr->dinfo()->image_height; | 231 const int height = decoderMgr->dinfo()->image_height; |
239 *codecOut = new SkJpegCodec(width, height, info, stream, decoderMgr.rele
ase(), | 232 *codecOut = new SkJpegCodec(width, height, info, stream, decoderMgr.rele
ase(), |
240 std::move(colorSpace), orientation, std::move(iccData)); | 233 std::move(colorSpace), orientation); |
241 } else { | 234 } else { |
242 SkASSERT(nullptr != decoderMgrOut); | 235 SkASSERT(nullptr != decoderMgrOut); |
243 *decoderMgrOut = decoderMgr.release(); | 236 *decoderMgrOut = decoderMgr.release(); |
244 } | 237 } |
245 return true; | 238 return true; |
246 } | 239 } |
247 | 240 |
248 SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) { | 241 SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) { |
249 SkAutoTDelete<SkStream> streamDeleter(stream); | 242 SkAutoTDelete<SkStream> streamDeleter(stream); |
250 SkCodec* codec = nullptr; | 243 SkCodec* codec = nullptr; |
251 if (ReadHeader(stream, &codec, nullptr)) { | 244 if (ReadHeader(stream, &codec, nullptr)) { |
252 // Codec has taken ownership of the stream, we do not need to delete it | 245 // Codec has taken ownership of the stream, we do not need to delete it |
253 SkASSERT(codec); | 246 SkASSERT(codec); |
254 streamDeleter.release(); | 247 streamDeleter.release(); |
255 return codec; | 248 return codec; |
256 } | 249 } |
257 return nullptr; | 250 return nullptr; |
258 } | 251 } |
259 | 252 |
260 SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStr
eam* stream, | 253 SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStr
eam* stream, |
261 JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origi
n, | 254 JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origi
n) |
262 sk_sp<SkData> iccData) | |
263 : INHERITED(width, height, info, stream, std::move(colorSpace), origin) | 255 : INHERITED(width, height, info, stream, std::move(colorSpace), origin) |
264 , fDecoderMgr(decoderMgr) | 256 , fDecoderMgr(decoderMgr) |
265 , fReadyState(decoderMgr->dinfo()->global_state) | 257 , fReadyState(decoderMgr->dinfo()->global_state) |
266 , fSwizzlerSubset(SkIRect::MakeEmpty()) | 258 , fSwizzlerSubset(SkIRect::MakeEmpty()) |
267 , fICCData(std::move(iccData)) | |
268 {} | 259 {} |
269 | 260 |
270 /* | 261 /* |
271 * Return the row bytes of a particular image type and width | 262 * Return the row bytes of a particular image type and width |
272 */ | 263 */ |
273 static size_t get_row_bytes(const j_decompress_ptr dinfo) { | 264 static size_t get_row_bytes(const j_decompress_ptr dinfo) { |
274 #ifdef TURBO_HAS_565 | 265 #ifdef TURBO_HAS_565 |
275 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : | 266 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : |
276 dinfo->out_color_components; | 267 dinfo->out_color_components; |
277 #else | 268 #else |
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
907 | 898 |
908 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); | 899 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); |
909 if (linesRead < remainingRows) { | 900 if (linesRead < remainingRows) { |
910 // FIXME: Handle incomplete YUV decodes without signalling an error. | 901 // FIXME: Handle incomplete YUV decodes without signalling an error. |
911 return kInvalidInput; | 902 return kInvalidInput; |
912 } | 903 } |
913 } | 904 } |
914 | 905 |
915 return kSuccess; | 906 return kSuccess; |
916 } | 907 } |
OLD | NEW |