1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
3
4use std::vec;
5
6use i_slint_core::{
7 graphics::{Image, SharedImageBuffer, SharedPixelBuffer},
8 ImageInner,
9};
10use napi::{
11 bindgen_prelude::{Buffer, External},
12 Env, JsUnknown,
13};
14
15// This is needed for typedoc check JsImageData::image
16pub type ImageData = Image;
17
18/// SlintPoint implements {@link ImageData}.
19#[napi]
20pub struct SlintImageData {
21 inner: Image,
22}
23
24impl From<Image> for SlintImageData {
25 fn from(image: Image) -> Self {
26 Self { inner: image }
27 }
28}
29
30#[napi]
31impl SlintImageData {
32 /// Constructs a new image with the given width and height.
33 /// Each pixel will set to red = 0, green = 0, blue = 0 and alpha = 0.
34 #[napi(constructor)]
35 pub fn new(width: u32, height: u32) -> Self {
36 Self { inner: Image::from_rgba8(SharedPixelBuffer::new(width, height)) }
37 }
38
39 /// Returns the width of the image in pixels.
40 #[napi(getter)]
41 pub fn width(&self) -> u32 {
42 self.inner.size().width
43 }
44
45 /// Returns the height of the image in pixels.
46 #[napi(getter)]
47 pub fn height(&self) -> u32 {
48 self.inner.size().height
49 }
50
51 /// Returns the image as buffer.
52 /// A Buffer is a subclass of Uint8Array.
53 #[napi(getter)]
54 pub fn data(&self) -> Buffer {
55 let image_inner: &ImageInner = (&self.inner).into();
56 if let Some(buffer) = image_inner.render_to_buffer(None) {
57 match buffer {
58 SharedImageBuffer::RGB8(buffer) => {
59 return Buffer::from(rgb_to_rgba(
60 buffer.as_bytes(),
61 (self.width() * self.height()) as usize,
62 ))
63 }
64 SharedImageBuffer::RGBA8(buffer) => return Buffer::from(buffer.as_bytes()),
65 SharedImageBuffer::RGBA8Premultiplied(buffer) => {
66 return Buffer::from(rgb_to_rgba(
67 buffer.as_bytes(),
68 (self.width() * self.height()) as usize,
69 ))
70 }
71 }
72 }
73
74 Buffer::from(vec![0; (self.width() * self.height() * 4) as usize])
75 }
76
77 #[napi(getter)]
78 pub fn path(&self, env: Env) -> napi::Result<JsUnknown> {
79 self.inner.path().map_or_else(
80 || env.get_undefined().map(|v| v.into_unknown()),
81 |p| env.create_string(p.to_string_lossy().as_ref()).map(|v| v.into_unknown()),
82 )
83 }
84
85 /// @hidden
86 #[napi(getter)]
87 pub fn image(&self) -> External<ImageData> {
88 External::new(self.inner.clone())
89 }
90}
91
92fn rgb_to_rgba(bytes: &[u8], size: usize) -> Vec<u8> {
93 let mut rgba_bytes: Vec = vec![];
94
95 for i: usize in 0..size {
96 if (i * 3) + 2 >= bytes.len() {
97 continue;
98 }
99
100 rgba_bytes.push(bytes[i * 3]);
101 rgba_bytes.push(bytes[(i * 3) + 1]);
102 rgba_bytes.push(bytes[(i * 3) + 2]);
103 rgba_bytes.push(255);
104 }
105
106 rgba_bytes
107}
108