Add MVP implementation of JPEGXL decoder.

Change-Id: I90140348eeb87c849a857a12008c201efc9e328d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/482596
Reviewed-by: Leon Scroggins <scroggo@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Evgenii Kliuchnikov 2022-02-02 13:45:33 +00:00 committed by SkCQ
parent d161e2f6ec
commit 0dae2e870d
12 changed files with 710 additions and 0 deletions

View File

@ -1054,6 +1054,14 @@ optional("jpeg_encode") {
]
}
optional("jpegxl_decode") {
enabled = skia_use_libjxl_decode
public_defines = [ "SK_CODEC_DECODES_JPEGXL" ]
deps = [ "//third_party/libjxl" ]
sources = [ "src/codec/SkJpegxlCodec.cpp" ]
}
optional("ndk_images") {
enabled = skia_use_ndk_images
public_defines = [ "SK_ENABLE_NDK_IMAGES" ]
@ -1285,6 +1293,7 @@ skia_component("skia") {
":hsw",
":jpeg_decode",
":jpeg_encode",
":jpegxl_decode",
":ndk_images",
":none",
":png_decode",

2
DEPS
View File

@ -26,10 +26,12 @@ deps = {
"third_party/externals/expat" : "https://chromium.googlesource.com/external/github.com/libexpat/libexpat.git@a28238bdeebc087071777001245df1876a11f5ee",
"third_party/externals/freetype" : "https://chromium.googlesource.com/chromium/src/third_party/freetype2.git@5e9caaee7885cbc82f9f821bbec7f6c86f25b33a",
"third_party/externals/harfbuzz" : "https://chromium.googlesource.com/external/github.com/harfbuzz/harfbuzz.git@a8b7f1880412c7f0c9ecdada0a4935011816c7dc",
"third_party/externals/highway" : "https://chromium.googlesource.com/external/github.com/google/highway.git@424360251cdcfc314cfc528f53c872ecd63af0f0",
"third_party/externals/icu" : "https://chromium.googlesource.com/chromium/deps/icu.git@a0718d4f121727e30b8d52c7a189ebf5ab52421f",
"third_party/externals/imgui" : "https://skia.googlesource.com/external/github.com/ocornut/imgui.git@55d35d8387c15bf0cfd71861df67af8cfbda7456",
"third_party/externals/libgifcodec" : "https://skia.googlesource.com/libgifcodec@fd59fa92a0c86788dcdd84d091e1ce81eda06a77",
"third_party/externals/libjpeg-turbo" : "https://chromium.googlesource.com/chromium/deps/libjpeg_turbo.git@24e310554f07c0fdb8ee52e3e708e4f3e9eb6e20",
"third_party/externals/libjxl" : "https://chromium.googlesource.com/external/gitlab.com/wg1/jpeg-xl.git@a205468bc5d3a353fb15dae2398a101dff52f2d3",
"third_party/externals/libpng" : "https://skia.googlesource.com/third_party/libpng.git@386707c6d19b974ca2e3db7f5c61873813c6fe44",
"third_party/externals/libwebp" : "https://chromium.googlesource.com/webm/libwebp.git@69c7f16111ec582bf1e7cb4d0d4f8d127e28a715",
"third_party/externals/microhttpd" : "https://android.googlesource.com/platform/external/libmicrohttpd@748945ec6f1c67b7efc934ab0808e1d32f2fb98d",

View File

@ -58,6 +58,7 @@ Milestone 98
will return nullptr.
* Removed SkCanvas::markCTM and SkCanvas::findMarkedCTM. These were created to be used with other
features that have since been deleted, so they served no purpose.
* Added limited JPEGXL support.
* * *

View File

@ -54,6 +54,7 @@ declare_args() {
skia_use_libheif = is_skia_dev_build
skia_use_libjpeg_turbo_decode = true
skia_use_libjpeg_turbo_encode = true
skia_use_libjxl_decode = false
skia_use_libpng_decode = true
skia_use_libpng_encode = true
skia_use_libwebp_decode = true

View File

@ -30,6 +30,7 @@ enum class SkEncodedImageFormat {
kDNG,
kHEIF,
kAVIF,
kJPEGXL,
};
#endif // SkEncodedImageFormat_DEFINED

View File

@ -31,6 +31,10 @@
#include "src/codec/SkJpegCodec.h"
#endif
#ifdef SK_CODEC_DECODES_JPEGXL
#include "src/codec/SkJpegxlCodec.h"
#endif
#ifdef SK_CODEC_DECODES_PNG
#include "src/codec/SkIcoCodec.h"
#include "src/codec/SkPngCodec.h"
@ -73,6 +77,9 @@ static std::vector<DecoderProc>* decoders() {
#endif
{ SkBmpCodec::IsBmp, SkBmpCodec::MakeFromStream },
{ SkWbmpCodec::IsWbmp, SkWbmpCodec::MakeFromStream },
#ifdef SK_CODEC_DECODES_JPEGXL
{ SkJpegxlCodec::IsJpegxl, SkJpegxlCodec::MakeFromStream },
#endif
};
return decoders;
}

453
src/codec/SkJpegxlCodec.cpp Normal file
View File

@ -0,0 +1,453 @@
/*
* Copyright 2021 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/codec/SkJpegxlCodec.h"
#include <limits>
#include <vector>
#include "include/codec/SkEncodedOrigin.h"
#include "include/core/SkData.h"
#include "include/core/SkEncodedImageFormat.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkStream.h"
#include "include/private/SkEncodedInfo.h"
#include "include/private/SkTFitsIn.h"
#include "include/private/SkTo.h"
#include "jxl/decode.h"
#include "jxl/decode_cxx.h"
#include "src/codec/SkFrameHolder.h"
#include "src/codec/SkSampler.h"
#include "src/core/SkOpts.h"
#include "src/core/SkStreamPriv.h"
namespace {
class Frame : public SkFrame {
public:
explicit Frame(int i, SkEncodedInfo::Alpha alpha) : INHERITED(i), fReportedAlpha(alpha) {}
SkEncodedInfo::Alpha onReportedAlpha() const override { return fReportedAlpha; }
private:
const SkEncodedInfo::Alpha fReportedAlpha;
using INHERITED = SkFrame;
};
} // namespace
bool SkJpegxlCodec::IsJpegxl(const void* buffer, size_t bytesRead) {
JxlSignature result = JxlSignatureCheck(reinterpret_cast<const uint8_t*>(buffer), bytesRead);
return (result == JXL_SIG_CODESTREAM) || (result == JXL_SIG_CONTAINER);
}
class SkJpegxlCodecPriv : public SkFrameHolder {
public:
SkJpegxlCodecPriv() : fDecoder(JxlDecoderMake(/* memory_manager= */ nullptr)) {}
JxlDecoderPtr fDecoder; // unique_ptr with custom destructor
JxlBasicInfo fInfo;
bool fSeenAllFrames = false;
std::vector<Frame> fFrames;
int fLastProcessedFrame = SkCodec::kNoFrame;
void* fDst;
size_t fPixelShift;
size_t fRowBytes;
SkColorType fDstColorType;
protected:
const SkFrame* onGetFrame(int i) const override {
SkASSERT(i >= 0 && static_cast<size_t>(i) < fFrames.size());
return static_cast<const SkFrame*>(&fFrames[i]);
}
};
SkJpegxlCodec::SkJpegxlCodec(std::unique_ptr<SkJpegxlCodecPriv> codec,
SkEncodedInfo&& info,
std::unique_ptr<SkStream> stream,
sk_sp<SkData> data)
: INHERITED(std::move(info), skcms_PixelFormat_RGBA_16161616LE, std::move(stream))
, fCodec(std::move(codec))
, fData(std::move(data)) {}
std::unique_ptr<SkCodec> SkJpegxlCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
Result* result) {
*result = kInternalError;
// Either wrap or copy stream data.
sk_sp<SkData> data = nullptr;
if (stream->getMemoryBase()) {
data = SkData::MakeWithoutCopy(stream->getMemoryBase(), stream->getLength());
} else {
data = SkCopyStreamToData(stream.get());
// Data is copied; stream can be released now.
stream.reset(nullptr);
}
auto priv = std::make_unique<SkJpegxlCodecPriv>();
JxlDecoder* dec = priv->fDecoder.get();
// Only query metadata this time.
auto status = JxlDecoderSubscribeEvents(dec, JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING);
if (status != JXL_DEC_SUCCESS) {
// Fresh instance must accept request for subscription.
SkDEBUGFAIL("libjxl returned unexpected status");
return nullptr;
}
status = JxlDecoderSetInput(dec, data->bytes(), data->size());
if (status != JXL_DEC_SUCCESS) {
// Fresh instance must accept first chunk of input.
SkDEBUGFAIL("libjxl returned unexpected status");
return nullptr;
}
status = JxlDecoderProcessInput(dec);
if (status == JXL_DEC_NEED_MORE_INPUT) {
*result = kIncompleteInput;
return nullptr;
}
if (status != JXL_DEC_BASIC_INFO) {
*result = kInvalidInput;
return nullptr;
}
JxlBasicInfo& info = priv->fInfo;
status = JxlDecoderGetBasicInfo(dec, &info);
if (status != JXL_DEC_SUCCESS) {
// Current event is "JXL_DEC_BASIC_INFO" -> can't fail.
SkDEBUGFAIL("libjxl returned unexpected status");
return nullptr;
}
// Check that image dimensions are not too large.
if (!SkTFitsIn<int32_t>(info.xsize) || !SkTFitsIn<int32_t>(info.ysize)) {
*result = kInvalidInput;
return nullptr;
}
int32_t width = SkTo<int32_t>(info.xsize);
int32_t height = SkTo<int32_t>(info.ysize);
bool hasAlpha = (info.alpha_bits != 0);
bool isGray = (info.num_color_channels == 1);
SkEncodedInfo::Alpha alpha =
hasAlpha ? SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha;
SkEncodedInfo::Color color;
if (hasAlpha) {
color = isGray ? SkEncodedInfo::kGrayAlpha_Color : SkEncodedInfo::kRGBA_Color;
} else {
color = isGray ? SkEncodedInfo::kGray_Color : SkEncodedInfo::kRGB_Color;
}
status = JxlDecoderProcessInput(dec);
if (status != JXL_DEC_COLOR_ENCODING) {
*result = kInvalidInput;
return nullptr;
}
size_t iccSize = 0;
// TODO(eustas): format field is currently ignored by decoder.
status = JxlDecoderGetICCProfileSize(
dec, /* format = */ nullptr, JXL_COLOR_PROFILE_TARGET_DATA, &iccSize);
if (status != JXL_DEC_SUCCESS) {
// Likely incompatible colorspace.
iccSize = 0;
}
std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
if (iccSize) {
auto icc = SkData::MakeUninitialized(iccSize);
// TODO(eustas): format field is currently ignored by decoder.
status = JxlDecoderGetColorAsICCProfile(dec,
/* format = */ nullptr,
JXL_COLOR_PROFILE_TARGET_DATA,
reinterpret_cast<uint8_t*>(icc->writable_data()),
iccSize);
if (status != JXL_DEC_SUCCESS) {
// Current event is JXL_DEC_COLOR_ENCODING -> can't fail.
SkDEBUGFAIL("libjxl returned unexpected status");
return nullptr;
}
profile = SkEncodedInfo::ICCProfile::Make(std::move(icc));
}
int bitsPerChannel = 16;
*result = kSuccess;
SkEncodedInfo encodedInfo =
SkEncodedInfo::Make(width, height, color, alpha, bitsPerChannel, std::move(profile));
return std::unique_ptr<SkCodec>(new SkJpegxlCodec(
std::move(priv), std::move(encodedInfo), std::move(stream), std::move(data)));
}
SkCodec::Result SkJpegxlCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
const Options& options, int* rowsDecodedPtr) {
// TODO(eustas): implement
if (options.fSubset) {
return kUnimplemented;
}
auto& codec = *fCodec.get();
const int index = options.fFrameIndex;
SkASSERT(0 == index || static_cast<size_t>(index) < codec.fFrames.size());
auto* dec = codec.fDecoder.get();
JxlDecoderStatus status;
if ((codec.fLastProcessedFrame >= index) || (codec.fLastProcessedFrame = SkCodec::kNoFrame)) {
codec.fLastProcessedFrame = SkCodec::kNoFrame;
JxlDecoderRewind(dec);
status = JxlDecoderSubscribeEvents(dec, JXL_DEC_FRAME | JXL_DEC_FULL_IMAGE);
if (status != JXL_DEC_SUCCESS) {
// Fresh decoder instance (after rewind) must accept subscription request.
SkDEBUGFAIL("libjxl returned unexpected status");
return kInternalError;
}
status = JxlDecoderSetInput(dec, fData->bytes(), fData->size());
if (status != JXL_DEC_SUCCESS) {
// Fresh decoder instance (after rewind) must accept first data chunk.
SkDEBUGFAIL("libjxl returned unexpected status");
return kInternalError;
}
SkASSERT(codec.fLastProcessedFrame + 1 == 0);
}
int nextFrame = codec.fLastProcessedFrame + 1;
if (nextFrame < index) {
JxlDecoderSkipFrames(dec, index - nextFrame);
}
// Decode till the frame start.
status = JxlDecoderProcessInput(dec);
// TODO(eustas): actually, frame is not completely processed; for streaming / partial decoding
// we should also add a flag that "last processed frame" is still incomplete, and
// flip that flag when frame decoding is over.
codec.fLastProcessedFrame = index;
if (status != JXL_DEC_FRAME) {
// TODO(eustas): check status: it might be either corrupted or incomplete input.
return kInternalError;
}
codec.fDst = dst;
codec.fRowBytes = rowBytes;
// TODO(eustas): consider grayscale.
uint32_t numColorChannels = 3;
// TODO(eustas): consider no-alpha.
uint32_t numAlphaChannels = 1;
// NB: SKIA works with little-endian F16s.
auto endianness = JXL_LITTLE_ENDIAN;
// Internally JXL does most processing in floats. By "default" we request
// output data type to be U8; it takes less memory, but results in some precision loss.
// We request F16 in two cases:
// - destination type is F16
// - color transformation is required; in this case values are remapped,
// and with 8-bit precision it is likely that visual artefact will appear
// (like banding, etc.)
bool halfFloatOutput = false;
if (fCodec->fDstColorType == kRGBA_F16_SkColorType) halfFloatOutput = true;
if (colorXform()) halfFloatOutput = true;
auto dataType = halfFloatOutput ? JXL_TYPE_FLOAT16 : JXL_TYPE_UINT8;
JxlPixelFormat format =
{numColorChannels + numAlphaChannels, dataType, endianness, /* align = */ 0};
status = JxlDecoderSetImageOutCallback(dec, &format, SkJpegxlCodec::imageOutCallback, this);
if (status != JXL_DEC_SUCCESS) {
// Current event is JXL_DEC_FRAME -> decoder must accept callback.
SkDEBUGFAIL("libjxl returned unexpected status");
return kInternalError;
}
// Decode till the frame start.
status = JxlDecoderProcessInput(dec);
if (status != JXL_DEC_FULL_IMAGE) {
// TODO(eustas): check status: it might be either corrupted or incomplete input.
return kInternalError;
}
// TODO(eustas): currently it is supposed that complete input is accessible;
// when streaming support is added JXL_DEC_NEED_MORE_INPUT would also
// become a legal outcome; amount of decoded scanlines should be calculated
// based on callback invocations / render-pipeline API.
*rowsDecodedPtr = dstInfo.height();
return kSuccess;
}
bool SkJpegxlCodec::onRewind() {
JxlDecoderRewind(fCodec->fDecoder.get());
return true;
}
bool SkJpegxlCodec::conversionSupported(const SkImageInfo& dstInfo, bool srcIsOpaque,
bool needsColorXform) {
fCodec->fDstColorType = dstInfo.colorType();
switch (dstInfo.colorType()) {
case kRGBA_8888_SkColorType:
return true; // memcpy
case kBGRA_8888_SkColorType:
return true; // rgba->bgra
case kRGBA_F16_SkColorType:
SkASSERT(needsColorXform); // TODO(eustas): not necessary for JXL.
return true; // memcpy
// TODO(eustas): implement
case kRGB_565_SkColorType:
return false;
case kGray_8_SkColorType:
return false;
case kAlpha_8_SkColorType:
return false;
default:
return false;
}
return true;
}
void SkJpegxlCodec::imageOutCallback(void* opaque, size_t x, size_t y,
size_t num_pixels, const void* pixels) {
SkJpegxlCodec* instance = reinterpret_cast<SkJpegxlCodec*>(opaque);
auto& codec = *instance->fCodec.get();
size_t offset = y * codec.fRowBytes + (x << codec.fPixelShift);
void* dst = SkTAddOffset<void>(codec.fDst, offset);
if (instance->colorXform()) {
instance->applyColorXform(dst, pixels, num_pixels);
return;
}
switch (codec.fDstColorType) {
case kRGBA_8888_SkColorType:
memcpy(dst, pixels, 4 * num_pixels);
return;
case kBGRA_8888_SkColorType:
SkOpts::RGBA_to_bgrA((uint32_t*) dst, (const uint32_t*)(pixels), num_pixels);
return;
case kRGBA_F16_SkColorType:
memcpy(dst, pixels, 8 * num_pixels);
return;
default:
SK_ABORT("Selected output format is not supported yet");
return;
}
}
bool SkJpegxlCodec::scanFrames() {
auto decoder = JxlDecoderMake(/* memory_manager = */ nullptr);
JxlDecoder* dec = decoder.get();
auto* frameHolder = fCodec.get();
auto& frames = frameHolder->fFrames;
const auto& info = fCodec->fInfo;
frames.clear();
auto alpha = (info.alpha_bits != 0) ? SkEncodedInfo::Alpha::kUnpremul_Alpha
: SkEncodedInfo::Alpha::kOpaque_Alpha;
auto status = JxlDecoderSubscribeEvents(dec, JXL_DEC_FRAME);
if (status != JXL_DEC_SUCCESS) {
// Fresh instance must accept request for subscription.
SkDEBUGFAIL("libjxl returned unexpected status");
return true;
}
status = JxlDecoderSetInput(dec, fData->bytes(), fData->size());
if (status != JXL_DEC_SUCCESS) {
// Fresh instance must accept first input chunk.
SkDEBUGFAIL("libjxl returned unexpected status");
return true;
}
while (true) {
status = JxlDecoderProcessInput(dec);
switch (status) {
case JXL_DEC_FRAME: {
size_t frameId = frames.size();
JxlFrameHeader frameHeader;
if (JxlDecoderGetFrameHeader(dec, &frameHeader) != JXL_DEC_SUCCESS) {
return true;
}
frames.emplace_back(static_cast<int>(frameId), alpha);
auto& frame = frames.back();
// TODO(eustas): for better consistency we need to track total duration and report
// frame duration as delta to previous frame.
int duration = (1000 * frameHeader.duration * info.animation.tps_denominator) /
info.animation.tps_numerator;
frame.setDuration(duration);
frameHolder->setAlphaAndRequiredFrame(&frame);
break;
}
case JXL_DEC_SUCCESS: {
return true;
}
default: {
return false;
}
}
}
}
int SkJpegxlCodec::onGetFrameCount() {
if (!fCodec->fInfo.have_animation) {
return 1;
}
if (!fCodec->fSeenAllFrames) {
fCodec->fSeenAllFrames = scanFrames();
}
return fCodec->fFrames.size();
}
bool SkJpegxlCodec::onGetFrameInfo(int index, FrameInfo* frameInfo) const {
if (index < 0) {
return false;
}
if (static_cast<size_t>(index) >= fCodec->fFrames.size()) {
return false;
}
fCodec->fFrames[index].fillIn(frameInfo, true);
return true;
}
int SkJpegxlCodec::onGetRepetitionCount() {
JxlBasicInfo& info = fCodec->fInfo;
if (!info.have_animation) {
return 0;
}
if (info.animation.num_loops == 0) {
return kRepetitionCountInfinite;
}
if (SkTFitsIn<int>(info.animation.num_loops)) {
return info.animation.num_loops - 1;
}
// Largest "non-infinite" value.
return std::numeric_limits<int>::max();
}
const SkFrameHolder* SkJpegxlCodec::getFrameHolder() const {
return fCodec.get();
}
// TODO(eustas): implement
// SkCodec::Result SkJpegxlCodec::onStartScanlineDecode(
// const SkImageInfo& /*dstInfo*/, const Options& /*options*/) { return kUnimplemented; }
// TODO(eustas): implement
// SkCodec::Result SkJpegxlCodec::onStartIncrementalDecode(
// const SkImageInfo& /*dstInfo*/, void*, size_t, const Options&) { return kUnimplemented; }
// TODO(eustas): implement
// SkCodec::Result SkJpegxlCodec::onIncrementalDecode(int*) { return kUnimplemented; }
// TODO(eustas): implement
// bool SkJpegxlCodec::onSkipScanlines(int /*countLines*/) { return false; }
// TODO(eustas): implement
// int SkJpegxlCodec::onGetScanlines(
// void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; }
// TODO(eustas): implement
// SkSampler* SkJpegxlCodec::getSampler(bool /*createIfNecessary*/) { return nullptr; }

