27#include "jxl/codestream_header.h"
28#include "jxl/decode.h"
29#include "jxl/decode_cxx.h"
54 JxlSignature
result = JxlSignatureCheck(
reinterpret_cast<const uint8_t*
>(
buffer), bytesRead);
55 return (
result == JXL_SIG_CODESTREAM) || (
result == JXL_SIG_CONTAINER);
78SkJpegxlCodec::SkJpegxlCodec(std::unique_ptr<SkJpegxlCodecPriv> codec,
80 std::unique_ptr<SkStream> stream,
83 , fCodec(
std::move(codec))
104 auto priv = std::make_unique<SkJpegxlCodecPriv>();
105 JxlDecoder* dec =
priv->fDecoder.get();
108 auto status = JxlDecoderSubscribeEvents(dec, JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING);
109 if (status != JXL_DEC_SUCCESS) {
115 status = JxlDecoderSetInput(dec, data->bytes(), data->size());
116 if (status != JXL_DEC_SUCCESS) {
122 status = JxlDecoderProcessInput(dec);
123 if (status == JXL_DEC_NEED_MORE_INPUT) {
127 if (status != JXL_DEC_BASIC_INFO) {
132 status = JxlDecoderGetBasicInfo(dec, &
info);
133 if (status != JXL_DEC_SUCCESS) {
140 if (!SkTFitsIn<int32_t>(
info.xsize) || !SkTFitsIn<int32_t>(
info.ysize)) {
144 int32_t
width = SkTo<int32_t>(
info.xsize);
147 bool hasAlpha = (
info.alpha_bits != 0);
148 bool isGray = (
info.num_color_channels == 1);
158 status = JxlDecoderProcessInput(dec);
159 if (status != JXL_DEC_COLOR_ENCODING) {
166 status = JxlDecoderGetICCProfileSize(
167 dec,
nullptr, JXL_COLOR_PROFILE_TARGET_DATA, &iccSize);
168 if (status != JXL_DEC_SUCCESS) {
172 std::unique_ptr<SkEncodedInfo::ICCProfile> profile =
nullptr;
176 status = JxlDecoderGetColorAsICCProfile(dec,
178 JXL_COLOR_PROFILE_TARGET_DATA,
179 reinterpret_cast<uint8_t*
>(icc->writable_data()),
181 if (status != JXL_DEC_SUCCESS) {
189 int bitsPerChannel = 16;
196 std::move(
priv), std::move(encodedInfo), std::move(
stream), std::move(data)));
205 auto& codec = *fCodec.get();
207 SkASSERT(0 == index ||
static_cast<size_t>(index) < codec.fFrames.size());
208 auto* dec = codec.fDecoder.get();
209 JxlDecoderStatus status;
211 if ((codec.fLastProcessedFrame >= index) || (codec.fLastProcessedFrame =
SkCodec::kNoFrame)) {
213 JxlDecoderRewind(dec);
214 status = JxlDecoderSubscribeEvents(dec, JXL_DEC_FRAME | JXL_DEC_FULL_IMAGE);
215 if (status != JXL_DEC_SUCCESS) {
220 status = JxlDecoderSetInput(dec, fData->
bytes(), fData->
size());
221 if (status != JXL_DEC_SUCCESS) {
226 SkASSERT(codec.fLastProcessedFrame + 1 == 0);
229 int nextFrame = codec.fLastProcessedFrame + 1;
230 if (nextFrame < index) {
231 JxlDecoderSkipFrames(dec, index - nextFrame);
235 status = JxlDecoderProcessInput(dec);
239 codec.fLastProcessedFrame = index;
240 if (status != JXL_DEC_FRAME) {
246 codec.fRowBytes = rowBytes;
249 uint32_t numColorChannels = 3;
251 uint32_t numAlphaChannels = 1;
253 auto endianness = JXL_LITTLE_ENDIAN;
262 bool halfFloatOutput =
false;
265 auto dataType = halfFloatOutput ? JXL_TYPE_FLOAT16 : JXL_TYPE_UINT8;
268 {numColorChannels + numAlphaChannels, dataType, endianness, 0};
269 status = JxlDecoderSetImageOutCallback(dec, &
format, SkJpegxlCodec::imageOutCallback,
this);
270 if (status != JXL_DEC_SUCCESS) {
277 status = JxlDecoderProcessInput(dec);
278 if (status != JXL_DEC_FULL_IMAGE) {
292 JxlDecoderRewind(fCodec->fDecoder.get());
297 bool needsColorXform) {
323void SkJpegxlCodec::imageOutCallback(
void* opaque,
size_t x,
size_t y,
324 size_t num_pixels,
const void* pixels) {
326 auto& codec = *
instance->fCodec.get();
327 size_t offset =
y * codec.fRowBytes + (
x << codec.fPixelShift);
328 void* dst = SkTAddOffset<void>(codec.fDst,
offset);
330 instance->applyColorXform(dst, pixels, num_pixels);
333 switch (codec.fDstColorType) {
335 memcpy(dst, pixels, 4 * num_pixels);
341 memcpy(dst, pixels, 8 * num_pixels);
344 SK_ABORT(
"Selected output format is not supported yet");
349bool SkJpegxlCodec::scanFrames() {
350 auto decoder = JxlDecoderMake(
nullptr);
351 JxlDecoder* dec = decoder.get();
352 auto* frameHolder = fCodec.get();
353 auto& frames = frameHolder->fFrames;
354 const auto&
info = fCodec->fInfo;
360 auto status = JxlDecoderSubscribeEvents(dec, JXL_DEC_FRAME);
361 if (status != JXL_DEC_SUCCESS) {
367 status = JxlDecoderSetInput(dec, fData->
bytes(), fData->
size());
368 if (status != JXL_DEC_SUCCESS) {
375 status = JxlDecoderProcessInput(dec);
377 case JXL_DEC_FRAME: {
378 size_t frameId = frames.size();
379 JxlFrameHeader frameHeader;
380 if (JxlDecoderGetFrameHeader(dec, &frameHeader) != JXL_DEC_SUCCESS) {
383 frames.emplace_back(
static_cast<int>(frameId), alpha);
384 auto&
frame = frames.back();
387 int duration = (1000 * frameHeader.duration *
info.animation.tps_denominator) /
388 info.animation.tps_numerator;
390 frameHolder->setAlphaAndRequiredFrame(&
frame);
393 case JXL_DEC_SUCCESS: {
404 if (!fCodec->fInfo.have_animation) {
408 if (!fCodec->fSeenAllFrames) {
409 fCodec->fSeenAllFrames = scanFrames();
412 return fCodec->fFrames.size();
419 if (
static_cast<size_t>(index) >= fCodec->fFrames.size()) {
422 fCodec->fFrames[index].fillIn(frameInfo,
true);
427 JxlBasicInfo&
info = fCodec->fInfo;
428 if (!
info.have_animation) {
432 if (
info.animation.num_loops == 0) {
436 if (SkTFitsIn<int>(
info.animation.num_loops)) {
437 return info.animation.num_loops - 1;
441 return std::numeric_limits<int>::max();
474std::unique_ptr<SkCodec>
Decode(std::unique_ptr<SkStream> stream,
476 SkCodecs::DecodeContext) {
479 outResult = &resultStorage;
486 SkCodecs::DecodeContext) {
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
#define SkDEBUGFAIL(message)
#define SK_ABORT(message,...)
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
#define INHERITED(method,...)
sk_sp< SkData > SkCopyStreamToData(SkStream *stream)
const SkImageInfo & dstInfo() const
static constexpr int kRepetitionCountInfinite
static constexpr int kNoFrame
const Options & options() const
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
const uint8_t * bytes() const
static sk_sp< SkData > MakeUninitialized(size_t length)
static std::unique_ptr< ICCProfile > Make(sk_sp< SkData >)
virtual SkEncodedInfo::Alpha onReportedAlpha() const =0
SkColorType fDstColorType
std::vector< Frame > fFrames
const SkFrame * onGetFrame(int i) const override
Result onGetPixels(const SkImageInfo &dstInfo, void *dst, size_t rowBytes, const Options &options, int *rowsDecodedPtr) override
int onGetRepetitionCount() override
int onGetFrameCount() override
bool conversionSupported(const SkImageInfo &, bool, bool) override
bool onGetFrameInfo(int, FrameInfo *) const override
static bool IsJpegxl(const void *, size_t)
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, Result *)
const SkFrameHolder * getFrameHolder() const override
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
virtual size_t getLength() const
virtual const void * getMemoryBase()
FlPixelBufferTexturePrivate * priv
static const uint8_t buffer[]
uint32_t uint32_t * format
SK_API bool IsJpegxl(const void *, size_t)
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
Swizzle_8888_u32 RGBA_to_bgrA
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
@ skcms_PixelFormat_RGBA_16161616LE
static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, int bitsPerComponent)
SkColorType colorType() const