1use crate::helpers::image_decoding_helper::{jpeg_scaled_dimensions, reduce_by_area, DecodedImage, EncodedImageFormat};
2use crate::helpers::image_saving_helper::{self, decode_image, load_error};
3use crate::helpers::pixel_format_helper::{scene_size, to_image, to_premul_rgba, try_bytes_per_pixel};
4use crate::i_drawable_bitmap_impl::IDrawableBitmapImpl;
5use crate::scene::{IVelloSceneSink, VelloCpuSceneSink, VelloSceneBrush, VelloSceneImage, VelloScenePaint};
6use crate::helpers::mipmap_helper;
7use crate::vello_extensions::{rect_path, to_sampling};
8use ferroui_base::media::imaging::{BitmapEncoderOptions, BitmapInterpolationMode};
9use ferroui_base::platform::{AlphaFormat, IBitmapImpl, ILockedFramebuffer, IReadableBitmapImpl, PixelFormat};
10use ferroui_base::{PixelSize, Rect, Vector};
11use kurbo::Affine;
12use peniko::{BlendMode, Extend, Fill, ImageData};
13use std::any::Any;
14use std::cell::RefCell;
15use std::io::{self, Read, Write};
16use std::rc::Rc;
17use std::sync::Mutex;
18
19fn decoded_to_image(rgba: Vec<u8>, width: u32, height: u32) -> io::Result<ImageData> {
21 let size = PixelSize::new(i32::try_from(width).map_err(|_| load_error())?, i32::try_from(height).map_err(|_| load_error())?);
22
23 Ok(to_image(rgba, size))
24}
25
26pub(crate) fn decode_bitmap(stream: &mut dyn Read) -> io::Result<(ImageData, bool)> {
29 let DecodedImage { rgba, width, height, opaque, .. } = decode_image(stream)?;
30
31 Ok((decoded_to_image(rgba, width, height)?, opaque))
32}
33
34pub(crate) fn decode_bitmap_to_size(
37 stream: &mut dyn Read,
38 decode_size: i32,
39 horizontal: bool,
40 interpolation_mode: BitmapInterpolationMode,
41) -> io::Result<ImageData> {
42 let DecodedImage { mut rgba, mut width, mut height, format, .. } = decode_image(stream)?;
43 if decode_size < 1 {
44 return Err(load_error());
45 }
46 let (natural_width, natural_height) = (width, height);
47
48 if format == EncodedImageFormat::Jpeg {
53 let scale = decode_size as f64 / if horizontal { width } else { height } as f64;
54 let (scaled_width, scaled_height) = jpeg_scaled_dimensions(width, height, scale);
55 if (scaled_width, scaled_height) != (width, height) {
56 rgba = reduce_by_area(&rgba, width as usize, height as usize, scaled_width as usize, scaled_height as usize);
57 (width, height) = (scaled_width, scaled_height);
58 }
59 }
60 let image = decoded_to_image(rgba, width, height)?;
61
62 let real_scale = if horizontal {
64 natural_height as f64 / natural_width as f64
65 } else {
66 natural_width as f64 / natural_height as f64
67 };
68
69 let desired = if horizontal {
70 PixelSize::new(decode_size, (real_scale * decode_size as f64) as i32)
71 } else {
72 PixelSize::new((real_scale * decode_size as f64) as i32, decode_size)
73 };
74
75 if desired.width as u32 != image.width || desired.height as u32 != image.height {
76 return scale_image(&image, desired, interpolation_mode);
77 }
78
79 Ok(image)
80}
81
82pub(crate) fn scale_image(
88 image: &ImageData,
89 destination_size: PixelSize,
90 interpolation_mode: BitmapInterpolationMode,
91) -> io::Result<ImageData> {
92 if destination_size.width < 1
93 || destination_size.height < 1
94 || destination_size.width > u16::MAX as i32
95 || destination_size.height > u16::MAX as i32
96 || image.width == 0
97 || image.height == 0
98 {
99 return Err(load_error());
100 }
101
102 let (width, height) = scene_size(destination_size);
103 let mut sink = VelloCpuSceneSink::new(width, height);
104
105 let destination = Rect::new(0.0, 0.0, destination_size.width as f64, destination_size.height as f64);
106 let is_upscaling =
107 destination_size.width as u32 > image.width || destination_size.height as u32 > image.height;
108 let (quality, mipmaps) = to_sampling(interpolation_mode, is_upscaling);
109
110 let transform =
111 Affine::scale_non_uniform(destination.width / image.width as f64, destination.height / image.height as f64);
112
113 match mipmaps.then(|| mipmap_helper::levels(image, transform)).flatten() {
116 Some(levels) => mipmap_helper::fill_with_levels(
117 &mut sink,
118 &rect_path(destination),
119 Affine::IDENTITY,
120 transform,
121 &levels,
122 1.0,
123 false,
124 ),
125 None => {
126 let paint = VelloScenePaint {
127 brush: VelloSceneBrush::Image(VelloSceneImage {
128 image: image.clone(),
129 x_extend: Extend::Pad,
130 y_extend: Extend::Pad,
131 quality,
132 alpha: 1.0,
133 }),
134 transform,
135 };
136 sink.fill(&rect_path(destination), Fill::NonZero, Affine::IDENTITY, &paint, BlendMode::default(), false);
137 }
138 }
139
140 let mut rgba = vec![0u8; width as usize * height as usize * 4];
141 sink.render_to_pixels(&mut rgba);
142
143 Ok(to_image(rgba, destination_size))
144}
145
146struct SourcePixels {
148 data: Vec<u8>,
150 row_bytes: usize,
151 format: PixelFormat,
152 alpha_format: AlphaFormat,
153}
154
155pub struct ImmutableBitmap {
163 image: Mutex<Option<ImageData>>,
164 source: Mutex<Option<SourcePixels>>,
165 opaque: bool,
167 dpi: Vector,
168 pixel_size: PixelSize,
169}
170
171impl ImmutableBitmap {
172 pub fn from_image(image: ImageData) -> Self {
174 let pixel_size = PixelSize::new(image.width as i32, image.height as i32);
175
176 Self {
177 image: Mutex::new(Some(image)),
178 source: Mutex::new(None),
179 opaque: false,
180 dpi: Vector::new(96.0, 96.0),
181 pixel_size,
182 }
183 }
184
185 pub fn from_stream(stream: &mut dyn Read) -> io::Result<Self> {
187 let (image, opaque) = decode_bitmap(stream)?;
189
190 Ok(Self { opaque, ..Self::from_image(image) })
191 }
192
193 pub fn from_stream_to_size(
196 stream: &mut dyn Read,
197 decode_size: i32,
198 horizontal: bool,
199 interpolation_mode: BitmapInterpolationMode,
200 ) -> io::Result<Self> {
201 Ok(Self::from_image(decode_bitmap_to_size(stream, decode_size, horizontal, interpolation_mode)?))
202 }
203
204 pub fn resized(
206 src: &ImmutableBitmap,
207 destination_size: PixelSize,
208 interpolation_mode: BitmapInterpolationMode,
209 ) -> io::Result<Self> {
210 let image = src.image().ok_or_else(load_error)?;
211
212 Ok(Self::from_image(scale_image(&image, destination_size, interpolation_mode)?))
213 }
214
215 pub fn from_pixels(
224 size: PixelSize,
225 dpi: Vector,
226 stride: i32,
227 format: PixelFormat,
228 alpha_format: AlphaFormat,
229 data: &[u8],
230 ) -> io::Result<Self> {
231 let create_error =
232 || io::Error::new(io::ErrorKind::InvalidInput, "Unable to create bitmap from provided data");
233
234 let pixel_bytes =
235 try_bytes_per_pixel(format).unwrap_or_else(|| panic!("Unknown pixel format: {format}"));
236 if size.width < 1 || size.height < 1 || size.width > u16::MAX as i32 || size.height > u16::MAX as i32 {
237 return Err(create_error());
238 }
239
240 let (width, height) = (size.width as usize, size.height as usize);
241 let row_bytes = width * pixel_bytes;
242 let abs_stride = stride.unsigned_abs() as usize;
243 let copy_bytes = row_bytes.min(abs_stride);
244
245 if data.len() < abs_stride * (height - 1) + copy_bytes {
246 return Err(create_error());
247 }
248
249 let mut pixels = vec![0u8; row_bytes * height];
252 for row in 0..height {
253 let source_row = if stride < 0 { height - 1 - row } else { row };
254 let source = &data[source_row * abs_stride..source_row * abs_stride + copy_bytes];
255 pixels[row * row_bytes..row * row_bytes + copy_bytes].copy_from_slice(source);
256 }
257
258 let rgba = to_premul_rgba(&pixels, row_bytes, size, format, alpha_format);
259
260 let source = (format != PixelFormat::RGBA8888 || alpha_format != AlphaFormat::Premul)
262 .then_some(SourcePixels { data: pixels, row_bytes, format, alpha_format });
263
264 Ok(Self {
265 image: Mutex::new(Some(to_image(rgba, size))),
266 source: Mutex::new(source),
267 opaque: false,
268 dpi,
269 pixel_size: size,
270 })
271 }
272}
273
274impl IBitmapImpl for ImmutableBitmap {
275 fn dpi(&self) -> Vector {
276 self.dpi
277 }
278
279 fn pixel_size(&self) -> PixelSize {
280 self.pixel_size
281 }
282
283 fn version(&self) -> i32 {
284 1
285 }
286
287 fn save(&self, stream: &mut dyn Write, options: &BitmapEncoderOptions) -> io::Result<()> {
288 let image = self.image().ok_or_else(|| io::Error::other("ImmutableBitmap has been disposed"))?;
289 image_saving_helper::save_image(&image, stream, options)
290 }
291
292 fn dispose(&self) {
293 self.image.lock().unwrap().take();
294 self.source.lock().unwrap().take();
295 }
296
297 fn as_any(&self) -> &dyn Any {
298 self
299 }
300
301 fn as_readable_bitmap(&self) -> Option<&dyn IReadableBitmapImpl> {
302 Some(self)
303 }
304}
305
306impl IDrawableBitmapImpl for ImmutableBitmap {
307 fn image(&self) -> Option<ImageData> {
308 self.image.lock().unwrap().clone()
309 }
310}
311
312impl IReadableBitmapImpl for ImmutableBitmap {
313 fn format(&self) -> Option<PixelFormat> {
314 Some(self.source.lock().unwrap().as_ref().map_or(PixelFormat::RGBA8888, |source| source.format))
315 }
316
317 fn alpha_format(&self) -> Option<AlphaFormat> {
318 Some(self.source.lock().unwrap().as_ref().map_or(self.decoded_alpha_format(), |source| source.alpha_format))
319 }
320
321 fn lock(&self) -> Rc<dyn ILockedFramebuffer> {
322 if let Some(source) = self.source.lock().unwrap().as_ref() {
325 return Rc::new(PixelsFramebuffer {
326 pixels: RefCell::new(source.data.clone()),
327 size: self.pixel_size,
328 row_bytes: source.row_bytes,
329 dpi: self.dpi,
330 format: source.format,
331 alpha_format: source.alpha_format,
332 });
333 }
334
335 let image = self.image().unwrap_or_else(|| panic!("ImmutableBitmap has been disposed"));
336
337 Rc::new(PixelsFramebuffer {
338 pixels: RefCell::new(image.data.data().to_vec()),
339 size: self.pixel_size,
340 row_bytes: self.pixel_size.width.max(0) as usize * 4,
341 dpi: self.dpi,
342 format: PixelFormat::RGBA8888,
343 alpha_format: self.decoded_alpha_format(),
344 })
345 }
346}
347
348impl ImmutableBitmap {
349 fn decoded_alpha_format(&self) -> AlphaFormat {
353 if self.opaque {
354 AlphaFormat::Opaque
355 } else {
356 AlphaFormat::Premul
357 }
358 }
359}
360
361pub(crate) struct PixelsFramebuffer {
363 pub pixels: RefCell<Vec<u8>>,
364 pub size: PixelSize,
365 pub row_bytes: usize,
366 pub dpi: Vector,
367 pub format: PixelFormat,
368 pub alpha_format: AlphaFormat,
369}
370
371impl ILockedFramebuffer for PixelsFramebuffer {
372 fn address(&self) -> *mut u8 {
373 self.pixels.borrow_mut().as_mut_ptr()
374 }
375
376 fn with_data(&self, access: &mut dyn FnMut(&mut [u8])) {
377 access(&mut self.pixels.borrow_mut());
378 }
379
380 fn size(&self) -> PixelSize {
381 self.size
382 }
383
384 fn row_bytes(&self) -> i32 {
385 self.row_bytes as i32
386 }
387
388 fn dpi(&self) -> Vector {
389 self.dpi
390 }
391
392 fn format(&self) -> PixelFormat {
393 self.format
394 }
395
396 fn alpha_format(&self) -> AlphaFormat {
397 self.alpha_format
398 }
399
400 fn dispose(&self) {}
401}