add runtime registration for encoders

If we want to make these external dependencies mix-and-match in Google3,
we'll need to group together the encoders and decoders, everything that
dependends on each external library.

I was tempted to try to remove these generic encoder entrypoints and
replace them with calls to the direct equivalents, but I'm not sure
that's necessary.  I think we can just register encoders like decoders.

Change-Id: I41d2d1bb3ceb1daafa62c95d345eb6a70249be75
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/213880
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Mike Klein 2019-05-15 11:45:43 -05:00 committed by Skia Commit-Bot
parent 753836fcad
commit 940c3f136d
6 changed files with 69 additions and 48 deletions

View File

@ -15,6 +15,9 @@
#include "include/core/SkDocument.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkGraphics.h"
#include "include/encode/SkJpegEncoder.h"
#include "include/encode/SkPngEncoder.h"
#include "include/encode/SkWebpEncoder.h"
#include "include/ports/SkTypeface_win.h"
#include "include/private/SkChecksum.h"
#include "include/private/SkHalf.h"
@ -1394,6 +1397,10 @@ int main(int argc, char** argv) {
SkCodec::Register( SkPngCodec::IsPng , SkPngCodec::MakeFromStream);
SkCodec::Register(SkWebpCodec::IsWebp, SkWebpCodec::MakeFromStream);
SkRegisterEncoder(SkEncodedImageFormat::kJPEG, SkJpegEncoder::Encode);
SkRegisterEncoder(SkEncodedImageFormat::kPNG , SkPngEncoder::Encode);
SkRegisterEncoder(SkEncodedImageFormat::kWEBP, SkWebpEncoder::Encode);
initializeEventTracingForTools();
#if !defined(SK_BUILD_FOR_GOOGLE3) && defined(SK_BUILD_FOR_IOS)

View File

@ -44,6 +44,16 @@ inline bool SkEncodeImage(SkWStream* dst, const SkBitmap& src, SkEncodedImageFor
return src.peekPixels(&pixmap) && SkEncodeImage(dst, pixmap, f, q);
}
/**
* Register an encoder for a given binary image format.
*
* This encoder may be used by SkEncodeImage / SkEncodePixmap / SkEncodeBitmap.
*
* Not thread safe.
*/
SK_API void SkRegisterEncoder(SkEncodedImageFormat fmt,
bool(*)(SkWStream*, const SkPixmap&, int quality));
/**
* Encode SkPixmap in the given binary image format.
*

View File

@ -71,6 +71,12 @@ public:
*/
static bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options);
static bool Encode(SkWStream* dst, const SkPixmap& src, int quality) {
Options options;
options.fQuality = quality;
return Encode(dst, src, options);
}
/**
* Create a jpeg encoder that will encode the |src| pixels to the |dst| stream.
* |options| may be used to control the encoding behavior.

View File

@ -69,6 +69,10 @@ public:
*/
static bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options);
static bool Encode(SkWStream* dst, const SkPixmap& src, int /*quality*/) {
return Encode(dst, src, Options{});
}
/**
* Create a png encoder that will encode the |src| pixels to the |dst| stream.
* |options| may be used to control the encoding behavior.

View File

@ -43,6 +43,20 @@ namespace SkWebpEncoder {
* Returns true on success. Returns false on an invalid or unsupported |src|.
*/
SK_API bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options);
inline bool Encode(SkWStream* dst, const SkPixmap& src, int quality) {
SkWebpEncoder::Options opts;
if (quality == 100) {
// fQuality acts as a signal for how much time to invest encoding a smaller file.
// This value matches blink::ImageEncoder::ComputeWebpOptions and WebPConfigInit.
opts.fQuality = 75;
opts.fCompression = SkWebpEncoder::Compression::kLossless;
} else {
opts.fQuality = quality;
opts.fCompression = SkWebpEncoder::Compression::kLossy;
}
return SkWebpEncoder::Encode(dst, src, opts);
}
}
#endif

