ruby-avif 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/avif/avif.c +136 -0
- data/ext/avif/extconf.rb +6 -0
- data/lib/avif/version.rb +3 -0
- data/lib/avif.rb +4 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9e1602d362c5f0fabc60f05abadf9edb5c0c5430fc27d0072b4b6c62cd54cb7b
|
4
|
+
data.tar.gz: 739a3e9949dbaa3720ab2762e5264812792a63dd58559e8099868b3f64ba72fb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ef50fe8c82cf526019ea6dd38c6ca3dc5f1536bc47ea8590e1f42ce12ee8527b7d7bca1b1164ad5d522f2b11c37e4dbc1b05cf7bc3a4b033a712c720162dca79
|
7
|
+
data.tar.gz: 5c67622865f6064ac5036595ae697447cf153a53c5f3e7015f67ed05a504ea4f6f7f7699f7071ae96d3a14b766e1a4703d8d5890e09ed37f6012487b95003380
|
data/ext/avif/avif.c
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "ruby/thread.h"
|
3
|
+
#include "avif/avif.h"
|
4
|
+
#include <stdio.h>
|
5
|
+
#include <string.h>
|
6
|
+
#include <stdlib.h>
|
7
|
+
|
8
|
+
static char *safe_strdup(const char *s) {
|
9
|
+
if (!s) return NULL;
|
10
|
+
size_t len = strlen(s) + 1;
|
11
|
+
char *p = malloc(len);
|
12
|
+
if (p) {
|
13
|
+
memcpy(p, s, len);
|
14
|
+
}
|
15
|
+
return p;
|
16
|
+
}
|
17
|
+
|
18
|
+
typedef struct {
|
19
|
+
char *path;
|
20
|
+
uint8_t *pixels;
|
21
|
+
uint32_t width;
|
22
|
+
uint32_t height;
|
23
|
+
avifResult result;
|
24
|
+
char *error_message;
|
25
|
+
} decode_payload_t;
|
26
|
+
|
27
|
+
static void *decode(void *arg) {
|
28
|
+
decode_payload_t *payload = (decode_payload_t *)arg;
|
29
|
+
|
30
|
+
payload->pixels = NULL;
|
31
|
+
payload->result = AVIF_RESULT_UNKNOWN_ERROR;
|
32
|
+
payload->error_message = NULL;
|
33
|
+
|
34
|
+
avifDecoder *decoder = avifDecoderCreate();
|
35
|
+
if (!decoder) {
|
36
|
+
payload->error_message = safe_strdup("avifDecoderCreate failed (out of memory)");
|
37
|
+
free(payload->path);
|
38
|
+
return NULL;
|
39
|
+
}
|
40
|
+
|
41
|
+
payload->result = avifDecoderSetIOFile(decoder, payload->path);
|
42
|
+
free(payload->path);
|
43
|
+
payload->path = NULL;
|
44
|
+
if (payload->result != AVIF_RESULT_OK) {
|
45
|
+
avifDecoderDestroy(decoder);
|
46
|
+
return NULL;
|
47
|
+
}
|
48
|
+
|
49
|
+
payload->result = avifDecoderParse(decoder);
|
50
|
+
if (payload->result != AVIF_RESULT_OK) {
|
51
|
+
avifDecoderDestroy(decoder);
|
52
|
+
return NULL;
|
53
|
+
}
|
54
|
+
|
55
|
+
payload->result = avifDecoderNextImage(decoder);
|
56
|
+
if (payload->result != AVIF_RESULT_OK) {
|
57
|
+
avifDecoderDestroy(decoder);
|
58
|
+
return NULL;
|
59
|
+
}
|
60
|
+
|
61
|
+
avifImage *image = decoder->image;
|
62
|
+
payload->width = image->width;
|
63
|
+
payload->height = image->height;
|
64
|
+
|
65
|
+
avifRGBImage rgb;
|
66
|
+
avifRGBImageSetDefaults(&rgb, image);
|
67
|
+
rgb.format = AVIF_RGB_FORMAT_RGBA;
|
68
|
+
rgb.depth = 8;
|
69
|
+
|
70
|
+
size_t pixel_size = (size_t)rgb.width * rgb.height * avifRGBImagePixelSize(&rgb);
|
71
|
+
payload->pixels = malloc(pixel_size);
|
72
|
+
if (!payload->pixels) {
|
73
|
+
payload->error_message = safe_strdup("Failed to allocate pixel buffer (out of memory)");
|
74
|
+
avifDecoderDestroy(decoder);
|
75
|
+
return NULL;
|
76
|
+
}
|
77
|
+
rgb.pixels = payload->pixels;
|
78
|
+
rgb.rowBytes = rgb.width * avifRGBImagePixelSize(&rgb);
|
79
|
+
|
80
|
+
payload->result = avifImageYUVToRGB(image, &rgb);
|
81
|
+
if (payload->result != AVIF_RESULT_OK) {
|
82
|
+
free(payload->pixels);
|
83
|
+
payload->pixels = NULL;
|
84
|
+
}
|
85
|
+
|
86
|
+
avifDecoderDestroy(decoder);
|
87
|
+
return NULL;
|
88
|
+
}
|
89
|
+
|
90
|
+
static VALUE avif_decode(VALUE self, VALUE path) {
|
91
|
+
Check_Type(path, T_STRING);
|
92
|
+
|
93
|
+
decode_payload_t payload;
|
94
|
+
|
95
|
+
long path_len = RSTRING_LEN(path);
|
96
|
+
payload.path = malloc(path_len + 1);
|
97
|
+
if (!payload.path) {
|
98
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for path string");
|
99
|
+
}
|
100
|
+
memcpy(payload.path, RSTRING_PTR(path), path_len);
|
101
|
+
payload.path[path_len] = '\0';
|
102
|
+
|
103
|
+
rb_thread_call_without_gvl(decode, &payload, RUBY_UBF_IO, NULL);
|
104
|
+
|
105
|
+
if (payload.error_message) {
|
106
|
+
char *err_msg = payload.error_message;
|
107
|
+
rb_raise(rb_eRuntimeError, "AVIF decoding failed: %s", err_msg);
|
108
|
+
free(err_msg);
|
109
|
+
}
|
110
|
+
if (payload.result != AVIF_RESULT_OK) {
|
111
|
+
rb_raise(rb_eRuntimeError, "AVIF decoding failed: %s", avifResultToString(payload.result));
|
112
|
+
}
|
113
|
+
|
114
|
+
size_t pixel_bytes = (size_t)payload.width * payload.height * 4;
|
115
|
+
|
116
|
+
VALUE pixel_string = rb_str_new((const char*)payload.pixels, pixel_bytes);
|
117
|
+
free(payload.pixels);
|
118
|
+
|
119
|
+
rb_str_freeze(pixel_string);
|
120
|
+
|
121
|
+
VALUE result_array = rb_ary_new_capa(3);
|
122
|
+
rb_ary_push(result_array, UINT2NUM(payload.width));
|
123
|
+
rb_ary_push(result_array, UINT2NUM(payload.height));
|
124
|
+
rb_ary_push(result_array, pixel_string);
|
125
|
+
|
126
|
+
rb_ary_freeze(result_array);
|
127
|
+
|
128
|
+
return result_array;
|
129
|
+
}
|
130
|
+
|
131
|
+
void Init_avif(void) {
|
132
|
+
rb_ext_ractor_safe(true);
|
133
|
+
|
134
|
+
VALUE rb_mAvif = rb_define_module("Avif");
|
135
|
+
rb_define_singleton_method(rb_mAvif, "decode", avif_decode, 1);
|
136
|
+
}
|
data/ext/avif/extconf.rb
ADDED
data/lib/avif/version.rb
ADDED
data/lib/avif.rb
ADDED
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-avif
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Luka Bak
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-07-06 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
12
|
+
description: Ractor safe Ruby FFI binding for decoding AVIF images.
|
13
|
+
email: bakluka@gmail.com
|
14
|
+
executables: []
|
15
|
+
extensions:
|
16
|
+
- ext/avif/extconf.rb
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- ext/avif/avif.c
|
20
|
+
- ext/avif/extconf.rb
|
21
|
+
- lib/avif.rb
|
22
|
+
- lib/avif/version.rb
|
23
|
+
homepage: https://github.com/bakluka/ruby-avif
|
24
|
+
licenses:
|
25
|
+
- MIT
|
26
|
+
metadata: {}
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 3.0.0
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubygems_version: 3.6.2
|
42
|
+
specification_version: 4
|
43
|
+
summary: Ruby FFI binding for libavif
|
44
|
+
test_files: []
|