feat(tools/eaglemode/plugins/avif): AVIF image plugin
Animation not implemented. https: //en.wikipedia.org/wiki/AVIF Change-Id: I80f8c4132c4335b2e60ce7b70eb424457e50c73f Reviewed-on: https://cl.tvl.fyi/c/depot/+/12428 Tested-by: BuildkiteCI Reviewed-by: tazjin <tazjin@tvl.su>
This commit is contained in:
parent
e4714db2d5
commit
1c898f7ddc
5 changed files with 277 additions and 0 deletions
16
tools/eaglemode/plugins/avif/default.nix
Normal file
16
tools/eaglemode/plugins/avif/default.nix
Normal file
|
@ -0,0 +1,16 @@
|
|||
{ depot, pkgs, ... }:
|
||||
|
||||
let
|
||||
em = depot.tools.eaglemode;
|
||||
emSrc = pkgs.srcOnly pkgs.em;
|
||||
in
|
||||
(em.buildPlugin {
|
||||
name = "avif";
|
||||
version = "canon";
|
||||
src = ./.;
|
||||
target = "PlAvif";
|
||||
}).overrideAttrs
|
||||
({ buildInputs ? [ ], nativeBuildInputs ? [ ], ... }: {
|
||||
buildInputs = buildInputs ++ [ pkgs.libavif ];
|
||||
nativeBuildInputs = nativeBuildInputs ++ [ pkgs.pkg-config ];
|
||||
})
|
|
@ -0,0 +1,6 @@
|
|||
#%rec:emFpPlugin%#
|
||||
|
||||
FileTypes = { ".avif" }
|
||||
Priority = 1.0
|
||||
Library = "PlAvif"
|
||||
Function = "PlAvifFpPluginFunc"
|
64
tools/eaglemode/plugins/avif/makers/PlAvif.maker.pm
Normal file
64
tools/eaglemode/plugins/avif/makers/PlAvif.maker.pm
Normal file
|
@ -0,0 +1,64 @@
|
|||
package PlAvif;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub GetDependencies
|
||||
{
|
||||
return ('emCore');
|
||||
}
|
||||
|
||||
sub IsEssential
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub GetFileHandlingrules
|
||||
{
|
||||
return ();
|
||||
}
|
||||
|
||||
sub GetExtraBuildOptions
|
||||
{
|
||||
return ();
|
||||
}
|
||||
|
||||
sub Build
|
||||
{
|
||||
shift;
|
||||
my %options=@_;
|
||||
|
||||
my @libAvifFlags=();
|
||||
if ($options{'avif-inc-dir'} eq '' && $options{'avif-lib-dir'} eq '') {
|
||||
@libAvifFlags=split("\n",readpipe(
|
||||
"perl \"".$options{'utils'}."/PkgConfig.pl\" libavif"
|
||||
));
|
||||
}
|
||||
if (!@libAvifFlags) {
|
||||
if ($options{'avif-inc-dir'} ne '') {
|
||||
push(@libAvifFlags, "--inc-search-dir", $options{'avif-inc-dir'});
|
||||
}
|
||||
if ($options{'avif-lib-dir'} ne '') {
|
||||
push(@libAvifFlags, "--lib-search-dir", $options{'avif-lib-dir'});
|
||||
}
|
||||
push(@libAvifFlags, "--link", "avif");
|
||||
}
|
||||
|
||||
system(
|
||||
@{$options{'unicc_call'}},
|
||||
"--math",
|
||||
"--rtti",
|
||||
"--exceptions",
|
||||
"--bin-dir" , "bin",
|
||||
"--lib-dir" , "lib",
|
||||
"--obj-dir" , "obj",
|
||||
"--inc-search-dir", "include",
|
||||
@libAvifFlags,
|
||||
"--link" , "emCore",
|
||||
"--type" , "dynlib",
|
||||
"--name" , "PlAvif",
|
||||
"src/PlAvif.cpp"
|
||||
)==0 or return 0;
|
||||
|
||||
return 1;
|
||||
}
|
190
tools/eaglemode/plugins/avif/src/PlAvif.cpp
Normal file
190
tools/eaglemode/plugins/avif/src/PlAvif.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
#include <emCore/emFpPlugin.h>
|
||||
#include <emCore/emImageFile.h>
|
||||
|
||||
#include "avif/avif.h"
|
||||
|
||||
class PlAvifImageFileModel : public emImageFileModel
|
||||
{
|
||||
public:
|
||||
|
||||
static emRef<PlAvifImageFileModel> Acquire(
|
||||
emContext & context, const emString & name, bool common=true
|
||||
);
|
||||
|
||||
protected:
|
||||
PlAvifImageFileModel(emContext & context, const emString & name);
|
||||
virtual ~PlAvifImageFileModel();
|
||||
virtual void TryStartLoading();
|
||||
virtual bool TryContinueLoading();
|
||||
virtual void QuitLoading();
|
||||
virtual void TryStartSaving();
|
||||
virtual bool TryContinueSaving();
|
||||
virtual void QuitSaving();
|
||||
virtual emUInt64 CalcMemoryNeed();
|
||||
virtual double CalcFileProgress();
|
||||
|
||||
private:
|
||||
struct LoadingState;
|
||||
LoadingState * L = NULL;
|
||||
};
|
||||
|
||||
|
||||
struct PlAvifImageFileModel::LoadingState {
|
||||
avifRGBImage rgb;
|
||||
avifDecoder * decoder;
|
||||
};
|
||||
|
||||
|
||||
emRef<PlAvifImageFileModel> PlAvifImageFileModel::Acquire(
|
||||
emContext & context, const emString & name, bool common
|
||||
)
|
||||
{
|
||||
EM_IMPL_ACQUIRE(PlAvifImageFileModel, context, name, common)
|
||||
}
|
||||
|
||||
|
||||
PlAvifImageFileModel::PlAvifImageFileModel(
|
||||
emContext & context, const emString & name
|
||||
)
|
||||
: emImageFileModel(context, name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PlAvifImageFileModel::~PlAvifImageFileModel()
|
||||
{
|
||||
PlAvifImageFileModel::QuitLoading();
|
||||
PlAvifImageFileModel::QuitSaving();
|
||||
}
|
||||
|
||||
|
||||
void PlAvifImageFileModel::TryStartLoading()
|
||||
{
|
||||
avifResult result;
|
||||
|
||||
L = new LoadingState;
|
||||
memset(L, 0, sizeof(LoadingState));
|
||||
|
||||
L->decoder = avifDecoderCreate();
|
||||
if (L->decoder == NULL) {
|
||||
throw emException("failed to create AVIF decoder");
|
||||
}
|
||||
|
||||
result = avifDecoderSetIOFile(L->decoder, GetFilePath());
|
||||
if (result != AVIF_RESULT_OK) {
|
||||
throw emException("%s", avifResultToString(result));
|
||||
}
|
||||
|
||||
result = avifDecoderParse(L->decoder);
|
||||
if (result != AVIF_RESULT_OK) {
|
||||
throw emException("%s", avifResultToString(result));
|
||||
}
|
||||
|
||||
FileFormatInfo = emString::Format(
|
||||
"AVIF %s %ubpc",
|
||||
avifPixelFormatToString(L->decoder->image->yuvFormat),
|
||||
L->decoder->image->depth
|
||||
);
|
||||
|
||||
|
||||
Signal(ChangeSignal);
|
||||
}
|
||||
|
||||
|
||||
bool PlAvifImageFileModel::TryContinueLoading()
|
||||
{
|
||||
avifResult result;
|
||||
|
||||
if (!Image.GetHeight()) {
|
||||
Image.Setup(
|
||||
L->decoder->image->width,
|
||||
L->decoder->image->height,
|
||||
L->decoder->alphaPresent ? 4 : 3
|
||||
);
|
||||
}
|
||||
|
||||
result = avifDecoderNextImage(L->decoder);
|
||||
if (result != AVIF_RESULT_OK) {
|
||||
throw emException("%s", avifResultToString(result));
|
||||
}
|
||||
|
||||
avifRGBImageSetDefaults(&L->rgb, L->decoder->image);
|
||||
L->rgb.format = L->decoder->alphaPresent ?
|
||||
AVIF_RGB_FORMAT_RGBA : AVIF_RGB_FORMAT_RGB;
|
||||
L->rgb.pixels = Image.GetWritableMap();
|
||||
L->rgb.width = Image.GetWidth();
|
||||
L->rgb.height = Image.GetHeight();
|
||||
L->rgb.depth = 8;
|
||||
L->rgb.rowBytes = Image.GetWidth() * Image.GetChannelCount();
|
||||
|
||||
result = avifImageYUVToRGB(L->decoder->image, &L->rgb);
|
||||
if (result != AVIF_RESULT_OK) {
|
||||
throw emException("%s", avifResultToString(result));
|
||||
}
|
||||
|
||||
Signal(ChangeSignal);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PlAvifImageFileModel::QuitLoading()
|
||||
{
|
||||
if (L) {
|
||||
if (L->decoder) avifDecoderDestroy(L->decoder);
|
||||
delete L;
|
||||
L = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PlAvifImageFileModel::TryStartSaving()
|
||||
{
|
||||
throw emException("PlAvifImageFileModel: Saving not implemented.");
|
||||
}
|
||||
|
||||
|
||||
bool PlAvifImageFileModel::TryContinueSaving()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PlAvifImageFileModel::QuitSaving()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
emUInt64 PlAvifImageFileModel::CalcMemoryNeed()
|
||||
{
|
||||
return
|
||||
(emUInt64)
|
||||
L->decoder->image->width *
|
||||
L->decoder->image->height *
|
||||
(L->decoder->alphaPresent ? 4 : 3);
|
||||
}
|
||||
|
||||
|
||||
double PlAvifImageFileModel::CalcFileProgress()
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
emPanel * PlAvifFpPluginFunc(
|
||||
emPanel::ParentArg parent, const emString & name,
|
||||
const emString & path, emFpPlugin * plugin,
|
||||
emString * errorBuf
|
||||
)
|
||||
{
|
||||
if (plugin->Properties.GetCount()) {
|
||||
*errorBuf="PlAvifFpPlugin: No properties allowed.";
|
||||
return NULL;
|
||||
}
|
||||
return new emImageFilePanel(
|
||||
parent, name,
|
||||
PlAvifImageFileModel::Acquire(
|
||||
parent.GetRootContext(), path
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ let
|
|||
config = depot.tools.eaglemode.etcDir {
|
||||
extraPaths = [
|
||||
depot.tools.eaglemode.commands.B
|
||||
depot.tools.eaglemode.plugins.avif
|
||||
depot.tools.eaglemode.plugins.qoi
|
||||
];
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue