• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright 2016 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  #include "gm.h"
9  #include "sk_tool_utils.h"
10  #include "SkAnimTimer.h"
11  #include "SkCanvas.h"
12  #include "SkCodec.h"
13  #include "SkColor.h"
14  #include "SkCommandLineFlags.h"
15  #include "SkFont.h"
16  #include "SkPaint.h"
17  #include "SkString.h"
18  #include "Resources.h"
19  
20  #include <vector>
21  
22  DEFINE_string(animatedGif, "images/test640x479.gif", "Animated gif in resources folder");
23  
24  class AnimatedGifGM : public skiagm::GM {
25  private:
26      std::unique_ptr<SkCodec>        fCodec;
27      int                             fFrame;
28      double                          fNextUpdate;
29      int                             fTotalFrames;
30      std::vector<SkCodec::FrameInfo> fFrameInfos;
31      std::vector<SkBitmap>           fFrames;
32  
drawFrame(SkCanvas * canvas,int frameIndex)33      void drawFrame(SkCanvas* canvas, int frameIndex) {
34          // FIXME: Create from an Image/ImageGenerator?
35          if (frameIndex >= (int) fFrames.size()) {
36              fFrames.resize(frameIndex + 1);
37          }
38          SkBitmap& bm = fFrames[frameIndex];
39          if (!bm.getPixels()) {
40              const SkImageInfo info = fCodec->getInfo().makeColorType(kN32_SkColorType);
41              bm.allocPixels(info);
42  
43              SkCodec::Options opts;
44              opts.fFrameIndex = frameIndex;
45              const int requiredFrame = fFrameInfos[frameIndex].fRequiredFrame;
46              if (requiredFrame != SkCodec::kNoFrame) {
47                  SkASSERT(requiredFrame >= 0
48                           && static_cast<size_t>(requiredFrame) < fFrames.size());
49                  SkBitmap& requiredBitmap = fFrames[requiredFrame];
50                  // For simplicity, do not try to cache old frames
51                  if (requiredBitmap.getPixels() &&
52                          sk_tool_utils::copy_to(&bm, requiredBitmap.colorType(), requiredBitmap)) {
53                      opts.fPriorFrame = requiredFrame;
54                  }
55              }
56  
57              if (SkCodec::kSuccess != fCodec->getPixels(info, bm.getPixels(),
58                                                         bm.rowBytes(), &opts)) {
59                  SkDebugf("Could not getPixels for frame %i: %s", frameIndex, FLAGS_animatedGif[0]);
60                  return;
61              }
62          }
63  
64          canvas->drawBitmap(bm, 0, 0);
65      }
66  
67  public:
AnimatedGifGM()68      AnimatedGifGM()
69      : fFrame(0)
70      , fNextUpdate (-1)
71      , fTotalFrames (-1) {}
72  
73  private:
onShortName()74      SkString onShortName() override {
75          return SkString("animatedGif");
76      }
77  
onISize()78      SkISize onISize() override {
79          if (this->initCodec()) {
80              SkISize dim = fCodec->getInfo().dimensions();
81              // Wide enough to display all the frames.
82              dim.fWidth *= fTotalFrames;
83              // Tall enough to show the row of frames plus an animating version.
84              dim.fHeight *= 2;
85              return dim;
86          }
87          return SkISize::Make(640, 480);
88      }
89  
initCodec()90      bool initCodec() {
91          if (fCodec) {
92              return true;
93          }
94          if (FLAGS_animatedGif.isEmpty()) {
95              SkDebugf("Nothing specified for --animatedGif!");
96              return false;
97          }
98  
99          std::unique_ptr<SkStream> stream(GetResourceAsStream(FLAGS_animatedGif[0]));
100          if (!stream) {
101              return false;
102          }
103  
104          fCodec = SkCodec::MakeFromStream(std::move(stream));
105          if (!fCodec) {
106              return false;
107          }
108  
109          fFrame = 0;
110          fFrameInfos = fCodec->getFrameInfo();
111          fTotalFrames = fFrameInfos.size();
112          return true;
113      }
114  
onDraw(SkCanvas * canvas,SkString * errorMsg)115      DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
116          if (!this->initCodec()) {
117              errorMsg->printf("Could not create codec from %s", FLAGS_animatedGif[0]);
118              return DrawResult::kFail;
119          }
120  
121          canvas->save();
122          for (int frameIndex = 0; frameIndex < fTotalFrames; frameIndex++) {
123              this->drawFrame(canvas, frameIndex);
124              canvas->translate(SkIntToScalar(fCodec->getInfo().width()), 0);
125          }
126          canvas->restore();
127  
128          SkAutoCanvasRestore acr(canvas, true);
129          canvas->translate(0, SkIntToScalar(fCodec->getInfo().height()));
130          this->drawFrame(canvas, fFrame);
131          return DrawResult::kOk;
132      }
133  
onAnimate(const SkAnimTimer & timer)134      bool onAnimate(const SkAnimTimer& timer) override {
135          if (!fCodec || fTotalFrames == 1) {
136              return false;
137          }
138  
139          double secs = timer.msec() * .1;
140          if (fNextUpdate < double(0)) {
141              // This is a sentinel that we have not done any updates yet.
142              // I'm assuming this gets called *after* onOnceBeforeDraw, so our first frame should
143              // already have been retrieved.
144              SkASSERT(fFrame == 0);
145              fNextUpdate = secs + fFrameInfos[fFrame].fDuration;
146  
147              return true;
148          }
149  
150          if (secs < fNextUpdate) {
151              return true;
152          }
153  
154          while (secs >= fNextUpdate) {
155              // Retrieve the next frame.
156              fFrame++;
157              if (fFrame == fTotalFrames) {
158                  fFrame = 0;
159              }
160  
161              // Note that we loop here. This is not safe if we need to draw the intermediate frame
162              // in order to draw correctly.
163              fNextUpdate += fFrameInfos[fFrame].fDuration;
164          }
165  
166          return true;
167      }
168  };
169  DEF_GM(return new AnimatedGifGM);
170  
171  
172  #include "SkAnimCodecPlayer.h"
173  #include "SkOSFile.h"
174  #include "SkMakeUnique.h"
175  
load_codec(const char filename[])176  static std::unique_ptr<SkCodec> load_codec(const char filename[]) {
177      return SkCodec::MakeFromData(SkData::MakeFromFileName(filename));
178  }
179  
180  class AnimCodecPlayerGM : public skiagm::GM {
181  private:
182      std::vector<std::unique_ptr<SkAnimCodecPlayer> > fPlayers;
183      uint32_t          fBaseMSec = 0;
184  
185  public:
AnimCodecPlayerGM()186      AnimCodecPlayerGM() {
187          const char* root = "/skia/anim/";
188          SkOSFile::Iter iter(root);
189          SkString path;
190          while (iter.next(&path)) {
191              SkString completepath;
192              completepath.printf("%s%s", root, path.c_str());
193              auto codec = load_codec(completepath.c_str());
194              if (codec) {
195                  fPlayers.push_back(skstd::make_unique<SkAnimCodecPlayer>(std::move(codec)));
196              }
197          }
198      }
199  
200  private:
onShortName()201      SkString onShortName() override {
202          return SkString("AnimCodecPlayer");
203      }
204  
onISize()205      SkISize onISize() override {
206          return { 1024, 768 };
207      }
208  
onDraw(SkCanvas * canvas)209      void onDraw(SkCanvas* canvas) override {
210          canvas->scale(0.25f, 0.25f);
211          for (auto& p : fPlayers) {
212              canvas->drawImage(p->getFrame(), 0, 0, nullptr);
213              canvas->translate(p->dimensions().width(), 0);
214          }
215      }
216  
onAnimate(const SkAnimTimer & timer)217      bool onAnimate(const SkAnimTimer& timer) override {
218          if (fBaseMSec == 0) {
219              fBaseMSec = timer.msec();
220          }
221          for (auto& p : fPlayers) {
222              (void)p->seek(timer.msec() - fBaseMSec);
223          }
224          return true;
225      }
226  };
227  DEF_GM(return new AnimCodecPlayerGM);
228