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 11 matching lines...) Expand all Loading... | |
22 extern "C" { | 22 extern "C" { |
23 #include "jerror.h" | 23 #include "jerror.h" |
24 #include "jpeglib.h" | 24 #include "jpeglib.h" |
25 } | 25 } |
26 | 26 |
27 bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) { | 27 bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) { |
28 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; | 28 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; |
29 return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig)); | 29 return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig)); |
30 } | 30 } |
31 | 31 |
32 static uint32_t get_endian_short(const uint8_t* data, bool littleEndian) { | |
33 if (littleEndian) { | |
34 return (data[1] << 8) | (data[0]); | |
35 } | |
36 | |
37 return (data[0] << 8) | (data[1]); | |
38 } | |
39 | |
40 static uint16_t get_endian_int(const uint8_t* data, bool littleEndian) { | |
41 if (littleEndian) { | |
42 return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0]); | |
43 } | |
44 | |
45 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]); | |
46 } | |
47 | |
48 const uint32_t kExifHeaderSize = 14; | |
49 const uint32_t kICCHeaderSize = 14; | |
50 const uint32_t kExifMarker = JPEG_APP0 + 1; | |
51 const uint32_t kICCMarker = JPEG_APP0 + 2; | |
52 | |
53 static bool is_orientation_marker(jpeg_marker_struct* marker, | |
54 SkCodec::SkImageOrientation* orientation) { | |
55 if (kExifMarker != marker->marker || marker->data_length < kExifHeaderSize) { | |
56 return false; | |
57 } | |
58 | |
59 const uint8_t* data = marker->data; | |
60 static const uint8_t kExifSig[] { 'E', 'x', 'i', 'f', '\0' }; | |
61 if (memcmp(data, kExifSig, sizeof(kExifSig))) { | |
62 return false; | |
63 } | |
64 | |
65 // II indicates Intel (little endian) and MM indicates motorola (big endian) . | |
66 if (('I' != data[6] || 'I' != data[7]) && ('M' != data[6] || 'M' != data[7]) ) { | |
67 return false; | |
68 } | |
69 bool littleEndian = ('I' == data[6]); | |
70 | |
71 // Get the offset from the start of the marker. | |
72 // Account for 'E', 'x', 'i', 'f', '\0', '<fill byte>'. | |
73 uint32_t offset = get_endian_int(data + 10, littleEndian); | |
74 offset += sizeof(kExifSig) + 1; | |
75 | |
76 // Require that the marker is at least large enough to contain the number of entries. | |
77 if (marker->data_length < offset + 2) { | |
78 return false; | |
79 } | |
80 uint32_t numEntries = get_endian_short(data + offset, littleEndian); | |
81 | |
82 // Tag (2 bytes), Datatype (2 bytes), Number of elements (4 bytes), Data (4 bytes) | |
83 const uint32_t kEntrySize = 12; | |
84 numEntries = SkTMin(numEntries, (marker->data_length - offset - 2) / kEntryS ize); | |
85 | |
86 // Advance the data to the start of the entries. | |
87 data += offset + 2; | |
88 | |
89 const uint16_t kOrientationTag = 0x112; | |
90 const uint16_t kOrientationType = 3; | |
91 for (uint32_t i = 0; i < numEntries; i++, data += kEntrySize) { | |
92 uint16_t tag = get_endian_short(data, littleEndian); | |
93 uint16_t type = get_endian_short(data + 2, littleEndian); | |
94 uint32_t count = get_endian_int(data + 4, littleEndian); | |
95 if (kOrientationTag == tag && kOrientationType == type && 1 == count) { | |
96 uint16_t val = get_endian_short(data + 8, littleEndian); | |
97 if (0 < val && val <= SkCodec::SkImageOrientation::kLast_SkImageOrie ntation) { | |
98 *orientation = (SkCodec::SkImageOrientation) val; | |
99 return true; | |
100 } | |
101 } | |
102 } | |
103 | |
104 return false; | |
105 } | |
106 | |
107 static SkCodec::SkImageOrientation get_exif_orientation(jpeg_decompress_struct* dinfo) { | |
108 SkCodec::SkImageOrientation orientation; | |
109 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marke r->next) { | |
110 if (is_orientation_marker(marker, &orientation)) { | |
111 return orientation; | |
112 } | |
113 } | |
114 | |
115 return SkCodec::SkImageOrientation::kDefault_SkImageOrientation; | |
116 } | |
117 | |
118 static bool is_icc_marker(jpeg_marker_struct* marker) { | |
119 if (kICCMarker != marker->marker || marker->data_length < kICCHeaderSize) { | |
120 return nullptr; | |
121 } | |
122 | |
123 static const uint8_t kICCSig[] { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I' , 'L', 'E', '\0' }; | |
124 if (memcmp(marker->data, kICCSig, sizeof(kICCSig))) { | |
125 return false; | |
126 } | |
127 | |
128 return true; | |
129 } | |
130 | |
131 /* | |
132 * ICC profiles may be stored using a sequence of multiple markers. We obtain t he ICC profile | |
133 * in two steps: | |
134 * (1) Discover all ICC profile markers and verify that they are numbered pr operly. | |
135 * (2) Copy the data from each marker into a contiguous ICC profile. | |
136 */ | |
137 static sk_sp<SkColorSpace> get_icc_profile(jpeg_decompress_struct* dinfo) { | |
138 // Note that 256 will be enough storage space since each markerIndex is stor ed in 8-bits. | |
139 jpeg_marker_struct* markerSequence[256]; | |
140 memset(markerSequence, 0, sizeof(markerSequence)); | |
141 uint8_t numMarkers = 0; | |
142 size_t totalBytes = 0; | |
143 | |
144 // Discover any ICC markers and verify that they are numbered properly. | |
145 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marke r->next) { | |
146 if (is_icc_marker(marker)) { | |
147 // Verify that numMarkers is valid and consistent. | |
148 if (0 == numMarkers) { | |
149 numMarkers = marker->data[13]; | |
150 if (0 == numMarkers) { | |
151 SkCodecPrintf("ICC Profile Error: numMarkers must be greater than zero.\n"); | |
152 return nullptr; | |
153 } | |
154 } else if (numMarkers != marker->data[13]) { | |
155 SkCodecPrintf("ICC Profile Error: numMarkers must be consistent. \n"); | |
156 return nullptr; | |
157 } | |
158 | |
159 // Verify that the markerIndex is valid and unique. Note that zero is not | |
160 // a valid index. | |
161 uint8_t markerIndex = marker->data[12]; | |
162 if (markerIndex == 0 || markerIndex > numMarkers) { | |
163 SkCodecPrintf("ICC Profile Error: markerIndex is invalid.\n"); | |
164 return nullptr; | |
165 } | |
166 if (markerSequence[markerIndex]) { | |
167 SkCodecPrintf("ICC Profile Error: Duplicate value of markerIndex .\n"); | |
168 return nullptr; | |
169 } | |
170 markerSequence[markerIndex] = marker; | |
171 SkASSERT(marker->data_length >= kICCHeaderSize); | |
172 totalBytes += marker->data_length - kICCHeaderSize; | |
173 } | |
174 } | |
175 | |
176 if (0 == totalBytes) { | |
177 // No non-empty ICC profile markers were found. | |
178 return nullptr; | |
179 } | |
180 | |
181 // Combine the ICC marker data into a contiguous profile. | |
182 SkAutoMalloc iccData(totalBytes); | |
183 void* dst = iccData.get(); | |
184 for (uint32_t i = 1; i <= numMarkers; i++) { | |
185 jpeg_marker_struct* marker = markerSequence[i]; | |
186 if (!marker) { | |
187 SkCodecPrintf("ICC Profile Error: Missing marker %d of %d.\n", i, nu mMarkers); | |
188 return nullptr; | |
189 } | |
190 | |
191 void* src = SkTAddOffset<void>(marker->data, kICCHeaderSize); | |
192 size_t bytes = marker->data_length - kICCHeaderSize; | |
193 memcpy(dst, src, bytes); | |
194 dst = SkTAddOffset<void>(dst, bytes); | |
195 } | |
196 | |
197 return SkColorSpace::NewICC(iccData.get(), totalBytes); | |
198 } | |
199 | |
32 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, | 200 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, |
33 JpegDecoderMgr** decoderMgrOut) { | 201 JpegDecoderMgr** decoderMgrOut) { |
34 | 202 |
35 // Create a JpegDecoderMgr to own all of the decompress information | 203 // Create a JpegDecoderMgr to own all of the decompress information |
36 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream)); | 204 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream)); |
37 | 205 |
38 // libjpeg errors will be caught and reported here | 206 // libjpeg errors will be caught and reported here |
39 if (setjmp(decoderMgr->getJmpBuf())) { | 207 if (setjmp(decoderMgr->getJmpBuf())) { |
40 return decoderMgr->returnFalse("setjmp"); | 208 return decoderMgr->returnFalse("setjmp"); |
41 } | 209 } |
42 | 210 |
43 // Initialize the decompress info and the source manager | 211 // Initialize the decompress info and the source manager |
44 decoderMgr->init(); | 212 decoderMgr->init(); |
45 | 213 |
214 // Instruct jpeg library to save the markers that we care about. Since | |
215 // the orientation and color profile will not change, we can skip this | |
216 // step on rewinds. | |
217 if (codecOut) { | |
218 jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF); | |
219 jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF); | |
220 } | |
221 | |
46 // Read the jpeg header | 222 // Read the jpeg header |
47 if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) { | 223 if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) { |
48 return decoderMgr->returnFalse("read_header"); | 224 return decoderMgr->returnFalse("read_header"); |
49 } | 225 } |
50 | 226 |
51 if (nullptr != codecOut) { | 227 if (codecOut) { |
52 // Recommend the color type to decode to | 228 // Recommend the color type to decode to |
53 const SkColorType colorType = decoderMgr->getColorType(); | 229 const SkColorType colorType = decoderMgr->getColorType(); |
54 | 230 |
55 // Create image info object and the codec | 231 // Create image info object and the codec |
56 const SkImageInfo& imageInfo = SkImageInfo::Make(decoderMgr->dinfo()->im age_width, | 232 const SkImageInfo& imageInfo = SkImageInfo::Make(decoderMgr->dinfo()->im age_width, |
57 decoderMgr->dinfo()->image_height, colorType, kOpaque_SkAlphaTyp e); | 233 decoderMgr->dinfo()->image_height, colorType, kOpaque_SkAlphaTyp e); |
58 *codecOut = new SkJpegCodec(imageInfo, stream, decoderMgr.release()); | 234 |
235 SkImageOrientation orientation = get_exif_orientation(decoderMgr->dinfo( )); | |
msarett
2016/03/18 19:37:02
I had originally planned to combine these calls in
| |
236 sk_sp<SkColorSpace> colorSpace = get_icc_profile(decoderMgr->dinfo()); | |
237 | |
238 *codecOut = new SkJpegCodec(imageInfo, stream, decoderMgr.release(), col orSpace, | |
239 orientation); | |
59 } else { | 240 } else { |
60 SkASSERT(nullptr != decoderMgrOut); | 241 SkASSERT(nullptr != decoderMgrOut); |
61 *decoderMgrOut = decoderMgr.release(); | 242 *decoderMgrOut = decoderMgr.release(); |
62 } | 243 } |
63 return true; | 244 return true; |
64 } | 245 } |
65 | 246 |
66 SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) { | 247 SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) { |
67 SkAutoTDelete<SkStream> streamDeleter(stream); | 248 SkAutoTDelete<SkStream> streamDeleter(stream); |
68 SkCodec* codec = nullptr; | 249 SkCodec* codec = nullptr; |
69 if (ReadHeader(stream, &codec, nullptr)) { | 250 if (ReadHeader(stream, &codec, nullptr)) { |
70 // Codec has taken ownership of the stream, we do not need to delete it | 251 // Codec has taken ownership of the stream, we do not need to delete it |
71 SkASSERT(codec); | 252 SkASSERT(codec); |
72 streamDeleter.release(); | 253 streamDeleter.release(); |
73 return codec; | 254 return codec; |
74 } | 255 } |
75 return nullptr; | 256 return nullptr; |
76 } | 257 } |
77 | 258 |
78 SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, | 259 SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, |
79 JpegDecoderMgr* decoderMgr) | 260 JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, SkImageOrien tation orientation) |
80 : INHERITED(srcInfo, stream) | 261 : INHERITED(srcInfo, stream, colorSpace, orientation) |
81 , fDecoderMgr(decoderMgr) | 262 , fDecoderMgr(decoderMgr) |
82 , fReadyState(decoderMgr->dinfo()->global_state) | 263 , fReadyState(decoderMgr->dinfo()->global_state) |
83 , fSwizzlerSubset(SkIRect::MakeEmpty()) | 264 , fSwizzlerSubset(SkIRect::MakeEmpty()) |
84 {} | 265 {} |
85 | 266 |
86 /* | 267 /* |
87 * Return the row bytes of a particular image type and width | 268 * Return the row bytes of a particular image type and width |
88 */ | 269 */ |
89 static size_t get_row_bytes(const j_decompress_ptr dinfo) { | 270 static size_t get_row_bytes(const j_decompress_ptr dinfo) { |
90 #ifdef TURBO_HAS_565 | 271 #ifdef TURBO_HAS_565 |
(...skipping 638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
729 | 910 |
730 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); | 911 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); |
731 if (linesRead < remainingRows) { | 912 if (linesRead < remainingRows) { |
732 // FIXME: Handle incomplete YUV decodes without signalling an error. | 913 // FIXME: Handle incomplete YUV decodes without signalling an error. |
733 return kInvalidInput; | 914 return kInvalidInput; |
734 } | 915 } |
735 } | 916 } |
736 | 917 |
737 return kSuccess; | 918 return kSuccess; |
738 } | 919 } |
OLD | NEW |