blob: 14b720988f8b554ed8b73382f66da53f83d32405 [file] [log] [blame]
halcanarya096d7a2015-03-27 12:16:53 -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
8#include "SkCodec.h"
msarett99f567e2015-08-05 12:58:26 -07009#include "SkCodecPriv.h"
halcanarya096d7a2015-03-27 12:16:53 -070010#include "SkColorPriv.h"
msarett99f567e2015-08-05 12:58:26 -070011#include "SkColorTable.h"
halcanarya096d7a2015-03-27 12:16:53 -070012#include "SkStream.h"
13#include "SkCodec_wbmp.h"
14
msarett99f567e2015-08-05 12:58:26 -070015// Each bit represents a pixel, so width is actually a number of bits.
16// A row will always be stored in bytes, so we round width up to the
17// nearest multiple of 8 to get the number of bits actually in the row.
18// We then divide by 8 to convert to bytes.
19static inline size_t get_src_row_bytes(int width) {
20 return SkAlign8(width) >> 3;
21}
22
23static inline void setup_color_table(SkColorType colorType,
24 SkPMColor* colorPtr, int* colorCount) {
25 if (kIndex_8_SkColorType == colorType) {
26 colorPtr[0] = SK_ColorBLACK;
27 colorPtr[1] = SK_ColorWHITE;
28 *colorCount = 2;
29 }
30}
31
halcanarya096d7a2015-03-27 12:16:53 -070032// http://en.wikipedia.org/wiki/Variable-length_quantity
33static bool read_mbf(SkStream* stream, uint64_t* value) {
34 uint64_t n = 0;
35 uint8_t data;
36 const uint64_t kLimit = 0xFE00000000000000;
37 SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7));
38 do {
39 if (n & kLimit) { // Will overflow on shift by 7.
40 return false;
41 }
42 if (stream->read(&data, 1) != 1) {
43 return false;
44 }
45 n = (n << 7) | (data & 0x7F);
46 } while (data & 0x80);
47 *value = n;
48 return true;
49}
50
51static bool read_header(SkStream* stream, SkISize* size) {
52 uint64_t width, height;
53 uint16_t data;
54 if (stream->read(&data, 2) != 2 || data != 0) {
55 return false;
56 }
57 if (!read_mbf(stream, &width) || width > 0xFFFF || !width) {
58 return false;
59 }
msarett99f567e2015-08-05 12:58:26 -070060 if (!read_mbf(stream, &height) || height > 0xFFFF || !height) {
halcanarya096d7a2015-03-27 12:16:53 -070061 return false;
62 }
63 if (size) {
64 *size = SkISize::Make(SkToS32(width), SkToS32(height));
65 }
66 return true;
67}
68
scroggob427db12015-08-12 07:24:13 -070069bool SkWbmpCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -070070 return read_header(this->stream(), nullptr);
msarett99f567e2015-08-05 12:58:26 -070071}
72
73SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info,
74 const SkPMColor* ctable, const Options& opts) {
msarett99f567e2015-08-05 12:58:26 -070075 // Create the swizzler based on the desired color type
76 switch (info.colorType()) {
77 case kIndex_8_SkColorType:
78 case kN32_SkColorType:
scroggocc2feb12015-08-14 08:32:46 -070079 case kRGB_565_SkColorType:
msarett99f567e2015-08-05 12:58:26 -070080 case kGray_8_SkColorType:
scroggoe7fc14b2015-10-02 13:14:46 -070081 break;
msarett99f567e2015-08-05 12:58:26 -070082 default:
halcanary96fcdcc2015-08-27 07:41:13 -070083 return nullptr;
halcanarya096d7a2015-03-27 12:16:53 -070084 }
scroggoe7fc14b2015-10-02 13:14:46 -070085 return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info,
86 opts.fZeroInitialized);
halcanarya096d7a2015-03-27 12:16:53 -070087}
88
msarette6dd0042015-10-09 11:07:34 -070089bool SkWbmpCodec::readRow(uint8_t* row) {
90 return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
msarett99f567e2015-08-05 12:58:26 -070091}
92
halcanarya096d7a2015-03-27 12:16:53 -070093SkWbmpCodec::SkWbmpCodec(const SkImageInfo& info, SkStream* stream)
msarett99f567e2015-08-05 12:58:26 -070094 : INHERITED(info, stream)
95 , fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
scroggo46c57472015-09-30 08:57:13 -070096 , fColorTable(nullptr)
97 , fSwizzler(nullptr)
msarett99f567e2015-08-05 12:58:26 -070098{}
halcanarya096d7a2015-03-27 12:16:53 -070099
100SkEncodedFormat SkWbmpCodec::onGetEncodedFormat() const {
101 return kWBMP_SkEncodedFormat;
102}
103
scroggoeb602a52015-07-09 08:16:03 -0700104SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
msarett99f567e2015-08-05 12:58:26 -0700105 void* dst,
scroggoeb602a52015-07-09 08:16:03 -0700106 size_t rowBytes,
scroggob636b452015-07-22 07:16:20 -0700107 const Options& options,
scroggoeb602a52015-07-09 08:16:03 -0700108 SkPMColor ctable[],
msarette6dd0042015-10-09 11:07:34 -0700109 int* ctableCount,
110 int* rowsDecoded) {
scroggob636b452015-07-22 07:16:20 -0700111 if (options.fSubset) {
112 // Subsets are not supported.
113 return kUnimplemented;
114 }
msarett99f567e2015-08-05 12:58:26 -0700115
scroggod1bc5742015-08-12 08:31:44 -0700116 if (!valid_alpha(info.alphaType(), this->getInfo().alphaType())) {
scroggo46c57472015-09-30 08:57:13 -0700117 return kInvalidConversion;
scroggod1bc5742015-08-12 08:31:44 -0700118 }
119
msarett99f567e2015-08-05 12:58:26 -0700120 // Prepare a color table if necessary
121 setup_color_table(info.colorType(), ctable, ctableCount);
122
msarett99f567e2015-08-05 12:58:26 -0700123 // Initialize the swizzler
124 SkAutoTDelete<SkSwizzler> swizzler(this->initializeSwizzler(info, ctable, options));
halcanary96fcdcc2015-08-27 07:41:13 -0700125 if (nullptr == swizzler.get()) {
msarett99f567e2015-08-05 12:58:26 -0700126 return kInvalidConversion;
halcanarya096d7a2015-03-27 12:16:53 -0700127 }
msarett99f567e2015-08-05 12:58:26 -0700128
129 // Perform the decode
halcanarya096d7a2015-03-27 12:16:53 -0700130 SkISize size = info.dimensions();
msarett99f567e2015-08-05 12:58:26 -0700131 SkAutoTMalloc<uint8_t> src(fSrcRowBytes);
132 void* dstRow = dst;
halcanarya096d7a2015-03-27 12:16:53 -0700133 for (int y = 0; y < size.height(); ++y) {
msarette6dd0042015-10-09 11:07:34 -0700134 if (!this->readRow(src.get())) {
135 *rowsDecoded = y;
136 return kIncompleteInput;
halcanarya096d7a2015-03-27 12:16:53 -0700137 }
msarett99f567e2015-08-05 12:58:26 -0700138 swizzler->swizzle(dstRow, src.get());
139 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
halcanarya096d7a2015-03-27 12:16:53 -0700140 }
scroggoeb602a52015-07-09 08:16:03 -0700141 return kSuccess;
halcanarya096d7a2015-03-27 12:16:53 -0700142}
143
144bool SkWbmpCodec::IsWbmp(SkStream* stream) {
halcanary96fcdcc2015-08-27 07:41:13 -0700145 return read_header(stream, nullptr);
halcanarya096d7a2015-03-27 12:16:53 -0700146}
147
148SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) {
scroggo0a7e69c2015-04-03 07:22:22 -0700149 SkAutoTDelete<SkStream> streamDeleter(stream);
halcanarya096d7a2015-03-27 12:16:53 -0700150 SkISize size;
151 if (!read_header(stream, &size)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700152 return nullptr;
halcanarya096d7a2015-03-27 12:16:53 -0700153 }
msarett99f567e2015-08-05 12:58:26 -0700154 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(),
155 kGray_8_SkColorType, kOpaque_SkAlphaType);
halcanary385fe4d2015-08-26 13:07:48 -0700156 return new SkWbmpCodec(info, streamDeleter.detach());
halcanarya096d7a2015-03-27 12:16:53 -0700157}
msarett99f567e2015-08-05 12:58:26 -0700158
msarette6dd0042015-10-09 11:07:34 -0700159int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
scroggo46c57472015-09-30 08:57:13 -0700160 void* dstRow = dst;
161 for (int y = 0; y < count; ++y) {
msarette6dd0042015-10-09 11:07:34 -0700162 if (!this->readRow(fSrcBuffer.get())) {
163 return y;
msarett99f567e2015-08-05 12:58:26 -0700164 }
scroggo46c57472015-09-30 08:57:13 -0700165 fSwizzler->swizzle(dstRow, fSrcBuffer.get());
166 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
msarett99f567e2015-08-05 12:58:26 -0700167 }
msarette6dd0042015-10-09 11:07:34 -0700168 return count;
msarett99f567e2015-08-05 12:58:26 -0700169}
scroggo46c57472015-09-30 08:57:13 -0700170
171SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
172 const Options& options, SkPMColor inputColorTable[], int* inputColorCount) {
scroggo46c57472015-09-30 08:57:13 -0700173 if (options.fSubset) {
174 // Subsets are not supported.
175 return kUnimplemented;
176 }
scroggo46c57472015-09-30 08:57:13 -0700177
178 if (!valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) {
179 return kInvalidConversion;
180 }
181
182 // Fill in the color table
183 setup_color_table(dstInfo.colorType(), inputColorTable, inputColorCount);
184
185 // Copy the color table to a pointer that can be owned by the scanline decoder
186 if (kIndex_8_SkColorType == dstInfo.colorType()) {
187 fColorTable.reset(new SkColorTable(inputColorTable, 2));
188 }
189
190 // Initialize the swizzler
191 fSwizzler.reset(this->initializeSwizzler(dstInfo,
192 get_color_ptr(fColorTable.get()), options));
193 if (nullptr == fSwizzler.get()) {
194 return kInvalidConversion;
195 }
196
197 fSrcBuffer.reset(fSrcRowBytes);
198
199 return kSuccess;
200}