1 /* 2 * Copyright 2018 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 SkAnimatedImage_DEFINED 9 #define SkAnimatedImage_DEFINED 10 11 #include "include/codec/SkCodecAnimation.h" 12 #include "include/core/SkBitmap.h" 13 #include "include/core/SkDrawable.h" 14 #include "include/core/SkMatrix.h" 15 #include "include/core/SkRect.h" 16 17 class SkAndroidCodec; 18 class SkImage; 19 class SkPicture; 20 21 /** 22 * Thread unsafe drawable for drawing animated images (e.g. GIF). 23 */ 24 class SK_API SkAnimatedImage : public SkDrawable { 25 public: 26 /** 27 * Create an SkAnimatedImage from the SkAndroidCodec. 28 * 29 * Returns null on failure to allocate pixels. On success, this will 30 * decode the first frame. 31 * 32 * @param info Width and height may require scaling. 33 * @param cropRect Rectangle to crop to after scaling. 34 * @param postProcess Picture to apply after scaling and cropping. 35 */ 36 static sk_sp<SkAnimatedImage> Make(std::unique_ptr<SkAndroidCodec>, 37 const SkImageInfo& info, SkIRect cropRect, sk_sp<SkPicture> postProcess); 38 39 /** 40 * Simpler version that uses the default size, no cropping, and no postProcess. 41 */ 42 static sk_sp<SkAnimatedImage> Make(std::unique_ptr<SkAndroidCodec>); 43 44 ~SkAnimatedImage() override; 45 46 /** 47 * Reset the animation to the beginning. 48 */ 49 void reset(); 50 51 /** 52 * Whether the animation completed. 53 * 54 * Returns true after all repetitions are complete, or an error stops the 55 * animation. Gets reset to false if the animation is restarted. 56 */ isFinished()57 bool isFinished() const { return fFinished; } 58 59 /** 60 * Returned by decodeNextFrame and currentFrameDuration if the animation 61 * is not running. 62 */ 63 static constexpr int kFinished = -1; 64 65 /** 66 * Decode the next frame. 67 * 68 * If the animation is on the last frame or has hit an error, returns 69 * kFinished. 70 */ 71 int decodeNextFrame(); 72 73 /** 74 * Returns the current frame as an SkImage. The SkImage will not change 75 * after it has been returned. 76 * If there is no current frame, nullptr will be returned. 77 */ 78 sk_sp<SkImage> getCurrentFrame(); 79 80 /** 81 * How long to display the current frame. 82 * 83 * Useful for the first frame, for which decodeNextFrame is called 84 * internally. 85 */ currentFrameDuration()86 int currentFrameDuration() { 87 return fCurrentFrameDuration; 88 } 89 90 /** 91 * Change the repetition count. 92 * 93 * By default, the image will repeat the number of times indicated in the 94 * encoded data. 95 * 96 * Use SkCodec::kRepetitionCountInfinite for infinite, and 0 to show all 97 * frames once and then stop. 98 */ 99 void setRepetitionCount(int count); 100 101 /** 102 * Return the currently set repetition count. 103 */ getRepetitionCount()104 int getRepetitionCount() const { 105 return fRepetitionCount; 106 } 107 108 /** 109 * Return the total number of frames in the animation. 110 */ getFrameCount()111 int getFrameCount() const { return fFrameCount; } 112 113 /** 114 * Change the filter mode. 115 * 116 * By default, the image will apply bilinear filtering when drawing in the 117 * OnDraw method. 118 */ 119 void setFilterMode(SkFilterMode filterMode); 120 121 /** 122 * Return the filter mode used for sampling when drawing. 123 */ getFilterMode()124 SkFilterMode getFilterMode() const { return fFilterMode; } 125 126 protected: 127 SkRect onGetBounds() override; 128 void onDraw(SkCanvas*) override; 129 130 private: 131 struct Frame { 132 SkBitmap fBitmap; 133 int fIndex; 134 SkCodecAnimation::DisposalMethod fDisposalMethod; 135 136 // init() may have to create a new SkPixelRef, if the 137 // current one is already in use by another owner (e.g. 138 // an SkPicture). This determines whether to copy the 139 // existing one to the new one. 140 enum class OnInit { 141 // Restore the image from the old SkPixelRef to the 142 // new one. 143 kRestoreIfNecessary, 144 // No need to restore. 145 kNoRestore, 146 }; 147 148 Frame(); 149 bool init(const SkImageInfo& info, OnInit); 150 bool copyTo(Frame*) const; 151 }; 152 153 std::unique_ptr<SkAndroidCodec> fCodec; 154 SkImageInfo fDecodeInfo; 155 const SkIRect fCropRect; 156 const sk_sp<SkPicture> fPostProcess; 157 const int fFrameCount; 158 SkMatrix fMatrix; 159 int fSampleSize; 160 161 bool fFinished; 162 int fCurrentFrameDuration; 163 Frame fDisplayFrame; 164 Frame fDecodingFrame; 165 Frame fRestoreFrame; 166 int fRepetitionCount; 167 int fRepetitionsCompleted; 168 SkFilterMode fFilterMode = SkFilterMode::kLinear; 169 170 SkAnimatedImage(std::unique_ptr<SkAndroidCodec>, const SkImageInfo& requestedInfo, 171 SkIRect cropRect, sk_sp<SkPicture> postProcess); 172 173 int computeNextFrame(int current, bool* animationEnded); 174 double finish(); 175 176 /** 177 * True if there is no crop, orientation, or post decoding scaling. 178 */ simple()179 bool simple() const { return fMatrix.isIdentity() && !fPostProcess 180 && fCropRect == fDecodeInfo.bounds(); } 181 182 /** 183 * Returns the current frame as an SkImage. 184 * 185 * Like getCurrentFrame, but only returns the raw data from the internal SkBitmap. (i.e. no 186 * scaling, orientation-correction or cropping.) If simple(), this is the final output. 187 */ 188 sk_sp<SkImage> getCurrentFrameSimple(); 189 190 using INHERITED = SkDrawable; 191 }; 192 193 #endif // SkAnimatedImage_DEFINED 194