105
src/codec/SkJpegxlCodec.h Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright 2021 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkJpegxlCodec_DEFINED
#define SkJpegxlCodec_DEFINED
#include <memory>
#include "src/codec/SkScalingCodec.h"
enum class SkEncodedImageFormat;
struct SkEncodedInfo;
enum SkEncodedOrigin;
class SkFrameHolder;
struct SkImageInfo;
class SkJpegxlCodecPriv;
class SkSampler;
class SkStream;
/*
*
* This class implements the decoding for jpegxl images
*
*/
class SkJpegxlCodec : public SkScalingCodec {
public:
static bool IsJpegxl(const void*, size_t);
/*
* Assumes IsJpegxl was called and returned true
* Takes ownership of the stream
*/
static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result*);
protected:
/* TODO(eustas): implement when downscaling is supported. */
/* SkISize onGetScaledDimensions(float desiredScale) const override; */
/* TODO(eustas): implement when up-/down-scaling is supported. */
/* bool onDimensionsSupported(const SkISize&) override; */
SkEncodedImageFormat onGetEncodedFormat() const override {
return SkEncodedImageFormat::kJPEGXL;
}
Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
const Options& options, int* rowsDecodedPtr) override;
/* TODO(eustas): add support for transcoded JPEG images? */
/* bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&,
SkYUVAPixmapInfo*) const override; */
/* TODO(eustas): add support for transcoded JPEG images? */
/* Result onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) override; */
/* TODO(eustas): implement when cropped output is supported. */
/* bool onGetValidSubset(SkIRect* desiredSubset) const override; */
bool onRewind() override;
/* TODO(eustas): top-down by default; do we need something else? */
/* SkScanlineOrder onGetScanlineOrder() const override; */
/* int onOutputScanline(int inputScanline) const override; */
bool conversionSupported(const SkImageInfo&, bool, bool) override;
int onGetFrameCount() override;
bool onGetFrameInfo(int, FrameInfo*) const override;
int onGetRepetitionCount() override;
private:
const SkFrameHolder* getFrameHolder() const override;
// Result onStartScanlineDecode(
// const SkImageInfo& /*dstInfo*/, const Options& /*options*/) override;
// Result onStartIncrementalDecode(
// const SkImageInfo& /*dstInfo*/, void*, size_t, const Options&) override;
// Result onIncrementalDecode(int*) override;
// bool onSkipScanlines(int /*countLines*/) override;
// int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) override;
// SkSampler* getSampler(bool /*createIfNecessary*/) override;
// Opaque codec implementation for lightweight header file.
std::unique_ptr<SkJpegxlCodecPriv> fCodec;
sk_sp<SkData> fData;
bool scanFrames();
static void imageOutCallback(
void* opaque, size_t x, size_t y, size_t num_pixels, const void* pixels);
SkJpegxlCodec(std::unique_ptr<SkJpegxlCodecPriv> codec,
SkEncodedInfo&& info,
std::unique_ptr<SkStream> stream,
sk_sp<SkData> data);
using INHERITED = SkScalingCodec;
};
#endif

