| 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 #ifndef SkScanlineDecoder_DEFINED | |
| 9 #define SkScanlineDecoder_DEFINED | |
| 10 | |
| 11 #include "../private/SkTemplates.h" | |
| 12 #include "SkCodec.h" | |
| 13 #include "SkImageInfo.h" | |
| 14 #include "SkTypes.h" | |
| 15 | |
| 16 class SkScanlineDecoder : public SkNoncopyable { | |
| 17 public: | |
| 18 /** | |
| 19 * If this stream represents an encoded image that we know how to decode | |
| 20 * in scanlines, return an SkScanlineDecoder that can decode it. Otherwise | |
| 21 * return NULL. | |
| 22 * | |
| 23 * start() must be called in order to decode any scanlines. | |
| 24 * | |
| 25 * If NULL is returned, the stream is deleted immediately. Otherwise, the | |
| 26 * SkScanlineDecoder takes ownership of it, and will delete it when done | |
| 27 * with it. | |
| 28 */ | |
| 29 static SkScanlineDecoder* NewFromStream(SkStream*); | |
| 30 | |
| 31 /** | |
| 32 * Similar to NewFromStream, but reads from an SkData. | |
| 33 * | |
| 34 * Will take a ref if it returns a scanline decoder, else will not affect | |
| 35 * the data. | |
| 36 */ | |
| 37 static SkScanlineDecoder* NewFromData(SkData*); | |
| 38 | |
| 39 /** | |
| 40 * Clean up after reading/skipping scanlines. | |
| 41 * | |
| 42 * It is possible that not all scanlines will have been read/skipped. In | |
| 43 * fact, in the case of subset decodes, it is likely that there will be | |
| 44 * scanlines at the bottom of the image that have been ignored. | |
| 45 */ | |
| 46 virtual ~SkScanlineDecoder() {} | |
| 47 | |
| 48 /** | |
| 49 * Return a size that approximately supports the desired scale factor. | |
| 50 * The codec may not be able to scale efficiently to the exact scale | |
| 51 * factor requested, so return a size that approximates that scale. | |
| 52 * The returned value is the codec's suggestion for the closest valid | |
| 53 * scale that it can natively support | |
| 54 * FIXME: share this with SkCodec | |
| 55 */ | |
| 56 SkISize getScaledDimensions(float desiredScale) { | |
| 57 return this->onGetScaledDimensions(desiredScale); | |
| 58 } | |
| 59 | |
| 60 /** | |
| 61 * Returns the default info, corresponding to the encoded data. | |
| 62 */ | |
| 63 const SkImageInfo& getInfo() { return fSrcInfo; } | |
| 64 | |
| 65 /** | |
| 66 * Initialize on the first scanline, with the specified options. | |
| 67 * | |
| 68 * This must be called in order to call getScanlnies or skipScanlines. If | |
| 69 * it has been called before, this will require rewinding the stream. | |
| 70 * | |
| 71 * @param dstInfo Info of the destination. If the dimensions do not match | |
| 72 * those of getInfo, this implies a scale. | |
| 73 * @param options Contains decoding options, including if memory is zero | |
| 74 * initialized. | |
| 75 * @param ctable A pointer to a color table. When dstInfo.colorType() is | |
| 76 * kIndex8, this should be non-NULL and have enough storage for 256 | |
| 77 * colors. The color table will be populated after decoding the palett
e. | |
| 78 * @param ctableCount A pointer to the size of the color table. When | |
| 79 * dstInfo.colorType() is kIndex8, this should be non-NULL. It will | |
| 80 * be modified to the true size of the color table (<= 256) after | |
| 81 * decoding the palette. | |
| 82 * @return Enum representing success or reason for failure. | |
| 83 */ | |
| 84 SkCodec::Result start(const SkImageInfo& dstInfo, const SkCodec::Options* op
tions, | |
| 85 SkPMColor ctable[], int* ctableCount); | |
| 86 | |
| 87 /** | |
| 88 * Simplified version of start() that asserts that info is NOT | |
| 89 * kIndex8_SkColorType and uses the default Options. | |
| 90 */ | |
| 91 SkCodec::Result start(const SkImageInfo& dstInfo); | |
| 92 | |
| 93 /** | |
| 94 * Write the next countLines scanlines into dst. | |
| 95 * | |
| 96 * Not valid to call before calling start(). | |
| 97 * | |
| 98 * @param dst Must be non-null, and large enough to hold countLines | |
| 99 * scanlines of size rowBytes. | |
| 100 * @param countLines Number of lines to write. | |
| 101 * @param rowBytes Number of bytes per row. Must be large enough to hold | |
| 102 * a scanline based on the SkImageInfo used to create this object. | |
| 103 */ | |
| 104 SkCodec::Result getScanlines(void* dst, int countLines, size_t rowBytes) { | |
| 105 SkASSERT(!fDstInfo.isEmpty()); | |
| 106 if ((rowBytes < fDstInfo.minRowBytes() && countLines > 1 ) || countLines
<= 0 | |
| 107 || fCurrScanline + countLines > fDstInfo.height()) { | |
| 108 return SkCodec::kInvalidParameters; | |
| 109 } | |
| 110 const SkCodec::Result result = this->onGetScanlines(dst, countLines, row
Bytes); | |
| 111 fCurrScanline += countLines; | |
| 112 return result; | |
| 113 } | |
| 114 | |
| 115 /** | |
| 116 * Skip count scanlines. | |
| 117 * | |
| 118 * Not valid to call before calling start(). | |
| 119 * | |
| 120 * The default version just calls onGetScanlines and discards the dst. | |
| 121 * NOTE: If skipped lines are the only lines with alpha, this default | |
| 122 * will make reallyHasAlpha return true, when it could have returned | |
| 123 * false. | |
| 124 */ | |
| 125 SkCodec::Result skipScanlines(int countLines) { | |
| 126 SkASSERT(!fDstInfo.isEmpty()); | |
| 127 if (fCurrScanline + countLines > fDstInfo.height()) { | |
| 128 // Arguably, we could just skip the scanlines which are remaining, | |
| 129 // and return kSuccess. We choose to return invalid so the client | |
| 130 // can catch their bug. | |
| 131 return SkCodec::kInvalidParameters; | |
| 132 } | |
| 133 const SkCodec::Result result = this->onSkipScanlines(countLines); | |
| 134 fCurrScanline += countLines; | |
| 135 return result; | |
| 136 } | |
| 137 | |
| 138 /** | |
| 139 * Some images may initially report that they have alpha due to the format | |
| 140 * of the encoded data, but then never use any colors which have alpha | |
| 141 * less than 100%. This function can be called *after* decoding to | |
| 142 * determine if such an image truly had alpha. Calling it before decoding | |
| 143 * is undefined. | |
| 144 * FIXME: see skbug.com/3582. | |
| 145 */ | |
| 146 bool reallyHasAlpha() const { | |
| 147 return this->onReallyHasAlpha(); | |
| 148 } | |
| 149 | |
| 150 /** | |
| 151 * Format of the encoded data. | |
| 152 */ | |
| 153 SkEncodedFormat getEncodedFormat() const { return this->onGetEncodedFormat()
; } | |
| 154 | |
| 155 /** | |
| 156 * The order in which rows are output from the scanline decoder is not the | |
| 157 * same for all variations of all image types. This explains the possible | |
| 158 * output row orderings. | |
| 159 */ | |
| 160 enum SkScanlineOrder { | |
| 161 /* | |
| 162 * By far the most common, this indicates that the image can be decoded | |
| 163 * reliably using the scanline decoder, and that rows will be output in | |
| 164 * the logical order. | |
| 165 */ | |
| 166 kTopDown_SkScanlineOrder, | |
| 167 | |
| 168 /* | |
| 169 * This indicates that the scanline decoder reliably outputs rows, but | |
| 170 * they will be returned in reverse order. If the scanline format is | |
| 171 * kBottomUp, the getY() API can be used to determine the actual | |
| 172 * y-coordinate of the next output row, but the client is not forced | |
| 173 * to take advantage of this, given that it's not too tough to keep | |
| 174 * track independently. | |
| 175 * | |
| 176 * For full image decodes, it is safe to get all of the scanlines at | |
| 177 * once, since the decoder will handle inverting the rows as it | |
| 178 * decodes. | |
| 179 * | |
| 180 * For subset decodes and sampling, it is simplest to get and skip | |
| 181 * scanlines one at a time, using the getY() API. It is possible to | |
| 182 * ask for larger chunks at a time, but this should be used with | |
| 183 * caution. As with full image decodes, the decoder will handle | |
| 184 * inverting the requested rows, but rows will still be delivered | |
| 185 * starting from the bottom of the image. | |
| 186 * | |
| 187 * Upside down bmps are an example. | |
| 188 */ | |
| 189 kBottomUp_SkScanlineOrder, | |
| 190 | |
| 191 /* | |
| 192 * This indicates that the scanline decoder reliably outputs rows, but | |
| 193 * they will not be in logical order. If the scanline format is | |
| 194 * kOutOfOrder, the getY() API should be used to determine the actual | |
| 195 * y-coordinate of the next output row. | |
| 196 * | |
| 197 * For this scanline ordering, it is advisable to get and skip | |
| 198 * scanlines one at a time. | |
| 199 * | |
| 200 * Interlaced gifs are an example. | |
| 201 */ | |
| 202 kOutOfOrder_SkScanlineOrder, | |
| 203 | |
| 204 /* | |
| 205 * Indicates that the entire image must be decoded in order to output | |
| 206 * any amount of scanlines. In this case, it is a REALLY BAD IDEA to | |
| 207 * request scanlines 1-by-1 or in small chunks. The client should | |
| 208 * determine which scanlines are needed and ask for all of them in | |
| 209 * a single call to getScanlines(). | |
| 210 * | |
| 211 * Interlaced pngs are an example. | |
| 212 */ | |
| 213 kNone_SkScanlineOrder, | |
| 214 }; | |
| 215 | |
| 216 /** | |
| 217 * An enum representing the order in which scanlines will be returned by | |
| 218 * the scanline decoder. | |
| 219 */ | |
| 220 SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder()
; } | |
| 221 | |
| 222 /** | |
| 223 * Returns the y-coordinate of the next row to be returned by the scanline | |
| 224 * decoder. This will be overridden in the case of | |
| 225 * kOutOfOrder_SkScanlineOrder and should be unnecessary in the case of | |
| 226 * kNone_SkScanlineOrder. | |
| 227 */ | |
| 228 int getY() const { | |
| 229 SkASSERT(kNone_SkScanlineOrder != this->getScanlineOrder()); | |
| 230 return this->onGetY(); | |
| 231 } | |
| 232 | |
| 233 protected: | |
| 234 SkScanlineDecoder(const SkImageInfo& srcInfo) | |
| 235 : fSrcInfo(srcInfo) | |
| 236 , fDstInfo() | |
| 237 , fOptions() | |
| 238 , fCurrScanline(0) {} | |
| 239 | |
| 240 virtual SkISize onGetScaledDimensions(float /* desiredScale */) { | |
| 241 // By default, scaling is not supported. | |
| 242 return this->getInfo().dimensions(); | |
| 243 } | |
| 244 | |
| 245 virtual SkEncodedFormat onGetEncodedFormat() const = 0; | |
| 246 | |
| 247 virtual bool onReallyHasAlpha() const { return false; } | |
| 248 | |
| 249 /** | |
| 250 * Most images types will be kTopDown and will not need to override this fu
nction. | |
| 251 */ | |
| 252 virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanl
ineOrder; } | |
| 253 | |
| 254 /** | |
| 255 * Most images will be kTopDown and will not need to override this function
. | |
| 256 */ | |
| 257 virtual int onGetY() const { return fCurrScanline; } | |
| 258 | |
| 259 const SkImageInfo& dstInfo() const { return fDstInfo; } | |
| 260 | |
| 261 const SkCodec::Options& options() const { return fOptions; } | |
| 262 | |
| 263 private: | |
| 264 const SkImageInfo fSrcInfo; | |
| 265 SkImageInfo fDstInfo; | |
| 266 SkCodec::Options fOptions; | |
| 267 int fCurrScanline; | |
| 268 | |
| 269 virtual SkCodec::Result onStart(const SkImageInfo& dstInfo, | |
| 270 const SkCodec::Options& options, | |
| 271 SkPMColor ctable[], int* ctableCount) = 0; | |
| 272 | |
| 273 // Naive default version just calls onGetScanlines on temp memory. | |
| 274 virtual SkCodec::Result onSkipScanlines(int countLines) { | |
| 275 SkAutoMalloc storage(fDstInfo.minRowBytes()); | |
| 276 // Note that we pass 0 to rowBytes so we continue to use the same memory
. | |
| 277 // Also note that while getScanlines checks that rowBytes is big enough, | |
| 278 // onGetScanlines bypasses that check. | |
| 279 // Calling the virtual method also means we do not double count | |
| 280 // countLines. | |
| 281 return this->onGetScanlines(storage.get(), countLines, 0); | |
| 282 } | |
| 283 | |
| 284 virtual SkCodec::Result onGetScanlines(void* dst, int countLines, | |
| 285 size_t rowBytes) = 0; | |
| 286 | |
| 287 }; | |
| 288 #endif // SkScanlineDecoder_DEFINED | |
| OLD | NEW |