chore: import upstream snapshot with attribution
Test / build-libghostty-vt (x86_64-windows-gnu) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-ios) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt-macos (x86_64-macos) (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-dist (push) Has been cancelled
Test / GTK x11=true wayland=true (push) Has been cancelled
Test / Build -Dsimd=false (push) Has been cancelled
Test / Build -Dsimd=true (push) Has been cancelled
Test / Build -Dsentry=false (push) Has been cancelled
Test / Build -Dsentry=true (push) Has been cancelled
Test / zig-fmt (push) Has been cancelled
Test / GitHub Actions Pins (push) Has been cancelled
Test / prettier (push) Has been cancelled
Test / swiftlint (push) Has been cancelled
Test / alejandra (push) Has been cancelled
Test / typos (push) Has been cancelled
Nix / Required Checks: Nix (push) Has been cancelled
Nix / check-zig-cache-hash (push) Has been cancelled
Test / skip (push) Has been cancelled
Test / Required Checks: Test (push) Has been cancelled
Test / build-bench (push) Has been cancelled
Test / list-examples (push) Has been cancelled
Test / Example ${{ matrix.dir }} (Windows) (push) Has been cancelled
Test / build-cmake (push) Has been cancelled
Test / test-lib-vt-pkgconfig (push) Has been cancelled
Test / build-flatpak (push) Has been cancelled
Test / build-snap (push) Has been cancelled
Test / build-libghostty-vt (aarch64-linux) (push) Has been cancelled
Test / build-libghostty-vt (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt (wasm32-freestanding) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux-musl) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-macos) (push) Has been cancelled
Test / build-libghostty-vt-android (aarch64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-android (arm-linux-androideabi) (push) Has been cancelled
Test / build-libghostty-vt-android (x86_64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-windows (push) Has been cancelled
Test / build-libghostty-windows-gnu (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-linux-libghostty (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-dist-lib-vt (push) Has been cancelled
Test / trigger-snap (push) Has been cancelled
Test / trigger-flatpak (push) Has been cancelled
Test / build-macos (push) Has been cancelled
Test / build-macos-freetype (push) Has been cancelled
Test / test (push) Has been cancelled
Test / test-lib-vt (push) Has been cancelled
Test / GTK x11=false wayland=false (push) Has been cancelled
Test / GTK x11=true wayland=false (push) Has been cancelled
Test / GTK x11=false wayland=true (push) Has been cancelled
Test / test-macos (push) Has been cancelled
Test / test-windows (push) Has been cancelled
Test / Build -Di18n=false (push) Has been cancelled
Test / Build -Di18n=true (push) Has been cancelled
Test / Build test/fuzz-libghostty (push) Has been cancelled
Test / shellcheck (push) Has been cancelled
Test / translations (push) Has been cancelled
Test / blueprint-compiler (push) Has been cancelled
Test / Test pkg/wuffs (push) Has been cancelled
Test / Test build on Debian 13 (push) Has been cancelled
Test / valgrind (push) Has been cancelled
Test / Example ${{ matrix.dir }} (push) Has been cancelled
Test / build-libghostty-vt (x86_64-windows-gnu) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-ios) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt-macos (x86_64-macos) (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-dist (push) Has been cancelled
Test / GTK x11=true wayland=true (push) Has been cancelled
Test / Build -Dsimd=false (push) Has been cancelled
Test / Build -Dsimd=true (push) Has been cancelled
Test / Build -Dsentry=false (push) Has been cancelled
Test / Build -Dsentry=true (push) Has been cancelled
Test / zig-fmt (push) Has been cancelled
Test / GitHub Actions Pins (push) Has been cancelled
Test / prettier (push) Has been cancelled
Test / swiftlint (push) Has been cancelled
Test / alejandra (push) Has been cancelled
Test / typos (push) Has been cancelled
Nix / Required Checks: Nix (push) Has been cancelled
Nix / check-zig-cache-hash (push) Has been cancelled
Test / skip (push) Has been cancelled
Test / Required Checks: Test (push) Has been cancelled
Test / build-bench (push) Has been cancelled
Test / list-examples (push) Has been cancelled
Test / Example ${{ matrix.dir }} (Windows) (push) Has been cancelled
Test / build-cmake (push) Has been cancelled
Test / test-lib-vt-pkgconfig (push) Has been cancelled
Test / build-flatpak (push) Has been cancelled
Test / build-snap (push) Has been cancelled
Test / build-libghostty-vt (aarch64-linux) (push) Has been cancelled
Test / build-libghostty-vt (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt (wasm32-freestanding) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux-musl) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-macos) (push) Has been cancelled
Test / build-libghostty-vt-android (aarch64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-android (arm-linux-androideabi) (push) Has been cancelled
Test / build-libghostty-vt-android (x86_64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-windows (push) Has been cancelled
Test / build-libghostty-windows-gnu (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-linux-libghostty (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-dist-lib-vt (push) Has been cancelled
Test / trigger-snap (push) Has been cancelled
Test / trigger-flatpak (push) Has been cancelled
Test / build-macos (push) Has been cancelled
Test / build-macos-freetype (push) Has been cancelled
Test / test (push) Has been cancelled
Test / test-lib-vt (push) Has been cancelled
Test / GTK x11=false wayland=false (push) Has been cancelled
Test / GTK x11=true wayland=false (push) Has been cancelled
Test / GTK x11=false wayland=true (push) Has been cancelled
Test / test-macos (push) Has been cancelled
Test / test-windows (push) Has been cancelled
Test / Build -Di18n=false (push) Has been cancelled
Test / Build -Di18n=true (push) Has been cancelled
Test / Build test/fuzz-libghostty (push) Has been cancelled
Test / shellcheck (push) Has been cancelled
Test / translations (push) Has been cancelled
Test / blueprint-compiler (push) Has been cancelled
Test / Test pkg/wuffs (push) Has been cancelled
Test / Test build on Debian 13 (push) Has been cancelled
Test / valgrind (push) Has been cancelled
Test / Example ${{ matrix.dir }} (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
pub const c = @cImport({
|
||||
for (defines) |d| @cDefine(d, "1");
|
||||
@cInclude("wuffs-v0.4.c");
|
||||
});
|
||||
|
||||
/// All the C macros defined so that the header matches the build.
|
||||
pub const defines: []const []const u8 = &[_][]const u8{
|
||||
"WUFFS_CONFIG__MODULES",
|
||||
"WUFFS_CONFIG__MODULE__AUX__BASE",
|
||||
"WUFFS_CONFIG__MODULE__AUX__IMAGE",
|
||||
"WUFFS_CONFIG__MODULE__BASE",
|
||||
"WUFFS_CONFIG__MODULE__ADLER32",
|
||||
"WUFFS_CONFIG__MODULE__CRC32",
|
||||
"WUFFS_CONFIG__MODULE__DEFLATE",
|
||||
"WUFFS_CONFIG__MODULE__JPEG",
|
||||
"WUFFS_CONFIG__MODULE__PNG",
|
||||
"WUFFS_CONFIG__MODULE__ZLIB",
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
pub const Error = std.mem.Allocator.Error || error{ WuffsError, Overflow };
|
||||
|
||||
pub fn check(log: anytype, status: *const c.struct_wuffs_base__status__struct) error{WuffsError}!void {
|
||||
if (!c.wuffs_base__status__is_ok(status)) {
|
||||
const e = c.wuffs_base__status__message(status);
|
||||
log.warn("decode err={s}", .{e});
|
||||
return error.WuffsError;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const c = @import("c.zig").c;
|
||||
const Error = @import("error.zig").Error;
|
||||
const check = @import("error.zig").check;
|
||||
const ImageData = @import("main.zig").ImageData;
|
||||
const maximum_image_size = @import("main.zig").maximum_image_size;
|
||||
const mul = std.math.mul;
|
||||
|
||||
const log = std.log.scoped(.wuffs_jpeg);
|
||||
|
||||
/// Decode a JPEG image.
|
||||
pub fn decode(alloc: Allocator, data: []const u8) Error!ImageData {
|
||||
// Work around some weirdness in WUFFS/Zig, there are some structs that
|
||||
// are defined as "extern" by the Zig compiler which means that Zig won't
|
||||
// allocate them on the stack at compile time. WUFFS has functions for
|
||||
// dynamically allocating these structs but they use the C malloc/free. This
|
||||
// gets around that by using the Zig allocator to allocate enough memory for
|
||||
// the struct and then casts it to the appropriate pointer.
|
||||
|
||||
const decoder_buf = try alloc.alloc(u8, c.sizeof__wuffs_jpeg__decoder());
|
||||
defer alloc.free(decoder_buf);
|
||||
|
||||
const decoder: ?*c.wuffs_jpeg__decoder = @ptrCast(decoder_buf);
|
||||
{
|
||||
const status = c.wuffs_jpeg__decoder__initialize(
|
||||
decoder,
|
||||
c.sizeof__wuffs_jpeg__decoder(),
|
||||
c.WUFFS_VERSION,
|
||||
0,
|
||||
);
|
||||
try check(log, &status);
|
||||
}
|
||||
|
||||
var source_buffer: c.wuffs_base__io_buffer = .{
|
||||
.data = .{ .ptr = @ptrCast(@constCast(data.ptr)), .len = data.len },
|
||||
.meta = .{
|
||||
.wi = data.len,
|
||||
.ri = 0,
|
||||
.pos = 0,
|
||||
.closed = true,
|
||||
},
|
||||
};
|
||||
|
||||
var image_config: c.wuffs_base__image_config = undefined;
|
||||
{
|
||||
const status = c.wuffs_jpeg__decoder__decode_image_config(
|
||||
decoder,
|
||||
&image_config,
|
||||
&source_buffer,
|
||||
);
|
||||
try check(log, &status);
|
||||
}
|
||||
|
||||
const width = c.wuffs_base__pixel_config__width(&image_config.pixcfg);
|
||||
const height = c.wuffs_base__pixel_config__height(&image_config.pixcfg);
|
||||
|
||||
c.wuffs_base__pixel_config__set(
|
||||
&image_config.pixcfg,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL,
|
||||
c.WUFFS_BASE__PIXEL_SUBSAMPLING__NONE,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
|
||||
const size: usize = try mul(
|
||||
usize,
|
||||
try mul(usize, width, height),
|
||||
@sizeOf(c.wuffs_base__color_u32_argb_premul),
|
||||
);
|
||||
|
||||
if (size > maximum_image_size) {
|
||||
log.warn("image size {d} is larger than the maximum allowed ({d})", .{ size, maximum_image_size });
|
||||
return error.Overflow;
|
||||
}
|
||||
|
||||
const destination = try alloc.alloc(
|
||||
u8,
|
||||
size,
|
||||
);
|
||||
errdefer alloc.free(destination);
|
||||
|
||||
// temporary buffer for intermediate processing of image
|
||||
const work_buffer = try alloc.alloc(
|
||||
u8,
|
||||
|
||||
// The type of this is a u64 on all systems but our allocator
|
||||
// uses a usize which is a u32 on 32-bit systems.
|
||||
std.math.cast(
|
||||
usize,
|
||||
c.wuffs_jpeg__decoder__workbuf_len(decoder).max_incl,
|
||||
) orelse return error.OutOfMemory,
|
||||
);
|
||||
defer alloc.free(work_buffer);
|
||||
|
||||
const work_slice = c.wuffs_base__make_slice_u8(
|
||||
work_buffer.ptr,
|
||||
work_buffer.len,
|
||||
);
|
||||
|
||||
var pixel_buffer: c.wuffs_base__pixel_buffer = undefined;
|
||||
{
|
||||
const status = c.wuffs_base__pixel_buffer__set_from_slice(
|
||||
&pixel_buffer,
|
||||
&image_config.pixcfg,
|
||||
c.wuffs_base__make_slice_u8(destination.ptr, destination.len),
|
||||
);
|
||||
try check(log, &status);
|
||||
}
|
||||
|
||||
{
|
||||
const status = c.wuffs_jpeg__decoder__decode_frame(
|
||||
decoder,
|
||||
&pixel_buffer,
|
||||
&source_buffer,
|
||||
c.WUFFS_BASE__PIXEL_BLEND__SRC,
|
||||
work_slice,
|
||||
null,
|
||||
);
|
||||
try check(log, &status);
|
||||
}
|
||||
|
||||
return .{
|
||||
.width = width,
|
||||
.height = height,
|
||||
.data = destination,
|
||||
};
|
||||
}
|
||||
|
||||
test "jpeg_decode_000000" {
|
||||
const data = try decode(std.testing.allocator, @embedFile("1x1#000000.jpg"));
|
||||
defer std.testing.allocator.free(data.data);
|
||||
|
||||
try std.testing.expectEqual(1, data.width);
|
||||
try std.testing.expectEqual(1, data.height);
|
||||
try std.testing.expectEqualSlices(u8, &.{ 0, 0, 0, 255 }, data.data);
|
||||
}
|
||||
|
||||
test "jpeg_decode_FFFFFF" {
|
||||
const data = try decode(std.testing.allocator, @embedFile("1x1#FFFFFF.jpg"));
|
||||
defer std.testing.allocator.free(data.data);
|
||||
|
||||
try std.testing.expectEqual(1, data.width);
|
||||
try std.testing.expectEqual(1, data.height);
|
||||
try std.testing.expectEqualSlices(u8, &.{ 255, 255, 255, 255 }, data.data);
|
||||
}
|
||||
|
||||
test "jpeg: too big" {
|
||||
const data = decode(std.testing.allocator, @embedFile("too_big.jpg"));
|
||||
try std.testing.expectError(error.Overflow, data);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub const png = @import("png.zig");
|
||||
pub const jpeg = @import("jpeg.zig");
|
||||
pub const swizzle = @import("swizzle.zig");
|
||||
pub const Error = @import("error.zig").Error;
|
||||
|
||||
/// The maximum image size, based on the 4G limit of Ghostty's
|
||||
/// `image-storage-limit` config.
|
||||
pub const maximum_image_size = 4 * 1024 * 1024 * 1024;
|
||||
|
||||
pub const ImageData = struct {
|
||||
width: u32,
|
||||
height: u32,
|
||||
data: []u8,
|
||||
};
|
||||
|
||||
test {
|
||||
std.testing.refAllDeclsRecursive(@This());
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const c = @import("c.zig").c;
|
||||
const Error = @import("error.zig").Error;
|
||||
const check = @import("error.zig").check;
|
||||
const ImageData = @import("main.zig").ImageData;
|
||||
const maximum_image_size = @import("main.zig").maximum_image_size;
|
||||
const mul = std.math.mul;
|
||||
|
||||
const log = std.log.scoped(.wuffs_png);
|
||||
|
||||
/// Decode a PNG image.
|
||||
pub fn decode(alloc: Allocator, data: []const u8) Error!ImageData {
|
||||
// Work around some weirdness in WUFFS/Zig, there are some structs that
|
||||
// are defined as "extern" by the Zig compiler which means that Zig won't
|
||||
// allocate them on the stack at compile time. WUFFS has functions for
|
||||
// dynamically allocating these structs but they use the C malloc/free. This
|
||||
// gets around that by using the Zig allocator to allocate enough memory for
|
||||
// the struct and then casts it to the appropriate pointer.
|
||||
|
||||
const decoder_buf = try alloc.alloc(u8, c.sizeof__wuffs_png__decoder());
|
||||
defer alloc.free(decoder_buf);
|
||||
|
||||
const decoder: ?*c.wuffs_png__decoder = @ptrCast(decoder_buf);
|
||||
{
|
||||
const status = c.wuffs_png__decoder__initialize(
|
||||
decoder,
|
||||
c.sizeof__wuffs_png__decoder(),
|
||||
c.WUFFS_VERSION,
|
||||
0,
|
||||
);
|
||||
try check(log, &status);
|
||||
}
|
||||
|
||||
var source_buffer: c.wuffs_base__io_buffer = .{
|
||||
.data = .{ .ptr = @ptrCast(@constCast(data.ptr)), .len = data.len },
|
||||
.meta = .{
|
||||
.wi = data.len,
|
||||
.ri = 0,
|
||||
.pos = 0,
|
||||
.closed = true,
|
||||
},
|
||||
};
|
||||
|
||||
var image_config: c.wuffs_base__image_config = undefined;
|
||||
{
|
||||
const status = c.wuffs_png__decoder__decode_image_config(
|
||||
decoder,
|
||||
&image_config,
|
||||
&source_buffer,
|
||||
);
|
||||
try check(log, &status);
|
||||
}
|
||||
|
||||
const width = c.wuffs_base__pixel_config__width(&image_config.pixcfg);
|
||||
const height = c.wuffs_base__pixel_config__height(&image_config.pixcfg);
|
||||
|
||||
c.wuffs_base__pixel_config__set(
|
||||
&image_config.pixcfg,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL,
|
||||
c.WUFFS_BASE__PIXEL_SUBSAMPLING__NONE,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
|
||||
const size: usize = try mul(
|
||||
usize,
|
||||
try mul(usize, width, height),
|
||||
@sizeOf(c.wuffs_base__color_u32_argb_premul),
|
||||
);
|
||||
|
||||
if (size > maximum_image_size) {
|
||||
log.warn("image size {d} is larger than the maximum allowed ({d})", .{ size, maximum_image_size });
|
||||
return error.Overflow;
|
||||
}
|
||||
|
||||
const destination = try alloc.alloc(
|
||||
u8,
|
||||
size,
|
||||
);
|
||||
errdefer alloc.free(destination);
|
||||
|
||||
// temporary buffer for intermediate processing of image
|
||||
const work_buffer = try alloc.alloc(
|
||||
u8,
|
||||
|
||||
// The type of this is a u64 on all systems but our allocator
|
||||
// uses a usize which is a u32 on 32-bit systems.
|
||||
std.math.cast(
|
||||
usize,
|
||||
c.wuffs_png__decoder__workbuf_len(decoder).max_incl,
|
||||
) orelse return error.OutOfMemory,
|
||||
);
|
||||
defer alloc.free(work_buffer);
|
||||
|
||||
const work_slice = c.wuffs_base__make_slice_u8(
|
||||
work_buffer.ptr,
|
||||
work_buffer.len,
|
||||
);
|
||||
|
||||
var pixel_buffer: c.wuffs_base__pixel_buffer = undefined;
|
||||
{
|
||||
const status = c.wuffs_base__pixel_buffer__set_from_slice(
|
||||
&pixel_buffer,
|
||||
&image_config.pixcfg,
|
||||
c.wuffs_base__make_slice_u8(destination.ptr, destination.len),
|
||||
);
|
||||
try check(log, &status);
|
||||
}
|
||||
|
||||
{
|
||||
const status = c.wuffs_png__decoder__decode_frame(
|
||||
decoder,
|
||||
&pixel_buffer,
|
||||
&source_buffer,
|
||||
c.WUFFS_BASE__PIXEL_BLEND__SRC,
|
||||
work_slice,
|
||||
null,
|
||||
);
|
||||
try check(log, &status);
|
||||
}
|
||||
|
||||
return .{
|
||||
.width = width,
|
||||
.height = height,
|
||||
.data = destination,
|
||||
};
|
||||
}
|
||||
|
||||
test "png_decode_000000" {
|
||||
const data = try decode(std.testing.allocator, @embedFile("1x1#000000.png"));
|
||||
defer std.testing.allocator.free(data.data);
|
||||
|
||||
try std.testing.expectEqual(1, data.width);
|
||||
try std.testing.expectEqual(1, data.height);
|
||||
try std.testing.expectEqualSlices(u8, &.{ 0, 0, 0, 255 }, data.data);
|
||||
}
|
||||
|
||||
test "png_decode_FFFFFF" {
|
||||
const data = try decode(std.testing.allocator, @embedFile("1x1#FFFFFF.png"));
|
||||
defer std.testing.allocator.free(data.data);
|
||||
|
||||
try std.testing.expectEqual(1, data.width);
|
||||
try std.testing.expectEqual(1, data.height);
|
||||
try std.testing.expectEqualSlices(u8, &.{ 255, 255, 255, 255 }, data.data);
|
||||
}
|
||||
|
||||
test "png: too big" {
|
||||
const data = decode(std.testing.allocator, @embedFile("too_big.png"));
|
||||
try std.testing.expectError(error.Overflow, data);
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const c = @import("c.zig").c;
|
||||
const Error = @import("error.zig").Error;
|
||||
|
||||
const log = std.log.scoped(.wuffs_swizzler);
|
||||
|
||||
pub fn gToRgba(alloc: Allocator, src: []const u8) Error![]u8 {
|
||||
return swizzle(
|
||||
alloc,
|
||||
src,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__Y,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn gaToRgba(alloc: Allocator, src: []const u8) Error![]u8 {
|
||||
return swizzle(
|
||||
alloc,
|
||||
src,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__YA_PREMUL,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn rgbToRgba(alloc: Allocator, src: []const u8) Error![]u8 {
|
||||
return swizzle(
|
||||
alloc,
|
||||
src,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGB,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn bgrToRgba(alloc: Allocator, src: []const u8) Error![]u8 {
|
||||
return swizzle(
|
||||
alloc,
|
||||
src,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__BGR,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn bgraToRgba(alloc: Allocator, src: []const u8) Error![]u8 {
|
||||
return swizzle(
|
||||
alloc,
|
||||
src,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
|
||||
);
|
||||
}
|
||||
|
||||
fn swizzle(
|
||||
alloc: Allocator,
|
||||
src: []const u8,
|
||||
comptime src_pixel_format: u32,
|
||||
comptime dst_pixel_format: u32,
|
||||
) Error![]u8 {
|
||||
const src_slice = c.wuffs_base__make_slice_u8(
|
||||
@constCast(src.ptr),
|
||||
src.len,
|
||||
);
|
||||
|
||||
const dst_fmt = c.wuffs_base__make_pixel_format(
|
||||
dst_pixel_format,
|
||||
);
|
||||
|
||||
assert(c.wuffs_base__pixel_format__is_direct(&dst_fmt));
|
||||
assert(c.wuffs_base__pixel_format__is_interleaved(&dst_fmt));
|
||||
assert(c.wuffs_base__pixel_format__bits_per_pixel(&dst_fmt) % 8 == 0);
|
||||
|
||||
const dst_size = c.wuffs_base__pixel_format__bits_per_pixel(&dst_fmt) / 8;
|
||||
|
||||
const src_fmt = c.wuffs_base__make_pixel_format(
|
||||
src_pixel_format,
|
||||
);
|
||||
|
||||
assert(c.wuffs_base__pixel_format__is_direct(&src_fmt));
|
||||
assert(c.wuffs_base__pixel_format__is_interleaved(&src_fmt));
|
||||
assert(c.wuffs_base__pixel_format__bits_per_pixel(&src_fmt) % 8 == 0);
|
||||
|
||||
const src_size = c.wuffs_base__pixel_format__bits_per_pixel(&src_fmt) / 8;
|
||||
|
||||
assert(src.len % src_size == 0);
|
||||
|
||||
const dst = try alloc.alloc(u8, src.len * dst_size / src_size);
|
||||
errdefer alloc.free(dst);
|
||||
|
||||
const dst_slice = c.wuffs_base__make_slice_u8(
|
||||
dst.ptr,
|
||||
dst.len,
|
||||
);
|
||||
|
||||
var swizzler: c.wuffs_base__pixel_swizzler = undefined;
|
||||
{
|
||||
const status = c.wuffs_base__pixel_swizzler__prepare(
|
||||
&swizzler,
|
||||
dst_fmt,
|
||||
c.wuffs_base__empty_slice_u8(),
|
||||
src_fmt,
|
||||
c.wuffs_base__empty_slice_u8(),
|
||||
c.WUFFS_BASE__PIXEL_BLEND__SRC,
|
||||
);
|
||||
if (!c.wuffs_base__status__is_ok(&status)) {
|
||||
const e = c.wuffs_base__status__message(&status);
|
||||
log.warn("{s}", .{e});
|
||||
return error.WuffsError;
|
||||
}
|
||||
}
|
||||
{
|
||||
_ = c.wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice(
|
||||
&swizzler,
|
||||
dst_slice,
|
||||
c.wuffs_base__empty_slice_u8(),
|
||||
src_slice,
|
||||
);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1021 KiB |
Reference in New Issue
Block a user