mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 14:20:24 +00:00
Fix #6969: Rasterize to Grayscale or Bitmap makes a grayscale image
This commit is contained in:
@@ -53,6 +53,21 @@ pub fn encode(rgba: &[u8], width: u32, height: u32, o: &PngOptions) -> Result<Ve
|
||||
write(&pixels, width, height, Layout { channels, bits: 8, color_type }, &[], o)
|
||||
}
|
||||
|
||||
/// Encode grey levels with alpha (two bytes a pixel, `width`×`height`, row-major) as a greyscale
|
||||
/// PNG: grey and alpha (colour type 4), or grey alone (colour type 0) when every pixel is opaque.
|
||||
pub fn encode_gray(gray_alpha: &[u8], width: u32, height: u32, o: &PngOptions) -> Result<Vec<u8>, String> {
|
||||
check_size(width, height)?;
|
||||
if gray_alpha.len() as u64 != u64::from(width) * u64::from(height) * 2 {
|
||||
return Err("PNG encoding failed: pixel buffer doesn't match the image size".into());
|
||||
}
|
||||
let px = gray_alpha.as_chunks::<2>().0;
|
||||
if px.iter().all(|p| p[1] == 255) {
|
||||
let levels: Vec<u8> = px.iter().map(|p| p[0]).collect();
|
||||
return write(&levels, width, height, Layout { channels: 1, bits: 8, color_type: 0 }, &[], o);
|
||||
}
|
||||
write(gray_alpha, width, height, Layout { channels: 2, bits: 8, color_type: 4 }, &[], o)
|
||||
}
|
||||
|
||||
/// Encode a palette image as an indexed PNG (colour type 3: `PLTE`, and `tRNS` for its
|
||||
/// transparent entry) at 1, 2, 4 or 8 bits per pixel, as few as the palette needs.
|
||||
pub fn encode_indexed(img: &Indexed, o: &PngOptions) -> Result<Vec<u8>, String> {
|
||||
|
||||
@@ -67,6 +67,41 @@ fn png_refuses_a_buffer_of_the_wrong_size() {
|
||||
assert!(encode(&[], 0, 0, &PngOptions::default()).is_err());
|
||||
}
|
||||
|
||||
/// Object › Rasterize's Grayscale and Bitmap images (#6969): a grey PNG of one channel when
|
||||
/// opaque and grey and alpha otherwise; Bitmap's black and white as a 1-bit TIFF when opaque,
|
||||
/// else as a grey PNG with alpha. Odd widths keep each row on a byte.
|
||||
#[test]
|
||||
fn gray_and_bilevel_images_store_gray() {
|
||||
let header = |file: &[u8]| (file[24], file[25]);
|
||||
let gray = |file: &[u8]| image::load_from_memory(file).unwrap().to_luma_alpha8().into_raw();
|
||||
// 3 × 2, premultiplied: black, red, light grey; white, mid grey, almost black.
|
||||
let mut img = Rendered {
|
||||
width: 3,
|
||||
height: 2,
|
||||
pixels: [[0, 0, 0], [255, 0, 0], [200; 3], [255; 3], [128; 3], [127; 3]].iter().flat_map(|&[r, g, b]| [r, g, b, 255]).collect(),
|
||||
};
|
||||
let levels: Vec<u8> = [0u8, 54, 200, 255, 128, 127].iter().flat_map(|&g| [g, 255]).collect();
|
||||
let file = img.to_gray_png().unwrap();
|
||||
assert_eq!(header(&file), (8, 0), "8-bit grey");
|
||||
assert_eq!(gray(&file), levels);
|
||||
let (mime, file) = img.to_bilevel(150.0).unwrap();
|
||||
assert_eq!(mime, "image/tiff");
|
||||
let mut d = ::tiff::decoder::Decoder::new(std::io::Cursor::new(&file)).unwrap();
|
||||
assert_eq!(d.colortype().unwrap(), ::tiff::ColorType::Gray(1));
|
||||
let bw: Vec<u8> = [0u8, 0, 255, 255, 255, 0].iter().flat_map(|&g| [g, 255]).collect();
|
||||
assert_eq!(gray(&file), bw, "from 128 up is white");
|
||||
// Half-covered white over the light grey; a clear pixel is white.
|
||||
img.pixels[8..12].copy_from_slice(&[100, 100, 100, 100]);
|
||||
img.pixels[20..24].copy_from_slice(&[0; 4]);
|
||||
let file = img.to_gray_png().unwrap();
|
||||
assert_eq!(header(&file), (8, 4), "grey and alpha");
|
||||
assert_eq!(gray(&file), [0, 255, 54, 255, 255, 100, 255, 255, 128, 255, 255, 0]);
|
||||
let (mime, file) = img.to_bilevel(150.0).unwrap();
|
||||
assert_eq!((mime, header(&file)), ("image/png", (8, 4)), "no 1-bit grey with alpha");
|
||||
assert_eq!(gray(&file), [0, 255, 0, 255, 255, 100, 255, 255, 255, 255, 255, 0], "still black and white");
|
||||
assert!(super::png::encode_gray(&levels[..10], 3, 2, &PngOptions::default()).is_err());
|
||||
}
|
||||
|
||||
/// A 40×30 pt document with a black circle off the pixel grid.
|
||||
fn circle_doc() -> Document {
|
||||
let mut d = Document::new(40.0, 30.0);
|
||||
|
||||
Reference in New Issue
Block a user