use super::colorspace::{ColorspaceHandle, FZ_COLORSPACE_RGB};
use super::geometry::fz_irect;
use super::{Handle, PIXMAPS};
pub struct Pixmap {
x: i32,
y: i32,
width: i32,
height: i32,
n: i32, alpha: bool,
stride: i32,
samples: Vec<u8>,
colorspace: ColorspaceHandle,
xres: i32,
yres: i32,
}
impl Pixmap {
pub fn new(cs: ColorspaceHandle, width: i32, height: i32, alpha: bool) -> Self {
let n = super::colorspace::fz_colorspace_n(0, cs) + i32::from(alpha);
let stride = width * n;
let size = (stride * height) as usize;
Self {
x: 0,
y: 0,
width,
height,
n,
alpha,
stride,
samples: vec![255u8; size],
colorspace: cs,
xres: 72,
yres: 72,
}
}
pub fn with_bbox(cs: ColorspaceHandle, bbox: fz_irect, alpha: bool) -> Self {
let width = bbox.x1 - bbox.x0;
let height = bbox.y1 - bbox.y0;
let n = super::colorspace::fz_colorspace_n(0, cs) + i32::from(alpha);
let stride = width * n;
let size = (stride * height).max(0) as usize;
Self {
x: bbox.x0,
y: bbox.y0,
width,
height,
n,
alpha,
stride,
samples: vec![255u8; size],
colorspace: cs,
xres: 72,
yres: 72,
}
}
pub fn clear(&mut self) {
self.samples.fill(0);
}
pub fn clear_with_value(&mut self, value: u8) {
self.samples.fill(value);
}
pub fn get_sample(&self, x: i32, y: i32, component: i32) -> Option<u8> {
if x < self.x
|| x >= self.x + self.width
|| y < self.y
|| y >= self.y + self.height
|| component < 0
|| component >= self.n
{
return None;
}
let local_x = x - self.x;
let local_y = y - self.y;
let offset = (local_y * self.stride + local_x * self.n + component) as usize;
self.samples.get(offset).copied()
}
pub fn set_sample(&mut self, x: i32, y: i32, component: i32, value: u8) {
if x < self.x
|| x >= self.x + self.width
|| y < self.y
|| y >= self.y + self.height
|| component < 0
|| component >= self.n
{
return;
}
let local_x = x - self.x;
let local_y = y - self.y;
let offset = (local_y * self.stride + local_x * self.n + component) as usize;
if let Some(sample) = self.samples.get_mut(offset) {
*sample = value;
}
}
pub fn w(&self) -> i32 {
self.width
}
pub fn h(&self) -> i32 {
self.height
}
pub fn x(&self) -> i32 {
self.x
}
pub fn y(&self) -> i32 {
self.y
}
pub fn n(&self) -> i32 {
self.n
}
pub fn stride(&self) -> i32 {
self.stride
}
pub fn has_alpha(&self) -> bool {
self.alpha
}
pub fn colorspace(&self) -> ColorspaceHandle {
self.colorspace
}
pub fn xres(&self) -> i32 {
self.xres
}
pub fn yres(&self) -> i32 {
self.yres
}
pub fn set_xres(&mut self, xres: i32) {
self.xres = xres;
}
pub fn set_yres(&mut self, yres: i32) {
self.yres = yres;
}
pub fn samples(&self) -> &[u8] {
&self.samples
}
pub fn samples_mut(&mut self) -> &mut [u8] {
&mut self.samples
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_new_pixmap(
_ctx: Handle,
cs: ColorspaceHandle,
w: i32,
h: i32,
_seps: Handle, alpha: i32,
) -> Handle {
let cs = if cs == 0 { FZ_COLORSPACE_RGB } else { cs };
PIXMAPS.insert(Pixmap::new(cs, w, h, alpha != 0))
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_new_pixmap_with_bbox(
_ctx: Handle,
cs: ColorspaceHandle,
bbox: fz_irect,
_seps: Handle,
alpha: i32,
) -> Handle {
let cs = if cs == 0 { FZ_COLORSPACE_RGB } else { cs };
PIXMAPS.insert(Pixmap::with_bbox(cs, bbox, alpha != 0))
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_keep_pixmap(_ctx: Handle, pix: Handle) -> Handle {
PIXMAPS.keep(pix)
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_drop_pixmap(_ctx: Handle, pix: Handle) {
let _ = PIXMAPS.remove(pix);
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_x(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.x;
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_y(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.y;
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_width(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.width;
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_height(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.height;
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_components(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.n;
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_colorants(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.n - i32::from(guard.alpha);
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_alpha(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return i32::from(guard.alpha);
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_stride(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.stride;
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_bbox(_ctx: Handle, pix: Handle) -> fz_irect {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return fz_irect {
x0: guard.x,
y0: guard.y,
x1: guard.x + guard.width,
y1: guard.y + guard.height,
};
}
}
fz_irect {
x0: 0,
y0: 0,
x1: 0,
y1: 0,
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_colorspace(_ctx: Handle, pix: Handle) -> ColorspaceHandle {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.colorspace;
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_clear_pixmap(_ctx: Handle, pix: Handle) {
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(mut p) = pixmap.lock() {
p.clear();
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_clear_pixmap_with_value(_ctx: Handle, pix: Handle, value: i32) {
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(mut p) = pixmap.lock() {
p.clear_with_value(value as u8);
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_invert_pixmap(_ctx: Handle, pix: Handle) {
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(mut p) = pixmap.lock() {
let colorants = (p.n - i32::from(p.alpha)) as usize;
for y in 0..p.height {
for x in 0..p.width {
let offset = (y * p.stride + x * p.n) as usize;
for c in 0..colorants {
if let Some(sample) = p.samples.get_mut(offset + c) {
*sample = 255 - *sample;
}
}
}
}
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_gamma_pixmap(_ctx: Handle, pix: Handle, gamma: f32) {
if gamma <= 0.0 {
return;
}
let mut gamma_table = [0u8; 256];
for (i, entry) in gamma_table.iter_mut().enumerate() {
let normalized = (i as f32) / 255.0;
let corrected = normalized.powf(1.0 / gamma);
*entry = (corrected * 255.0).round().clamp(0.0, 255.0) as u8;
}
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(mut p) = pixmap.lock() {
let colorants = (p.n - i32::from(p.alpha)) as usize;
for y in 0..p.height {
for x in 0..p.width {
let offset = (y * p.stride + x * p.n) as usize;
for c in 0..colorants {
if let Some(sample) = p.samples.get_mut(offset + c) {
*sample = gamma_table[*sample as usize];
}
}
}
}
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_get_pixmap_sample(_ctx: Handle, pix: Handle, x: i32, y: i32, n: i32) -> u8 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
if let Some(sample) = guard.get_sample(x, y, n) {
return sample;
}
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_set_pixmap_sample(_ctx: Handle, pix: Handle, x: i32, y: i32, n: i32, v: u8) {
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(mut p) = pixmap.lock() {
p.set_sample(x, y, n, v);
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_samples(_ctx: Handle, pix: Handle) -> *mut u8 {
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(mut guard) = pixmap.lock() {
if !guard.samples.is_empty() {
return guard.samples.as_mut_ptr();
}
}
}
std::ptr::null_mut()
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_samples_size(_ctx: Handle, pix: Handle) -> usize {
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(guard) = pixmap.lock() {
return guard.samples.len();
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_clone_pixmap(_ctx: Handle, pix: Handle) -> Handle {
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(guard) = pixmap.lock() {
let cloned = Pixmap {
x: guard.x,
y: guard.y,
width: guard.width,
height: guard.height,
n: guard.n,
alpha: guard.alpha,
stride: guard.stride,
samples: guard.samples.clone(),
colorspace: guard.colorspace,
xres: guard.xres,
yres: guard.yres,
};
return PIXMAPS.insert(cloned);
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_convert_pixmap(
_ctx: Handle,
pix: Handle,
cs: ColorspaceHandle,
_prf: Handle, _default_cs: Handle,
_color_params: Handle,
keep_alpha: i32,
) -> Handle {
let cs = if cs == 0 { FZ_COLORSPACE_RGB } else { cs };
let target_n = super::colorspace::fz_colorspace_n(0, cs);
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(guard) = pixmap.lock() {
let alpha = if keep_alpha != 0 { guard.alpha } else { false };
let new_n = target_n + i32::from(alpha);
let new_stride = guard.width * new_n;
let new_size = (new_stride * guard.height).max(0) as usize;
let mut new_samples = vec![0u8; new_size];
let src_colorants = (guard.n - i32::from(guard.alpha)) as usize;
let dst_colorants = target_n as usize;
for y in 0..guard.height {
for x in 0..guard.width {
let src_offset = (y * guard.stride + x * guard.n) as usize;
let dst_offset = (y * new_stride + x * new_n) as usize;
let mut src_colors = [0u8; 4];
for (c, color) in src_colors.iter_mut().enumerate().take(src_colorants.min(4)) {
*color = guard.samples.get(src_offset + c).copied().unwrap_or(0);
}
let dst_colors = convert_color(
guard.colorspace,
cs,
&src_colors[..src_colorants.min(4)],
dst_colorants,
);
for c in 0..dst_colorants {
if let Some(sample) = new_samples.get_mut(dst_offset + c) {
*sample = dst_colors.get(c).copied().unwrap_or(0);
}
}
if alpha && guard.alpha {
let src_alpha_offset = src_offset + src_colorants;
let dst_alpha_offset = dst_offset + dst_colorants;
if let (Some(&src_alpha), Some(dst_alpha)) = (
guard.samples.get(src_alpha_offset),
new_samples.get_mut(dst_alpha_offset),
) {
*dst_alpha = src_alpha;
}
} else if alpha {
let dst_alpha_offset = dst_offset + dst_colorants;
if let Some(dst_alpha) = new_samples.get_mut(dst_alpha_offset) {
*dst_alpha = 255;
}
}
}
}
let converted = Pixmap {
x: guard.x,
y: guard.y,
width: guard.width,
height: guard.height,
n: new_n,
alpha,
stride: new_stride,
samples: new_samples,
colorspace: cs,
xres: guard.xres,
yres: guard.yres,
};
return PIXMAPS.insert(converted);
}
}
0
}
fn convert_color(
src_cs: ColorspaceHandle,
dst_cs: ColorspaceHandle,
src: &[u8],
dst_n: usize,
) -> Vec<u8> {
use super::colorspace::{FZ_COLORSPACE_CMYK, FZ_COLORSPACE_GRAY, FZ_COLORSPACE_RGB};
let mut dst = vec![0u8; dst_n];
match (src_cs, dst_cs) {
(s, d) if s == d => {
for (i, &v) in src.iter().enumerate().take(dst_n) {
dst[i] = v;
}
}
(FZ_COLORSPACE_GRAY, FZ_COLORSPACE_RGB) => {
let gray = src.first().copied().unwrap_or(0);
dst[0] = gray;
dst[1] = gray;
dst[2] = gray;
}
(FZ_COLORSPACE_RGB, FZ_COLORSPACE_GRAY) => {
let r = src.first().copied().unwrap_or(0) as u32;
let g = src.get(1).copied().unwrap_or(0) as u32;
let b = src.get(2).copied().unwrap_or(0) as u32;
let gray = ((r * 77 + g * 150 + b * 29) >> 8) as u8;
dst[0] = gray;
}
(FZ_COLORSPACE_CMYK, FZ_COLORSPACE_RGB) => {
let c = src.first().copied().unwrap_or(0) as f32 / 255.0;
let m = src.get(1).copied().unwrap_or(0) as f32 / 255.0;
let y = src.get(2).copied().unwrap_or(0) as f32 / 255.0;
let k = src.get(3).copied().unwrap_or(0) as f32 / 255.0;
dst[0] = ((1.0 - c) * (1.0 - k) * 255.0) as u8;
dst[1] = ((1.0 - m) * (1.0 - k) * 255.0) as u8;
dst[2] = ((1.0 - y) * (1.0 - k) * 255.0) as u8;
}
(FZ_COLORSPACE_RGB, FZ_COLORSPACE_CMYK) => {
let r = src.first().copied().unwrap_or(0) as f32 / 255.0;
let g = src.get(1).copied().unwrap_or(0) as f32 / 255.0;
let b = src.get(2).copied().unwrap_or(0) as f32 / 255.0;
let k = 1.0 - r.max(g).max(b);
if k < 1.0 {
dst[0] = ((1.0 - r - k) / (1.0 - k) * 255.0) as u8;
dst[1] = ((1.0 - g - k) / (1.0 - k) * 255.0) as u8;
dst[2] = ((1.0 - b - k) / (1.0 - k) * 255.0) as u8;
}
dst[3] = (k * 255.0) as u8;
}
(FZ_COLORSPACE_GRAY, FZ_COLORSPACE_CMYK) => {
let gray = src.first().copied().unwrap_or(0);
dst[0] = 0;
dst[1] = 0;
dst[2] = 0;
dst[3] = 255 - gray;
}
(FZ_COLORSPACE_CMYK, FZ_COLORSPACE_GRAY) => {
let c = src.first().copied().unwrap_or(0) as f32 / 255.0;
let m = src.get(1).copied().unwrap_or(0) as f32 / 255.0;
let y = src.get(2).copied().unwrap_or(0) as f32 / 255.0;
let k = src.get(3).copied().unwrap_or(0) as f32 / 255.0;
let r = (1.0 - c) * (1.0 - k);
let g = (1.0 - m) * (1.0 - k);
let b = (1.0 - y) * (1.0 - k);
dst[0] = ((r * 0.3 + g * 0.59 + b * 0.11) * 255.0) as u8;
}
_ => {
for (i, &v) in src.iter().enumerate().take(dst_n) {
dst[i] = v;
}
}
}
dst
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_tint_pixmap(_ctx: Handle, pix: Handle, r: i32, g: i32, b: i32) {
if let Some(pixmap) = PIXMAPS.get(pix) {
if let Ok(mut p) = pixmap.lock() {
if p.n - i32::from(p.alpha) != 1 {
return;
}
let r_factor = (r as f32) / 255.0;
let g_factor = (g as f32) / 255.0;
let b_factor = (b as f32) / 255.0;
for y in 0..p.height {
for x in 0..p.width {
let offset = (y * p.stride + x * p.n) as usize;
if let Some(sample) = p.samples.get_mut(offset) {
let gray = *sample as f32;
let factor = (r_factor + g_factor + b_factor) / 3.0;
*sample = (gray * factor).clamp(0.0, 255.0) as u8;
}
}
}
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_set_pixmap_resolution(_ctx: Handle, pix: Handle, xres: i32, yres: i32) {
if let Some(pm) = PIXMAPS.get(pix) {
if let Ok(mut guard) = pm.lock() {
guard.xres = xres;
guard.yres = yres;
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_resolution(_ctx: Handle, pix: Handle, xres: *mut i32, yres: *mut i32) {
let (rx, ry) = if let Some(pm) = PIXMAPS.get(pix) {
if let Ok(guard) = pm.lock() {
(guard.xres, guard.yres)
} else {
(72, 72)
}
} else {
(72, 72)
};
if !xres.is_null() {
unsafe {
*xres = rx;
}
}
if !yres.is_null() {
unsafe {
*yres = ry;
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_is_valid(_ctx: Handle, pix: Handle) -> i32 {
if PIXMAPS.get(pix).is_some() { 1 } else { 0 }
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_scale_pixmap(_ctx: Handle, pix: Handle, xscale: f32, yscale: f32) -> Handle {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
let new_width = ((guard.width as f32) * xscale) as i32;
let new_height = ((guard.height as f32) * yscale) as i32;
if new_width <= 0 || new_height <= 0 {
return 0;
}
let mut scaled = Pixmap::new(guard.colorspace, new_width, new_height, guard.alpha);
for y in 0..new_height {
for x in 0..new_width {
let src_x = ((x as f32) / xscale) as i32;
let src_y = ((y as f32) / yscale) as i32;
for c in 0..guard.n {
if let Some(value) = guard.get_sample(src_x, src_y, c) {
scaled.set_sample(x, y, c, value);
}
}
}
}
return PIXMAPS.insert(scaled);
}
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_xres(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.xres();
}
}
72 }
#[unsafe(no_mangle)]
pub extern "C" fn fz_pixmap_yres(_ctx: Handle, pix: Handle) -> i32 {
if let Some(p) = PIXMAPS.get(pix) {
if let Ok(guard) = p.lock() {
return guard.yres();
}
}
72 }
#[unsafe(no_mangle)]
pub extern "C" fn fz_set_pixmap_xres(_ctx: Handle, pix: Handle, xres: i32) {
if let Some(pm) = PIXMAPS.get(pix) {
if let Ok(mut guard) = pm.lock() {
guard.set_xres(xres);
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fz_set_pixmap_yres(_ctx: Handle, pix: Handle, yres: i32) {
if let Some(pm) = PIXMAPS.get(pix) {
if let Ok(mut guard) = pm.lock() {
guard.set_yres(yres);
}
}
}
#[cfg(test)]
mod tests {
use super::super::colorspace::FZ_COLORSPACE_GRAY;
use super::*;
#[test]
fn test_pixmap_create() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 100, 100, 0, 1);
assert_ne!(handle, 0);
assert_eq!(fz_pixmap_width(0, handle), 100);
assert_eq!(fz_pixmap_height(0, handle), 100);
assert_eq!(fz_pixmap_components(0, handle), 4); assert_eq!(fz_pixmap_alpha(0, handle), 1);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_create_gray() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_GRAY, 50, 50, 0, 0);
assert_ne!(handle, 0);
assert_eq!(fz_pixmap_components(0, handle), 1); assert_eq!(fz_pixmap_colorants(0, handle), 1);
assert_eq!(fz_pixmap_alpha(0, handle), 0);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_clear() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
fz_clear_pixmap_with_value(0, handle, 128);
assert_eq!(fz_get_pixmap_sample(0, handle, 0, 0, 0), 128);
fz_clear_pixmap(0, handle);
assert_eq!(fz_get_pixmap_sample(0, handle, 0, 0, 0), 0);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_set_get_sample() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
fz_set_pixmap_sample(0, handle, 5, 5, 0, 255);
assert_eq!(fz_get_pixmap_sample(0, handle, 5, 5, 0), 255);
assert_eq!(fz_get_pixmap_sample(0, handle, 5, 5, 1), 255);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_keep() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
let kept = fz_keep_pixmap(0, handle);
assert_eq!(kept, handle);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_x_y() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
assert_eq!(fz_pixmap_x(0, handle), 0);
assert_eq!(fz_pixmap_y(0, handle), 0);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_stride() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
let stride = fz_pixmap_stride(0, handle);
assert_eq!(stride, 30);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_stride_with_alpha() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 1);
let stride = fz_pixmap_stride(0, handle);
assert_eq!(stride, 40);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_bbox() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 100, 50, 0, 0);
let bbox = fz_pixmap_bbox(0, handle);
assert_eq!(bbox.x0, 0);
assert_eq!(bbox.y0, 0);
assert_eq!(bbox.x1, 100);
assert_eq!(bbox.y1, 50);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_colorspace() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
let cs = fz_pixmap_colorspace(0, handle);
assert_eq!(cs, FZ_COLORSPACE_RGB);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_invalid_handle() {
assert_eq!(fz_pixmap_width(0, 0), 0);
assert_eq!(fz_pixmap_height(0, 0), 0);
assert_eq!(fz_pixmap_components(0, 0), 0);
assert_eq!(fz_pixmap_x(0, 0), 0);
assert_eq!(fz_pixmap_y(0, 0), 0);
assert_eq!(fz_pixmap_alpha(0, 0), 0);
assert_eq!(fz_pixmap_stride(0, 0), 0);
assert_eq!(fz_pixmap_colorants(0, 0), 0);
assert_eq!(fz_get_pixmap_sample(0, 0, 0, 0, 0), 0);
}
#[test]
fn test_pixmap_invert() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_GRAY, 2, 2, 0, 0);
fz_set_pixmap_sample(0, handle, 0, 0, 0, 100);
fz_set_pixmap_sample(0, handle, 1, 0, 0, 200);
fz_invert_pixmap(0, handle);
assert_eq!(fz_get_pixmap_sample(0, handle, 0, 0, 0), 155);
assert_eq!(fz_get_pixmap_sample(0, handle, 1, 0, 0), 55);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_gamma() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_GRAY, 2, 2, 0, 0);
fz_clear_pixmap_with_value(0, handle, 128);
fz_gamma_pixmap(0, handle, 1.0);
let sample = fz_get_pixmap_sample(0, handle, 0, 0, 0);
assert!((125..=131).contains(&sample));
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_sample_bounds() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
assert_eq!(fz_get_pixmap_sample(0, handle, -1, 0, 0), 0);
assert_eq!(fz_get_pixmap_sample(0, handle, 0, -1, 0), 0);
assert_eq!(fz_get_pixmap_sample(0, handle, 10, 0, 0), 0);
assert_eq!(fz_get_pixmap_sample(0, handle, 0, 10, 0), 0);
assert_eq!(fz_get_pixmap_sample(0, handle, 0, 0, 3), 0);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_internal_new() {
let pixmap = Pixmap::new(FZ_COLORSPACE_RGB, 100, 50, true);
assert_eq!(pixmap.width, 100);
assert_eq!(pixmap.height, 50);
assert_eq!(pixmap.n, 4); assert!(pixmap.alpha);
assert_eq!(pixmap.stride, 400); assert_eq!(pixmap.samples.len(), 400 * 50);
}
#[test]
fn test_pixmap_internal_get_set_sample() {
let mut pixmap = Pixmap::new(FZ_COLORSPACE_RGB, 10, 10, false);
pixmap.set_sample(5, 5, 0, 123);
assert_eq!(pixmap.get_sample(5, 5, 0), Some(123));
assert_eq!(pixmap.get_sample(-1, 0, 0), None);
assert_eq!(pixmap.get_sample(100, 0, 0), None);
}
#[test]
fn test_pixmap_internal_clear() {
let mut pixmap = Pixmap::new(FZ_COLORSPACE_GRAY, 5, 5, false);
pixmap.clear_with_value(255);
assert_eq!(pixmap.get_sample(0, 0, 0), Some(255));
assert_eq!(pixmap.get_sample(4, 4, 0), Some(255));
}
#[test]
fn test_clone_pixmap() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
fz_set_pixmap_sample(0, handle, 5, 5, 0, 123);
let cloned = fz_clone_pixmap(0, handle);
assert_ne!(cloned, 0);
assert_ne!(cloned, handle);
assert_eq!(fz_pixmap_width(0, cloned), 10);
assert_eq!(fz_get_pixmap_sample(0, cloned, 5, 5, 0), 123);
fz_set_pixmap_sample(0, handle, 5, 5, 0, 200);
assert_eq!(fz_get_pixmap_sample(0, cloned, 5, 5, 0), 123);
fz_drop_pixmap(0, handle);
fz_drop_pixmap(0, cloned);
}
#[test]
fn test_clone_pixmap_invalid() {
let result = fz_clone_pixmap(0, 99999);
assert_eq!(result, 0);
}
#[test]
fn test_convert_pixmap_gray_to_rgb() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_GRAY, 10, 10, 0, 0);
fz_set_pixmap_sample(0, handle, 5, 5, 0, 128);
let converted = fz_convert_pixmap(0, handle, FZ_COLORSPACE_RGB, 0, 0, 0, 0);
assert_ne!(converted, 0);
assert_eq!(fz_pixmap_colorspace(0, converted), FZ_COLORSPACE_RGB);
assert_eq!(fz_pixmap_components(0, converted), 3);
assert_eq!(fz_get_pixmap_sample(0, converted, 5, 5, 0), 128);
assert_eq!(fz_get_pixmap_sample(0, converted, 5, 5, 1), 128);
assert_eq!(fz_get_pixmap_sample(0, converted, 5, 5, 2), 128);
fz_drop_pixmap(0, handle);
fz_drop_pixmap(0, converted);
}
#[test]
fn test_convert_pixmap_rgb_to_gray() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
fz_set_pixmap_sample(0, handle, 5, 5, 0, 255);
fz_set_pixmap_sample(0, handle, 5, 5, 1, 0);
fz_set_pixmap_sample(0, handle, 5, 5, 2, 0);
let converted = fz_convert_pixmap(0, handle, FZ_COLORSPACE_GRAY, 0, 0, 0, 0);
assert_ne!(converted, 0);
assert_eq!(fz_pixmap_colorspace(0, converted), FZ_COLORSPACE_GRAY);
assert_eq!(fz_pixmap_components(0, converted), 1);
let gray = fz_get_pixmap_sample(0, converted, 5, 5, 0);
assert!(gray > 0 && gray < 128);
fz_drop_pixmap(0, handle);
fz_drop_pixmap(0, converted);
}
#[test]
fn test_convert_pixmap_with_alpha() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_GRAY, 10, 10, 0, 1);
fz_set_pixmap_sample(0, handle, 5, 5, 0, 128); fz_set_pixmap_sample(0, handle, 5, 5, 1, 200);
let converted = fz_convert_pixmap(0, handle, FZ_COLORSPACE_RGB, 0, 0, 0, 1);
assert_ne!(converted, 0);
assert_eq!(fz_pixmap_components(0, converted), 4);
assert_eq!(fz_pixmap_alpha(0, converted), 1);
assert_eq!(fz_get_pixmap_sample(0, converted, 5, 5, 3), 200);
fz_drop_pixmap(0, handle);
fz_drop_pixmap(0, converted);
}
#[test]
fn test_convert_pixmap_invalid() {
let result = fz_convert_pixmap(0, 99999, FZ_COLORSPACE_RGB, 0, 0, 0, 0);
assert_eq!(result, 0);
}
#[test]
fn test_pixmap_samples_returns_pointer() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
let samples = fz_pixmap_samples(0, handle);
assert!(!samples.is_null());
let size = fz_pixmap_samples_size(0, handle);
assert_eq!(size, 10 * 10 * 3);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_samples_invalid_handle() {
let samples = fz_pixmap_samples(0, 99999);
assert!(samples.is_null());
let size = fz_pixmap_samples_size(0, 99999);
assert_eq!(size, 0);
}
#[test]
fn test_tint_pixmap() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_GRAY, 10, 10, 0, 0);
fz_set_pixmap_sample(0, handle, 5, 5, 0, 200);
fz_tint_pixmap(0, handle, 255, 0, 0);
let sample = fz_get_pixmap_sample(0, handle, 5, 5, 0);
assert!(sample < 200);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_tint_pixmap_non_gray() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
fz_set_pixmap_sample(0, handle, 5, 5, 0, 100);
fz_tint_pixmap(0, handle, 255, 0, 0);
assert_eq!(fz_get_pixmap_sample(0, handle, 5, 5, 0), 100);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_resolution() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
let mut xres: i32 = 0;
let mut yres: i32 = 0;
fz_pixmap_resolution(0, handle, &mut xres, &mut yres);
assert_eq!(xres, 72);
assert_eq!(yres, 72);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_set_pixmap_resolution() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
let mut xres: i32 = 0;
let mut yres: i32 = 0;
fz_pixmap_resolution(0, handle, &mut xres, &mut yres);
assert_eq!(xres, 72);
assert_eq!(yres, 72);
fz_set_pixmap_resolution(0, handle, 300, 300);
fz_pixmap_resolution(0, handle, &mut xres, &mut yres);
assert_eq!(xres, 300);
assert_eq!(yres, 300);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_pixmap_xres_yres_individual() {
let handle = fz_new_pixmap(0, FZ_COLORSPACE_RGB, 10, 10, 0, 0);
assert_eq!(fz_pixmap_xres(0, handle), 72);
assert_eq!(fz_pixmap_yres(0, handle), 72);
fz_set_pixmap_xres(0, handle, 150);
assert_eq!(fz_pixmap_xres(0, handle), 150);
assert_eq!(fz_pixmap_yres(0, handle), 72);
fz_set_pixmap_yres(0, handle, 200);
assert_eq!(fz_pixmap_xres(0, handle), 150);
assert_eq!(fz_pixmap_yres(0, handle), 200);
fz_drop_pixmap(0, handle);
}
#[test]
fn test_convert_color_gray_to_rgb() {
use super::super::colorspace::{FZ_COLORSPACE_GRAY, FZ_COLORSPACE_RGB};
let result = convert_color(FZ_COLORSPACE_GRAY, FZ_COLORSPACE_RGB, &[128], 3);
assert_eq!(result, vec![128, 128, 128]);
}
#[test]
fn test_convert_color_rgb_to_gray() {
use super::super::colorspace::{FZ_COLORSPACE_GRAY, FZ_COLORSPACE_RGB};
let result = convert_color(FZ_COLORSPACE_RGB, FZ_COLORSPACE_GRAY, &[255, 255, 255], 1);
assert!(result[0] >= 250);
let result2 = convert_color(FZ_COLORSPACE_RGB, FZ_COLORSPACE_GRAY, &[0, 0, 0], 1);
assert_eq!(result2[0], 0);
}
#[test]
fn test_convert_color_same_space() {
use super::super::colorspace::FZ_COLORSPACE_RGB;
let result = convert_color(FZ_COLORSPACE_RGB, FZ_COLORSPACE_RGB, &[100, 150, 200], 3);
assert_eq!(result, vec![100, 150, 200]);
}
}