Quelle SkCodec.h
Sprache: C
/*
* Copyright 2015 Google Inc .
*
* Use of this source code is governed by a BSD - style license that can be
* found in the LICENSE file .
*/
#ifndef SkCodec_DEFINED
#define SkCodec_DEFINED
#include "include/codec/SkEncodedOrigin.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPixmap.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h"
#include "include/core/SkSpan.h"
#include "include/core/SkTypes.h"
#include "include/core/SkYUVAPixmaps.h"
#include "include/private/SkEncodedInfo.h"
#include "include/private/SkHdrMetadata.h"
#include "include/private/base/SkNoncopyable.h"
#include "modules/skcms/skcms.h"
#include <cstddef>
#include <functional>
#include <memory>
#include <optional>
#include <string_view>
#include <tuple>
#include <vector>
class SkData;
class SkFrameHolder;
class SkImage;
class SkPngChunkReader;
class SkSampler;
class SkStream;
struct SkGainmapInfo;
enum SkAlphaType :
int ;
enum class SkEncodedImageFormat;
namespace SkCodecAnimation {
enum class Blend;
enum class DisposalMethod;
}
namespace DM {
class CodecSrc;
}
// namespace DM
namespace SkCodecs {
struct Decoder;
}
/**
* Abstraction layer directly on top of an image codec .
*/
class SK_API SkCodec : SkNoncopyable {
public:
/**
* Minimum number of bytes that must be buffered in SkStream input .
*
* An SkStream passed to NewFromStream must be able to use this many
* bytes to determine the image type . Then the same SkStream must be
* passed to the correct decoder to read from the beginning .
*
* This can be accomplished by implementing peek ( ) to support peeking
* this many bytes , or by implementing rewind ( ) to be able to rewind ( )
* after reading this many bytes .
*/
static constexpr size_t MinBufferedBytesNeeded() {
return 32 ; }
/**
* Error codes for various SkCodec methods .
*/
enum Result {
/**
* General return value for success .
*/
kSuccess,
/**
* The input is incomplete . A partial image was generated .
*/
kIncompleteInput,
/**
* Like kIncompleteInput , except the input had an error .
*
* If returned from an incremental decode , decoding cannot continue ,
* even with more data .
*/
kErrorInInput,
/**
* The generator cannot convert to match the request , ignoring
* dimensions .
*/
kInvalidConversion,
/**
* The generator cannot scale to requested size .
*/
kInvalidScale,
/**
* Parameters ( besides info ) are invalid . e . g . NULL pixels , rowBytes
* too small , etc .
*/
kInvalidParameters,
/**
* The input did not contain a valid image .
*/
kInvalidInput,
/**
* Fulfilling this request requires rewinding the input , which is not
* supported for this input .
*/
kCouldNotRewind,
/**
* An internal error , such as OOM .
*/
kInternalError,
/**
* This method is not implemented by this codec .
* FIXME : Perhaps this should be kUnsupported ?
*/
kUnimplemented,
/**
* If the memory allocation exceeded the provided budget .
*/
kOutOfMemory,
};
/**
* Readable string representing the error code .
*/
static const char * ResultToString(Result);
/**
* For container formats that contain both still images and image sequences ,
* instruct the decoder how the output should be selected . ( Refer to comments
* for each value for more details . )
*/
enum class SelectionPolicy {
/**
* If the container format contains both still images and image sequences ,
* SkCodec should choose one of the still images . This is the default .
* Note that kPreferStillImage may prevent use of the animation features
* if the input is not rewindable .
*/
kPreferStillImage,
/**
* If the container format contains both still images and image sequences ,
* SkCodec should choose one of the image sequences for animation .
*/
kPreferAnimation,
};
/**
* If this stream represents an encoded image that we know how to decode ,
* return an SkCodec that can decode it . Otherwise return NULL .
*
* As stated above , this call must be able to peek or read
* MinBufferedBytesNeeded to determine the correct format , and then start
* reading from the beginning . First it will attempt to peek , and it
* assumes that if less than MinBufferedBytesNeeded bytes ( but more than
* zero ) are returned , this is because the stream is shorter than this ,
* so falling back to reading would not provide more data . If peek ( )
* returns zero bytes , this call will instead attempt to read ( ) . This
* will require that the stream can be rewind ( ) ed .
*
* If Result is not NULL , it will be set to either kSuccess if an SkCodec
* is returned or a reason for the failure if NULL is returned .
*
* If SkPngChunkReader is not NULL , take a ref and pass it to libpng if
* the image is a png .
*
* If the SkPngChunkReader is not NULL then :
* If the image is not a PNG , the SkPngChunkReader will be ignored .
* If the image is a PNG , the SkPngChunkReader will be reffed .
* If the PNG has unknown chunks , the SkPngChunkReader will be used
* to handle these chunks . SkPngChunkReader will be called to read
* any unknown chunk at any point during the creation of the codec
* or the decode . Note that if SkPngChunkReader fails to read a
* chunk , this could result in a failure to create the codec or a
* failure to decode the image .
* If the PNG does not contain unknown chunks , the SkPngChunkReader
* will not be used or modified .
*
* If NULL is returned , the stream is deleted immediately . Otherwise , the
* SkCodec takes ownership of it , and will delete it when done with it .
*/
static std::unique_ptr<SkCodec> MakeFromStream(
std::unique_ptr<SkStream>,
SkSpan<
const SkCodecs::Decoder> decoders,
Result* = nullptr,
SkPngChunkReader* = nullptr,
SelectionPolicy selectionPolicy = SelectionPolicy::kPreferStillImage);
// deprecated
static std::unique_ptr<SkCodec> MakeFromStream(
std::unique_ptr<SkStream>,
Result* = nullptr,
SkPngChunkReader* = nullptr,
SelectionPolicy selectionPolicy = SelectionPolicy::kPreferStillImage);
/**
* If this data represents an encoded image that we know how to decode ,
* return an SkCodec that can decode it . Otherwise return NULL .
*
* If the SkPngChunkReader is not NULL then :
* If the image is not a PNG , the SkPngChunkReader will be ignored .
* If the image is a PNG , the SkPngChunkReader will be reffed .
* If the PNG has unknown chunks , the SkPngChunkReader will be used
* to handle these chunks . SkPngChunkReader will be called to read
* any unknown chunk at any point during the creation of the codec
* or the decode . Note that if SkPngChunkReader fails to read a
* chunk , this could result in a failure to create the codec or a
* failure to decode the image .
* If the PNG does not contain unknown chunks , the SkPngChunkReader
* will not be used or modified .
*/
static std::unique_ptr<SkCodec> MakeFromData(sk_sp<
const SkData>,
SkSpan<
const SkCodecs::Decoder> decoders,
SkPngChunkReader* = nullptr);
// deprecated
static std::unique_ptr<SkCodec> MakeFromData(sk_sp<
const SkData>, SkPngChunkReader* = null
ptr);
virtual ~SkCodec();
/**
* Return a reasonable SkImageInfo to decode into .
*
* If the image has an ICC profile that does not map to an SkColorSpace ,
* the returned SkImageInfo will use SRGB .
*/
SkImageInfo getInfo() const { return fEncodedInfo.makeImageInfo(); }
SkISize dimensions() const { return {fEncodedInfo.width(), fEncodedInfo.height()}; }
SkIRect bounds() const {
return SkIRect::MakeWH(fEncodedInfo.width(), fEncodedInfo.height());
}
/**
* Return the ICC profile of the encoded data .
*/
const skcms_ICCProfile* getICCProfile() const {
return this->getEncodedInfo().profile();
}
/**
* Return the HDR metadata associated with this image . Note that even SDR images can include
* HDR metadata ( e . g , indicating how to inverse tone map when displayed on an HDR display ) .
*/
const skhdr::Metadata& getHdrMetadata() const { return fEncodedInfo.getHdrMetadata(); }
/**
* Whether the encoded input uses 16 or more bits per component .
*/
bool hasHighBitDepthEncodedData() const {
// API design note: We don't return `bitsPerComponent` because it may be
// misleading in some cases - see https://crbug.com/359350061#comment4
// for more details.
return this->getEncodedInfo().bitsPerComponent() >= 16 ;
}
/**
* Returns the image orientation stored in the EXIF data .
* If there is no EXIF data , or if we cannot read the EXIF data , returns kTopLeft .
*/
SkEncodedOrigin getOrigin() const { return fOrigin; }
/**
* Return a size that approximately supports the desired scale factor .
* The codec may not be able to scale efficiently to the exact scale
* factor requested , so return a size that approximates that scale .
* The returned value is the codec ' s suggestion for the closest valid
* scale that it can natively support
*/
SkISize getScaledDimensions(float desiredScale) const {
// Negative and zero scales are errors.
SkASSERT(desiredScale > 0 .0 f);
if (desiredScale <= 0 .0 f) {
return SkISize::Make(0 , 0 );
}
// Upscaling is not supported. Return the original size if the client
// requests an upscale.
if (desiredScale >= 1 .0 f) {
return this->dimensions();
}
return this->onGetScaledDimensions(desiredScale);
}
/**
* Return ( via desiredSubset ) a subset which can decoded from this codec ,
* or false if this codec cannot decode subsets or anything similar to
* desiredSubset .
*
* @ param desiredSubset In / out parameter . As input , a desired subset of
* the original bounds ( as specified by getInfo ) . If true is returned ,
* desiredSubset may have been modified to a subset which is
* supported . Although a particular change may have been made to
* desiredSubset to create something supported , it is possible other
* changes could result in a valid subset .
* If false is returned , desiredSubset ' s value is undefined .
* @ return true if this codec supports decoding desiredSubset ( as
* returned , potentially modified )
*/
bool getValidSubset(SkIRect* desiredSubset) const {
return this->onGetValidSubset(desiredSubset);
}
/**
* Format of the encoded data .
*/
SkEncodedImageFormat getEncodedFormat() const { return this->onGetEncodedFormat(); }
/**
* Whether or not the memory passed to getPixels is zero initialized .
*/
enum ZeroInitialized {
/**
* The memory passed to getPixels is zero initialized . The SkCodec
* may take advantage of this by skipping writing zeroes .
*/
kYes_ZeroInitialized,
/**
* The memory passed to getPixels has not been initialized to zero ,
* so the SkCodec must write all zeroes to memory .
*
* This is the default . It will be used if no Options struct is used .
*/
kNo_ZeroInitialized,
};
/**
* Additional options to pass to getPixels .
*/
struct Options {
Options()
: fZeroInitialized(kNo_ZeroInitialized)
, fSubset(nullptr)
, fFrameIndex(0 )
, fPriorFrame(kNoFrame)
, fMaxDecodeMemory(0 ) {}
ZeroInitialized fZeroInitialized;
/**
* If not NULL , represents a subset of the original image to decode .
* Must be within the bounds returned by getInfo ( ) .
* If the EncodedFormat is SkEncodedImageFormat : : kWEBP ( the only one which
* currently supports subsets ) , the top and left values must be even .
*
* In getPixels and incremental decode , we will attempt to decode the
* exact rectangular subset specified by fSubset .
*
* In a scanline decode , it does not make sense to specify a subset
* top or subset height , since the client already controls which rows
* to get and which rows to skip . During scanline decodes , we will
* require that the subset top be zero and the subset height be equal
* to the full height . We will , however , use the values of
* subset left and subset width to decode partial scanlines on calls
* to getScanlines ( ) .
*/
const SkIRect* fSubset;
/**
* The frame to decode .
*
* Only meaningful for multi - frame images .
*/
int fFrameIndex;
/**
* If not kNoFrame , the dst already contains the prior frame at this index .
*
* Only meaningful for multi - frame images .
*
* If fFrameIndex needs to be blended with a prior frame ( as reported by
* getFrameInfo [ fFrameIndex ] . fRequiredFrame ) , the client can set this to
* any non - kRestorePrevious frame in [ fRequiredFrame , fFrameIndex ) to
* indicate that that frame is already in the dst . Options . fZeroInitialized
* is ignored in this case .
*
* If set to kNoFrame , the codec will decode any necessary required frame ( s ) first .
*/
int fPriorFrame;
/**
* If non - zero , image decoding will fail if cumulative allocations exceed this many bytes .
*/
size_t fMaxDecodeMemory;
};
/**
* Decode into the given pixels , a block of memory of size at
* least ( info . fHeight - 1 ) * rowBytes + ( info . fWidth *
* bytesPerPixel )
*
* Repeated calls to this function should give the same results ,
* allowing the PixelRef to be immutable .
*
* @ param info A description of the format ( config , size )
* expected by the caller . This can simply be identical
* to the info returned by getInfo ( ) .
*
* This contract also allows the caller to specify
* different output - configs , which the implementation can
* decide to support or not .
*
* A size that does not match getInfo ( ) implies a request
* to scale . If the generator cannot perform this scale ,
* it will return kInvalidScale .
*
* If the info contains a non - null SkColorSpace , the codec
* will perform the appropriate color space transformation .
*
* If the caller passes in the SkColorSpace that maps to the
* ICC profile reported by getICCProfile ( ) , the color space
* transformation is a no - op .
*
* If the caller passes a null SkColorSpace , no color space
* transformation will be done .
*
* If a scanline decode is in progress , scanline mode will end , requiring the client to call
* startScanlineDecode ( ) in order to return to decoding scanlines .
*
* For certain codecs , reading into a smaller bitmap than the original dimensions may not
* produce correct results ( e . g . animated webp ) .
*
* @ return Result kSuccess , or another value explaining the type of failure .
*/
Result getPixels(const SkImageInfo& info, void * pixels, size_t rowBytes, const Options*);
/**
* Simplified version of getPixels ( ) that uses the default Options .
*/
Result getPixels(const SkImageInfo& info, void * pixels, size_t rowBytes) {
return this->getPixels(info, pixels, rowBytes, nullptr);
}
Result getPixels(const SkPixmap& pm, const Options* opts = nullptr) {
return this->getPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), opts);
}
/**
* Return an image containing the pixels . If the codec ' s origin is not " upper left " ,
* This will rotate the output image accordingly .
*/
std::tuple<sk_sp<SkImage>, SkCodec::Result> getImage(const SkImageInfo& info,
const Options* opts = nullptr);
std::tuple<sk_sp<SkImage>, SkCodec::Result> getImage();
/**
* If decoding to YUV is supported , this returns true . Otherwise , this
* returns false and the caller will ignore output parameter yuvaPixmapInfo .
*
* @ param supportedDataTypes Indicates the data type / planar config combinations that are
* supported by the caller . If the generator supports decoding to
* YUV ( A ) , but not as a type in supportedDataTypes , this method
* returns false .
* @ param yuvaPixmapInfo Output parameter that specifies the planar configuration , subsampling ,
* orientation , chroma siting , plane color types , and row bytes .
*/
bool queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes,
SkYUVAPixmapInfo* yuvaPixmapInfo) const ;
/**
* Returns kSuccess , or another value explaining the type of failure .
* This always attempts to perform a full decode . To get the planar
* configuration without decoding use queryYUVAInfo ( ) .
*
* @ param yuvaPixmaps Contains preallocated pixmaps configured according to a successful call
* to queryYUVAInfo ( ) .
*/
Result getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps);
/**
* Prepare for an incremental decode with the specified options .
*
* This may require a rewind .
*
* If kIncompleteInput is returned , may be called again after more data has
* been provided to the source SkStream .
*
* @ param dstInfo Info of the destination . If the dimensions do not match
* those of getInfo , this implies a scale .
* @ param dst Memory to write to . Needs to be large enough to hold the subset ,
* if present , or the full image as described in dstInfo .
* @ param options Contains decoding options , including if memory is zero
* initialized and whether to decode a subset .
* @ return Enum representing success or reason for failure .
*/
Result startIncrementalDecode(const SkImageInfo& dstInfo, void * dst, size_t rowBytes,
const Options*);
Result startIncrementalDecode(const SkImageInfo& dstInfo, void * dst, size_t rowBytes) {
return this->startIncrementalDecode(dstInfo, dst, rowBytes, nullptr);
}
/**
* Start / continue the incremental decode .
*
* Not valid to call before a call to startIncrementalDecode ( ) returns
* kSuccess .
*
* If kIncompleteInput is returned , may be called again after more data has
* been provided to the source SkStream .
*
* Unlike getPixels and getScanlines , this does not do any filling . This is
* left up to the caller , since they may be skipping lines or continuing the
* decode later . In the latter case , they may choose to initialize all lines
* first , or only initialize the remaining lines after the first call .
*
* @ param rowsDecoded Optional output variable returning the total number of
* lines initialized . Only meaningful if this method returns kIncompleteInput .
* Otherwise the implementation may not set it .
* Note that some implementations may have initialized this many rows , but
* not necessarily finished those rows ( e . g . interlaced PNG ) . This may be
* useful for determining what rows the client needs to initialize .
* @ return kSuccess if all lines requested in startIncrementalDecode have
* been completely decoded . kIncompleteInput otherwise .
*/
Result incrementalDecode(int * rowsDecoded = nullptr) {
if (!fStartedIncrementalDecode) {
return kInvalidParameters;
}
return this->onIncrementalDecode(rowsDecoded);
}
/**
* The remaining functions revolve around decoding scanlines .
*/
/**
* Prepare for a scanline decode with the specified options .
*
* After this call , this class will be ready to decode the first scanline .
*
* This must be called in order to call getScanlines or skipScanlines .
*
* This may require rewinding the stream .
*
* Not all SkCodecs support this .
*
* @ param dstInfo Info of the destination . If the dimensions do not match
* those of getInfo , this implies a scale .
* @ param options Contains decoding options , including if memory is zero
* initialized .
* @ return Enum representing success or reason for failure .
*/
Result startScanlineDecode(const SkImageInfo& dstInfo, const Options* options);
/**
* Simplified version of startScanlineDecode ( ) that uses the default Options .
*/
Result startScanlineDecode(const SkImageInfo& dstInfo) {
return this->startScanlineDecode(dstInfo, nullptr);
}
/**
* Write the next countLines scanlines into dst .
*
* Not valid to call before calling startScanlineDecode ( ) .
*
* @ param dst Must be non - null , and large enough to hold countLines
* scanlines of size rowBytes .
* @ param countLines Number of lines to write .
* @ param rowBytes Number of bytes per row . Must be large enough to hold
* a scanline based on the SkImageInfo used to create this object .
* @ return the number of lines successfully decoded . If this value is
* less than countLines , this will fill the remaining lines with a
* default value .
*/
int getScanlines(void * dst, int countLines, size_t rowBytes);
/**
* Skip count scanlines .
*
* Not valid to call before calling startScanlineDecode ( ) .
*
* The default version just calls onGetScanlines and discards the dst .
* NOTE : If skipped lines are the only lines with alpha , this default
* will make reallyHasAlpha return true , when it could have returned
* false .
*
* @ return true if the scanlines were successfully skipped
* false on failure , possible reasons for failure include :
* An incomplete input image stream .
* Calling this function before calling startScanlineDecode ( ) .
* If countLines is less than zero or so large that it moves
* the current scanline past the end of the image .
*/
bool skipScanlines(int countLines);
/**
* The order in which rows are output from the scanline decoder is not the
* same for all variations of all image types . This explains the possible
* output row orderings .
*/
enum SkScanlineOrder {
/*
* By far the most common , this indicates that the image can be decoded
* reliably using the scanline decoder , and that rows will be output in
* the logical order .
*/
kTopDown_SkScanlineOrder,
/*
* This indicates that the scanline decoder reliably outputs rows , but
* they will be returned in reverse order . If the scanline format is
* kBottomUp , the nextScanline ( ) API can be used to determine the actual
* y - coordinate of the next output row , but the client is not forced
* to take advantage of this , given that it ' s not too tough to keep
* track independently .
*
* For full image decodes , it is safe to get all of the scanlines at
* once , since the decoder will handle inverting the rows as it
* decodes .
*
* For subset decodes and sampling , it is simplest to get and skip
* scanlines one at a time , using the nextScanline ( ) API . It is
* possible to ask for larger chunks at a time , but this should be used
* with caution . As with full image decodes , the decoder will handle
* inverting the requested rows , but rows will still be delivered
* starting from the bottom of the image .
*
* Upside down bmps are an example .
*/
kBottomUp_SkScanlineOrder,
};
/**
* An enum representing the order in which scanlines will be returned by
* the scanline decoder .
*
* This is undefined before startScanlineDecode ( ) is called .
*/
SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder(); }
/**
* Returns the y - coordinate of the next row to be returned by the scanline
* decoder .
*
* This will equal fCurrScanline , except in the case of strangely
* encoded image types ( bottom - up bmps ) .
*
* Results are undefined when not in scanline decoding mode .
*/
int nextScanline() const { return this->outputScanline(fCurrScanline); }
/**
* Returns the output y - coordinate of the row that corresponds to an input
* y - coordinate . The input y - coordinate represents where the scanline
* is located in the encoded data .
*
* This will equal inputScanline , except in the case of strangely
* encoded image types ( bottom - up bmps , interlaced gifs ) .
*/
int outputScanline(int inputScanline) const ;
/**
* Return the number of frames in the image .
*
* May require reading through the stream .
*
* Note that some codecs may be unable to gather ` FrameInfo ` for all frames
* in case of ` kIncompleteInput ` . For such codecs ` getFrameCount ` may
* initially report a low frame count . After the underlying ` SkStream `
* provides additional data , then calling ` getFrameCount ` again may return
* an updated , increased frame count .
*/
int getFrameCount() {
return this->onGetFrameCount();
}
// Sentinel value used when a frame index implies "no frame":
// - FrameInfo::fRequiredFrame set to this value means the frame
// is independent.
// - Options::fPriorFrame set to this value means no (relevant) prior frame
// is residing in dst's memory.
static constexpr int kNoFrame = -1 ;
/**
* Information about individual frames in a multi - framed image .
*/
struct FrameInfo {
/**
* The frame that this frame needs to be blended with , or
* kNoFrame if this frame is independent ( so it can be
* drawn over an uninitialized buffer ) .
*
* Note that this is the * earliest * frame that can be used
* for blending . Any frame from [ fRequiredFrame , i ) can be
* used , unless its fDisposalMethod is kRestorePrevious .
*/
int fRequiredFrame;
/**
* Number of milliseconds to show this frame .
*/
int fDuration;
/**
* Whether the end marker for this frame is contained in the stream .
*
* Note : this does not guarantee that an attempt to decode will be complete .
* There could be an error in the stream .
*/
bool fFullyReceived;
/**
* This is conservative ; it will still return non - opaque if e . g . a
* color index - based frame has a color with alpha but does not use it .
*/
SkAlphaType fAlphaType;
/**
* Whether the updated rectangle contains alpha .
*
* This is conservative ; it will still be set to true if e . g . a color
* index - based frame has a color with alpha but does not use it . In
* addition , it may be set to true , even if the final frame , after
* blending , is opaque .
*/
bool fHasAlphaWithinBounds;
/**
* How this frame should be modified before decoding the next one .
*/
SkCodecAnimation::DisposalMethod fDisposalMethod;
/**
* How this frame should blend with the prior frame .
*/
SkCodecAnimation::Blend fBlend;
/**
* The rectangle updated by this frame .
*
* It may be empty , if the frame does not change the image . It will
* always be contained by SkCodec : : dimensions ( ) .
*/
SkIRect fFrameRect;
};
/**
* Return info about a single frame .
*
* Does not read through the stream , so it should be called after
* getFrameCount ( ) to parse any frames that have not already been parsed .
*
* Only supported by animated ( multi - frame ) codecs . Note that this is a
* property of the codec ( the SkCodec subclass ) , not the image .
*
* To elaborate , some codecs support animation ( e . g . GIF ) . Others do not
* ( e . g . BMP ) . Animated codecs can still represent single frame images .
* Calling getFrameInfo ( 0 , etc ) will return true for a single frame GIF
* even if the overall image is not animated ( in that the pixels on screen
* do not change over time ) . When incrementally decoding a GIF image , we
* might only know that there ' s a single frame * so far * .
*
* For non - animated SkCodec subclasses , it ' s sufficient but not necessary
* for this method to always return false .
*/
bool getFrameInfo(int index, FrameInfo* info) const {
if (index < 0 ) {
return false ;
}
return this->onGetFrameInfo(index, info);
}
/**
* Return info about all the frames in the image .
*
* May require reading through the stream to determine info about the
* frames ( including the count ) .
*
* As such , future decoding calls may require a rewind .
*
* This may return an empty vector for non - animated codecs . See the
* getFrameInfo ( int , FrameInfo * ) comment .
*/
std::vector<FrameInfo> getFrameInfo();
static constexpr int kRepetitionCountInfinite = -1 ;
/**
* Return the number of times to repeat , if this image is animated . This number does not
* include the first play through of each frame . For example , a repetition count of 4 means
* that each frame is played 5 times and then the animation stops .
*
* It can return kRepetitionCountInfinite , a negative number , meaning that the animation
* should loop forever .
*
* May require reading the stream to find the repetition count .
*
* As such , future decoding calls may require a rewind .
*
* ` getRepetitionCount ` will return ` 0 ` in two cases :
* 1 . Still ( non - animated ) images .
* 2 . Animated images that only play the animation once ( i . e . that don ' t
* repeat the animation )
* ` isAnimated ` can be used to disambiguate between these two cases .
*/
int getRepetitionCount() {
return this->onGetRepetitionCount();
}
/**
* ` isAnimated ` returns whether the full input is expected to contain an
* animated image ( i . e . more than 1 image frame ) . This can be used to
* disambiguate the meaning of ` getRepetitionCount ` returning ` 0 ` ( see
* ` getRepetitionCount ` ' s doc comment for more details ) .
*
* Note that in some codecs ` getFrameCount ( ) ` only returns the number of
* frames for which all the metadata has been already successfully decoded .
* Therefore for a partial input ` isAnimated ( ) ` may return " yes " , even
* though ` getFrameCount ( ) ` may temporarily return ` 1 ` until more of the
* input is available .
*
* When handling partial input , some codecs may not know until later ( e . g .
* until encountering additional image frames ) whether the given image has
* more than one frame . Such codecs may initially return
* ` IsAnimated : : kUnknown ` and only later give a definitive " yes " or " no "
* answer . GIF format is one example where this may happen .
*
* Other codecs may be able to decode the information from the metadata
* present before the first image frame . Such codecs should be able to give
* a definitive " yes " or " no " answer as soon as they are constructed . PNG
* format is one example where this happens .
*/
enum class IsAnimated {
kYes,
kNo,
kUnknown,
};
IsAnimated isAnimated() { return this->onIsAnimated(); }
protected :
const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; }
using XformFormat = skcms_PixelFormat;
SkCodec(SkEncodedInfo&&,
XformFormat srcFormat,
std::unique_ptr<SkStream>,
SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
virtual bool onGetGainmapCodec(SkGainmapInfo*, std::unique_ptr<SkCodec>*) { return false ; }
virtual bool onGetGainmapInfo(SkGainmapInfo*) { return false ; }
// TODO(issues.skia.org/363544350): This API only works for JPEG images. Remove this API once
// it is no longer used.
virtual bool onGetGainmapInfo(SkGainmapInfo*, std::unique_ptr<SkStream>*) { return false ; }
virtual SkISize onGetScaledDimensions(float /*desiredScale*/) const {
// By default, scaling is not supported.
return this->dimensions();
}
// FIXME: What to do about subsets??
/**
* Subclasses should override if they support dimensions other than the
* srcInfo ' s .
*/
virtual bool onDimensionsSupported(const SkISize&) {
return false ;
}
virtual SkEncodedImageFormat onGetEncodedFormat() const = 0 ;
/**
* @ param rowsDecoded When the encoded image stream is incomplete , this function
* will return kIncompleteInput and rowsDecoded will be set to
* the number of scanlines that were successfully decoded .
* This will allow getPixels ( ) to fill the uninitialized memory .
*/
virtual Result onGetPixels(const SkImageInfo& info,
void * pixels, size_t rowBytes, const Options&,
int * rowsDecoded) = 0 ;
virtual bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&,
SkYUVAPixmapInfo*) const { return false ; }
virtual Result onGetYUVAPlanes(const SkYUVAPixmaps&) { return kUnimplemented; }
virtual bool onGetValidSubset(SkIRect* /*desiredSubset*/) const {
// By default, subsets are not supported.
return false ;
}
/**
* If the stream was previously read , attempt to rewind .
*
* If the stream needed to be rewound , call onRewind .
* @ returns true if the codec is at the right position and can be used .
* false if there was a failure to rewind .
*
* This is called by getPixels ( ) , getYUV8Planes ( ) , startIncrementalDecode ( ) and
* startScanlineDecode ( ) . Subclasses may call if they need to rewind at another time .
*/
[[nodiscard]] bool rewindIfNeeded();
/**
* Called by onRewind ( ) , attempts to rewind fStream .
*/
bool rewindStream();
/**
* Called by rewindIfNeeded , if the stream needed to be rewound .
*
* Subclasses should call rewindStream ( ) if they own one , and then
* do any set up needed after .
*/
virtual bool onRewind() {
if (!this->rewindStream()) {
return false ;
}
return true;
}
/**
* Get method for the input stream
*/
SkStream* stream() {
return fStream.get();
}
/**
* The remaining functions revolve around decoding scanlines .
*/
/**
* Most images types will be kTopDown and will not need to override this function .
*/
virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; }
const SkImageInfo& dstInfo() const { return fDstInfo; }
const Options& options() const { return fOptions; }
/**
* Returns the number of scanlines that have been decoded so far .
* This is unaffected by the SkScanlineOrder .
*
* Returns - 1 if we have not started a scanline decode .
*/
int currScanline() const { return fCurrScanline; }
virtual int onOutputScanline(int inputScanline) const ;
/**
* Return whether we can convert to dst .
*
* Will be called for the appropriate frame , prior to initializing the colorXform .
*/
virtual bool conversionSupported(const SkImageInfo& dst, bool srcIsOpaque,
bool needsColorXform);
// Some classes never need a colorXform e.g.
// - ICO uses its embedded codec's colorXform
// - WBMP is just Black/White
virtual bool usesColorXform() const { return true; }
void applyColorXform(void * dst, const void * src, int count) const ;
bool colorXform() const { return fXformTime != kNo_XformTime; }
bool xformOnDecode() const { return fXformTime == kDecodeRow_XformTime; }
virtual int onGetFrameCount() {
return 1 ;
}
virtual bool onGetFrameInfo(int , FrameInfo*) const {
return false ;
}
virtual int onGetRepetitionCount() {
return 0 ;
}
virtual IsAnimated onIsAnimated() {
return IsAnimated::kNo;
}
// Returns true if the requested amount keeps the current total under Options::fMaxDecodeMemory.
bool allocateFromBudget(size_t numBytes);
private :
const SkEncodedInfo fEncodedInfo;
XformFormat fSrcXformFormat;
std::unique_ptr<SkStream> fStream;
bool fNeedsRewind = false ;
const SkEncodedOrigin fOrigin;
SkImageInfo fDstInfo;
Options fOptions;
enum XformTime {
kNo_XformTime,
kPalette_XformTime,
kDecodeRow_XformTime,
};
XformTime fXformTime;
XformFormat fDstXformFormat; // Based on fDstInfo.
skcms_ICCProfile fDstProfileStorage;
// This tracks either fDstProfileStorage or the ICC profile in fEncodedInfo.
// For the latter case it is important to not make a profile copy because skcms_Transform
// only performs a shallow pointer comparison to decide whether it can skip the color space
// transformation.
const skcms_ICCProfile* fDstProfile = &fDstProfileStorage;
skcms_AlphaFormat fDstXformAlphaFormat;
// Only meaningful during scanline decodes.
int fCurrScanline = -1 ;
// How many bytes we are allowed to use when decoding.
size_t fDecodeBudget = 0 ;
bool fStartedIncrementalDecode = false ;
// Allows SkAndroidCodec to call handleFrameIndex (potentially decoding a prior frame and
// clearing to transparent) without SkCodec itself calling it, too.
bool fUsingCallbackForHandleFrameIndex = false ;
bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha, bool srcIsOpaque);
/**
* Return whether these dimensions are supported as a scale .
*
* The codec may choose to cache the information about scale and subset .
* Either way , the same information will be passed to onGetPixels / onStart
* on success .
*
* This must return true for a size returned from getScaledDimensions .
*/
bool dimensionsSupported(const SkISize& dim) {
return dim == this->dimensions() || this->onDimensionsSupported(dim);
}
Result getPixelsBudgeted(const SkImageInfo& info,
void * pixels,
size_t rowBytes,
const Options*);
/**
* For multi - framed images , return the object with information about the frames .
*/
virtual const SkFrameHolder* getFrameHolder() const {
return nullptr;
}
// Callback for decoding a prior frame. The `Options::fFrameIndex` is ignored,
// being replaced by frameIndex. This allows opts to actually be a subclass of
// SkCodec::Options which SkCodec itself does not know how to copy or modify,
// but just passes through to the caller (where it can be reinterpret_cast'd).
using GetPixelsCallback = std::function<Result(const SkImageInfo&, void * pixels,
size_t rowBytes, const Options& opts,
int frameIndex)>;
/**
* Check for a valid Options . fFrameIndex , and decode prior frames if necessary .
*
* If GetPixelsCallback is not null , it will be used to decode a prior frame instead
* of using this SkCodec directly . It may also be used recursively , if that in turn
* depends on a prior frame . This is used by SkAndroidCodec .
*/
Result handleFrameIndex(const SkImageInfo&, void * pixels, size_t rowBytes, const Options&,
GetPixelsCallback = nullptr);
// Methods for scanline decoding.
virtual Result onStartScanlineDecode(const SkImageInfo& /*dstInfo*/,
const Options& /*options*/) {
return kUnimplemented;
}
/**
* Checks whether the implementation supports incremental decoding for the given info .
*
* Note that onStartIncrementalDecode can stil fail regardless of this result .
*/
virtual bool onSupportsIncrementalDecode(const SkImageInfo&) { return false ; }
virtual Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t,
const Options&) {
return kUnimplemented;
}
virtual Result onIncrementalDecode(int *) {
return kUnimplemented;
}
virtual bool onSkipScanlines(int /*countLines*/) { return false; }
virtual int onGetScanlines(void * /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; }
/**
* On an incomplete decode , getPixels ( ) and getScanlines ( ) will call this function
* to fill any uinitialized memory .
*
* @ param dstInfo Contains the destination color type
* Contains the destination alpha type
* Contains the destination width
* The height stored in this info is unused
* @ param dst Pointer to the start of destination pixel memory
* @ param rowBytes Stride length in destination pixel memory
* @ param zeroInit Indicates if memory is zero initialized
* @ param linesRequested Number of lines that the client requested
* @ param linesDecoded Number of lines that were successfully decoded
*/
void fillIncompleteImage(const SkImageInfo& dstInfo, void * dst, size_t rowBytes,
ZeroInitialized zeroInit, int linesRequested, int linesDecoded);
/**
* Return an object which will allow forcing scanline decodes to sample in X .
*
* May create a sampler , if one is not currently being used . Otherwise , does
* not affect ownership .
*
* Only valid during scanline decoding or incremental decoding .
*/
virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; }
/**
* Return the underlying encoded data . This may be nullptr if the original
* stream could not be duplicated / read .
*/
virtual sk_sp<const SkData> getEncodedData() const ;
friend class DM::CodecSrc; // for fillIncompleteImage
friend class PNGCodecGM; // for fillIncompleteImage
friend class SkSampledCodec;
friend class SkIcoCodec;
friend class SkPngCodec; // for onGetGainmapCodec
friend class SkAndroidCodec; // for handleFrameIndex
friend class SkCodecPriv; // for fEncodedInfo
};
namespace SkCodecs {
using DecodeContext = void *;
using IsFormatCallback = bool (*)(const void * data, size_t len);
using MakeFromStreamCallback = std::unique_ptr<SkCodec> (*)(std::unique_ptr<SkStream>,
SkCodec::Result*,
DecodeContext);
struct SK_API Decoder {
// By convention, we use all lowercase letters and go with the primary filename extension.
// For example "png", "jpg", "ico", "webp", etc
std::string_view id;
IsFormatCallback isFormat;
MakeFromStreamCallback makeFromStream;
};
// Add the decoder to the end of a linked list of decoders, which will be used to identify calls to
// SkCodec::MakeFromStream. If a decoder with the same id already exists, this new decoder
// will replace the existing one (in the same position). This is not thread-safe, so make sure all
// initialization is done before the first call.
void SK_API Register (Decoder d);
/**
* Return a SkImage produced by the codec , but attempts to defer image allocation until the
* image is actually used / drawn . This deferral allows the system to cache the result , either on the
* CPU or on the GPU , depending on where the image is drawn . If memory is low , the cache may
* be purged , causing the next draw of the image to have to re - decode .
*
* If alphaType is nullopt , the image ' s alpha type will be chosen automatically based on the
* image format . Transparent images will default to kPremul_SkAlphaType . If alphaType contains
* kPremul_SkAlphaType or kUnpremul_SkAlphaType , that alpha type will be used . Forcing opaque
* ( passing kOpaque_SkAlphaType ) is not allowed , and will return nullptr .
*
* @ param codec A non - null codec ( e . g . from SkPngDecoder : : Decode )
* @ return created SkImage , or nullptr
*/
SK_API sk_sp<SkImage> DeferredImage(std::unique_ptr<SkCodec> codec,
std::optional<SkAlphaType> alphaType = std::nullopt);
}
#endif // SkCodec_DEFINED
Messung V0.5 in Prozent C=88 H=100 G=94
¤ Dauer der Verarbeitung: 0.36 Sekunden
(vorverarbeitet am 2026-08-26)
¤
*© Formatika GbR, Deutschland
2026-08-25
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=277311
#Domains=752002