58 lines
2.1 KiB
Zig
58 lines
2.1 KiB
Zig
const std = @import("std");
|
|
const Io = std.Io;
|
|
const STBImage = @import("stb_image");
|
|
|
|
// https://en.wikipedia.org/wiki/ICO_(file_format)#Icon_file_structure
|
|
|
|
pub fn main(init: std.process.Init) !void {
|
|
const io = init.io;
|
|
const gpa = init.gpa;
|
|
const arena = init.arena.allocator();
|
|
const args = try init.minimal.args.toSlice(arena);
|
|
|
|
if (args.len != 3) {
|
|
std.debug.print("Usage: ./png-to-icon <png-file> <output-ico>", .{});
|
|
std.process.exit(1);
|
|
}
|
|
|
|
const cwd = Io.Dir.cwd();
|
|
const input_png_path = args[1];
|
|
const output_ico_path = args[2];
|
|
|
|
const input_png_data = try cwd.readFileAlloc(io, input_png_path, gpa, .unlimited);
|
|
defer gpa.free(input_png_data);
|
|
|
|
const png_image = try STBImage.load(input_png_data);
|
|
defer png_image.deinit();
|
|
|
|
std.debug.assert(png_image.width > 0 and png_image.width <= 256);
|
|
std.debug.assert(png_image.height > 0 and png_image.height <= 256);
|
|
|
|
const output_ico_file = try cwd.createFile(io, output_ico_path, .{});
|
|
defer output_ico_file.close(io);
|
|
|
|
var buffer: [4096 * 4]u8 = undefined;
|
|
var file_writer = output_ico_file.writer(io, &buffer);
|
|
const writer = &file_writer.interface;
|
|
|
|
// ICONDIR structure
|
|
try writer.writeInt(u16, 0, .little); // Must always be zero
|
|
try writer.writeInt(u16, 1, .little); // Image type. 1 for .ICO
|
|
try writer.writeInt(u16, 1, .little); // Number of images
|
|
|
|
// ICONDIRENTRY structure
|
|
try writer.writeInt(u8, @truncate(png_image.width), .little); // Image width
|
|
try writer.writeInt(u8, @truncate(png_image.height), .little); // Image height
|
|
try writer.writeInt(u8, 0, .little); // Number of colors in color pallete. 0 means that color pallete is not used
|
|
try writer.writeInt(u8, 0, .little); // Must always be zero
|
|
try writer.writeInt(u16, 0, .little); // Color plane
|
|
try writer.writeInt(u16, 32, .little); // Bits per pixel
|
|
try writer.writeInt(u32, @intCast(input_png_data.len), .little); // Image size in bytes
|
|
try writer.writeInt(u32, 22, .little); // Offset to image data from the start
|
|
|
|
// PNG image data
|
|
try writer.writeAll(input_png_data);
|
|
try writer.flush();
|
|
}
|
|
|