2019-07-22 22:28:55 +00:00
|
|
|
// imagemagick plugins
|
|
|
|
const std = @import("std");
|
|
|
|
const images = @import("image.zig");
|
|
|
|
|
|
|
|
const Image = images.Image;
|
|
|
|
|
2020-05-12 20:48:20 +00:00
|
|
|
const mc = @cImport({
|
|
|
|
@cInclude("wand/magick_wand.h");
|
|
|
|
});
|
2019-07-22 23:32:50 +00:00
|
|
|
|
|
|
|
pub const MagickContext = struct {
|
|
|
|
wand: *mc.MagickWand,
|
|
|
|
|
|
|
|
pub fn init() !MagickContext {
|
2019-07-23 00:50:11 +00:00
|
|
|
mc.InitializeMagick(null);
|
2019-07-22 23:32:50 +00:00
|
|
|
|
|
|
|
var wand = mc.NewMagickWand();
|
|
|
|
if (wand == null) return error.WandCreateFail;
|
|
|
|
|
|
|
|
return MagickContext{
|
|
|
|
.wand = wand.?,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn deinit(self: *MagickContext) void {
|
|
|
|
_ = mc.DestroyMagickWand(self.wand);
|
2019-07-23 00:50:11 +00:00
|
|
|
mc.DestroyMagick();
|
2019-07-22 23:32:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn doErr(self: *MagickContext) !void {
|
|
|
|
return error.WandError;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-07-22 23:37:57 +00:00
|
|
|
fn magickLoad(image: *Image) !MagickContext {
|
2019-07-22 23:32:50 +00:00
|
|
|
var mctx = try MagickContext.init();
|
|
|
|
errdefer mctx.deinit();
|
|
|
|
|
|
|
|
var curpath = try std.cstr.addNullByte(image.allocator, image.curpath);
|
|
|
|
defer image.allocator.free(curpath);
|
|
|
|
|
2020-01-15 01:31:20 +00:00
|
|
|
std.debug.warn("loading '{}'\n", .{curpath});
|
2019-07-23 00:50:11 +00:00
|
|
|
|
|
|
|
if (mc.MagickReadImage(mctx.wand, curpath.ptr) != 1)
|
2019-07-22 23:37:57 +00:00
|
|
|
return error.MagickReadFail;
|
2019-07-22 23:32:50 +00:00
|
|
|
|
2019-07-22 23:37:57 +00:00
|
|
|
return mctx;
|
|
|
|
}
|
2019-07-22 23:32:50 +00:00
|
|
|
|
2019-07-23 01:15:06 +00:00
|
|
|
fn magickSave(image: *Image, wand: *mc.MagickWand) !void {
|
|
|
|
const allocator = image.allocator;
|
2019-07-22 23:32:50 +00:00
|
|
|
|
2019-07-23 01:15:06 +00:00
|
|
|
var tmpnam = try images.temporaryName(allocator);
|
|
|
|
var c_tmpnam = try std.cstr.addNullByte(allocator, tmpnam);
|
|
|
|
defer allocator.free(c_tmpnam);
|
2019-07-22 23:32:50 +00:00
|
|
|
|
2020-01-15 01:31:20 +00:00
|
|
|
std.debug.warn("\tmagick: saving to '{}'..", .{c_tmpnam});
|
2019-07-22 23:37:57 +00:00
|
|
|
|
2019-07-23 01:15:06 +00:00
|
|
|
if (mc.MagickWriteImage(wand, c_tmpnam.ptr) != 1)
|
2019-07-22 23:37:57 +00:00
|
|
|
return error.MagickWriteFail;
|
2019-07-23 01:15:06 +00:00
|
|
|
|
2020-01-15 01:31:20 +00:00
|
|
|
std.debug.warn("OK\n", .{});
|
2019-07-23 21:30:16 +00:00
|
|
|
|
|
|
|
try image.reopen(tmpnam);
|
2019-07-22 23:37:57 +00:00
|
|
|
}
|
|
|
|
|
2019-07-23 01:22:01 +00:00
|
|
|
/// Rotate the given image.
|
|
|
|
/// bgfill must point to a null-terminated string.
|
|
|
|
pub fn runRotate(image: *Image, deg: f32, bgfill: []const u8) !void {
|
2019-07-22 23:37:57 +00:00
|
|
|
var mctx = try magickLoad(image);
|
|
|
|
defer mctx.deinit();
|
|
|
|
|
2019-07-23 01:15:06 +00:00
|
|
|
var bg = mc.NewPixelWand();
|
2019-07-23 00:50:11 +00:00
|
|
|
defer mc.DestroyPixelWand(bg);
|
|
|
|
|
2019-07-23 01:22:01 +00:00
|
|
|
if (mc.PixelSetColor(bg, bgfill.ptr) != 1)
|
2019-07-23 00:50:11 +00:00
|
|
|
return error.PixelSetColorFail;
|
|
|
|
|
2019-07-23 01:22:01 +00:00
|
|
|
if (mc.MagickRotateImage(mctx.wand, bg, deg) != 1)
|
2019-07-23 00:50:11 +00:00
|
|
|
return error.RotateFail;
|
2019-07-22 23:37:57 +00:00
|
|
|
|
2019-07-23 01:15:06 +00:00
|
|
|
try magickSave(image, mctx.wand);
|
2019-07-22 22:28:55 +00:00
|
|
|
}
|