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