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