1 /* 2 * Copyright 2015 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 #include "SkJpegInfo.h" 9 10 #include "SkTo.h" 11 12 #ifndef SK_HAS_JPEG_LIBRARY 13 14 namespace { 15 class JpegSegment { 16 public: 17 JpegSegment(const void* data, size_t size) 18 : fData(static_cast<const char*>(data)) 19 , fSize(size) 20 , fOffset(0) 21 , fLength(0) {} 22 bool read() { 23 if (!this->readBigendianUint16(&fMarker)) { 24 return false; 25 } 26 if (JpegSegment::StandAloneMarker(fMarker)) { 27 fLength = 0; 28 fBuffer = nullptr; 29 return true; 30 } 31 if (!this->readBigendianUint16(&fLength) || fLength < 2) { 32 return false; 33 } 34 fLength -= 2; // Length includes itself for some reason. 35 if (fOffset + fLength > fSize) { 36 return false; // Segment too long. 37 } 38 fBuffer = &fData[fOffset]; 39 fOffset += fLength; 40 return true; 41 } 42 43 bool isSOF() { 44 return (fMarker & 0xFFF0) == 0xFFC0 && fMarker != 0xFFC4 && 45 fMarker != 0xFFC8 && fMarker != 0xFFCC; 46 } 47 uint16_t marker() { return fMarker; } 48 uint16_t length() { return fLength; } 49 const char* data() { return fBuffer; } 50 51 static uint16_t GetBigendianUint16(const char* ptr) { 52 // "the most significant byte shall come first" 53 return (static_cast<uint8_t>(ptr[0]) << 8) | 54 static_cast<uint8_t>(ptr[1]); 55 } 56 57 private: 58 const char* const fData; 59 const size_t fSize; 60 size_t fOffset; 61 const char* fBuffer; 62 uint16_t fMarker; 63 uint16_t fLength; 64 65 bool readBigendianUint16(uint16_t* value) { 66 if (fOffset + 2 > fSize) { 67 return false; 68 } 69 *value = JpegSegment::GetBigendianUint16(&fData[fOffset]); 70 fOffset += 2; 71 return true; 72 } 73 static bool StandAloneMarker(uint16_t marker) { 74 // RST[m] markers or SOI, EOI, TEM 75 return (marker & 0xFFF8) == 0xFFD0 || marker == 0xFFD8 || 76 marker == 0xFFD9 || marker == 0xFF01; 77 } 78 }; 79 } // namespace 80 81 bool SkGetJpegInfo(const void* data, size_t len, 82 SkISize* size, 83 SkEncodedInfo::Color* colorType, 84 SkEncodedOrigin* orientation) { 85 static const uint16_t kSOI = 0xFFD8; 86 static const uint16_t kAPP0 = 0xFFE0; 87 JpegSegment segment(data, len); 88 if (!segment.read() || segment.marker() != kSOI) { 89 return false; // not a JPEG 90 } 91 if (!segment.read() || segment.marker() != kAPP0) { 92 return false; // not an APP0 segment 93 } 94 static const char kJfif[] = {'J', 'F', 'I', 'F', '\0'}; 95 SkASSERT(segment.data()); 96 if (SkToSizeT(segment.length()) < sizeof(kJfif) || 97 0 != memcmp(segment.data(), kJfif, sizeof(kJfif))) { 98 return false; // Not JFIF JPEG 99 } 100 do { 101 if (!segment.read()) { 102 return false; // malformed JPEG 103 } 104 } while (!segment.isSOF()); 105 if (segment.length() < 6) { 106 return false; // SOF segment is short 107 } 108 if (8 != segment.data()[0]) { 109 return false; // Only support 8-bit precision 110 } 111 int numberOfComponents = segment.data()[5]; 112 if (numberOfComponents != 1 && numberOfComponents != 3) { 113 return false; // Invalid JFIF 114 } 115 if (size) { 116 *size = {JpegSegment::GetBigendianUint16(&segment.data()[3]), 117 JpegSegment::GetBigendianUint16(&segment.data()[1])}; 118 } 119 if (colorType) { 120 *colorType = numberOfComponents == 3 ? SkEncodedInfo::kYUV_Color 121 : SkEncodedInfo::kGray_Color; 122 } 123 if (orientation) { 124 *orientation = kTopLeft_SkEncodedOrigin; 125 } 126 return true; 127 } 128 #endif // SK_HAS_JPEG_LIBRARY 129