Add support to webp encoded dragged images

This commit is contained in:
Martín Capello 2024-10-09 15:44:41 -03:00
parent 16f3e53ce9
commit b1d1265450
4 changed files with 123 additions and 0 deletions

View File

@ -105,6 +105,13 @@ else()
target_sources(app-lib PRIVATE font_path_unix.cpp)
endif()
# This defines a specific webp decoding utility function for using
# in Windows when dragging and dropping images that are stored as
# webp files (like Chrome does).
if(WIN32 AND ENABLE_WEBP)
target_sources(app-lib PRIVATE util/decode_webp.cpp)
endif()
# Trial-version vs Full version (enable save command)
if(ENABLE_TRIAL_MODE)
target_compile_definitions(app-lib PUBLIC -DENABLE_TRIAL_MODE)

View File

@ -23,6 +23,10 @@
#include "doc/layer_list.h"
#include "render/dithering.h"
#if ENABLE_WEBP && LAF_WINDOWS
#include "app/util/decode_webp.h"
#endif
#include <algorithm>
namespace app {

View File

@ -0,0 +1,81 @@
// Aseprite
// Copyright (C) 2024 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#include "app/util/decode_webp.h"
#include <webp/demux.h>
#include <webp/mux.h>
namespace app {
namespace util {
os::SurfaceRef decode_webp(const uint8_t* buf, uint32_t len)
{
// I've considered using the FileFormatsManager here but we don't have a file
// in this case just the bytes. At some point maye we should refactor this or
// the WepFormat class to avoid duplicated logic.
WebPData webp_data;
WebPDataInit(&webp_data);
webp_data.bytes = &buf[0];
webp_data.size = len;
WebPAnimDecoderOptions dec_options;
WebPAnimDecoderOptionsInit(&dec_options);
dec_options.color_mode = MODE_RGBA;
WebPAnimDecoder* dec = WebPAnimDecoderNew(&webp_data, &dec_options);
if (dec == nullptr) {
// Error parsing WebP image
return nullptr;
}
WebPAnimInfo anim_info;
if (!WebPAnimDecoderGetInfo(dec, &anim_info)) {
// Error getting global info about the WebP animation
return nullptr;
}
WebPDecoderConfig config;
WebPInitDecoderConfig(&config);
if (WebPGetFeatures(webp_data.bytes, webp_data.size, &config.input)) {
}
else {
config.input.has_alpha = false;
}
const int w = anim_info.canvas_width;
const int h = anim_info.canvas_height;
if (anim_info.frame_count <= 0)
return nullptr;
auto surface = os::instance()->makeSurface(w, h);
// We just want the first frame, so we don't iterate.
WebPAnimDecoderHasMoreFrames(dec);
uint8_t* frame_rgba;
int frame_timestamp = 0;
if (!WebPAnimDecoderGetNext(dec, &frame_rgba, &frame_timestamp)) {
// Error loading WebP frame
return nullptr;
}
const uint32_t* src = (const uint32_t*)frame_rgba;
for (int y = 0; y < h; ++y, src += w) {
memcpy(surface->getData(0, y), src, w * sizeof(uint32_t));
}
WebPAnimDecoderReset(dec);
WebPAnimDecoderDelete(dec);
return surface;
}
} // namespace util
} // namespace app

View File

@ -0,0 +1,31 @@
// Aseprite
// Copyright (C) 2024 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_UTIL_DECODE_WEBP_H_INCLUDED
#define APP_UTIL_DECODE_WEBP_H_INCLUDED
#pragma once
#include "os/surface.h"
#include "os/system.h"
namespace app {
namespace util {
// Decodes webp content passed in buf and returns a surface with just the first
// frame.
os::SurfaceRef decode_webp(const uint8_t* buf, uint32_t len);
static void* once = []() {
os::set_decode_webp(decode_webp);
return nullptr;
}();
}
}
#endif