blob: 72e659e71adf10a022d3b55857bcb72479bba787 [file] [log] [blame]
halcanary96287f72015-05-07 11:46:59 -07001/*
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
halcanary96287f72015-05-07 11:46:59 -07008#include "SkJpegInfo.h"
9
Hal Canaryc640d0d2018-06-13 09:59:02 -040010#include "SkTo.h"
11
Hal Canary83e0f1b2018-04-05 16:58:41 -040012#ifndef SK_HAS_JPEG_LIBRARY
13
halcanary96287f72015-05-07 11:46:59 -070014namespace {
15class JpegSegment {
16public:
Hal Canary83e0f1b2018-04-05 16:58:41 -040017 JpegSegment(const void* data, size_t size)
18 : fData(static_cast<const char*>(data))
19 , fSize(size)
halcanary96287f72015-05-07 11:46:59 -070020 , 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;
halcanary96fcdcc2015-08-27 07:41:13 -070028 fBuffer = nullptr;
halcanary96287f72015-05-07 11:46:59 -070029 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
57private:
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
Hal Canary83e0f1b2018-04-05 16:58:41 -040081bool SkGetJpegInfo(const void* data, size_t len,
82 SkISize* size,
83 SkEncodedInfo::Color* colorType,
84 SkEncodedOrigin* orientation) {
halcanary96287f72015-05-07 11:46:59 -070085 static const uint16_t kSOI = 0xFFD8;
86 static const uint16_t kAPP0 = 0xFFE0;
Hal Canary83e0f1b2018-04-05 16:58:41 -040087 JpegSegment segment(data, len);
halcanary96287f72015-05-07 11:46:59 -070088 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 }
Hal Canary83e0f1b2018-04-05 16:58:41 -0400115 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;
halcanary96287f72015-05-07 11:46:59 -0700125 }
126 return true;
127}
Hal Canary83e0f1b2018-04-05 16:58:41 -0400128#endif // SK_HAS_JPEG_LIBRARY