libpng 1.6.58.1-aarch64-linux → 1.6.58.2-aarch64-linux
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 +4 -4
- data/.rubocop.yml +3 -3
- data/README.adoc +128 -19
- data/lib/libpng/version.rb +1 -1
- data/lib/libpng.rb +177 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 75f0cfb37e59edf68ee4debbfacd284af495c705d5944db655eff6ad8b3b39e3
|
|
4
|
+
data.tar.gz: 21aba446ec81467ffc3b0a16405bbf2cc317fe99ad9fb38a508ade23c37943d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b2501953eb4b4911ca2cd7121d870f76e6129fae27872d2fc569189978438b88acc80fcbb9669aca1b26301b8aab80057fb4f8888f42a1435a42c72412cd377
|
|
7
|
+
data.tar.gz: dbb67d49744d157d0b5c8527d677e0183340d875d0dad43701caa72a705a5b9b1415a59e6c85c81ea8ae5b01a915cb36ef2ef172d6392145812ccef14cc5ea9a
|
data/.rubocop.yml
CHANGED
|
@@ -10,15 +10,15 @@ Gemspec/DevelopmentDependencies:
|
|
|
10
10
|
# methods that walk libpng's chunked API; splitting would obscure the
|
|
11
11
|
# 1-to-1 mapping with the C API.
|
|
12
12
|
Metrics/AbcSize:
|
|
13
|
-
Max:
|
|
13
|
+
Max: 70
|
|
14
14
|
Metrics/ClassLength:
|
|
15
15
|
Max: 200
|
|
16
16
|
Metrics/CyclomaticComplexity:
|
|
17
17
|
Max: 20
|
|
18
18
|
Metrics/MethodLength:
|
|
19
|
-
Max:
|
|
19
|
+
Max: 70
|
|
20
20
|
Metrics/ModuleLength:
|
|
21
|
-
Max:
|
|
21
|
+
Max: 350
|
|
22
22
|
Metrics/PerceivedComplexity:
|
|
23
23
|
Max: 20
|
|
24
24
|
Metrics/ParameterLists:
|
data/README.adoc
CHANGED
|
@@ -22,9 +22,33 @@ Or install manually:
|
|
|
22
22
|
|
|
23
23
|
gem install libpng
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
No C compiler, libpng development headers, or system packages
|
|
27
|
-
at install time.
|
|
25
|
+
RubyGems automatically selects the pre-compiled gem that matches your
|
|
26
|
+
platform. No C compiler, libpng development headers, or system packages
|
|
27
|
+
are required at install time when a binary gem is available. The
|
|
28
|
+
platform-agnostic `ruby` gem is the fallback: it downloads the libpng
|
|
29
|
+
source tarball at install time and compiles it via CMake (requires
|
|
30
|
+
`cmake`, `ninja`, and zlib headers).
|
|
31
|
+
|
|
32
|
+
== Supported platforms
|
|
33
|
+
|
|
34
|
+
The following pre-compiled platform gems are published for each release
|
|
35
|
+
(see the link:https://rubygems.org/gems/libpng/versions[RubyGems versions page]
|
|
36
|
+
for the current set):
|
|
37
|
+
|
|
38
|
+
[cols="1,1,3", options="header"]
|
|
39
|
+
|===
|
|
40
|
+
| Gem platform | Target | Build host
|
|
41
|
+
| `ruby` (source) | Any platform (compiles on install) | n/a
|
|
42
|
+
| `x86_64-linux` | x86_64 Linux (glibc) | `ubuntu-latest`
|
|
43
|
+
| `x86_64-linux-musl` | x86_64 Linux (musl, e.g. Alpine) | `ruby:<ver>-alpine` on x86_64
|
|
44
|
+
| `aarch64-linux` | ARM64 Linux (glibc) | `ubuntu-24.04-arm` (native)
|
|
45
|
+
| `aarch64-linux-musl` | ARM64 Linux (musl) | `ruby:<ver>-alpine` on arm64
|
|
46
|
+
| `x64-mingw32` | x64 Windows, RubyInstaller < 3.0 (MSVCRT) | `windows-latest`
|
|
47
|
+
| `x64-mingw-ucrt` | x64 Windows, RubyInstaller >= 3.0 (UCRT) | `windows-latest`
|
|
48
|
+
| `aarch64-mingw-ucrt` | ARM64 Windows (Ruby >= 3.4) | `windows-11-arm` (native)
|
|
49
|
+
| `x86_64-darwin` | Intel macOS | `macos-15-intel`
|
|
50
|
+
| `arm64-darwin` | Apple Silicon macOS | `macos-latest`
|
|
51
|
+
|===
|
|
28
52
|
|
|
29
53
|
== Usage
|
|
30
54
|
|
|
@@ -52,12 +76,57 @@ at install time.
|
|
|
52
76
|
|
|
53
77
|
Libpng.encode(width, height, pixels,
|
|
54
78
|
pixel_format: "RGBA",
|
|
55
|
-
convert_to_8bit: false
|
|
79
|
+
convert_to_8bit: false,
|
|
80
|
+
strip_colorspace: true)
|
|
56
81
|
|
|
57
|
-
`convert_to_8bit: true
|
|
82
|
+
`convert_to_8bit: true`:: causes libpng to convert 16-bit input to 8-bit
|
|
58
83
|
on write (input is still passed as a packed byte buffer; use this if you
|
|
59
84
|
have packed 16-bit-per-channel data).
|
|
60
85
|
|
|
86
|
+
`strip_colorspace: true`:: (default) walks the PNG chunk list after
|
|
87
|
+
encode and keeps only `IHDR`, `IDAT`, and `IEND`, dropping the sRGB/gAMA
|
|
88
|
+
chunks libpng's simplified API emits by default. This matches the
|
|
89
|
+
"classic" libpng write path (e.g. libemf2svg) and produces byte-identical
|
|
90
|
+
output. Set to `false` to keep the ancillary color chunks.
|
|
91
|
+
|
|
92
|
+
=== Standard API (encode_standard)
|
|
93
|
+
|
|
94
|
+
For parity with libpng's classic write path -- the same code path used
|
|
95
|
+
by `libemf2svg`'s `rgb2png` -- use `encode_standard` instead of
|
|
96
|
+
`encode`. It calls `png_create_write_struct` + `png_set_IHDR` +
|
|
97
|
+
`png_set_rows` + `png_write_png(PNG_TRANSFORM_IDENTITY)` directly, with
|
|
98
|
+
filter and zlib-compression control exposed:
|
|
99
|
+
|
|
100
|
+
Libpng.encode_standard(width, height, pixels,
|
|
101
|
+
pixel_format: "RGBA",
|
|
102
|
+
filter: :default,
|
|
103
|
+
compression_level: 6)
|
|
104
|
+
|
|
105
|
+
`pixel_format`:: `GRAY`, `GA`, `RGB`, or `RGBA` only. The byte-order
|
|
106
|
+
variants (`BGR`, `ARGB`, `BGRA`, `ABGR`) are simplified-API only --
|
|
107
|
+
the standard API always emits host-order.
|
|
108
|
+
|
|
109
|
+
`filter`:: One of `:default` (adaptive -- libpng picks the best filter
|
|
110
|
+
per row, the libemf2svg default), `:adaptive` (same), `:none`, `:sub`,
|
|
111
|
+
`:up`, `:avg`, `:paeth`, or `:all`.
|
|
112
|
+
|
|
113
|
+
`compression_level`:: zlib level 0-9. Default 6 (Z_DEFAULT_COMPRESSION,
|
|
114
|
+
matching libemf2svg).
|
|
115
|
+
|
|
116
|
+
Output is written directly into a Ruby String via `png_set_write_fn` --
|
|
117
|
+
no `Tempfile`, no disk I/O. The FFI write callback is held on a local
|
|
118
|
+
Array so it survives the libpng calls.
|
|
119
|
+
|
|
120
|
+
Differences from `encode`:
|
|
121
|
+
- Emits only `IHDR` / `IDAT` / `IEND` (no post-hoc chunk stripping
|
|
122
|
+
needed).
|
|
123
|
+
- Standard API only -- no `convert_to_8bit` option.
|
|
124
|
+
- Errors are raised via a `png_set_error_fn` callback (set on
|
|
125
|
+
`png_create_write_struct`). libpng expects error callbacks to
|
|
126
|
+
longjmp; we rb_raise instead, which unwinds the Ruby stack. The
|
|
127
|
+
`ensure` block calls `png_destroy_write_struct` to release the C
|
|
128
|
+
state.
|
|
129
|
+
|
|
61
130
|
== Ractor safety
|
|
62
131
|
|
|
63
132
|
`Libpng.encode` and `Libpng.decode` are Ractor-safe. Every call
|
|
@@ -65,25 +134,26 @@ allocates and frees its own libpng `png_image`; no shared mutable state
|
|
|
65
134
|
exists on the Ruby side. Calls from multiple Ractors run concurrently
|
|
66
135
|
without locking.
|
|
67
136
|
|
|
68
|
-
Example:
|
|
137
|
+
Example (Ruby 3.x uses `Ractor#take`; Ruby 4.0+ uses `Ractor#value`):
|
|
69
138
|
|
|
70
139
|
r = Ractor.new do
|
|
71
140
|
Libpng.encode(2, 2, "\xFF" * 16, pixel_format: "RGBA")
|
|
72
141
|
end
|
|
73
|
-
r.take
|
|
142
|
+
r.take # Ruby 3.x
|
|
143
|
+
r.value # Ruby 4.0+ (Ractor#take was removed in 4.0)
|
|
74
144
|
|
|
75
145
|
== Versioning
|
|
76
146
|
|
|
77
147
|
This gem follows a `{LIBPNG_VERSION}.{ITERATION}` scheme:
|
|
78
148
|
|
|
79
149
|
- `LIBPNG_VERSION` is the upstream libpng release the gem is built
|
|
80
|
-
against (currently 1.6.
|
|
150
|
+
against (currently `1.6.58`).
|
|
81
151
|
- `ITERATION` is a counter that bumps on Ruby-side changes (recipe bug
|
|
82
152
|
fixes, CI tweaks, doc updates). It resets to 0 each time
|
|
83
153
|
`LIBPNG_VERSION` bumps.
|
|
84
154
|
|
|
85
|
-
For example, `1.6.
|
|
86
|
-
`1.6.
|
|
155
|
+
For example, `1.6.58.0` is the first release against libpng 1.6.58,
|
|
156
|
+
`1.6.58.1` is a Ruby-side fix, and `1.6.59.0` would be a release against
|
|
87
157
|
the next upstream libpng.
|
|
88
158
|
|
|
89
159
|
== How it works
|
|
@@ -91,15 +161,54 @@ the next upstream libpng.
|
|
|
91
161
|
The gem has three layers:
|
|
92
162
|
|
|
93
163
|
1. `lib/libpng.rb` -- Ruby FFI wrapper. Loads `libpng16.{so,dylib,dll}`
|
|
94
|
-
from the gem's `lib/libpng/` directory at runtime
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
164
|
+
from the gem's `lib/libpng/` directory at runtime and exposes
|
|
165
|
+
`Libpng.encode` / `Libpng.decode` against libpng's "simplified"
|
|
166
|
+
high-level C API (`png_image_*`). The wrapper manually lays out the
|
|
167
|
+
`png_image` struct via explicit byte offsets into an
|
|
168
|
+
`FFI::MemoryPointer` rather than `FFI::Struct`, because `FFI::Struct`
|
|
169
|
+
carries class-level state that is not shareable across non-main
|
|
170
|
+
Ractors.
|
|
171
|
+
|
|
172
|
+
2. `lib/libpng/recipe.rb` -- a `MiniPortileCMake` recipe that downloads
|
|
173
|
+
the libpng source tarball pinned by `LIBPNG_URL` / `LIBPNG_SHA256`,
|
|
174
|
+
runs CMake with `PNG_SHARED=ON PNG_STATIC=OFF PNG_TESTS=OFF`, and
|
|
175
|
+
copies the resulting shared lib into `lib/libpng/`. Invoked only when
|
|
176
|
+
installing the **source** (`ruby` platform) gem.
|
|
177
|
+
|
|
178
|
+
3. `ext/extconf.rb` -- gem extension entry point. Calls `Recipe#cook_if_not`,
|
|
179
|
+
which is a no-op once the per-platform checkpoint file
|
|
180
|
+
(`ports/.../<name>-<ver>-<platform>.installed`) exists. After cooking,
|
|
181
|
+
emits a dummy `Makefile` via `mkmf` so RubyGems is satisfied (no Ruby
|
|
182
|
+
C extension is compiled). The pre-compiled platform gems unset
|
|
183
|
+
`spec.extensions`, so this never runs for them.
|
|
184
|
+
|
|
185
|
+
=== Pre-compiled platform gems
|
|
186
|
+
|
|
187
|
+
`Rakefile` defines `gem:native:<platform>` tasks for each target. Each
|
|
188
|
+
task clones the gemspec, sets `spec.platform`, adds
|
|
189
|
+
`lib/libpng/*.{dll,so,dylib}` to `spec.files`, removes the
|
|
190
|
+
`mini_portile2` dependency (no longer needed at install time), and
|
|
191
|
+
unsets `spec.extensions` -- the resulting gem installs with no compiler.
|
|
192
|
+
|
|
193
|
+
The release workflow (`.github/workflows/release.yml`) builds all 10
|
|
194
|
+
platforms in parallel on the appropriate native runner:
|
|
195
|
+
|
|
196
|
+
- x86_64 Linux glibc -- `ubuntu-latest`
|
|
197
|
+
- ARM64 Linux glibc -- `ubuntu-24.04-arm` (native)
|
|
198
|
+
- x86_64 Linux musl -- `ruby:<ver>-alpine` via `docker run` on `ubuntu-latest`
|
|
199
|
+
- ARM64 Linux musl -- `ruby:<ver>-alpine` via `docker run` on `ubuntu-24.04-arm`
|
|
200
|
+
- x64 Windows (both MSVCRT and UCRT) -- `windows-latest` with `step-security/msvc-dev-cmd`
|
|
201
|
+
- ARM64 Windows -- `windows-11-arm` (native) with `arch: arm64`
|
|
202
|
+
- Intel macOS -- `macos-15-intel`
|
|
203
|
+
- Apple Silicon macOS -- `macos-latest`
|
|
204
|
+
|
|
205
|
+
Linux glibc and macOS builds run natively on the matching runner. Linux
|
|
206
|
+
musl builds run inside `ruby:<ver>-alpine` containers via `docker run`
|
|
207
|
+
rather than the workflow `container:` field, because Actions' JS runtime
|
|
208
|
+
has no arm64-musl build and therefore cannot run Alpine containers on
|
|
209
|
+
arm64 runners. Windows builds use the Visual Studio toolchain via
|
|
210
|
+
`step-security/msvc-dev-cmd` (a maintained drop-in for the deleted
|
|
211
|
+
`ilammy/msvc-dev-tools`).
|
|
103
212
|
|
|
104
213
|
== License
|
|
105
214
|
|
data/lib/libpng/version.rb
CHANGED
data/lib/libpng.rb
CHANGED
|
@@ -45,6 +45,20 @@ module Libpng
|
|
|
45
45
|
%i[pointer pointer pointer int pointer int pointer], :int
|
|
46
46
|
attach_function :png_image_free, [:pointer], :void
|
|
47
47
|
|
|
48
|
+
# libpng standard (non-simplified) write API. Used by encode_standard.
|
|
49
|
+
attach_function :png_create_write_struct,
|
|
50
|
+
%i[string pointer pointer pointer], :pointer
|
|
51
|
+
attach_function :png_create_info_struct, [:pointer], :pointer
|
|
52
|
+
attach_function :png_destroy_write_struct, %i[pointer pointer], :void
|
|
53
|
+
attach_function :png_set_IHDR,
|
|
54
|
+
%i[pointer pointer uint32 uint32 int int int int int], :void
|
|
55
|
+
attach_function :png_set_rows, %i[pointer pointer pointer], :void
|
|
56
|
+
attach_function :png_set_filter, %i[pointer int int], :void
|
|
57
|
+
attach_function :png_set_compression_level, %i[pointer int], :void
|
|
58
|
+
attach_function :png_set_write_fn,
|
|
59
|
+
%i[pointer pointer pointer pointer], :void
|
|
60
|
+
attach_function :png_write_png, %i[pointer pointer int pointer], :void
|
|
61
|
+
|
|
48
62
|
# PNG_IMAGE_FORMAT_* bit flags and named formats from png.h.
|
|
49
63
|
FORMAT_FLAG_ALPHA = 0x01
|
|
50
64
|
FORMAT_FLAG_COLOR = 0x02
|
|
@@ -77,6 +91,64 @@ module Libpng
|
|
|
77
91
|
'ABGR' => FORMAT_ABGR
|
|
78
92
|
}.freeze
|
|
79
93
|
|
|
94
|
+
# PNG_COLOR_MASK_* and PNG_COLOR_TYPE_* (png.h).
|
|
95
|
+
COLOR_MASK_PALETTE = 0x01
|
|
96
|
+
COLOR_MASK_COLOR = 0x02
|
|
97
|
+
COLOR_MASK_ALPHA = 0x04
|
|
98
|
+
|
|
99
|
+
COLOR_TYPE_GRAY = 0
|
|
100
|
+
COLOR_TYPE_PALETTE = COLOR_MASK_COLOR | COLOR_MASK_PALETTE
|
|
101
|
+
COLOR_TYPE_RGB = COLOR_MASK_COLOR
|
|
102
|
+
COLOR_TYPE_RGB_ALPHA = COLOR_MASK_COLOR | COLOR_MASK_ALPHA
|
|
103
|
+
COLOR_TYPE_GRAY_ALPHA = COLOR_MASK_ALPHA
|
|
104
|
+
|
|
105
|
+
# Map our FORMAT_* to PNG_COLOR_TYPE_*. encode_standard doesn't support
|
|
106
|
+
# the BGR/ARGB/BGRA/ABGR byte-order variants because the standard API
|
|
107
|
+
# encodes host-order; callers wanting those formats should use the
|
|
108
|
+
# simplified encode path or pre-swap bytes.
|
|
109
|
+
COLOR_TYPE_BY_FORMAT = {
|
|
110
|
+
FORMAT_GRAY => COLOR_TYPE_GRAY,
|
|
111
|
+
FORMAT_GA => COLOR_TYPE_GRAY_ALPHA,
|
|
112
|
+
FORMAT_AG => COLOR_TYPE_GRAY_ALPHA,
|
|
113
|
+
FORMAT_RGB => COLOR_TYPE_RGB,
|
|
114
|
+
FORMAT_RGBA => COLOR_TYPE_RGB_ALPHA
|
|
115
|
+
}.freeze
|
|
116
|
+
|
|
117
|
+
# png_set_IHDR pass-through constants (png.h).
|
|
118
|
+
INTERLACE_NONE = 0
|
|
119
|
+
INTERLACE_ADAM7 = 1
|
|
120
|
+
COMPRESSION_TYPE_DEFAULT = 0
|
|
121
|
+
FILTER_TYPE_DEFAULT = 0
|
|
122
|
+
TRANSFORM_IDENTITY = 0x0000
|
|
123
|
+
|
|
124
|
+
# png_set_filter bitmask (PNG_FILTER_*). :default lets libpng use
|
|
125
|
+
# adaptive filtering across all filter types -- this is what
|
|
126
|
+
# libemf2svg/rgb2png effectively does via PNG_FILTER_TYPE_DEFAULT in
|
|
127
|
+
# the IHDR.
|
|
128
|
+
FILTER_HEURISTIC_DEFAULT = 0
|
|
129
|
+
FILTER_NONE = 0x08
|
|
130
|
+
FILTER_SUB = 0x10
|
|
131
|
+
FILTER_UP = 0x20
|
|
132
|
+
FILTER_AVG = 0x40
|
|
133
|
+
FILTER_PAETH = 0x80
|
|
134
|
+
FILTER_ALL = FILTER_NONE | FILTER_SUB | FILTER_UP | FILTER_AVG | FILTER_PAETH
|
|
135
|
+
|
|
136
|
+
FILTER_MASK_BY_NAME = {
|
|
137
|
+
default: nil, # don't call png_set_filter at all
|
|
138
|
+
adaptive: FILTER_ALL, # call with all filters allowed (same as default)
|
|
139
|
+
none: FILTER_NONE,
|
|
140
|
+
sub: FILTER_SUB,
|
|
141
|
+
up: FILTER_UP,
|
|
142
|
+
avg: FILTER_AVG,
|
|
143
|
+
paeth: FILTER_PAETH,
|
|
144
|
+
all: FILTER_ALL
|
|
145
|
+
}.freeze
|
|
146
|
+
|
|
147
|
+
# PNG_LIBPNG_VER_STRING. Used as the user_png_ver arg to
|
|
148
|
+
# png_create_write_struct. Must match the libpng16.{so,dylib,dll} we
|
|
149
|
+
# ship -- if these ever drift, png_create_write_struct aborts.
|
|
150
|
+
LIBPNG_VER_STRING_C = Libpng::LIBPNG_VERSION.dup.freeze
|
|
151
|
+
|
|
80
152
|
# png_image::version value libpng checks for. Defined in png.h as
|
|
81
153
|
# PNG_IMAGE_VERSION == 1.
|
|
82
154
|
PNG_IMAGE_VERSION = 1
|
|
@@ -192,6 +264,111 @@ module Libpng
|
|
|
192
264
|
end
|
|
193
265
|
end
|
|
194
266
|
|
|
267
|
+
# Encode raw pixels via libpng's standard write API
|
|
268
|
+
# (png_create_write_struct -> png_set_IHDR -> png_set_rows ->
|
|
269
|
+
# png_write_png(PNG_TRANSFORM_IDENTITY)). This matches the byte
|
|
270
|
+
# output of the "classic" libpng write path used by libemf2svg's
|
|
271
|
+
# rgb2png, and avoids the sRGB/gAMA chunks the simplified API
|
|
272
|
+
# injects by default.
|
|
273
|
+
#
|
|
274
|
+
# +width+, +height+ image dimensions in pixels
|
|
275
|
+
# +pixels+ String of raw pixel bytes (row-major, top-down)
|
|
276
|
+
# +pixel_format+ "RGB", "RGBA", "GRAY", "GA" (default: "RGBA")
|
|
277
|
+
# +filter+ :default (adaptive), :none, :sub, :up, :avg,
|
|
278
|
+
# :paeth, :all, :adaptive (default: :default)
|
|
279
|
+
# +compression_level+ zlib level 0-9 (default: 6 = Z_DEFAULT_COMPRESSION)
|
|
280
|
+
#
|
|
281
|
+
# Output is accumulated in a Ruby String via png_set_write_fn --
|
|
282
|
+
# no Tempfile, no disk I/O. The FFI write callback is held on a
|
|
283
|
+
# local Array so it isn't GC'd mid-call.
|
|
284
|
+
#
|
|
285
|
+
# Errors are raised via a png_set_error_fn callback (set on
|
|
286
|
+
# png_create_write_struct). libpng expects error callbacks to
|
|
287
|
+
# longjmp; rb_raise from the FFI callback unwinds the Ruby stack
|
|
288
|
+
# instead, which works for our usage but means the png_struct is
|
|
289
|
+
# not cleanly torn down inside libpng. The ensure block calls
|
|
290
|
+
# png_destroy_write_struct to release the C state.
|
|
291
|
+
#
|
|
292
|
+
# Ractor-safe: all state is per-call. FFI callbacks are not
|
|
293
|
+
# shareable across Ractors, but they're locals and stay scoped
|
|
294
|
+
# to one Ractor.
|
|
295
|
+
def encode_standard(width, height, pixels, pixel_format: 'RGBA',
|
|
296
|
+
filter: :default, compression_level: 6)
|
|
297
|
+
raise Error, 'width must be positive' unless width.positive?
|
|
298
|
+
raise Error, 'height must be positive' unless height.positive?
|
|
299
|
+
|
|
300
|
+
fmt = FORMAT_BY_NAME[pixel_format.to_s.upcase] ||
|
|
301
|
+
raise(Error, "unknown pixel_format #{pixel_format.inspect}")
|
|
302
|
+
color_type = COLOR_TYPE_BY_FORMAT[fmt] ||
|
|
303
|
+
raise(Error, "encode_standard does not support #{pixel_format} " \
|
|
304
|
+
'(use GRAY, GA, RGB, or RGBA; byte-order variants ' \
|
|
305
|
+
'like BGRA/ARGB/ABGR are simplified-API only)')
|
|
306
|
+
|
|
307
|
+
bytes_per_pixel = bytes_per_pixel_for_format(fmt)
|
|
308
|
+
stride = width * bytes_per_pixel
|
|
309
|
+
expected = stride * height
|
|
310
|
+
raise Error, "pixels too short: expected #{expected}, got #{pixels.bytesize}" if pixels.bytesize < expected
|
|
311
|
+
|
|
312
|
+
filter_sym = filter.to_sym
|
|
313
|
+
unless FILTER_MASK_BY_NAME.key?(filter_sym)
|
|
314
|
+
raise Error, "unknown filter #{filter.inspect} " \
|
|
315
|
+
'(expected :default, :adaptive, :none, :sub, :up, :avg, :paeth, or :all)'
|
|
316
|
+
end
|
|
317
|
+
filter_mask = FILTER_MASK_BY_NAME[filter_sym]
|
|
318
|
+
raise Error, 'compression_level must be 0..9' unless (0..9).cover?(compression_level)
|
|
319
|
+
|
|
320
|
+
output = String.new.force_encoding('ASCII-8BIT')
|
|
321
|
+
|
|
322
|
+
# FFI::Function objects need a stable reference for the duration of
|
|
323
|
+
# the libpng calls -- otherwise they can be GC'd before libpng
|
|
324
|
+
# invokes them.
|
|
325
|
+
callbacks = []
|
|
326
|
+
write_cb = FFI::Function.new(:void, %i[pointer pointer size_t]) do |_, data, len|
|
|
327
|
+
output << data.read_bytes(len)
|
|
328
|
+
end
|
|
329
|
+
error_cb = FFI::Function.new(:void, %i[pointer string]) do |_, msg|
|
|
330
|
+
raise Error, "libpng: #{msg}"
|
|
331
|
+
end
|
|
332
|
+
callbacks << write_cb << error_cb
|
|
333
|
+
|
|
334
|
+
png_ptr = FFI::Pointer.new(0)
|
|
335
|
+
info_ptr = FFI::Pointer.new(0)
|
|
336
|
+
begin
|
|
337
|
+
png_ptr = png_create_write_struct(LIBPNG_VER_STRING_C, nil, error_cb, nil)
|
|
338
|
+
raise Error, 'png_create_write_struct returned NULL' if png_ptr.null?
|
|
339
|
+
|
|
340
|
+
info_ptr = png_create_info_struct(png_ptr)
|
|
341
|
+
raise Error, 'png_create_info_struct returned NULL' if info_ptr.null?
|
|
342
|
+
|
|
343
|
+
png_set_compression_level(png_ptr, compression_level)
|
|
344
|
+
png_set_write_fn(png_ptr, nil, write_cb, nil)
|
|
345
|
+
png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
|
|
346
|
+
INTERLACE_NONE, COMPRESSION_TYPE_DEFAULT, FILTER_TYPE_DEFAULT)
|
|
347
|
+
png_set_filter(png_ptr, FILTER_HEURISTIC_DEFAULT, filter_mask) if filter_mask
|
|
348
|
+
|
|
349
|
+
FFI::MemoryPointer.new(:uint8, pixels.bytesize) do |px|
|
|
350
|
+
px.write_bytes(pixels)
|
|
351
|
+
FFI::MemoryPointer.new(:pointer, height) do |rows|
|
|
352
|
+
height.times { |y| rows.put_pointer(y * FFI.type_size(:pointer), px + (y * stride)) }
|
|
353
|
+
png_set_rows(png_ptr, info_ptr, rows)
|
|
354
|
+
png_write_png(png_ptr, info_ptr, TRANSFORM_IDENTITY, nil)
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
output
|
|
359
|
+
ensure
|
|
360
|
+
unless png_ptr.null?
|
|
361
|
+
FFI::MemoryPointer.new(:pointer) do |pp|
|
|
362
|
+
pp.write_pointer(png_ptr)
|
|
363
|
+
FFI::MemoryPointer.new(:pointer) do |ip|
|
|
364
|
+
ip.write_pointer(info_ptr)
|
|
365
|
+
png_destroy_write_struct(pp, ip)
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
195
372
|
private
|
|
196
373
|
|
|
197
374
|
# Lower-level encode that produces the raw libpng output (with sRGB
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: libpng
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.6.58.
|
|
4
|
+
version: 1.6.58.2
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|