162 lines
4.8 KiB
Zig
162 lines
4.8 KiB
Zig
const std = @import("std");
|
|
|
|
const c = @cImport({
|
|
@cInclude("stdlib.h");
|
|
@cInclude("spng.h");
|
|
});
|
|
|
|
pub const spng_decode_flags = c.spng_decode_flags;
|
|
|
|
pub const SPNG_FMT_RGBA8 = c.SPNG_FMT_RGBA8;
|
|
pub const SPNG_FMT_RGBA16 = c.SPNG_FMT_RGBA16;
|
|
pub const SPNG_FMT_RGB8 = c.SPNG_FMT_RGB8;
|
|
|
|
pub const SPNG_DECODE_TRNS = c.SPNG_DECODE_TRNS;
|
|
pub const SPNG_DECODE_GAMMA = c.SPNG_DECODE_GAMMA;
|
|
pub const SPNG_DECODE_PROGRESSIVE = c.SPNG_DECODE_PROGRESSIVE;
|
|
|
|
pub const spng_ihdr = c.spng_ihdr;
|
|
|
|
const spng_errno = c.spng_errno;
|
|
const spng_text_type = c.spng_text_type;
|
|
const spng_color_type = c.spng_color_type;
|
|
const spng_filter = c.spng_filter;
|
|
const spng_filter_choice = c.spng_filter_choice;
|
|
const spng_interace_method = c.spng_interace_method;
|
|
const spng_format = c.spng_format;
|
|
const spng_ctx_flags = c.spng_ctx_flags;
|
|
const spng_crc_action = c.spng_crc_action;
|
|
const spng_encode_flags = c.spng_encode_flags;
|
|
const spng_plte_entry = c.spng_plte_entry;
|
|
const spng_plte = c.spng_plte;
|
|
const spng_trns = c.spng_trns;
|
|
const spng_chrm_int = c.spng_chrm_int;
|
|
const spng_iccp = c.spng_iccp;
|
|
const spng_sbit = c.spng_sbit;
|
|
const spng_text = c.spng_text;
|
|
const spng_bkgd = c.spng_bkgd;
|
|
const spng_hist = c.spng_hist;
|
|
const spng_phys = c.spng_phys;
|
|
const spng_splt_entry = c.spng_splt_entry;
|
|
const spng_splt = c.spng_splt;
|
|
const spng_time = c.spng_time;
|
|
const spng_offs = c.spng_offs;
|
|
const spng_exif = c.spng_exif;
|
|
const spng_chunk = c.spng_chunk;
|
|
const spng_location = c.spng_location;
|
|
const song_unknown_chunk = c.spng_unknown_chunk;
|
|
const spng_option = c.spng_option;
|
|
|
|
const spng_ctx = c.spng_ctx;
|
|
|
|
fn checkResult(res: c_int) !void {
|
|
if (res != 0) {
|
|
std.debug.print("string: {s}\n", .{std.mem.span(c.spng_strerror(res))});
|
|
return error.InvalidResult;
|
|
}
|
|
}
|
|
|
|
pub const SpngContext = struct {
|
|
_ctx: *spng_ctx,
|
|
|
|
pub fn newDecoder() !@This() {
|
|
return .{
|
|
._ctx = c.spng_ctx_new(0) orelse return error.UnableToCreateSpngContext,
|
|
};
|
|
}
|
|
|
|
pub fn newEncoder() !@This() {
|
|
return .{
|
|
._ctx = c.spng_ctx_new(c.SPNG_CTX_ENCODER) orelse return error.UnableToCreateSpngContext,
|
|
};
|
|
}
|
|
|
|
pub fn setBuffer(self: *@This(), buffer: []const u8) !void {
|
|
try checkResult(c.spng_set_png_buffer(self._ctx, buffer.ptr, buffer.len));
|
|
}
|
|
|
|
pub fn setFileRaw(self: @This(), file: *c.FILE) !void {
|
|
const res = c.spng_set_png_file(self._ctx, file);
|
|
try checkResult(res);
|
|
}
|
|
|
|
pub fn setFile(self: @This(), path: []const u8) !void {
|
|
const file = c.fopen(path.ptr, "r");
|
|
if (file == null) {
|
|
return error.FileNotOpen;
|
|
}
|
|
_ = c.fseek(file, 0, c.SEEK_END);
|
|
const sz = c.ftell(file);
|
|
std.debug.print("file size: {s} {d}\n", .{ path, sz });
|
|
c.rewind(file);
|
|
|
|
try self.setFileRaw(file);
|
|
}
|
|
|
|
// decodes the image and writes to the out buffer.
|
|
pub fn decode(self: *@This(), out: []u8, fmt: c_int, flags: c_int) !usize {
|
|
var res = c.spng_decode_image(self._ctx, out.ptr, out.len, fmt, flags);
|
|
try checkResult(res);
|
|
var size: usize = 0;
|
|
|
|
res = c.spng_decoded_image_size(self._ctx, fmt, &size);
|
|
try checkResult(res);
|
|
|
|
return size;
|
|
}
|
|
|
|
pub fn getHeader(self: *@This()) !spng_ihdr {
|
|
var outHeader: spng_ihdr = undefined;
|
|
|
|
try checkResult(c.spng_get_ihdr(self._ctx, &outHeader));
|
|
|
|
return outHeader;
|
|
}
|
|
|
|
// TODO: sets png stream
|
|
// pub fn setPngStream(self: *@This(), : spng_rw_fn) !void {
|
|
// try checkResult(c.spng_set_png_buffer(self._ctx, buffer.ptr, buffer.len));
|
|
// }
|
|
|
|
pub fn deinit(self: *@This()) void {
|
|
c.spng_ctx_free(self._ctx);
|
|
}
|
|
};
|
|
|
|
pub fn loadFileAlloc(filename: []const u8, allocator: std.mem.Allocator) ![]u8 {
|
|
var file = try std.fs.cwd().openFile(filename, .{});
|
|
const filesize = (try file.stat()).size;
|
|
return file.readToEndAlloc(allocator, filesize);
|
|
}
|
|
|
|
test "spngtest" {
|
|
const allocator = std.testing.allocator;
|
|
const pngBuffer = try allocator.alloc(u8, 1000 * 1000 * 100);
|
|
defer allocator.free(pngBuffer);
|
|
|
|
var decoder = try SpngContext.newDecoder();
|
|
defer decoder.deinit();
|
|
try decoder.setBuffer(pngBuffer);
|
|
|
|
const decodeBuffer = try allocator.alloc(u8, 500 * 1000 * 1000);
|
|
defer allocator.free(decodeBuffer);
|
|
|
|
var decoder2 = try SpngContext.newDecoder();
|
|
defer decoder2.deinit();
|
|
const buffer = try loadFileAlloc("testpng.png", allocator);
|
|
defer allocator.free(buffer);
|
|
|
|
try decoder2.setBuffer(buffer);
|
|
|
|
const header = try decoder2.getHeader();
|
|
|
|
try std.testing.expect(header.width == 383);
|
|
try std.testing.expect(header.height == 345);
|
|
|
|
const len = try decoder2.decode(decodeBuffer, SPNG_FMT_RGBA8, SPNG_DECODE_TRNS);
|
|
try std.testing.expect(len == 528540);
|
|
|
|
var encoder = try SpngContext.newDecoder();
|
|
defer encoder.deinit();
|
|
}
|