15
third_party/highway/BUILD.gn vendored Normal file
View File

@ -0,0 +1,15 @@
# Copyright 2021 Google LLC
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("../third_party.gni")
third_party("highway") {
public_include_dirs = [ "../externals/highway" ]
sources = [
"../externals/highway/hwy/aligned_allocator.cc",
"../externals/highway/hwy/targets.cc",
]
}

100
third_party/libjxl/BUILD.gn vendored Normal file
View File

@ -0,0 +1,100 @@
# Copyright 2021 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("../third_party.gni")
third_party("libjxl") {
deps = [
"//third_party/brotli",
"//third_party/highway",
]
public_include_dirs = [
".",
"../externals/libjxl/lib/include",
]
include_dirs = [ "../externals/libjxl" ]
defines = [
# Does not really matter.
"JPEGXL_MAJOR_VERSION=1",
"JPEGXL_MINOR_VERSION=0",
"JPEGXL_PATCH_VERSION=0",
"JPEGXL_ENABLE_SKCMS=1",
"JPEGXL_ENABLE_TRANSCODE_JPEG=0",
]
if (is_official_build) {
defines += [ "JXL_DEBUG_ON_ABORT=0" ]
}
sources = [
"../externals/libjxl/lib/jxl/ac_strategy.cc",
"../externals/libjxl/lib/jxl/alpha.cc",
"../externals/libjxl/lib/jxl/ans_common.cc",
"../externals/libjxl/lib/jxl/aux_out.cc",
"../externals/libjxl/lib/jxl/base/cache_aligned.cc",
"../externals/libjxl/lib/jxl/base/data_parallel.cc",
"../externals/libjxl/lib/jxl/base/descriptive_statistics.cc",
"../externals/libjxl/lib/jxl/base/padded_bytes.cc",
"../externals/libjxl/lib/jxl/base/status.cc",
"../externals/libjxl/lib/jxl/blending.cc",
"../externals/libjxl/lib/jxl/chroma_from_luma.cc",
"../externals/libjxl/lib/jxl/coeff_order.cc",
"../externals/libjxl/lib/jxl/color_encoding_internal.cc",
"../externals/libjxl/lib/jxl/color_management.cc",
"../externals/libjxl/lib/jxl/compressed_dc.cc",
"../externals/libjxl/lib/jxl/convolve.cc",
"../externals/libjxl/lib/jxl/dct_scales.cc",
"../externals/libjxl/lib/jxl/dec_ans.cc",
"../externals/libjxl/lib/jxl/dec_cache.cc",
"../externals/libjxl/lib/jxl/dec_context_map.cc",
"../externals/libjxl/lib/jxl/dec_external_image.cc",
"../externals/libjxl/lib/jxl/dec_frame.cc",
"../externals/libjxl/lib/jxl/dec_group.cc",
"../externals/libjxl/lib/jxl/dec_group_border.cc",
"../externals/libjxl/lib/jxl/dec_huffman.cc",
"../externals/libjxl/lib/jxl/dec_modular.cc",
"../externals/libjxl/lib/jxl/dec_noise.cc",
"../externals/libjxl/lib/jxl/dec_patch_dictionary.cc",
"../externals/libjxl/lib/jxl/dec_reconstruct.cc",
"../externals/libjxl/lib/jxl/dec_upsample.cc",
"../externals/libjxl/lib/jxl/dec_xyb.cc",
"../externals/libjxl/lib/jxl/decode.cc",
"../externals/libjxl/lib/jxl/decode_to_jpeg.cc",
"../externals/libjxl/lib/jxl/enc_bit_writer.cc",
"../externals/libjxl/lib/jxl/entropy_coder.cc",
"../externals/libjxl/lib/jxl/epf.cc",
"../externals/libjxl/lib/jxl/fields.cc",
"../externals/libjxl/lib/jxl/filters.cc",
"../externals/libjxl/lib/jxl/frame_header.cc",
"../externals/libjxl/lib/jxl/gauss_blur.cc",
"../externals/libjxl/lib/jxl/headers.cc",
"../externals/libjxl/lib/jxl/huffman_table.cc",
"../externals/libjxl/lib/jxl/icc_codec.cc",
"../externals/libjxl/lib/jxl/icc_codec_common.cc",
"../externals/libjxl/lib/jxl/image.cc",
"../externals/libjxl/lib/jxl/image_bundle.cc",
"../externals/libjxl/lib/jxl/image_metadata.cc",
"../externals/libjxl/lib/jxl/jpeg/dec_jpeg_data.cc",
"../externals/libjxl/lib/jxl/jpeg/dec_jpeg_data_writer.cc",
"../externals/libjxl/lib/jxl/jpeg/jpeg_data.cc",
"../externals/libjxl/lib/jxl/loop_filter.cc",
"../externals/libjxl/lib/jxl/luminance.cc",
"../externals/libjxl/lib/jxl/memory_manager_internal.cc",
"../externals/libjxl/lib/jxl/modular/encoding/dec_ma.cc",
"../externals/libjxl/lib/jxl/modular/encoding/encoding.cc",
"../externals/libjxl/lib/jxl/modular/modular_image.cc",
"../externals/libjxl/lib/jxl/modular/transform/squeeze.cc",
"../externals/libjxl/lib/jxl/modular/transform/transform.cc",
"../externals/libjxl/lib/jxl/opsin_params.cc",
"../externals/libjxl/lib/jxl/passes_state.cc",
"../externals/libjxl/lib/jxl/quant_weights.cc",
"../externals/libjxl/lib/jxl/quantizer.cc",
"../externals/libjxl/lib/jxl/splines.cc",
"../externals/libjxl/lib/jxl/toc.cc",
]
}

