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 SkCodec_DEFINED
9#define SkCodec_DEFINED
10
11#include "include/codec/SkEncodedOrigin.h"
12#include "include/core/SkImageInfo.h"
13#include "include/core/SkPixmap.h"
14#include "include/core/SkRect.h"
15#include "include/core/SkRefCnt.h"
16#include "include/core/SkSize.h"
17#include "include/core/SkTypes.h"
18#include "include/core/SkYUVAPixmaps.h"
19#include "include/private/SkEncodedInfo.h"
20#include "include/private/base/SkNoncopyable.h"
21#include "modules/skcms/skcms.h"
22
23#include <cstddef>
24#include <functional>
25#include <memory>
26#include <string>
27#include <tuple>
28#include <vector>
29
30class SkData;
31class SkFrameHolder;
32class SkImage;
33class SkPngChunkReader;
34class SkSampler;
35class SkStream;
36struct SkGainmapInfo;
37enum SkAlphaType : int;
38enum class SkEncodedImageFormat;
39
40namespace SkCodecAnimation {
41enum class Blend;
42enum class DisposalMethod;
43}
44
45namespace DM {
46class CodecSrc;
47} // namespace DM
48
49/**
50 * Abstraction layer directly on top of an image codec.
51 */
52class SK_API SkCodec : SkNoncopyable {
53public:
54 /**
55 * Minimum number of bytes that must be buffered in SkStream input.
56 *
57 * An SkStream passed to NewFromStream must be able to use this many
58 * bytes to determine the image type. Then the same SkStream must be
59 * passed to the correct decoder to read from the beginning.
60 *
61 * This can be accomplished by implementing peek() to support peeking
62 * this many bytes, or by implementing rewind() to be able to rewind()
63 * after reading this many bytes.
64 */
65 static constexpr size_t MinBufferedBytesNeeded() { return 32; }
66
67 /**
68 * Error codes for various SkCodec methods.
69 */
70 enum Result {
71 /**
72 * General return value for success.
73 */
74 kSuccess,
75 /**
76 * The input is incomplete. A partial image was generated.
77 */
78 kIncompleteInput,
79 /**
80 * Like kIncompleteInput, except the input had an error.
81 *
82 * If returned from an incremental decode, decoding cannot continue,
83 * even with more data.
84 */
85 kErrorInInput,
86 /**
87 * The generator cannot convert to match the request, ignoring
88 * dimensions.
89 */
90 kInvalidConversion,
91 /**
92 * The generator cannot scale to requested size.
93 */
94 kInvalidScale,
95 /**
96 * Parameters (besides info) are invalid. e.g. NULL pixels, rowBytes
97 * too small, etc.
98 */
99 kInvalidParameters,
100 /**
101 * The input did not contain a valid image.
102 */
103 kInvalidInput,
104 /**
105 * Fulfilling this request requires rewinding the input, which is not
106 * supported for this input.
107 */
108 kCouldNotRewind,
109 /**
110 * An internal error, such as OOM.
111 */
112 kInternalError,
113 /**
114 * This method is not implemented by this codec.
115 * FIXME: Perhaps this should be kUnsupported?
116 */
117 kUnimplemented,
118 };
119
120 /**
121 * Readable string representing the error code.
122 */
123 static const char* ResultToString(Result);
124
125 /**
126 * For container formats that contain both still images and image sequences,
127 * instruct the decoder how the output should be selected. (Refer to comments
128 * for each value for more details.)
129 */
130 enum class SelectionPolicy {
131 /**
132 * If the container format contains both still images and image sequences,
133 * SkCodec should choose one of the still images. This is the default.
134 */
135 kPreferStillImage,
136 /**
137 * If the container format contains both still images and image sequences,
138 * SkCodec should choose one of the image sequences for animation.
139 */
140 kPreferAnimation,
141 };
142
143 /**
144 * If this stream represents an encoded image that we know how to decode,
145 * return an SkCodec that can decode it. Otherwise return NULL.
146 *
147 * As stated above, this call must be able to peek or read
148 * MinBufferedBytesNeeded to determine the correct format, and then start
149 * reading from the beginning. First it will attempt to peek, and it
150 * assumes that if less than MinBufferedBytesNeeded bytes (but more than
151 * zero) are returned, this is because the stream is shorter than this,
152 * so falling back to reading would not provide more data. If peek()
153 * returns zero bytes, this call will instead attempt to read(). This
154 * will require that the stream can be rewind()ed.
155 *
156 * If Result is not NULL, it will be set to either kSuccess if an SkCodec
157 * is returned or a reason for the failure if NULL is returned.
158 *
159 * If SkPngChunkReader is not NULL, take a ref and pass it to libpng if
160 * the image is a png.
161 *
162 * If the SkPngChunkReader is not NULL then:
163 * If the image is not a PNG, the SkPngChunkReader will be ignored.
164 * If the image is a PNG, the SkPngChunkReader will be reffed.
165 * If the PNG has unknown chunks, the SkPngChunkReader will be used
166 * to handle these chunks. SkPngChunkReader will be called to read
167 * any unknown chunk at any point during the creation of the codec
168 * or the decode. Note that if SkPngChunkReader fails to read a
169 * chunk, this could result in a failure to create the codec or a
170 * failure to decode the image.
171 * If the PNG does not contain unknown chunks, the SkPngChunkReader
172 * will not be used or modified.
173 *
174 * If NULL is returned, the stream is deleted immediately. Otherwise, the
175 * SkCodec takes ownership of it, and will delete it when done with it.
176 */
177 static std::unique_ptr<SkCodec> MakeFromStream(
178 std::unique_ptr<SkStream>, Result* = nullptr,
179 SkPngChunkReader* = nullptr,
180 SelectionPolicy selectionPolicy = SelectionPolicy::kPreferStillImage);
181
182 /**
183 * If this data represents an encoded image that we know how to decode,
184 * return an SkCodec that can decode it. Otherwise return NULL.
185 *
186 * If the SkPngChunkReader is not NULL then:
187 * If the image is not a PNG, the SkPngChunkReader will be ignored.
188 * If the image is a PNG, the SkPngChunkReader will be reffed.
189 * If the PNG has unknown chunks, the SkPngChunkReader will be used
190 * to handle these chunks. SkPngChunkReader will be called to read
191 * any unknown chunk at any point during the creation of the codec
192 * or the decode. Note that if SkPngChunkReader fails to read a
193 * chunk, this could result in a failure to create the codec or a
194 * failure to decode the image.
195 * If the PNG does not contain unknown chunks, the SkPngChunkReader
196 * will not be used or modified.
197 */
198 static std::unique_ptr<SkCodec> MakeFromData(sk_sp<SkData>, SkPngChunkReader* = nullptr);
199
200 virtual ~SkCodec();
201
202 /**
203 * Return a reasonable SkImageInfo to decode into.
204 *
205 * If the image has an ICC profile that does not map to an SkColorSpace,
206 * the returned SkImageInfo will use SRGB.
207 */
208 SkImageInfo getInfo() const { return fEncodedInfo.makeImageInfo(); }
209
210 SkISize dimensions() const { return {.fWidth: fEncodedInfo.width(), .fHeight: fEncodedInfo.height()}; }
211 SkIRect bounds() const {
212 return SkIRect::MakeWH(w: fEncodedInfo.width(), h: fEncodedInfo.height());
213 }
214
215 /**
216 * Return the ICC profile of the encoded data.
217 */
218 const skcms_ICCProfile* getICCProfile() const {
219 return this->getEncodedInfo().profile();
220 }
221
222 /**
223 * Returns the image orientation stored in the EXIF data.
224 * If there is no EXIF data, or if we cannot read the EXIF data, returns kTopLeft.
225 */
226 SkEncodedOrigin getOrigin() const { return fOrigin; }
227
228 /**
229 * Return a size that approximately supports the desired scale factor.
230 * The codec may not be able to scale efficiently to the exact scale
231 * factor requested, so return a size that approximates that scale.
232 * The returned value is the codec's suggestion for the closest valid
233 * scale that it can natively support
234 */
235 SkISize getScaledDimensions(float desiredScale) const {
236 // Negative and zero scales are errors.
237 SkASSERT(desiredScale > 0.0f);
238 if (desiredScale <= 0.0f) {
239 return SkISize::Make(w: 0, h: 0);
240 }
241
242 // Upscaling is not supported. Return the original size if the client
243 // requests an upscale.
244 if (desiredScale >= 1.0f) {
245 return this->dimensions();
246 }
247 return this->onGetScaledDimensions(desiredScale);
248 }
249
250 /**
251 * Return (via desiredSubset) a subset which can decoded from this codec,
252 * or false if this codec cannot decode subsets or anything similar to
253 * desiredSubset.
254 *
255 * @param desiredSubset In/out parameter. As input, a desired subset of
256 * the original bounds (as specified by getInfo). If true is returned,
257 * desiredSubset may have been modified to a subset which is
258 * supported. Although a particular change may have been made to
259 * desiredSubset to create something supported, it is possible other
260 * changes could result in a valid subset.
261 * If false is returned, desiredSubset's value is undefined.
262 * @return true if this codec supports decoding desiredSubset (as
263 * returned, potentially modified)
264 */
265 bool getValidSubset(SkIRect* desiredSubset) const {
266 return this->onGetValidSubset(desiredSubset);
267 }
268
269 /**
270 * Format of the encoded data.
271 */
272 SkEncodedImageFormat getEncodedFormat() const { return this->onGetEncodedFormat(); }
273
274 /**
275 * Whether or not the memory passed to getPixels is zero initialized.
276 */
277 enum ZeroInitialized {
278 /**
279 * The memory passed to getPixels is zero initialized. The SkCodec
280 * may take advantage of this by skipping writing zeroes.
281 */
282 kYes_ZeroInitialized,
283 /**
284 * The memory passed to getPixels has not been initialized to zero,
285 * so the SkCodec must write all zeroes to memory.
286 *
287 * This is the default. It will be used if no Options struct is used.
288 */
289 kNo_ZeroInitialized,
290 };
291
292 /**
293 * Additional options to pass to getPixels.
294 */
295 struct Options {
296 Options()
297 : fZeroInitialized(kNo_ZeroInitialized)
298 , fSubset(nullptr)
299 , fFrameIndex(0)
300 , fPriorFrame(kNoFrame)
301 {}
302
303 ZeroInitialized fZeroInitialized;
304 /**
305 * If not NULL, represents a subset of the original image to decode.
306 * Must be within the bounds returned by getInfo().
307 * If the EncodedFormat is SkEncodedImageFormat::kWEBP (the only one which
308 * currently supports subsets), the top and left values must be even.
309 *
310 * In getPixels and incremental decode, we will attempt to decode the
311 * exact rectangular subset specified by fSubset.
312 *
313 * In a scanline decode, it does not make sense to specify a subset
314 * top or subset height, since the client already controls which rows
315 * to get and which rows to skip. During scanline decodes, we will
316 * require that the subset top be zero and the subset height be equal
317 * to the full height. We will, however, use the values of
318 * subset left and subset width to decode partial scanlines on calls
319 * to getScanlines().
320 */
321 const SkIRect* fSubset;
322
323 /**
324 * The frame to decode.
325 *
326 * Only meaningful for multi-frame images.
327 */
328 int fFrameIndex;
329
330 /**
331 * If not kNoFrame, the dst already contains the prior frame at this index.
332 *
333 * Only meaningful for multi-frame images.
334 *
335 * If fFrameIndex needs to be blended with a prior frame (as reported by
336 * getFrameInfo[fFrameIndex].fRequiredFrame), the client can set this to
337 * any non-kRestorePrevious frame in [fRequiredFrame, fFrameIndex) to
338 * indicate that that frame is already in the dst. Options.fZeroInitialized
339 * is ignored in this case.
340 *
341 * If set to kNoFrame, the codec will decode any necessary required frame(s) first.
342 */
343 int fPriorFrame;
344 };
345
346 /**
347 * Decode into the given pixels, a block of memory of size at
348 * least (info.fHeight - 1) * rowBytes + (info.fWidth *
349 * bytesPerPixel)
350 *
351 * Repeated calls to this function should give the same results,
352 * allowing the PixelRef to be immutable.
353 *
354 * @param info A description of the format (config, size)
355 * expected by the caller. This can simply be identical
356 * to the info returned by getInfo().
357 *
358 * This contract also allows the caller to specify
359 * different output-configs, which the implementation can
360 * decide to support or not.
361 *
362 * A size that does not match getInfo() implies a request
363 * to scale. If the generator cannot perform this scale,
364 * it will return kInvalidScale.
365 *
366 * If the info contains a non-null SkColorSpace, the codec
367 * will perform the appropriate color space transformation.
368 *
369 * If the caller passes in the SkColorSpace that maps to the
370 * ICC profile reported by getICCProfile(), the color space
371 * transformation is a no-op.
372 *
373 * If the caller passes a null SkColorSpace, no color space
374 * transformation will be done.
375 *
376 * If a scanline decode is in progress, scanline mode will end, requiring the client to call
377 * startScanlineDecode() in order to return to decoding scanlines.
378 *
379 * @return Result kSuccess, or another value explaining the type of failure.
380 */
381 Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*);
382
383 /**
384 * Simplified version of getPixels() that uses the default Options.
385 */
386 Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
387 return this->getPixels(info, pixels, rowBytes, nullptr);
388 }
389
390 Result getPixels(const SkPixmap& pm, const Options* opts = nullptr) {
391 return this->getPixels(info: pm.info(), pixels: pm.writable_addr(), rowBytes: pm.rowBytes(), opts);
392 }
393
394 /**
395 * Return an image containing the pixels.
396 */
397 std::tuple<sk_sp<SkImage>, SkCodec::Result> getImage(const SkImageInfo& info,
398 const Options* opts = nullptr);
399 std::tuple<sk_sp<SkImage>, SkCodec::Result> getImage();
400
401 /**
402 * If decoding to YUV is supported, this returns true. Otherwise, this
403 * returns false and the caller will ignore output parameter yuvaPixmapInfo.
404 *
405 * @param supportedDataTypes Indicates the data type/planar config combinations that are
406 * supported by the caller. If the generator supports decoding to
407 * YUV(A), but not as a type in supportedDataTypes, this method
408 * returns false.
409 * @param yuvaPixmapInfo Output parameter that specifies the planar configuration, subsampling,
410 * orientation, chroma siting, plane color types, and row bytes.
411 */
412 bool queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes,
413 SkYUVAPixmapInfo* yuvaPixmapInfo) const;
414
415 /**
416 * Returns kSuccess, or another value explaining the type of failure.
417 * This always attempts to perform a full decode. To get the planar
418 * configuration without decoding use queryYUVAInfo().
419 *
420 * @param yuvaPixmaps Contains preallocated pixmaps configured according to a successful call
421 * to queryYUVAInfo().
422 */
423 Result getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps);
424
425 /**
426 * Prepare for an incremental decode with the specified options.
427 *
428 * This may require a rewind.
429 *
430 * If kIncompleteInput is returned, may be called again after more data has
431 * been provided to the source SkStream.
432 *
433 * @param dstInfo Info of the destination. If the dimensions do not match
434 * those of getInfo, this implies a scale.
435 * @param dst Memory to write to. Needs to be large enough to hold the subset,
436 * if present, or the full image as described in dstInfo.
437 * @param options Contains decoding options, including if memory is zero
438 * initialized and whether to decode a subset.
439 * @return Enum representing success or reason for failure.
440 */
441 Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
442 const Options*);
443
444 Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes) {
445 return this->startIncrementalDecode(dstInfo, dst, rowBytes, nullptr);
446 }
447
448 /**
449 * Start/continue the incremental decode.
450 *
451 * Not valid to call before a call to startIncrementalDecode() returns
452 * kSuccess.
453 *
454 * If kIncompleteInput is returned, may be called again after more data has
455 * been provided to the source SkStream.
456 *
457 * Unlike getPixels and getScanlines, this does not do any filling. This is
458 * left up to the caller, since they may be skipping lines or continuing the
459 * decode later. In the latter case, they may choose to initialize all lines
460 * first, or only initialize the remaining lines after the first call.
461 *
462 * @param rowsDecoded Optional output variable returning the total number of
463 * lines initialized. Only meaningful if this method returns kIncompleteInput.
464 * Otherwise the implementation may not set it.
465 * Note that some implementations may have initialized this many rows, but
466 * not necessarily finished those rows (e.g. interlaced PNG). This may be
467 * useful for determining what rows the client needs to initialize.
468 * @return kSuccess if all lines requested in startIncrementalDecode have
469 * been completely decoded. kIncompleteInput otherwise.
470 */
471 Result incrementalDecode(int* rowsDecoded = nullptr) {
472 if (!fStartedIncrementalDecode) {
473 return kInvalidParameters;
474 }
475 return this->onIncrementalDecode(rowsDecoded);
476 }
477
478 /**
479 * The remaining functions revolve around decoding scanlines.
480 */
481
482 /**
483 * Prepare for a scanline decode with the specified options.
484 *
485 * After this call, this class will be ready to decode the first scanline.
486 *
487 * This must be called in order to call getScanlines or skipScanlines.
488 *
489 * This may require rewinding the stream.
490 *
491 * Not all SkCodecs support this.
492 *
493 * @param dstInfo Info of the destination. If the dimensions do not match
494 * those of getInfo, this implies a scale.
495 * @param options Contains decoding options, including if memory is zero
496 * initialized.
497 * @return Enum representing success or reason for failure.
498 */
499 Result startScanlineDecode(const SkImageInfo& dstInfo, const Options* options);
500
501 /**
502 * Simplified version of startScanlineDecode() that uses the default Options.
503 */
504 Result startScanlineDecode(const SkImageInfo& dstInfo) {
505 return this->startScanlineDecode(dstInfo, options: nullptr);
506 }
507
508 /**
509 * Write the next countLines scanlines into dst.
510 *
511 * Not valid to call before calling startScanlineDecode().
512 *
513 * @param dst Must be non-null, and large enough to hold countLines
514 * scanlines of size rowBytes.
515 * @param countLines Number of lines to write.
516 * @param rowBytes Number of bytes per row. Must be large enough to hold
517 * a scanline based on the SkImageInfo used to create this object.
518 * @return the number of lines successfully decoded. If this value is
519 * less than countLines, this will fill the remaining lines with a
520 * default value.
521 */
522 int getScanlines(void* dst, int countLines, size_t rowBytes);
523
524 /**
525 * Skip count scanlines.
526 *
527 * Not valid to call before calling startScanlineDecode().
528 *
529 * The default version just calls onGetScanlines and discards the dst.
530 * NOTE: If skipped lines are the only lines with alpha, this default
531 * will make reallyHasAlpha return true, when it could have returned
532 * false.
533 *
534 * @return true if the scanlines were successfully skipped
535 * false on failure, possible reasons for failure include:
536 * An incomplete input image stream.
537 * Calling this function before calling startScanlineDecode().
538 * If countLines is less than zero or so large that it moves
539 * the current scanline past the end of the image.
540 */
541 bool skipScanlines(int countLines);
542
543 /**
544 * The order in which rows are output from the scanline decoder is not the
545 * same for all variations of all image types. This explains the possible
546 * output row orderings.
547 */
548 enum SkScanlineOrder {
549 /*
550 * By far the most common, this indicates that the image can be decoded
551 * reliably using the scanline decoder, and that rows will be output in
552 * the logical order.
553 */
554 kTopDown_SkScanlineOrder,
555
556 /*
557 * This indicates that the scanline decoder reliably outputs rows, but
558 * they will be returned in reverse order. If the scanline format is
559 * kBottomUp, the nextScanline() API can be used to determine the actual
560 * y-coordinate of the next output row, but the client is not forced
561 * to take advantage of this, given that it's not too tough to keep
562 * track independently.
563 *
564 * For full image decodes, it is safe to get all of the scanlines at
565 * once, since the decoder will handle inverting the rows as it
566 * decodes.
567 *
568 * For subset decodes and sampling, it is simplest to get and skip
569 * scanlines one at a time, using the nextScanline() API. It is
570 * possible to ask for larger chunks at a time, but this should be used
571 * with caution. As with full image decodes, the decoder will handle
572 * inverting the requested rows, but rows will still be delivered
573 * starting from the bottom of the image.
574 *
575 * Upside down bmps are an example.
576 */
577 kBottomUp_SkScanlineOrder,
578 };
579
580 /**
581 * An enum representing the order in which scanlines will be returned by
582 * the scanline decoder.
583 *
584 * This is undefined before startScanlineDecode() is called.
585 */
586 SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder(); }
587
588 /**
589 * Returns the y-coordinate of the next row to be returned by the scanline
590 * decoder.
591 *
592 * This will equal fCurrScanline, except in the case of strangely
593 * encoded image types (bottom-up bmps).
594 *
595 * Results are undefined when not in scanline decoding mode.
596 */
597 int nextScanline() const { return this->outputScanline(inputScanline: fCurrScanline); }
598
599 /**
600 * Returns the output y-coordinate of the row that corresponds to an input
601 * y-coordinate. The input y-coordinate represents where the scanline
602 * is located in the encoded data.
603 *
604 * This will equal inputScanline, except in the case of strangely
605 * encoded image types (bottom-up bmps, interlaced gifs).
606 */
607 int outputScanline(int inputScanline) const;
608
609 /**
610 * Return the number of frames in the image.
611 *
612 * May require reading through the stream.
613 */
614 int getFrameCount() {
615 return this->onGetFrameCount();
616 }
617
618 // Sentinel value used when a frame index implies "no frame":
619 // - FrameInfo::fRequiredFrame set to this value means the frame
620 // is independent.
621 // - Options::fPriorFrame set to this value means no (relevant) prior frame
622 // is residing in dst's memory.
623 static constexpr int kNoFrame = -1;
624
625 // This transitional definition was added in August 2018, and will eventually be removed.
626#ifdef SK_LEGACY_SKCODEC_NONE_ENUM
627 static constexpr int kNone = kNoFrame;
628#endif
629
630 /**
631 * Information about individual frames in a multi-framed image.
632 */
633 struct FrameInfo {
634 /**
635 * The frame that this frame needs to be blended with, or
636 * kNoFrame if this frame is independent (so it can be
637 * drawn over an uninitialized buffer).
638 *
639 * Note that this is the *earliest* frame that can be used
640 * for blending. Any frame from [fRequiredFrame, i) can be
641 * used, unless its fDisposalMethod is kRestorePrevious.
642 */
643 int fRequiredFrame;
644
645 /**
646 * Number of milliseconds to show this frame.
647 */
648 int fDuration;
649
650 /**
651 * Whether the end marker for this frame is contained in the stream.
652 *
653 * Note: this does not guarantee that an attempt to decode will be complete.
654 * There could be an error in the stream.
655 */
656 bool fFullyReceived;
657
658 /**
659 * This is conservative; it will still return non-opaque if e.g. a
660 * color index-based frame has a color with alpha but does not use it.
661 */
662 SkAlphaType fAlphaType;
663
664 /**
665 * Whether the updated rectangle contains alpha.
666 *
667 * This is conservative; it will still be set to true if e.g. a color
668 * index-based frame has a color with alpha but does not use it. In
669 * addition, it may be set to true, even if the final frame, after
670 * blending, is opaque.
671 */
672 bool fHasAlphaWithinBounds;
673
674 /**
675 * How this frame should be modified before decoding the next one.
676 */
677 SkCodecAnimation::DisposalMethod fDisposalMethod;
678
679 /**
680 * How this frame should blend with the prior frame.
681 */
682 SkCodecAnimation::Blend fBlend;
683
684 /**
685 * The rectangle updated by this frame.
686 *
687 * It may be empty, if the frame does not change the image. It will
688 * always be contained by SkCodec::dimensions().
689 */
690 SkIRect fFrameRect;
691 };
692
693 /**
694 * Return info about a single frame.
695 *
696 * Does not read through the stream, so it should be called after
697 * getFrameCount() to parse any frames that have not already been parsed.
698 *
699 * Only supported by animated (multi-frame) codecs. Note that this is a
700 * property of the codec (the SkCodec subclass), not the image.
701 *
702 * To elaborate, some codecs support animation (e.g. GIF). Others do not
703 * (e.g. BMP). Animated codecs can still represent single frame images.
704 * Calling getFrameInfo(0, etc) will return true for a single frame GIF
705 * even if the overall image is not animated (in that the pixels on screen
706 * do not change over time). When incrementally decoding a GIF image, we
707 * might only know that there's a single frame *so far*.
708 *
709 * For non-animated SkCodec subclasses, it's sufficient but not necessary
710 * for this method to always return false.
711 */
712 bool getFrameInfo(int index, FrameInfo* info) const {
713 if (index < 0) {
714 return false;
715 }
716 return this->onGetFrameInfo(index, info);
717 }
718
719 /**
720 * Return info about all the frames in the image.
721 *
722 * May require reading through the stream to determine info about the
723 * frames (including the count).
724 *
725 * As such, future decoding calls may require a rewind.
726 *
727 * This may return an empty vector for non-animated codecs. See the
728 * getFrameInfo(int, FrameInfo*) comment.
729 */
730 std::vector<FrameInfo> getFrameInfo();
731
732 static constexpr int kRepetitionCountInfinite = -1;
733
734 /**
735 * Return the number of times to repeat, if this image is animated. This number does not
736 * include the first play through of each frame. For example, a repetition count of 4 means
737 * that each frame is played 5 times and then the animation stops.
738 *
739 * It can return kRepetitionCountInfinite, a negative number, meaning that the animation
740 * should loop forever.
741 *
742 * May require reading the stream to find the repetition count.
743 *
744 * As such, future decoding calls may require a rewind.
745 *
746 * For still (non-animated) image codecs, this will return 0.
747 */
748 int getRepetitionCount() {
749 return this->onGetRepetitionCount();
750 }
751
752 // Register a decoder at runtime by passing two function pointers:
753 // - peek() to return true if the span of bytes appears to be your encoded format;
754 // - make() to attempt to create an SkCodec from the given stream.
755 // Not thread safe.
756 static void Register(
757 bool (*peek)(const void*, size_t),
758 std::unique_ptr<SkCodec> (*make)(std::unique_ptr<SkStream>, SkCodec::Result*));
759
760protected:
761 const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; }
762
763 using XformFormat = skcms_PixelFormat;
764
765 SkCodec(SkEncodedInfo&&,
766 XformFormat srcFormat,
767 std::unique_ptr<SkStream>,
768 SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
769
770 void setSrcXformFormat(XformFormat pixelFormat);
771
772 XformFormat getSrcXformFormat() const {
773 return fSrcXformFormat;
774 }
775
776 virtual bool onGetGainmapInfo(SkGainmapInfo*, std::unique_ptr<SkStream>*) { return false; }
777
778 virtual SkISize onGetScaledDimensions(float /*desiredScale*/) const {
779 // By default, scaling is not supported.
780 return this->dimensions();
781 }
782
783 // FIXME: What to do about subsets??
784 /**
785 * Subclasses should override if they support dimensions other than the
786 * srcInfo's.
787 */
788 virtual bool onDimensionsSupported(const SkISize&) {
789 return false;
790 }
791
792 virtual SkEncodedImageFormat onGetEncodedFormat() const = 0;
793
794 /**
795 * @param rowsDecoded When the encoded image stream is incomplete, this function
796 * will return kIncompleteInput and rowsDecoded will be set to
797 * the number of scanlines that were successfully decoded.
798 * This will allow getPixels() to fill the uninitialized memory.
799 */
800 virtual Result onGetPixels(const SkImageInfo& info,
801 void* pixels, size_t rowBytes, const Options&,
802 int* rowsDecoded) = 0;
803
804 virtual bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&,
805 SkYUVAPixmapInfo*) const { return false; }
806
807 virtual Result onGetYUVAPlanes(const SkYUVAPixmaps&) { return kUnimplemented; }
808
809 virtual bool onGetValidSubset(SkIRect* /*desiredSubset*/) const {
810 // By default, subsets are not supported.
811 return false;
812 }
813
814 /**
815 * If the stream was previously read, attempt to rewind.
816 *
817 * If the stream needed to be rewound, call onRewind.
818 * @returns true if the codec is at the right position and can be used.
819 * false if there was a failure to rewind.
820 *
821 * This is called by getPixels(), getYUV8Planes(), startIncrementalDecode() and
822 * startScanlineDecode(). Subclasses may call if they need to rewind at another time.
823 */
824 [[nodiscard]] bool rewindIfNeeded();
825
826 /**
827 * Called by rewindIfNeeded, if the stream needed to be rewound.
828 *
829 * Subclasses should do any set up needed after a rewind.
830 */
831 virtual bool onRewind() {
832 return true;
833 }
834
835 /**
836 * Get method for the input stream
837 */
838 SkStream* stream() {
839 return fStream.get();
840 }
841
842 /**
843 * The remaining functions revolve around decoding scanlines.
844 */
845
846 /**
847 * Most images types will be kTopDown and will not need to override this function.
848 */
849 virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; }
850
851 const SkImageInfo& dstInfo() const { return fDstInfo; }
852
853 const Options& options() const { return fOptions; }
854
855 /**
856 * Returns the number of scanlines that have been decoded so far.
857 * This is unaffected by the SkScanlineOrder.
858 *
859 * Returns -1 if we have not started a scanline decode.
860 */
861 int currScanline() const { return fCurrScanline; }
862
863 virtual int onOutputScanline(int inputScanline) const;
864
865 /**
866 * Return whether we can convert to dst.
867 *
868 * Will be called for the appropriate frame, prior to initializing the colorXform.
869 */
870 virtual bool conversionSupported(const SkImageInfo& dst, bool srcIsOpaque,
871 bool needsColorXform);
872
873 // Some classes never need a colorXform e.g.
874 // - ICO uses its embedded codec's colorXform
875 // - WBMP is just Black/White
876 virtual bool usesColorXform() const { return true; }
877 void applyColorXform(void* dst, const void* src, int count) const;
878
879 bool colorXform() const { return fXformTime != kNo_XformTime; }
880 bool xformOnDecode() const { return fXformTime == kDecodeRow_XformTime; }
881
882 virtual int onGetFrameCount() {
883 return 1;
884 }
885
886 virtual bool onGetFrameInfo(int, FrameInfo*) const {
887 return false;
888 }
889
890 virtual int onGetRepetitionCount() {
891 return 0;
892 }
893
894private:
895 const SkEncodedInfo fEncodedInfo;
896 XformFormat fSrcXformFormat;
897 std::unique_ptr<SkStream> fStream;
898 bool fNeedsRewind = false;
899 const SkEncodedOrigin fOrigin;
900
901 SkImageInfo fDstInfo;
902 Options fOptions;
903
904 enum XformTime {
905 kNo_XformTime,
906 kPalette_XformTime,
907 kDecodeRow_XformTime,
908 };
909 XformTime fXformTime;
910 XformFormat fDstXformFormat; // Based on fDstInfo.
911 skcms_ICCProfile fDstProfile;
912 skcms_AlphaFormat fDstXformAlphaFormat;
913
914 // Only meaningful during scanline decodes.
915 int fCurrScanline = -1;
916
917 bool fStartedIncrementalDecode = false;
918
919 // Allows SkAndroidCodec to call handleFrameIndex (potentially decoding a prior frame and
920 // clearing to transparent) without SkCodec itself calling it, too.
921 bool fUsingCallbackForHandleFrameIndex = false;
922
923 bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha, bool srcIsOpaque);
924
925 /**
926 * Return whether these dimensions are supported as a scale.
927 *
928 * The codec may choose to cache the information about scale and subset.
929 * Either way, the same information will be passed to onGetPixels/onStart
930 * on success.
931 *
932 * This must return true for a size returned from getScaledDimensions.
933 */
934 bool dimensionsSupported(const SkISize& dim) {
935 return dim == this->dimensions() || this->onDimensionsSupported(dim);
936 }
937
938 /**
939 * For multi-framed images, return the object with information about the frames.
940 */
941 virtual const SkFrameHolder* getFrameHolder() const {
942 return nullptr;
943 }
944
945 // Callback for decoding a prior frame. The `Options::fFrameIndex` is ignored,
946 // being replaced by frameIndex. This allows opts to actually be a subclass of
947 // SkCodec::Options which SkCodec itself does not know how to copy or modify,
948 // but just passes through to the caller (where it can be reinterpret_cast'd).
949 using GetPixelsCallback = std::function<Result(const SkImageInfo&, void* pixels,
950 size_t rowBytes, const Options& opts,
951 int frameIndex)>;
952
953 /**
954 * Check for a valid Options.fFrameIndex, and decode prior frames if necessary.
955 *
956 * If GetPixelsCallback is not null, it will be used to decode a prior frame instead
957 * of using this SkCodec directly. It may also be used recursively, if that in turn
958 * depends on a prior frame. This is used by SkAndroidCodec.
959 */
960 Result handleFrameIndex(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&,
961 GetPixelsCallback = nullptr);
962
963 // Methods for scanline decoding.
964 virtual Result onStartScanlineDecode(const SkImageInfo& /*dstInfo*/,
965 const Options& /*options*/) {
966 return kUnimplemented;
967 }
968
969 virtual Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t,
970 const Options&) {
971 return kUnimplemented;
972 }
973
974 virtual Result onIncrementalDecode(int*) {
975 return kUnimplemented;
976 }
977
978
979 virtual bool onSkipScanlines(int /*countLines*/) { return false; }
980
981 virtual int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; }
982
983 /**
984 * On an incomplete decode, getPixels() and getScanlines() will call this function
985 * to fill any uinitialized memory.
986 *
987 * @param dstInfo Contains the destination color type
988 * Contains the destination alpha type
989 * Contains the destination width
990 * The height stored in this info is unused
991 * @param dst Pointer to the start of destination pixel memory
992 * @param rowBytes Stride length in destination pixel memory
993 * @param zeroInit Indicates if memory is zero initialized
994 * @param linesRequested Number of lines that the client requested
995 * @param linesDecoded Number of lines that were successfully decoded
996 */
997 void fillIncompleteImage(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
998 ZeroInitialized zeroInit, int linesRequested, int linesDecoded);
999
1000 /**
1001 * Return an object which will allow forcing scanline decodes to sample in X.
1002 *
1003 * May create a sampler, if one is not currently being used. Otherwise, does
1004 * not affect ownership.
1005 *
1006 * Only valid during scanline decoding or incremental decoding.
1007 */
1008 virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; }
1009
1010 friend class DM::CodecSrc; // for fillIncompleteImage
1011 friend class SkSampledCodec;
1012 friend class SkIcoCodec;
1013 friend class SkAndroidCodec; // for fEncodedInfo
1014};
1015
1016namespace SkCodecs {
1017
1018using DecodeContext = void*;
1019using IsFormatCallback = bool (*)(const void* data, size_t len);
1020using MakeFromStreamCallback = std::unique_ptr<SkCodec> (*)(std::unique_ptr<SkStream>,
1021 SkCodec::Result*,
1022 DecodeContext);
1023
1024struct SK_API Decoder {
1025 // By convention, we use all lowercase letters and go with the primary filename extension.
1026 // For example "png", "jpg", "ico", "webp", etc
1027 std::string id;
1028 IsFormatCallback isFormat;
1029 MakeFromStreamCallback makeFromStream;
1030};
1031
1032// Add the decoder to the end of a linked list of decoders, which will be used to identify calls to
1033// SkCodec::MakeFromStream. If a decoder with the same id already exists, this new decoder
1034// will replace the existing one (in the same position). This is not thread-safe, so make sure all
1035// initialization is done before the first call.
1036void SK_API Register(Decoder d);
1037}
1038
1039#endif // SkCodec_DEFINED
1040

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com

source code of flutter_engine/third_party/skia/include/codec/SkCodec.h