Don't include filter byte in PngImage.data
This commit is contained in:
parent
886dedd487
commit
7122214523
7 changed files with 46 additions and 128 deletions
|
|
@ -41,40 +41,7 @@ impl Display for Interlacing {
|
||||||
pub fn interlace_image(png: &PngImage) -> PngImage {
|
pub fn interlace_image(png: &PngImage) -> PngImage {
|
||||||
let mut passes: Vec<BitVec<u8, Msb0>> = vec![BitVec::new(); 7];
|
let mut passes: Vec<BitVec<u8, Msb0>> = vec![BitVec::new(); 7];
|
||||||
let bits_per_pixel = png.ihdr.bpp();
|
let bits_per_pixel = png.ihdr.bpp();
|
||||||
for (index, line) in png.scan_lines().enumerate() {
|
for (index, line) in png.scan_lines(false).enumerate() {
|
||||||
match index % 8 {
|
|
||||||
// Add filter bytes to passes that will be in the output image
|
|
||||||
0 => {
|
|
||||||
passes[0].extend_from_raw_slice(&[0]);
|
|
||||||
if png.ihdr.width >= 5 {
|
|
||||||
passes[1].extend_from_raw_slice(&[0]);
|
|
||||||
}
|
|
||||||
if png.ihdr.width >= 3 {
|
|
||||||
passes[3].extend_from_raw_slice(&[0]);
|
|
||||||
}
|
|
||||||
if png.ihdr.width >= 2 {
|
|
||||||
passes[5].extend_from_raw_slice(&[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4 => {
|
|
||||||
passes[2].extend_from_raw_slice(&[0]);
|
|
||||||
if png.ihdr.width >= 3 {
|
|
||||||
passes[3].extend_from_raw_slice(&[0]);
|
|
||||||
}
|
|
||||||
if png.ihdr.width >= 2 {
|
|
||||||
passes[5].extend_from_raw_slice(&[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 | 6 => {
|
|
||||||
passes[4].extend_from_raw_slice(&[0]);
|
|
||||||
if png.ihdr.width >= 2 {
|
|
||||||
passes[5].extend_from_raw_slice(&[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
passes[6].extend_from_raw_slice(&[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let bit_vec = line.data.view_bits::<Msb0>();
|
let bit_vec = line.data.view_bits::<Msb0>();
|
||||||
for (i, bit) in bit_vec.iter().by_vals().enumerate() {
|
for (i, bit) in bit_vec.iter().by_vals().enumerate() {
|
||||||
// Avoid moving padded 0's into new image
|
// Avoid moving padded 0's into new image
|
||||||
|
|
@ -148,15 +115,14 @@ pub fn deinterlace_image(png: &PngImage) -> PngImage {
|
||||||
/// Deinterlace by bits, for images with less than 8bpp
|
/// Deinterlace by bits, for images with less than 8bpp
|
||||||
fn deinterlace_bits(png: &PngImage) -> Vec<u8> {
|
fn deinterlace_bits(png: &PngImage) -> Vec<u8> {
|
||||||
let bits_per_pixel = png.ihdr.bpp();
|
let bits_per_pixel = png.ihdr.bpp();
|
||||||
let bits_per_line = 8 + bits_per_pixel as usize * png.ihdr.width as usize;
|
let bits_per_line = bits_per_pixel as usize * png.ihdr.width as usize;
|
||||||
// Initialize each output line with a starting filter byte of 0
|
// Initialize each output line with blank data
|
||||||
// as well as some blank data
|
|
||||||
let mut lines: Vec<BitVec<u8, Msb0>> =
|
let mut lines: Vec<BitVec<u8, Msb0>> =
|
||||||
vec![bitvec![u8, Msb0; 0; bits_per_line]; png.ihdr.height as usize];
|
vec![bitvec![u8, Msb0; 0; bits_per_line]; png.ihdr.height as usize];
|
||||||
let mut current_pass = 1;
|
let mut current_pass = 1;
|
||||||
let mut pass_constants = interlaced_constants(current_pass);
|
let mut pass_constants = interlaced_constants(current_pass);
|
||||||
let mut current_y: usize = pass_constants.y_shift as usize;
|
let mut current_y: usize = pass_constants.y_shift as usize;
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
let bit_vec = line.data.view_bits::<Msb0>();
|
let bit_vec = line.data.view_bits::<Msb0>();
|
||||||
let bits_in_line = ((png.ihdr.width - u32::from(pass_constants.x_shift)
|
let bits_in_line = ((png.ihdr.width - u32::from(pass_constants.x_shift)
|
||||||
+ u32::from(pass_constants.x_step)
|
+ u32::from(pass_constants.x_step)
|
||||||
|
|
@ -170,8 +136,8 @@ fn deinterlace_bits(png: &PngImage) -> Vec<u8> {
|
||||||
}
|
}
|
||||||
let current_x: usize = pass_constants.x_shift as usize
|
let current_x: usize = pass_constants.x_shift as usize
|
||||||
+ (i / bits_per_pixel as usize) * pass_constants.x_step as usize;
|
+ (i / bits_per_pixel as usize) * pass_constants.x_step as usize;
|
||||||
// Copy this bit into the output line, offset by 8 because of filter byte
|
// Copy this bit into the output line
|
||||||
let index = 8 + (i % bits_per_pixel as usize) + current_x * bits_per_pixel as usize;
|
let index = (i % bits_per_pixel as usize) + current_x * bits_per_pixel as usize;
|
||||||
lines[current_y].set(index, bit);
|
lines[current_y].set(index, bit);
|
||||||
}
|
}
|
||||||
// Calculate the next line and move to next pass if necessary
|
// Calculate the next line and move to next pass if necessary
|
||||||
|
|
@ -197,19 +163,18 @@ fn deinterlace_bits(png: &PngImage) -> Vec<u8> {
|
||||||
/// Deinterlace by bytes, for images with at least 8bpp
|
/// Deinterlace by bytes, for images with at least 8bpp
|
||||||
fn deinterlace_bytes(png: &PngImage) -> Vec<u8> {
|
fn deinterlace_bytes(png: &PngImage) -> Vec<u8> {
|
||||||
let bytes_per_pixel = png.ihdr.bpp() / 8;
|
let bytes_per_pixel = png.ihdr.bpp() / 8;
|
||||||
let bytes_per_line = 1 + bytes_per_pixel as usize * png.ihdr.width as usize;
|
let bytes_per_line = bytes_per_pixel as usize * png.ihdr.width as usize;
|
||||||
// Initialize each output line with a starting filter byte of 0
|
// Initialize each output line with some blank data
|
||||||
// as well as some blank data
|
|
||||||
let mut lines: Vec<Vec<u8>> = vec![vec![0; bytes_per_line]; png.ihdr.height as usize];
|
let mut lines: Vec<Vec<u8>> = vec![vec![0; bytes_per_line]; png.ihdr.height as usize];
|
||||||
let mut current_pass = 1;
|
let mut current_pass = 1;
|
||||||
let mut pass_constants = interlaced_constants(current_pass);
|
let mut pass_constants = interlaced_constants(current_pass);
|
||||||
let mut current_y: usize = pass_constants.y_shift as usize;
|
let mut current_y: usize = pass_constants.y_shift as usize;
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
for (i, byte) in line.data.iter().enumerate() {
|
for (i, byte) in line.data.iter().enumerate() {
|
||||||
let current_x: usize = pass_constants.x_shift as usize
|
let current_x: usize = pass_constants.x_shift as usize
|
||||||
+ (i / bytes_per_pixel as usize) * pass_constants.x_step as usize;
|
+ (i / bytes_per_pixel as usize) * pass_constants.x_step as usize;
|
||||||
// Copy this byte into the output line, offset by 1 because of filter byte
|
// Copy this byte into the output line
|
||||||
let index = 1 + (i % bytes_per_pixel as usize) + current_x * bytes_per_pixel as usize;
|
let index = (i % bytes_per_pixel as usize) + current_x * bytes_per_pixel as usize;
|
||||||
lines[current_y][index] = *byte;
|
lines[current_y][index] = *byte;
|
||||||
}
|
}
|
||||||
// Calculate the next line and move to next pass if necessary
|
// Calculate the next line and move to next pass if necessary
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
pub(crate) mod scan_lines;
|
pub(crate) mod scan_lines;
|
||||||
|
|
||||||
use self::scan_lines::{ScanLines, ScanLinesMut};
|
use self::scan_lines::ScanLines;
|
||||||
|
|
||||||
/// Compression level to use for the Brute filter strategy
|
/// Compression level to use for the Brute filter strategy
|
||||||
const BRUTE_LEVEL: i32 = 1; // 1 is fastest, 2-4 are not useful, 5 is slower but more effective
|
const BRUTE_LEVEL: i32 = 1; // 1 is fastest, 2-4 are not useful, 5 is slower but more effective
|
||||||
|
|
@ -29,7 +29,7 @@ const BRUTE_LINES: usize = 4; // Values over 8 are generally not useful
|
||||||
pub struct PngImage {
|
pub struct PngImage {
|
||||||
/// The headers stored in the IHDR chunk
|
/// The headers stored in the IHDR chunk
|
||||||
pub ihdr: IhdrData,
|
pub ihdr: IhdrData,
|
||||||
/// The uncompressed, optionally filtered data from the IDAT chunk
|
/// The uncompressed, unfiltered data from the IDAT chunk
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
/// The palette containing colors used in an Indexed image
|
/// The palette containing colors used in an Indexed image
|
||||||
/// Contains 3 bytes per color (R+G+B), up to 768
|
/// Contains 3 bytes per color (R+G+B), up to 768
|
||||||
|
|
@ -280,14 +280,8 @@ impl PngImage {
|
||||||
|
|
||||||
/// Return an iterator over the scanlines of the image
|
/// Return an iterator over the scanlines of the image
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scan_lines(&self) -> ScanLines<'_> {
|
pub fn scan_lines(&self, has_filter: bool) -> ScanLines<'_> {
|
||||||
ScanLines::new(self)
|
ScanLines::new(self, has_filter)
|
||||||
}
|
|
||||||
|
|
||||||
/// Return an iterator over the scanlines of the image
|
|
||||||
#[inline]
|
|
||||||
pub fn scan_lines_mut(&mut self) -> ScanLinesMut<'_> {
|
|
||||||
ScanLinesMut::new(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reverse all filters applied on the image, returning an unfiltered IDAT bytestream
|
/// Reverse all filters applied on the image, returning an unfiltered IDAT bytestream
|
||||||
|
|
@ -297,7 +291,7 @@ impl PngImage {
|
||||||
let mut last_line: Vec<u8> = Vec::new();
|
let mut last_line: Vec<u8> = Vec::new();
|
||||||
let mut last_pass = None;
|
let mut last_pass = None;
|
||||||
let mut unfiltered_buf = Vec::new();
|
let mut unfiltered_buf = Vec::new();
|
||||||
for line in self.scan_lines() {
|
for line in self.scan_lines(true) {
|
||||||
if last_pass != line.pass {
|
if last_pass != line.pass {
|
||||||
last_line.clear();
|
last_line.clear();
|
||||||
last_pass = line.pass;
|
last_pass = line.pass;
|
||||||
|
|
@ -305,7 +299,6 @@ impl PngImage {
|
||||||
last_line.resize(line.data.len(), 0);
|
last_line.resize(line.data.len(), 0);
|
||||||
let filter = RowFilter::try_from(line.filter).map_err(|_| PngError::InvalidData)?;
|
let filter = RowFilter::try_from(line.filter).map_err(|_| PngError::InvalidData)?;
|
||||||
filter.unfilter_line(bpp, line.data, &last_line, &mut unfiltered_buf)?;
|
filter.unfilter_line(bpp, line.data, &last_line, &mut unfiltered_buf)?;
|
||||||
unfiltered.push(0);
|
|
||||||
unfiltered.extend_from_slice(&unfiltered_buf);
|
unfiltered.extend_from_slice(&unfiltered_buf);
|
||||||
std::mem::swap(&mut last_line, &mut unfiltered_buf);
|
std::mem::swap(&mut last_line, &mut unfiltered_buf);
|
||||||
unfiltered_buf.clear();
|
unfiltered_buf.clear();
|
||||||
|
|
@ -328,7 +321,7 @@ impl PngImage {
|
||||||
let mut prev_line = Vec::new();
|
let mut prev_line = Vec::new();
|
||||||
let mut prev_pass: Option<u8> = None;
|
let mut prev_pass: Option<u8> = None;
|
||||||
let mut f_buf = Vec::new();
|
let mut f_buf = Vec::new();
|
||||||
for line in self.scan_lines() {
|
for line in self.scan_lines(false) {
|
||||||
if prev_pass != line.pass || line.data.len() != prev_line.len() {
|
if prev_pass != line.pass || line.data.len() != prev_line.len() {
|
||||||
prev_line = vec![0; line.data.len()];
|
prev_line = vec![0; line.data.len()];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,16 @@ pub struct ScanLines<'a> {
|
||||||
iter: ScanLineRanges,
|
iter: ScanLineRanges,
|
||||||
/// A reference to the PNG image being iterated upon
|
/// A reference to the PNG image being iterated upon
|
||||||
raw_data: &'a [u8],
|
raw_data: &'a [u8],
|
||||||
|
/// Whether the raw data contains filter bytes
|
||||||
|
has_filter: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScanLines<'a> {
|
impl<'a> ScanLines<'a> {
|
||||||
pub fn new(png: &'a PngImage) -> Self {
|
pub fn new(png: &'a PngImage, has_filter: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
iter: ScanLineRanges::new(png),
|
iter: ScanLineRanges::new(png, has_filter),
|
||||||
raw_data: &png.data,
|
raw_data: &png.data,
|
||||||
|
has_filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -25,43 +28,16 @@ impl<'a> Iterator for ScanLines<'a> {
|
||||||
self.iter.next().map(|(len, pass)| {
|
self.iter.next().map(|(len, pass)| {
|
||||||
let (data, rest) = self.raw_data.split_at(len);
|
let (data, rest) = self.raw_data.split_at(len);
|
||||||
self.raw_data = rest;
|
self.raw_data = rest;
|
||||||
let (&filter, data) = data.split_first().unwrap();
|
let (&filter, data) = if self.has_filter {
|
||||||
|
data.split_first().unwrap()
|
||||||
|
} else {
|
||||||
|
(&0, data)
|
||||||
|
};
|
||||||
ScanLine { filter, data, pass }
|
ScanLine { filter, data, pass }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// An iterator over the scan lines of a PNG image
|
|
||||||
pub struct ScanLinesMut<'a> {
|
|
||||||
iter: ScanLineRanges,
|
|
||||||
/// A reference to the PNG image being iterated upon
|
|
||||||
raw_data: Option<&'a mut [u8]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ScanLinesMut<'a> {
|
|
||||||
pub fn new(png: &'a mut PngImage) -> Self {
|
|
||||||
Self {
|
|
||||||
iter: ScanLineRanges::new(png),
|
|
||||||
raw_data: Some(&mut png.data),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for ScanLinesMut<'a> {
|
|
||||||
type Item = ScanLineMut<'a>;
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.iter.next().map(|(len, pass)| {
|
|
||||||
let tmp = self.raw_data.take().unwrap();
|
|
||||||
let (data, rest) = tmp.split_at_mut(len);
|
|
||||||
self.raw_data = Some(rest);
|
|
||||||
let (&mut filter, data) = data.split_first_mut().unwrap();
|
|
||||||
ScanLineMut { filter, data, pass }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
/// An iterator over the scan line locations of a PNG image
|
/// An iterator over the scan line locations of a PNG image
|
||||||
struct ScanLineRanges {
|
struct ScanLineRanges {
|
||||||
|
|
@ -71,10 +47,11 @@ struct ScanLineRanges {
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
left: usize,
|
left: usize,
|
||||||
|
has_filter: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScanLineRanges {
|
impl ScanLineRanges {
|
||||||
pub fn new(png: &PngImage) -> Self {
|
pub fn new(png: &PngImage, has_filter: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bits_per_pixel: png.ihdr.bit_depth.as_u8() * png.channels_per_pixel(),
|
bits_per_pixel: png.ihdr.bit_depth.as_u8() * png.channels_per_pixel(),
|
||||||
width: png.ihdr.width,
|
width: png.ihdr.width,
|
||||||
|
|
@ -85,6 +62,7 @@ impl ScanLineRanges {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
has_filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,8 +144,10 @@ impl Iterator for ScanLineRanges {
|
||||||
(self.width, None)
|
(self.width, None)
|
||||||
};
|
};
|
||||||
let bits_per_line = pixels_per_line * u32::from(self.bits_per_pixel);
|
let bits_per_line = pixels_per_line * u32::from(self.bits_per_pixel);
|
||||||
let bytes_per_line = ((bits_per_line + 7) / 8) as usize;
|
let mut len = ((bits_per_line + 7) / 8) as usize;
|
||||||
let len = bytes_per_line + 1;
|
if self.has_filter {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
self.left = self.left.checked_sub(len)?;
|
self.left = self.left.checked_sub(len)?;
|
||||||
Some((len, current_pass))
|
Some((len, current_pass))
|
||||||
}
|
}
|
||||||
|
|
@ -183,14 +163,3 @@ pub struct ScanLine<'a> {
|
||||||
/// The current pass if the image is interlaced
|
/// The current pass if the image is interlaced
|
||||||
pub pass: Option<u8>,
|
pub pass: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// A scan line in a PNG image
|
|
||||||
pub struct ScanLineMut<'a> {
|
|
||||||
/// The filter type used to encode the current scan line (0-4)
|
|
||||||
pub filter: u8,
|
|
||||||
/// The byte data for the current scan line, encoded with the filter specified in the `filter` field
|
|
||||||
pub data: &'a mut [u8],
|
|
||||||
/// The current pass if the image is interlaced
|
|
||||||
pub pass: Option<u8>,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,7 @@ pub fn cleaned_alpha_channel(png: &PngImage) -> Option<PngImage> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut reduced = Vec::with_capacity(png.data.len());
|
let mut reduced = Vec::with_capacity(png.data.len());
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
reduced.push(line.filter);
|
|
||||||
for pixel in line.data.chunks(bpp) {
|
for pixel in line.data.chunks(bpp) {
|
||||||
if pixel.iter().skip(bpp - bpc).all(|b| *b == 0) {
|
if pixel.iter().skip(bpp - bpc).all(|b| *b == 0) {
|
||||||
reduced.resize(reduced.len() + bpp, 0);
|
reduced.resize(reduced.len() + bpp, 0);
|
||||||
|
|
@ -54,7 +53,7 @@ pub fn reduced_alpha_channel(png: &PngImage, optimize_alpha: bool) -> Option<Png
|
||||||
let mut has_transparency = false;
|
let mut has_transparency = false;
|
||||||
let mut used_colors = vec![false; 256];
|
let mut used_colors = vec![false; 256];
|
||||||
|
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
for pixel in line.data.chunks(bpp) {
|
for pixel in line.data.chunks(bpp) {
|
||||||
if optimize_alpha && pixel.iter().skip(colored_bytes).all(|b| *b == 0) {
|
if optimize_alpha && pixel.iter().skip(colored_bytes).all(|b| *b == 0) {
|
||||||
// Fully transparent, we may be able to reduce with tRNS
|
// Fully transparent, we may be able to reduce with tRNS
|
||||||
|
|
@ -83,8 +82,7 @@ pub fn reduced_alpha_channel(png: &PngImage, optimize_alpha: bool) -> Option<Png
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut raw_data = Vec::with_capacity(png.data.len());
|
let mut raw_data = Vec::with_capacity(png.data.len());
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
raw_data.push(line.filter);
|
|
||||||
for pixel in line.data.chunks(bpp) {
|
for pixel in line.data.chunks(bpp) {
|
||||||
match transparency_pixel {
|
match transparency_pixel {
|
||||||
Some(ref trns) if pixel.iter().skip(colored_bytes).all(|b| *b == 0) => {
|
Some(ref trns) if pixel.iter().skip(colored_bytes).all(|b| *b == 0) => {
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,11 @@ pub fn reduce_bit_depth(png: &PngImage, minimum_bits: usize) -> Option<PngImage>
|
||||||
|
|
||||||
// Reduce from 16 to 8 bits per channel per pixel
|
// Reduce from 16 to 8 bits per channel per pixel
|
||||||
let mut reduced = Vec::with_capacity(
|
let mut reduced = Vec::with_capacity(
|
||||||
(png.ihdr.width * png.ihdr.height * u32::from(png.channels_per_pixel()) + png.ihdr.height)
|
(png.ihdr.width * png.ihdr.height * u32::from(png.channels_per_pixel())) as usize,
|
||||||
as usize,
|
|
||||||
);
|
);
|
||||||
let mut high_byte = 0;
|
let mut high_byte = 0;
|
||||||
|
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
reduced.push(line.filter);
|
|
||||||
for (i, &byte) in line.data.iter().enumerate() {
|
for (i, &byte) in line.data.iter().enumerate() {
|
||||||
if i % 2 == 0 {
|
if i % 2 == 0 {
|
||||||
// High byte
|
// High byte
|
||||||
|
|
@ -79,7 +77,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngImage, mut minimum_bits: usize) -> Op
|
||||||
if minimum_bits >= bit_depth {
|
if minimum_bits >= bit_depth {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
if png.ihdr.color_type == ColorType::Indexed {
|
if png.ihdr.color_type == ColorType::Indexed {
|
||||||
let line_max = line
|
let line_max = line
|
||||||
.data
|
.data
|
||||||
|
|
@ -129,8 +127,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngImage, mut minimum_bits: usize) -> Op
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut reduced = BitVec::<u8, Msb0>::with_capacity(png.data.len() * 8);
|
let mut reduced = BitVec::<u8, Msb0>::with_capacity(png.data.len() * 8);
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
reduced.extend_from_raw_slice(&[line.filter]);
|
|
||||||
let bit_vec = line.data.view_bits::<Msb0>();
|
let bit_vec = line.data.view_bits::<Msb0>();
|
||||||
for (i, bit) in bit_vec.iter().by_vals().enumerate() {
|
for (i, bit) in bit_vec.iter().by_vals().enumerate() {
|
||||||
let bit_index = bit_depth - (i % bit_depth);
|
let bit_index = bit_depth - (i % bit_depth);
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,7 @@ pub fn reduce_rgba_to_grayscale_alpha(png: &PngImage) -> Option<PngImage> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let colored_bytes = bpp - byte_depth;
|
let colored_bytes = bpp - byte_depth;
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
reduced.push(line.filter);
|
|
||||||
let mut low_bytes = Vec::with_capacity(4);
|
let mut low_bytes = Vec::with_capacity(4);
|
||||||
let mut high_bytes = Vec::with_capacity(4);
|
let mut high_bytes = Vec::with_capacity(4);
|
||||||
let mut trans_bytes = Vec::with_capacity(byte_depth as usize);
|
let mut trans_bytes = Vec::with_capacity(byte_depth as usize);
|
||||||
|
|
@ -117,8 +116,7 @@ pub fn reduce_to_palette(png: &PngImage) -> Option<PngImage> {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.filter(|t| png.ihdr.color_type == ColorType::RGB && t.len() >= 6)
|
.filter(|t| png.ihdr.color_type == ColorType::RGB && t.len() >= 6)
|
||||||
.map(|t| RGB8::new(t[1], t[3], t[5]));
|
.map(|t| RGB8::new(t[1], t[3], t[5]));
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
raw_data.push(line.filter);
|
|
||||||
let ok = if png.ihdr.color_type == ColorType::RGB {
|
let ok = if png.ihdr.color_type == ColorType::RGB {
|
||||||
reduce_scanline_to_palette(
|
reduce_scanline_to_palette(
|
||||||
line.data.as_rgb().iter().cloned().map(|px| {
|
line.data.as_rgb().iter().cloned().map(|px| {
|
||||||
|
|
@ -221,8 +219,7 @@ pub fn reduce_rgb_to_grayscale(png: &PngImage) -> Option<PngImage> {
|
||||||
let byte_depth: u8 = png.ihdr.bit_depth.as_u8() >> 3;
|
let byte_depth: u8 = png.ihdr.bit_depth.as_u8() >> 3;
|
||||||
let bpp: usize = 3 * byte_depth as usize;
|
let bpp: usize = 3 * byte_depth as usize;
|
||||||
let mut cur_pixel = Vec::with_capacity(bpp);
|
let mut cur_pixel = Vec::with_capacity(bpp);
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
reduced.push(line.filter);
|
|
||||||
for (i, byte) in line.data.iter().enumerate() {
|
for (i, byte) in line.data.iter().enumerate() {
|
||||||
cur_pixel.push(*byte);
|
cur_pixel.push(*byte);
|
||||||
if i % bpp == bpp - 1 {
|
if i % bpp == bpp - 1 {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ pub fn reduced_palette(png: &PngImage, optimize_alpha: bool) -> Option<PngImage>
|
||||||
let palette = png.palette.as_ref()?;
|
let palette = png.palette.as_ref()?;
|
||||||
|
|
||||||
// Find palette entries that are never used
|
// Find palette entries that are never used
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
match png.ihdr.bit_depth {
|
match png.ihdr.bit_depth {
|
||||||
BitDepth::Eight => {
|
BitDepth::Eight => {
|
||||||
for &byte in line.data {
|
for &byte in line.data {
|
||||||
|
|
@ -120,8 +120,7 @@ fn do_palette_reduction(png: &PngImage, palette_map: &[Option<u8>; 256]) -> Opti
|
||||||
let mut raw_data = Vec::with_capacity(png.data.len());
|
let mut raw_data = Vec::with_capacity(png.data.len());
|
||||||
|
|
||||||
// Reassign data bytes to new indices
|
// Reassign data bytes to new indices
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines(false) {
|
||||||
raw_data.push(line.filter);
|
|
||||||
for byte in line.data {
|
for byte in line.data {
|
||||||
raw_data.push(byte_map[*byte as usize]);
|
raw_data.push(byte_map[*byte as usize]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue