ltk_webkit/wpe/print/
sheet.rs

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
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use image::{ imageops, Rgb, RgbImage };

use super::geometry::Geometry;
use super::pdf;

/// The page as it would be printed, `out_width` pixels wide with its margins, in RGBA: its width and height too.
pub( super ) fn sheet( rgba: &[ u8 ], width: u32, first: u32, rows: u32, height: u32, geometry: &Geometry, out_width: u32 ) -> Result<( Vec<u8>, u32, u32 ), String>
{
	if width == 0 || height == 0 || out_width == 0 { return Err( "empty page".to_string() ); }
	let area = RgbImage::from_raw( width, height, pdf::flatten( rgba, width, first, rows, height ) ).ok_or( "the page does not fit its size" )?;
	let ( paper_width, paper_height )       = geometry.paper;
	let ( left, bottom, area_w, area_h )    = geometry.area;
	let px      = out_width as f64 / paper_width;
	let sheet_h = ( paper_height * px ).round().max( 1.0 ) as u32;
	let scaled  = imageops::resize( &area, ( area_w * px ).round().max( 1.0 ) as u32, ( area_h * px ).round().max( 1.0 ) as u32, imageops::FilterType::Triangle );
	let mut out = RgbImage::from_pixel( out_width, sheet_h, Rgb( [ 255; 3 ] ) );
	let top     = paper_height - bottom - area_h;
	imageops::replace( &mut out, &scaled, ( left * px ).round() as i64, ( top * px ).round() as i64 );
	let rgba = out.pixels().flat_map( |p| [ p[ 0 ], p[ 1 ], p[ 2 ], 255 ] ).collect();
	Ok( ( rgba, out_width, sheet_h ) )
}

#[ cfg( test ) ]
mod tests
{
	use super::*;
	use crate::types::PrintSettings;

	#[ test ]
	fn the_margins_are_white_and_the_page_is_inside()
	{
		let g = super::super::geometry::geometry( &PrintSettings::default(), 1.0, 72.0 ).unwrap();
		let ( w, h ) = ( 100u32, 140u32 );
		let black    = [ 0u8, 0, 0, 255 ].repeat( ( w * h ) as usize );
		let ( rgba, width, height ) = sheet( &black, w, 0, h, h, &g, 300 ).unwrap();
		assert_eq!( width, 300 );
		assert_eq!( height, ( 300.0 * g.paper.1 / g.paper.0 ).round() as u32 );
		let at = |x: u32, y: u32| rgba[ ( ( y * width + x ) * 4 ) as usize ];
		assert_eq!( at( 2, 2 ), 255 );
		assert_eq!( at( width / 2, height / 2 ), 0 );
	}
}