1use crate::points::pt;
35use image::{DynamicImage, ImageFormat, RgbImage, RgbaImage};
36use tiny_skia::*;
37
38pub struct Canvas {
73 pub pixmap: Pixmap,
75 width: u32,
78 height: u32,
80 pub scale: f32,
84}
85
86impl Canvas {
87 pub fn new(width: u32, height: u32) -> Canvas {
89 Canvas {
90 pixmap: Pixmap::new(width, height).unwrap(),
91 width,
92 height,
93 scale: 1.0,
94 }
95 }
96
97 pub fn from_image(image: &DynamicImage) -> Canvas {
98 let rgba_img = image.to_rgba8();
99
100 let img_width = rgba_img.width();
101 let img_height = rgba_img.height();
102 let mut pixmap = Pixmap::new(img_width, img_height).unwrap();
103 pixmap.data_mut().copy_from_slice(rgba_img.as_raw());
104
105 Canvas {
106 pixmap: pixmap.to_owned(),
107 width: image.width(),
108 height: image.height(),
109 scale: 1.0,
110 }
111 }
112
113 pub fn with_scale(width: u32, height: u32, scale: f32) -> Canvas {
117 let w = scale * width as f32;
118 let h = scale * height as f32;
119 Canvas {
120 pixmap: Pixmap::new(w as u32, h as u32).unwrap(),
121 width,
122 height,
123 scale,
124 }
125 }
126
127 pub fn width(&self) -> u32 {
130 self.width
131 }
132
133 pub fn height(&self) -> u32 {
135 self.height
136 }
137
138 pub fn w_f32(&self) -> f32 {
140 self.width as f32
141 }
142
143 pub fn h_f32(&self) -> f32 {
145 self.height as f32
146 }
147
148 pub fn w_usize(&self) -> usize {
150 self.width as usize
151 }
152
153 pub fn h_usize(&self) -> usize {
155 self.height as usize
156 }
157
158 pub fn fill(&mut self, color: Color) {
160 self.pixmap.fill(color);
161 }
162
163 pub fn fill_path(
165 &mut self,
166 path: &Path,
167 paint: &mut Paint,
168 fill_rule: FillRule,
169 transform: Transform,
170 clip_mask: Option<&Mask>,
171 ) {
172 let mut transform = transform;
173 transform = transform.post_scale(self.scale, self.scale);
174 self.pixmap
175 .fill_path(path, paint, fill_rule, transform, clip_mask);
176 }
177
178 pub fn fill_rect(
180 &mut self,
181 rect: Rect,
182 paint: &mut Paint,
183 transform: Transform,
184 clip_mask: Option<&Mask>,
185 ) {
186 let mut transform = transform;
187 transform = transform.post_scale(self.scale, self.scale);
188 self.pixmap.fill_rect(rect, paint, transform, clip_mask);
189 }
190
191 pub fn stroke_path(
193 &mut self,
194 path: &Path,
195 paint: &mut Paint,
196 stroke: &Stroke,
197 transform: Transform,
198 clip_mask: Option<&Mask>,
199 ) {
200 let mut transform = transform;
201 transform = transform.post_scale(self.scale, self.scale);
202 self.pixmap
203 .stroke_path(path, paint, stroke, transform, clip_mask);
204 }
205
206 pub fn dot(&mut self, x: f32, y: f32, color: Color) {
209 let width = self.pixmap.width();
210 let pixel_map = self.pixmap.pixels_mut();
211 let k = y as usize * width as usize + x as usize;
212 pixel_map[k] = color.premultiply().to_color_u8();
213 }
214
215 pub fn save_png<P: AsRef<std::path::Path>>(&self, path: P) {
217 self.pixmap.save_png(path).expect("Error writing png");
218 }
219
220 pub fn save_jpg<P: AsRef<std::path::Path>>(&self, path: P) {
222 let img: RgbaImage = self.into();
223 img.save_with_format(path, ImageFormat::Jpeg)
224 .expect("Error writing jpeg");
225 }
226
227 pub fn save_tiff<P: AsRef<std::path::Path>>(&self, path: P) {
229 let img: RgbaImage = self.into();
230 img.save_with_format(path, ImageFormat::Tiff)
231 .expect("Error writing tiff");
232 }
233
234 pub fn data(&self) -> &[u8] {
235 self.pixmap.data()
236 }
237
238 pub fn take(self) -> Vec<u8> {
239 self.pixmap.take()
240 }
241}
242
243pub fn paint_solid<'a>(color: Color) -> Paint<'a> {
245 let mut paint = Paint {
246 anti_alias: true,
247 ..Default::default()
248 };
249 paint.set_color(color);
250 paint
251}
252
253pub fn paint_shader(shader: Shader) -> Paint {
255 Paint {
256 anti_alias: true,
257 shader,
258 ..Default::default()
259 }
260}
261
262pub fn paint_lg<'a>(x0: f32, y0: f32, x1: f32, y1: f32, stops: Vec<GradientStop>) -> Paint<'a> {
264 let lg = LinearGradient::new(
265 pt(x0, y0),
266 pt(x1, y1),
267 stops,
268 SpreadMode::Pad,
269 Transform::identity(),
270 )
271 .unwrap();
272 paint_shader(lg)
273}
274
275pub fn paint_rg<'a>(
276 x0: f32,
277 y0: f32,
278 x1: f32,
279 y1: f32,
280 radius: f32,
281 stops: Vec<GradientStop>,
282) -> Paint<'a> {
283 let rg = RadialGradient::new(
284 pt(x0, y0),
285 pt(x1, y1),
286 radius,
287 stops,
288 SpreadMode::Pad,
289 Transform::identity(),
290 )
291 .unwrap();
292 paint_shader(rg)
293}
294
295fn image_to_canvas(width: u32, height: u32, data: Vec<u8>) -> Canvas {
296 let pixmap = PixmapRef::from_bytes(&data, width, height).unwrap();
297 Canvas {
298 pixmap: pixmap.to_owned(),
299 width,
300 height,
301 scale: 1.0,
302 }
303}
304
305impl From<&RgbaImage> for Canvas {
307 fn from(ib: &RgbaImage) -> Self {
308 image_to_canvas(ib.width(), ib.height(), ib.clone().into_vec())
309 }
310}
311
312impl From<&RgbImage> for Canvas {
314 fn from(ib: &RgbImage) -> Self {
315 let mut data4: Vec<u8> = Vec::new();
316 let data = ib.clone().into_vec();
317 for d in data.chunks(3) {
318 data4.extend(d);
319 data4.push(255)
320 }
321 image_to_canvas(ib.width(), ib.height(), data4)
322 }
323}
324
325impl From<RgbaImage> for Canvas {
327 fn from(ib: RgbaImage) -> Self {
328 image_to_canvas(ib.width(), ib.height(), ib.into_vec())
329 }
330}
331
332impl From<RgbImage> for Canvas {
334 fn from(ib: RgbImage) -> Self {
335 let mut data4: Vec<u8> = Vec::new();
336 let data = ib.clone().into_vec();
337 for d in data.chunks(3) {
338 data4.extend(d);
339 data4.push(255)
340 }
341 image_to_canvas(ib.width(), ib.height(), data4)
342 }
343}
344
345impl From<Canvas> for RgbaImage {
347 fn from(canvas: Canvas) -> Self {
348 let data = canvas.pixmap.data().to_vec();
349 RgbaImage::from_vec(canvas.width(), canvas.height(), data).unwrap()
350 }
351}
352
353impl From<&Canvas> for RgbaImage {
355 fn from(canvas: &Canvas) -> Self {
356 let data = canvas.pixmap.data().to_vec();
357 RgbaImage::from_vec(canvas.width(), canvas.height(), data).unwrap()
358 }
359}