11
third_party/libjxl/jxl/jxl_export.h vendored Normal file
View File

@ -0,0 +1,11 @@
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_LIBJXL_JXL_JXL_EXPORT_H_
#define THIRD_PARTY_LIBJXL_JXL_JXL_EXPORT_H_
#define JXL_EXPORT
#define JXL_DEPRECATED
#endif // THIRD_PARTY_LIBJXL_JXL_JXL_EXPORT_H_

View File

@ -166,6 +166,7 @@ static DEFINE_string2(match, m, nullptr,
#endif
static DEFINE_string(jpgs , PATH_PREFIX "jpgs" , "Directory to read jpgs from.");
static DEFINE_string(jxls , PATH_PREFIX "jxls" , "Directory to read jxls from.");
static DEFINE_string(skps , PATH_PREFIX "skps" , "Directory to read skps from.");
static DEFINE_string(mskps , PATH_PREFIX "mskps" , "Directory to read mskps from.");
static DEFINE_string(lotties, PATH_PREFIX "lotties", "Directory to read (Bodymovin) jsons from.");
@ -769,6 +770,10 @@ void Viewer::initSlides() {
[](const SkString& name, const SkString& path) -> sk_sp<Slide> {
return sk_make_sp<ImageSlide>(name, path);}
},
{ ".jxl", "jxl-dir", FLAGS_jxls,
[](const SkString& name, const SkString& path) -> sk_sp<Slide> {
return sk_make_sp<ImageSlide>(name, path);}
},
#if defined(SK_ENABLE_SKOTTIE)
{ ".json", "skottie-dir", FLAGS_lotties,
[](const SkString& name, const SkString& path) -> sk_sp<Slide> {