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 "src/codec/SkWbmpCodec.h"
9
10#include "include/codec/SkCodec.h"
11#include "include/core/SkData.h"
12#include "include/core/SkStream.h"
13#include "include/private/SkColorData.h"
14#include "include/private/SkTo.h"
15#include "src/codec/SkCodecPriv.h"
16#include "src/codec/SkColorTable.h"
17
18// Each bit represents a pixel, so width is actually a number of bits.
19// A row will always be stored in bytes, so we round width up to the
20// nearest multiple of 8 to get the number of bits actually in the row.
21// We then divide by 8 to convert to bytes.
22static inline size_t get_src_row_bytes(int width) {
23 return SkAlign8(width) >> 3;
24}
25
26static inline bool valid_color_type(const SkImageInfo& dstInfo) {
27 switch (dstInfo.colorType()) {
28 case kRGBA_8888_SkColorType:
29 case kBGRA_8888_SkColorType:
30 case kGray_8_SkColorType:
31 case kRGB_565_SkColorType:
32 return true;
33 case kRGBA_F16_SkColorType:
34 return dstInfo.colorSpace();
35 default:
36 return false;
37 }
38}
39
40static bool read_byte(SkStream* stream, uint8_t* data)
41{
42 return stream->read(data, 1) == 1;
43}
44
45// http://en.wikipedia.org/wiki/Variable-length_quantity
46static bool read_mbf(SkStream* stream, uint64_t* value) {
47 uint64_t n = 0;
48 uint8_t data;
49 const uint64_t kLimit = 0xFE00000000000000;
50 SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7));
51 do {
52 if (n & kLimit) { // Will overflow on shift by 7.
53 return false;
54 }
55 if (stream->read(&data, 1) != 1) {
56 return false;
57 }
58 n = (n << 7) | (data & 0x7F);
59 } while (data & 0x80);
60 *value = n;
61 return true;
62}
63
64static bool read_header(SkStream* stream, SkISize* size) {
65 {
66 uint8_t data;
67 if (!read_byte(stream, &data) || data != 0) { // unknown type
68 return false;
69 }
70 if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
71 return false;
72 }
73 }
74
75 uint64_t width, height;
76 if (!read_mbf(stream, &width) || width > 0xFFFF || !width) {
77 return false;
78 }
79 if (!read_mbf(stream, &height) || height > 0xFFFF || !height) {
80 return false;
81 }
82 if (size) {
83 *size = SkISize::Make(SkToS32(width), SkToS32(height));
84 }
85 return true;
86}
87
88bool SkWbmpCodec::onRewind() {
89 return read_header(this->stream(), nullptr);
90}
91
92bool SkWbmpCodec::readRow(uint8_t* row) {
93 return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
94}
95
96SkWbmpCodec::SkWbmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream)
97 // Wbmp does not need a colorXform, so choose an arbitrary srcFormat.
98 : INHERITED(std::move(info), skcms_PixelFormat(),
99 std::move(stream))
100 , fSrcRowBytes(get_src_row_bytes(this->dimensions().width()))
101 , fSwizzler(nullptr)
102{}
103
104SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const {
105 return SkEncodedImageFormat::kWBMP;
106}
107
108bool SkWbmpCodec::conversionSupported(const SkImageInfo& dst, bool srcIsOpaque,
109 bool /*needsColorXform*/) {
110 return valid_color_type(dst) && valid_alpha(dst.alphaType(), srcIsOpaque);
111}
112
113SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
114 void* dst,
115 size_t rowBytes,
116 const Options& options,
117 int* rowsDecoded) {
118 if (options.fSubset) {
119 // Subsets are not supported.
120 return kUnimplemented;
121 }
122
123 // Initialize the swizzler
124 std::unique_ptr<SkSwizzler> swizzler = SkSwizzler::Make(this->getEncodedInfo(), nullptr, info,
125 options);
126 SkASSERT(swizzler);
127
128 // Perform the decode
129 SkISize size = info.dimensions();
130 SkAutoTMalloc<uint8_t> src(fSrcRowBytes);
131 void* dstRow = dst;
132 for (int y = 0; y < size.height(); ++y) {
133 if (!this->readRow(src.get())) {
134 *rowsDecoded = y;
135 return kIncompleteInput;
136 }
137 swizzler->swizzle(dstRow, src.get());
138 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
139 }
140 return kSuccess;
141}
142
143bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) {
144 SkMemoryStream stream(buffer, bytesRead, false);
145 return read_header(&stream, nullptr);
146}
147
148std::unique_ptr<SkCodec> SkWbmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
149 Result* result) {
150 SkISize size;
151 if (!read_header(stream.get(), &size)) {
152 // This already succeeded in IsWbmp, so this stream was corrupted in/
153 // after rewind.
154 *result = kCouldNotRewind;
155 return nullptr;
156 }
157 *result = kSuccess;
158 auto info = SkEncodedInfo::Make(size.width(), size.height(), SkEncodedInfo::kGray_Color,
159 SkEncodedInfo::kOpaque_Alpha, 1);
160 return std::unique_ptr<SkCodec>(new SkWbmpCodec(std::move(info), std::move(stream)));
161}
162
163int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
164 void* dstRow = dst;
165 for (int y = 0; y < count; ++y) {
166 if (!this->readRow(fSrcBuffer.get())) {
167 return y;
168 }
169 fSwizzler->swizzle(dstRow, fSrcBuffer.get());
170 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
171 }
172 return count;
173}
174
175bool SkWbmpCodec::onSkipScanlines(int count) {
176 const size_t bytesToSkip = count * fSrcRowBytes;
177 return this->stream()->skip(bytesToSkip) == bytesToSkip;
178}
179
180SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
181 const Options& options) {
182 if (options.fSubset) {
183 // Subsets are not supported.
184 return kUnimplemented;
185 }
186
187 fSwizzler = SkSwizzler::Make(this->getEncodedInfo(), nullptr, dstInfo, options);
188 SkASSERT(fSwizzler);
189
190 fSrcBuffer.reset(fSrcRowBytes);
191
192 return kSuccess;
193}
194