aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules/skottie/src/SkottieTool.cpp
blob: 4038724f68649ded19b373c7d2b4d21cb41456b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkCanvas.h"
#include "SkCommandLineFlags.h"
#include "SkGraphics.h"
#include "SkOSFile.h"
#include "SkOSPath.h"
#include "SkStream.h"
#include "SkSurface.h"

#if defined(SK_ENABLE_SKOTTIE)
#include "Skottie.h"
#endif

DEFINE_string2(input, i, nullptr, "Input .json file.");
DEFINE_string2(writePath, w, nullptr, "Output directory.  Frames are names [0-9]{6}.png.");

DEFINE_double(t0,   0, "Timeline start [0..1].");
DEFINE_double(t1,   1, "Timeline stop [0..1].");
DEFINE_double(fps, 30, "Decode frames per second.");

DEFINE_int32(width , 800, "Render width.");
DEFINE_int32(height, 600, "Render height.");

int main(int argc, char** argv) {
#if defined(SK_ENABLE_SKOTTIE)
    SkCommandLineFlags::Parse(argc, argv);
    SkAutoGraphics ag;

    if (FLAGS_input.isEmpty() || FLAGS_writePath.isEmpty()) {
        SkDebugf("Missing required 'input' and 'writePath' args.\n");
        return 1;
    }

    if (FLAGS_fps <= 0) {
        SkDebugf("Invalid fps: %f.\n", FLAGS_fps);
        return 1;
    }

    if (!sk_mkdir(FLAGS_writePath[0])) {
        return 1;
    }

    auto anim = skottie::Animation::MakeFromFile(FLAGS_input[0]);
    if (!anim) {
        SkDebugf("Could not load animation: '%s'.\n", FLAGS_input[0]);
        return 1;
    }

    auto surface = SkSurface::MakeRasterN32Premul(FLAGS_width, FLAGS_height);
    if (!surface) {
        SkDebugf("Could not allocate a %d x %d buffer.\n", FLAGS_width, FLAGS_height);
        return 1;
    }

    auto* canvas = surface->getCanvas();
    canvas->concat(SkMatrix::MakeRectToRect(SkRect::MakeSize(anim->size()),
                                            SkRect::MakeIWH(FLAGS_width, FLAGS_height),
                                            SkMatrix::kCenter_ScaleToFit));

    static constexpr double kMaxFrames = 10000;
    const auto t0 = SkTPin(FLAGS_t0, 0.0, 1.0),
               t1 = SkTPin(FLAGS_t1,  t0, 1.0),
               advance = 1 / std::min(anim->duration() * FLAGS_fps, kMaxFrames);

    size_t frame_index = 0;
    for (auto t = t0; t <= t1; t += advance) {
        canvas->clear(SK_ColorTRANSPARENT);

        anim->seek(t);
        anim->render(canvas);

        auto png_data = surface->makeImageSnapshot()->encodeToData();
        if (!png_data) {
            SkDebugf("Failed to encode frame #%lu\n", frame_index);
            return 1;
        }

        const auto frame_file = SkStringPrintf("0%06d.png", frame_index++);

        SkFILEWStream wstream(SkOSPath::Join(FLAGS_writePath[0], frame_file.c_str()).c_str());
        if (!wstream.isValid()) {
            SkDebugf("Could not open '%s/%s' for writing.\n",
                     FLAGS_writePath[0], frame_file.c_str());
            return 1;
        }

        wstream.write(png_data->data(), png_data->size());
    }
#else
    SkDebugf("This tool requires Skottie support.\n");
#endif

    return 0;
}