/
image.nim
117 lines (107 loc) · 4.01 KB
/
image.nim
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
110
111
112
113
114
115
116
117
import pixie
import httpclient
import frameos/utils/font
proc downloadImage*(url: string): Image =
let client = newHttpClient(timeout = 30000)
try:
let content = client.getContent(url)
result = decodeImage(content)
finally:
client.close()
proc rotateDegrees*(image: Image, degrees: int): Image {.raises: [PixieError].} =
case (degrees + 1080) mod 360: # TODO: yuck
of 90:
result = newImage(image.height, image.width)
for y in 0 ..< result.height:
for x in 0 ..< result.width:
result.data[result.dataIndex(x, y)] =
image.data[image.dataIndex(y, image.height - x - 1)]
of 180:
result = newImage(image.width, image.height)
for y in 0 ..< result.height:
for x in 0 ..< result.width:
result.data[result.dataIndex(x, y)] =
image.data[image.dataIndex(image.width - x - 1, image.height - y - 1)]
of 270:
result = newImage(image.height, image.width)
for y in 0 ..< result.height:
for x in 0 ..< result.width:
result.data[result.dataIndex(x, y)] =
image.data[image.dataIndex(image.width - y - 1, x)]
else:
result = image
proc writeError*(image: Image, width, height: int, message: string) =
let typeface = getDefaultTypeface()
let font = newFont(typeface, 32, parseHtmlColor("#000000"))
let borderFont = newFont(typeface, 32, parseHtmlColor("#ffffff"))
let padding = 10.0
let types = typeset(
spans = [newSpan(message, font)],
bounds = vec2(width.toFloat() - 2 * padding,
height.toFloat() - 2 * padding),
hAlign = CenterAlign,
vAlign = MiddleAlign,
)
let borderTypes = typeset(
spans = [newSpan(message, borderFont)],
bounds = vec2(width.toFloat() - 2 * padding,
height.toFloat() - 2 * padding),
hAlign = CenterAlign,
vAlign = MiddleAlign,
)
image.strokeText(borderTypes, translate(vec2(padding, padding)), strokeWidth = 2)
image.fillText(types, translate(vec2(padding, padding)))
proc renderError*(width, height: int, message: string): Image =
result = newImage(width, height)
result.fill(parseHtmlColor("#ffffff"))
writeError(result, width, height, message)
proc scaleAndDrawImage*(targetImage: Image, srcImage: Image,
scalingMode: string) {.raises: [PixieError].} =
if srcImage.width == targetImage.width and srcImage.height ==
targetImage.height:
targetImage.draw(srcImage)
else:
case scalingMode:
of "cover":
let scaleRatio = max(
targetImage.width.float32 / srcImage.width.float32,
targetImage.height.float32 / srcImage.height.float32
)
let scaledWidth = srcImage.width.float32 * scaleRatio
let scaledHeight = srcImage.height.float32 * scaleRatio
let xOffset = (scaledWidth - targetImage.width.float32) / 2
let yOffset = (scaledHeight - targetImage.height.float32) / 2
targetImage.draw(
srcImage,
translate(vec2(-xOffset, -yOffset)) * scale(vec2(scaleRatio,
scaleRatio)),
OverwriteBlend
)
of "contain":
let scaleRatio = min(
targetImage.width.float32 / srcImage.width.float32,
targetImage.height.float32 / srcImage.height.float32
)
let scaledWidth = srcImage.width.float32 * scaleRatio
let scaledHeight = srcImage.height.float32 * scaleRatio
let xOffset = (targetImage.width.float32 - scaledWidth) / 2
let yOffset = (targetImage.height.float32 - scaledHeight) / 2
targetImage.draw(
srcImage,
scale(vec2(scaleRatio, scaleRatio)) * translate(vec2(xOffset, yOffset)),
OverwriteBlend
)
of "stretch":
targetImage.draw(
srcImage,
scale(vec2(
targetImage.width.float32 / srcImage.width.float32,
targetImage.height.float32 / srcImage.height.float32
)),
OverwriteBlend
)
else:
let xOffset = (targetImage.width - srcImage.width) div 2
let yOffset = (targetImage.height - srcImage.height) div 2
targetImage.draw(srcImage, translate(vec2(xOffset.float32,
yOffset.float32)))