123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921 |
- /*
- * 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 "../private/SkNoncopyable.h"
- #include "../private/SkTemplates.h"
- #include "../private/SkEncodedInfo.h"
- #include "SkCodecAnimation.h"
- #include "SkColor.h"
- #include "SkEncodedImageFormat.h"
- #include "SkEncodedOrigin.h"
- #include "SkImageInfo.h"
- #include "SkPixmap.h"
- #include "SkSize.h"
- #include "SkStream.h"
- #include "SkTypes.h"
- #include "SkYUVASizeInfo.h"
- #include <vector>
- class SkColorSpace;
- class SkData;
- class SkFrameHolder;
- class SkPngChunkReader;
- class SkSampler;
- namespace DM {
- class CodecSrc;
- class ColorCodecSrc;
- }
- /**
- * 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,
- };
- /**
- * Readable string representing the error code.
- */
- static const char* ResultToString(Result);
- /**
- * 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>, Result* = nullptr,
- SkPngChunkReader* = nullptr);
- /**
- * 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<SkData>, SkPngChunkReader* = nullptr);
- virtual ~SkCodec();
- /**
- * Return a reasonable SkImageInfo to decode into.
- */
- SkImageInfo getInfo() const { return fEncodedInfo.makeImageInfo(); }
- SkISize dimensions() const { return {fEncodedInfo.width(), fEncodedInfo.height()}; }
- SkIRect bounds() const {
- return SkIRect::MakeWH(fEncodedInfo.width(), fEncodedInfo.height());
- }
- /**
- * 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.0f);
- if (desiredScale <= 0.0f) {
- return SkISize::Make(0, 0);
- }
- // Upscaling is not supported. Return the original size if the client
- // requests an upscale.
- if (desiredScale >= 1.0f) {
- 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)
- {}
- 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;
- };
- /**
- * 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 same color space that was
- * reported by the codec, the color space transformation is
- * a no-op.
- *
- * If a scanline decode is in progress, scanline mode will end, requiring the client to call
- * startScanlineDecode() in order to return to decoding scanlines.
- *
- * @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);
- }
- /**
- * If decoding to YUV is supported, this returns true. Otherwise, this
- * returns false and does not modify any of the parameters.
- *
- * @param sizeInfo Output parameter indicating the sizes and required
- * allocation widths of the Y, U, V, and A planes. Given current codec
- * limitations the size of the A plane will always be 0 and the Y, U, V
- * channels will always be planar.
- * @param colorSpace Output parameter. If non-NULL this is set to kJPEG,
- * otherwise this is ignored.
- */
- bool queryYUV8(SkYUVASizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
- if (nullptr == sizeInfo) {
- return false;
- }
- bool result = this->onQueryYUV8(sizeInfo, colorSpace);
- if (result) {
- for (int i = 0; i <= 2; ++i) {
- SkASSERT(sizeInfo->fSizes[i].fWidth > 0 && sizeInfo->fSizes[i].fHeight > 0 &&
- sizeInfo->fWidthBytes[i] > 0);
- }
- SkASSERT(!sizeInfo->fSizes[3].fWidth &&
- !sizeInfo->fSizes[3].fHeight &&
- !sizeInfo->fWidthBytes[3]);
- }
- return result;
- }
- /**
- * Returns kSuccess, or another value explaining the type of failure.
- * This always attempts to perform a full decode. If the client only
- * wants size, it should call queryYUV8().
- *
- * @param sizeInfo Needs to exactly match the values returned by the
- * query, except the WidthBytes may be larger than the
- * recommendation (but not smaller).
- * @param planes Memory for each of the Y, U, and V planes.
- */
- Result getYUV8Planes(const SkYUVASizeInfo& sizeInfo, void* planes[SkYUVASizeInfo::kMaxCount]) {
- if (!planes || !planes[0] || !planes[1] || !planes[2]) {
- return kInvalidInput;
- }
- SkASSERT(!planes[3]); // TODO: is this a fair assumption?
- if (!this->rewindIfNeeded()) {
- return kCouldNotRewind;
- }
- return this->onGetYUV8Planes(sizeInfo, planes);
- }
- /**
- * Prepare for an incremental decode with the specified options.
- *
- * This may require a rewind.
- *
- * @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 calling startIncrementalDecode().
- *
- * After the first call, should only be called again if 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.
- */
- 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;
- // This transitional definition was added in August 2018, and will eventually be removed.
- #ifdef SK_LEGACY_SKCODEC_NONE_ENUM
- static constexpr int kNone = kNoFrame;
- #endif
- /**
- * 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.
- *
- * 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;
- /**
- * How this frame should be modified before decoding the next one.
- */
- SkCodecAnimation::DisposalMethod fDisposalMethod;
- };
- /**
- * Return info about a single frame.
- *
- * Only supported by multi-frame images. Does not read through the stream,
- * so it should be called after getFrameCount() to parse any frames that
- * have not already been parsed.
- */
- 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.
- *
- * For still (non-animated) image codecs, this will return an empty vector.
- */
- 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.
- *
- * For still (non-animated) image codecs, this will return 0.
- */
- int getRepetitionCount() {
- return this->onGetRepetitionCount();
- }
- protected:
- const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; }
- using XformFormat = skcms_PixelFormat;
- SkCodec(SkEncodedInfo&&,
- XformFormat srcFormat,
- std::unique_ptr<SkStream>,
- SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
- 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 onQueryYUV8(SkYUVASizeInfo*, SkYUVColorSpace*) const {
- return false;
- }
- virtual Result onGetYUV8Planes(const SkYUVASizeInfo&,
- void*[SkYUVASizeInfo::kMaxCount] /*planes*/) {
- 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.
- */
- bool SK_WARN_UNUSED_RESULT rewindIfNeeded();
- /**
- * Called by rewindIfNeeded, if the stream needed to be rewound.
- *
- * Subclasses should do any set up needed after a rewind.
- */
- virtual bool onRewind() {
- 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;
- }
- private:
- const SkEncodedInfo fEncodedInfo;
- const XformFormat fSrcXformFormat;
- std::unique_ptr<SkStream> fStream;
- bool fNeedsRewind;
- const SkEncodedOrigin fOrigin;
- SkImageInfo fDstInfo;
- Options fOptions;
- enum XformTime {
- kNo_XformTime,
- kPalette_XformTime,
- kDecodeRow_XformTime,
- };
- XformTime fXformTime;
- XformFormat fDstXformFormat; // Based on fDstInfo.
- skcms_ICCProfile fDstProfile;
- skcms_AlphaFormat fDstXformAlphaFormat;
- // Only meaningful during scanline decodes.
- int fCurrScanline;
- bool fStartedIncrementalDecode;
- 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);
- }
- /**
- * For multi-framed images, return the object with information about the frames.
- */
- virtual const SkFrameHolder* getFrameHolder() const {
- return nullptr;
- }
- /**
- * Check for a valid Options.fFrameIndex, and decode prior frames if necessary.
- */
- Result handleFrameIndex(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&);
- // Methods for scanline decoding.
- virtual Result onStartScanlineDecode(const SkImageInfo& /*dstInfo*/,
- const Options& /*options*/) {
- return kUnimplemented;
- }
- 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; }
- friend class DM::CodecSrc; // for fillIncompleteImage
- friend class SkSampledCodec;
- friend class SkIcoCodec;
- friend class SkAndroidCodec; // for fEncodedInfo
- };
- #endif // SkCodec_DEFINED
|