bcfc554fde
Note: The polarity of the staging flag is inverted from usual because a G3 dependency with no SkUserConfig.h relies on the legacy API. Once this lands, we will migrate them and others, then remove the staging API. The inverted staging flag is kind of nice, actually - I may use that pattern in the future. It means less total CLs and it's just as easy to flip the bit on or off during debugging. Bug: skia:104662 Change-Id: I48cba1eeae3e2e6f79918c6d243e0666e68ec71b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/310656 Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Adlai Holler <adlai@google.com>
119 lines
3.5 KiB
C++
119 lines
3.5 KiB
C++
/*
|
|
* Copyright 2018 Google LLC
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "fuzz/Fuzz.h"
|
|
#include "include/core/SkBitmap.h"
|
|
#include "include/core/SkImage.h"
|
|
#include "include/core/SkImageInfo.h"
|
|
#include "include/core/SkPixmap.h"
|
|
#include "include/encode/SkJpegEncoder.h"
|
|
#include "include/encode/SkPngEncoder.h"
|
|
#include "include/encode/SkWebpEncoder.h"
|
|
#include "include/utils/SkRandom.h"
|
|
#include "src/core/SkOSFile.h"
|
|
|
|
#include <vector>
|
|
|
|
// These values were picked arbitrarily to hopefully limit the size of the
|
|
// serialized SkPixmaps.
|
|
constexpr int MAX_WIDTH = 512;
|
|
constexpr int MAX_HEIGHT = 512;
|
|
|
|
static SkBitmap make_fuzzed_bitmap(Fuzz* fuzz) {
|
|
SkBitmap bm;
|
|
uint32_t w, h;
|
|
fuzz->nextRange(&w, 1, MAX_WIDTH);
|
|
fuzz->nextRange(&h, 1, MAX_HEIGHT);
|
|
if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(w, h))) {
|
|
return bm;
|
|
}
|
|
uint32_t n = w * h;
|
|
fuzz->nextN((SkPMColor*)bm.getPixels(), n);
|
|
return bm;
|
|
}
|
|
|
|
DEF_FUZZ(PNGEncoder, fuzz) {
|
|
auto bm = make_fuzzed_bitmap(fuzz);
|
|
|
|
auto opts = SkPngEncoder::Options{};
|
|
fuzz->nextRange(&opts.fZLibLevel, 0, 9);
|
|
|
|
SkDynamicMemoryWStream dest;
|
|
SkPngEncoder::Encode(&dest, bm.pixmap(), opts);
|
|
}
|
|
|
|
DEF_FUZZ(JPEGEncoder, fuzz) {
|
|
auto bm = make_fuzzed_bitmap(fuzz);
|
|
|
|
auto opts = SkJpegEncoder::Options{};
|
|
fuzz->nextRange(&opts.fQuality, 0, 100);
|
|
|
|
SkDynamicMemoryWStream dest;
|
|
(void)SkJpegEncoder::Encode(&dest, bm.pixmap(), opts);
|
|
}
|
|
|
|
DEF_FUZZ(WEBPEncoder, fuzz) {
|
|
auto bm = make_fuzzed_bitmap(fuzz);
|
|
|
|
auto opts = SkWebpEncoder::Options{};
|
|
fuzz->nextRange(&opts.fQuality, 0.0f, 100.0f);
|
|
bool lossy;
|
|
fuzz->next(&lossy);
|
|
if (lossy) {
|
|
opts.fCompression = SkWebpEncoder::Compression::kLossy;
|
|
} else {
|
|
opts.fCompression = SkWebpEncoder::Compression::kLossless;
|
|
}
|
|
|
|
SkDynamicMemoryWStream dest;
|
|
(void)SkWebpEncoder::Encode(&dest, bm.pixmap(), opts);
|
|
}
|
|
|
|
// Not a real fuzz endpoint, but a helper to take in real, good images
|
|
// and dump out a corpus for this fuzzer.
|
|
DEF_FUZZ(_MakeEncoderCorpus, fuzz) {
|
|
auto bytes = fuzz->fBytes;
|
|
SkDebugf("bytes %d\n", bytes->size());
|
|
auto img = SkImage::MakeFromEncoded(bytes);
|
|
if (nullptr == img.get()) {
|
|
SkDebugf("invalid image, could not decode\n");
|
|
return;
|
|
}
|
|
if (img->width() > MAX_WIDTH || img->height() > MAX_HEIGHT) {
|
|
SkDebugf("Too big (%d x %d)\n", img->width(), img->height());
|
|
return;
|
|
}
|
|
std::vector<int32_t> dstPixels;
|
|
int rowBytes = img->width() * 4;
|
|
dstPixels.resize(img->height() * rowBytes);
|
|
SkPixmap pm(SkImageInfo::MakeN32Premul(img->width(), img->height()),
|
|
&dstPixels.front(), rowBytes);
|
|
if (!img->readPixels(nullptr, pm, 0, 0)) {
|
|
SkDebugf("Could not read pixmap\n");
|
|
return;
|
|
}
|
|
|
|
SkString s("./encoded_corpus/enc_");
|
|
static SkRandom rand;
|
|
s.appendU32(rand.nextU());
|
|
auto file = sk_fopen(s.c_str(), SkFILE_Flags::kWrite_SkFILE_Flag);
|
|
if (!file) {
|
|
SkDebugf("Can't initialize file\n");
|
|
return;
|
|
}
|
|
auto total = pm.info().bytesPerPixel() * pm.width() * pm.height();
|
|
SkDebugf("Writing %d (%d x %d) bytes\n", total, pm.width(), pm.height());
|
|
// Write out the size in two bytes since that's what the fuzzer will
|
|
// read first.
|
|
uint32_t w = pm.width();
|
|
sk_fwrite(&w, sizeof(uint32_t), file);
|
|
uint32_t h = pm.height();
|
|
sk_fwrite(&h, sizeof(uint32_t), file);
|
|
sk_fwrite(pm.addr(), total, file);
|
|
sk_fclose(file);
|
|
}
|