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