-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathpillow.lua
109 lines (91 loc) · 2.84 KB
/
pillow.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
--[=[
Fast image resampling based on Pillow SIMD.
Written by Cosmin Apreutesei. Public Domain.
pillow_image(bmp) -> img create an image object from a bitmap
img:resize([w], [h], [filter], [cx1], [cy1], [cx2], [cy2]) resize and/or crop
img:bitmap() -> bmp get the image as a bitmap with bmp:free()
img:free() free the image
]=]
local ffi = require'ffi'
require'cpu_supports'
local C = ffi.load('pillow_simd'..(cpu_supports'avx2' and '_avx2' or ''))
ffi.cdef[[
typedef struct _pillow_image_t pillow_image_t;
pillow_image_t* pillow_image_create_for_data(
char *data, const char* mode, int w, int h, int stride, int bottom_up);
void pillow_image_free(pillow_image_t*);
int pillow_image_width (pillow_image_t* im);
int pillow_image_height (pillow_image_t* im);
char* pillow_image_mode (pillow_image_t* im);
char** pillow_image_rows (pillow_image_t* im);
pillow_image_t* pillow_resample(
pillow_image_t* im, int w, int h, int cx, int cy, int cw, int ch, int filter);
]]
local function ptr(p) return p ~= nil and p or nil end
local modes = {
rgbx8 = 'RGB',
rgba8 = 'RGBA',
RGBa8 = 'RGBa', --premultiplied alpha
g8 = 'L',
cmyk8 = 'CMYK',
yccx8 = 'YCbCr', --not in bitmap module
labx8 = 'Lab', --not in bitmap module
}
local formats = {}
for k,v in pairs(modes) do formats[v] = k end
function pillow_image(bmp)
local mode = assert(modes[bmp.format], 'unsupported format')
return assert(ptr(C.pillow_image_create_for_data(
bmp.data, mode, bmp.w, bmp.h, bmp.stride, bmp.bottom_up and 1 or 0)))
end
local filters = {
lanczos = 1,
bilinear = 2,
bicubic = 3,
box = 4,
hamming = 5,
}
local min, max = math.min, math.max
local function clamp(x, x0, x1)
return min(max(x, x0), x1)
end
local function resize(im, w, h, filter, cx1, cy1, cx2, cy2)
local filter = assert(filters[filter or 'bilinear'], 'unknown filter')
local w0 = im:width()
local h0 = im:height()
cx1 = cx1 or 0
cy1 = cy1 or 0
cx2 = cx2 or w0
cy2 = cy2 or h0
if cx2 < 0 then cx2 = w0 - (-cx2) end
if cy2 < 0 then cy2 = h0 - (-cy2) end
cx1 = clamp(cx1, 0, w0)
cy1 = clamp(cy1, 0, h0)
cx2 = clamp(cx2, 0, w0)
cy2 = clamp(cy2, 0, h0)
cx2 = max(cx2, cx1)
cy2 = max(cy2, cy1)
w = max(w or (cx2 - cx1), 1)
h = max(h or (cy2 - cy1), 1)
return assert(ptr(C.pillow_resample(im, w, h, cx1, cy1, cx2, cy2, filter)))
end
local function to_bitmap(im)
local w = im:width()
local h = im:height()
local stride = w * 4
return {
format = formats[im:mode()],
w = w, h = h, stride = stride, size = stride * h,
rows = im:rows(),
free = function() im:free() end,
}
end
ffi.metatype('pillow_image_t', {__index = {
free = C.pillow_image_free,
rows = C.pillow_image_rows,
width = C.pillow_image_width,
height = C.pillow_image_height,
mode = function(im) return ffi.string(C.pillow_image_mode(im)) end,
bitmap = to_bitmap,
resize = resize,
}})