xref: /third_party/skia/fuzz/FuzzEncoders.cpp (revision cb93a386)
1/*
2 * Copyright 2018 Google LLC
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 "fuzz/Fuzz.h"
9#include "include/core/SkBitmap.h"
10#include "include/core/SkImage.h"
11#include "include/core/SkImageInfo.h"
12#include "include/core/SkPixmap.h"
13#include "include/encode/SkJpegEncoder.h"
14#include "include/encode/SkPngEncoder.h"
15#include "include/encode/SkWebpEncoder.h"
16#include "include/utils/SkRandom.h"
17#include "src/core/SkOSFile.h"
18
19#include <vector>
20
21// These values were picked arbitrarily to hopefully limit the size of the
22// serialized SkPixmaps.
23constexpr int MAX_WIDTH = 512;
24constexpr int MAX_HEIGHT = 512;
25
26static SkBitmap make_fuzzed_bitmap(Fuzz* fuzz) {
27    SkBitmap bm;
28    uint32_t w, h;
29    fuzz->nextRange(&w, 1, MAX_WIDTH);
30    fuzz->nextRange(&h, 1, MAX_HEIGHT);
31    if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(w, h))) {
32        return bm;
33    }
34    uint32_t n = w * h;
35    fuzz->nextN((SkPMColor*)bm.getPixels(), n);
36    return bm;
37}
38
39DEF_FUZZ(PNGEncoder, fuzz) {
40    auto bm = make_fuzzed_bitmap(fuzz);
41
42    auto opts = SkPngEncoder::Options{};
43    fuzz->nextRange(&opts.fZLibLevel, 0, 9);
44
45    SkDynamicMemoryWStream dest;
46    SkPngEncoder::Encode(&dest, bm.pixmap(), opts);
47}
48
49DEF_FUZZ(JPEGEncoder, fuzz) {
50    auto bm = make_fuzzed_bitmap(fuzz);
51
52    auto opts = SkJpegEncoder::Options{};
53    fuzz->nextRange(&opts.fQuality, 0, 100);
54
55    SkDynamicMemoryWStream dest;
56    (void)SkJpegEncoder::Encode(&dest, bm.pixmap(), opts);
57}
58
59DEF_FUZZ(WEBPEncoder, fuzz) {
60    auto bm = make_fuzzed_bitmap(fuzz);
61
62    auto opts = SkWebpEncoder::Options{};
63    fuzz->nextRange(&opts.fQuality, 0.0f, 100.0f);
64    bool lossy;
65    fuzz->next(&lossy);
66    if (lossy) {
67        opts.fCompression = SkWebpEncoder::Compression::kLossy;
68    } else {
69        opts.fCompression = SkWebpEncoder::Compression::kLossless;
70    }
71
72    SkDynamicMemoryWStream dest;
73    (void)SkWebpEncoder::Encode(&dest, bm.pixmap(), opts);
74}
75
76// Not a real fuzz endpoint, but a helper to take in real, good images
77// and dump out a corpus for this fuzzer.
78DEF_FUZZ(_MakeEncoderCorpus, fuzz) {
79    auto bytes = fuzz->fBytes;
80    SkDebugf("bytes %zu\n", bytes->size());
81    auto img = SkImage::MakeFromEncoded(bytes);
82    if (nullptr == img.get()) {
83        SkDebugf("invalid image, could not decode\n");
84        return;
85    }
86    if (img->width() > MAX_WIDTH || img->height() > MAX_HEIGHT) {
87        SkDebugf("Too big (%d x %d)\n", img->width(), img->height());
88        return;
89    }
90    std::vector<int32_t> dstPixels;
91    int rowBytes = img->width() * 4;
92    dstPixels.resize(img->height() * rowBytes);
93    SkPixmap pm(SkImageInfo::MakeN32Premul(img->width(), img->height()),
94        &dstPixels.front(), rowBytes);
95    if (!img->readPixels(nullptr, pm, 0, 0)) {
96        SkDebugf("Could not read pixmap\n");
97        return;
98    }
99
100    SkString s("./encoded_corpus/enc_");
101    static SkRandom rand;
102    s.appendU32(rand.nextU());
103    auto file = sk_fopen(s.c_str(), SkFILE_Flags::kWrite_SkFILE_Flag);
104    if (!file) {
105        SkDebugf("Can't initialize file\n");
106        return;
107    }
108    auto total = pm.info().bytesPerPixel() * pm.width() * pm.height();
109    SkDebugf("Writing %d (%d x %d) bytes\n", total, pm.width(), pm.height());
110    // Write out the size in two bytes since that's what the fuzzer will
111    // read first.
112    uint32_t w = pm.width();
113    sk_fwrite(&w, sizeof(uint32_t), file);
114    uint32_t h = pm.height();
115    sk_fwrite(&h, sizeof(uint32_t), file);
116    sk_fwrite(pm.addr(), total, file);
117    sk_fclose(file);
118}
119