View File

@ -9,24 +9,34 @@
#include "include/encode/SkPngEncoder.h"
#include "include/encode/SkWebpEncoder.h"
#include "src/images/SkImageEncoderPriv.h"
#include <vector>
#ifndef SK_HAS_JPEG_LIBRARY
bool SkJpegEncoder::Encode(SkWStream*, const SkPixmap&, const Options&) { return false; }
std::unique_ptr<SkEncoder> SkJpegEncoder::Make(SkWStream*, const SkPixmap&, const Options&) {
return nullptr;
struct EncoderProc {
SkEncodedImageFormat format;
bool (*encode)(SkWStream*, const SkPixmap&, int quality);
};
static std::vector<EncoderProc>* encoders() {
static auto* encoders = new std::vector<EncoderProc> {
#ifdef SK_HAS_JPEG_LIBRARY
{ SkEncodedImageFormat::kJPEG, SkJpegEncoder::Encode },
#endif
#ifdef SK_HAS_PNG_LIBRARY
{ SkEncodedImageFormat::kPNG, SkPngEncoder::Encode },
#endif
#ifdef SK_HAS_WEBP_LIBRARY
{ SkEncodedImageFormat::kWEBP, SkWebpEncoder::Encode },
#endif
};
return encoders;
}
#endif
#ifndef SK_HAS_PNG_LIBRARY
bool SkPngEncoder::Encode(SkWStream*, const SkPixmap&, const Options&) { return false; }
std::unique_ptr<SkEncoder> SkPngEncoder::Make(SkWStream*, const SkPixmap&, const Options&) {
return nullptr;
void SkRegisterEncoder(SkEncodedImageFormat format,
bool (*encode)(SkWStream*, const SkPixmap&, int)) {
encoders()->push_back({format, encode});
}
#endif
#ifndef SK_HAS_WEBP_LIBRARY
bool SkWebpEncoder::Encode(SkWStream*, const SkPixmap&, const Options&) { return false; }
#endif
bool SkEncodeImage(SkWStream* dst, const SkPixmap& src,
SkEncodedImageFormat format, int quality) {
@ -36,42 +46,12 @@ bool SkEncodeImage(SkWStream* dst, const SkPixmap& src,
#elif SK_USE_WIC_ENCODER
return SkEncodeImageWithWIC(dst, src, format, quality);
#else
switch(format) {
case SkEncodedImageFormat::kJPEG: {
SkJpegEncoder::Options opts;
opts.fQuality = quality;
return SkJpegEncoder::Encode(dst, src, opts);
for (auto encoder : *encoders()) {
if (encoder.format == format) {
return encoder.encode(dst, src, quality);
}
case SkEncodedImageFormat::kPNG: {
SkPngEncoder::Options opts;
return SkPngEncoder::Encode(dst, src, opts);
}
case SkEncodedImageFormat::kWEBP: {
SkWebpEncoder::Options opts;
if (quality == 100) {
opts.fCompression = SkWebpEncoder::Compression::kLossless;
// Note: SkEncodeImage treats 0 quality as the lowest quality
// (greatest compression) and 100 as the highest quality (least
// compression). For kLossy, this matches libwebp's
// interpretation, so it is passed directly to libwebp. But
// with kLossless, libwebp always creates the highest quality
// image. In this case, fQuality is reinterpreted as how much
// effort (time) to put into making a smaller file. This API
// does not provide a way to specify this value (though it can
// be specified by using SkWebpEncoder::Encode) so we have to
// pick one arbitrarily. This value matches that chosen by
// blink::ImageEncoder::ComputeWebpOptions as well
// WebPConfigInit.
opts.fQuality = 75;
} else {
opts.fCompression = SkWebpEncoder::Compression::kLossy;
opts.fQuality = quality;
}
return SkWebpEncoder::Encode(dst, src, opts);
}
default:
return false;
}
return false;
#endif
}