use crate::sections::image_data_section::ChannelBytes;
use crate::sections::PsdCursor;
use thiserror::Error;
pub trait IntoRgba {
fn rgba_idx(&self, idx: usize) -> Option<usize>;
fn red(&self) -> &ChannelBytes;
fn green(&self) -> Option<&ChannelBytes>;
fn blue(&self) -> Option<&ChannelBytes>;
fn alpha(&self) -> Option<&ChannelBytes>;
fn psd_width(&self) -> u32;
fn psd_height(&self) -> u32;
fn generate_rgba(&self) -> Vec<u8> {
let rgba_len = (self.psd_width() * self.psd_height() * 4) as usize;
let red = self.red();
let green = self.green();
let blue = self.blue();
let alpha = self.alpha();
let mut rgba = vec![0; rgba_len];
use crate::psd_channel::PsdChannelKind::*;
self.insert_channel_bytes(&mut rgba, Red, red);
if let Some(green) = green {
self.insert_channel_bytes(&mut rgba, Green, green);
} else {
self.insert_channel_bytes(&mut rgba, Green, red);
}
if let Some(blue) = blue {
self.insert_channel_bytes(&mut rgba, Blue, blue);
} else {
self.insert_channel_bytes(&mut rgba, Blue, red);
}
if let Some(alpha_channel) = alpha {
self.insert_channel_bytes(&mut rgba, TransparencyMask, alpha_channel);
} else {
for idx in 0..rgba_len / 4 {
rgba[idx * 4 + 3] = 255;
}
}
rgba
}
fn generate_16_bit_grayscale_rgba(&self) -> Vec<u8> {
match self.red() {
ChannelBytes::RawData(red) => match self.green().unwrap() {
ChannelBytes::RawData(green) => sixteen_to_eight_rgba(red, green),
ChannelBytes::RleCompressed(green) => {
let green = &rle_decompress(green);
sixteen_to_eight_rgba(red, green)
}
},
ChannelBytes::RleCompressed(red) => {
let red = &rle_decompress(red);
match self.green().unwrap() {
ChannelBytes::RawData(green) => sixteen_to_eight_rgba(red, green),
ChannelBytes::RleCompressed(green) => {
let green = &rle_decompress(green);
sixteen_to_eight_rgba(red, green)
}
}
}
}
}
fn insert_channel_bytes(
&self,
rgba: &mut Vec<u8>,
channel_kind: PsdChannelKind,
channel_bytes: &ChannelBytes,
) {
match channel_bytes {
ChannelBytes::RawData(channel_bytes) => {
let offset = channel_kind.rgba_offset().unwrap();
for (idx, byte) in channel_bytes.iter().enumerate() {
if let Some(rgba_idx) = self.rgba_idx(idx) {
rgba[rgba_idx * 4 + offset] = *byte;
}
}
}
ChannelBytes::RleCompressed(channel_bytes) => {
self.insert_rle_channel(rgba, channel_kind, &channel_bytes);
}
}
}
fn insert_rle_channel(
&self,
rgba: &mut Vec<u8>,
channel_kind: PsdChannelKind,
channel_bytes: &[u8],
) {
let mut cursor = PsdCursor::new(&channel_bytes[..]);
let mut idx = 0;
let offset = channel_kind.rgba_offset().unwrap();
let len = cursor.get_ref().len() as u64;
while cursor.position() < len {
let header = cursor.read_i8() as i16;
if header == -128 {
continue;
} else if header >= 0 {
let bytes_to_read = 1 + header;
if cursor.position() + bytes_to_read as u64 > len {
break;
}
for byte in cursor.read(bytes_to_read as u32) {
if let Some(rgba_idx) = self.rgba_idx(idx) {
if let Some(buffer) = rgba.get_mut(rgba_idx * 4 + offset) {
*buffer = *byte;
}
}
idx += 1;
}
} else {
let repeat = 1 - header;
if cursor.position() + 1 > len {
break;
}
let byte = cursor.read_1()[0];
for _ in 0..repeat {
if let Some(rgba_idx) = self.rgba_idx(idx) {
if let Some(buffer) = rgba.get_mut(rgba_idx * 4 + offset) {
*buffer = byte;
}
}
idx += 1;
}
};
}
}
}
fn rle_decompress(bytes: &[u8]) -> Vec<u8> {
let mut cursor = PsdCursor::new(&bytes[..]);
let mut decompressed = vec![];
while cursor.position() != cursor.get_ref().len() as u64 {
let header = cursor.read_i8() as i16;
if header == -128 {
continue;
} else if header >= 0 {
let bytes_to_read = 1 + header;
for byte in cursor.read(bytes_to_read as u32) {
decompressed.push(*byte);
}
} else {
let repeat = 1 - header;
let byte = cursor.read_1()[0];
for _ in 0..repeat {
decompressed.push(byte);
}
};
}
decompressed
}
fn sixteen_to_eight_rgba(channel1: &[u8], channel2: &[u8]) -> Vec<u8> {
let mut eight = Vec::with_capacity(channel1.len());
for idx in 0..channel1.len() {
if idx % 2 == 1 {
continue;
}
let sixteen_bit = [channel1[idx], channel1[idx + 1]];
let sixteen_bit = u16::from_be_bytes(sixteen_bit);
let eight_bit = (sixteen_bit / 256) as u8;
eight.push(eight_bit);
eight.push(eight_bit);
eight.push(eight_bit);
eight.push(255);
}
for idx in 0..channel2.len() {
if idx % 2 == 1 {
continue;
}
let sixteen_bit = [channel2[idx], channel2[idx + 1]];
let sixteen_bit = u16::from_be_bytes(sixteen_bit);
let eight_bit = (sixteen_bit / 256) as u8;
eight.push(eight_bit);
eight.push(eight_bit);
eight.push(eight_bit);
eight.push(255);
}
eight
}
#[derive(Debug, Eq, PartialEq)]
#[allow(missing_docs)]
pub enum PsdChannelCompression {
RawData = 0,
RleCompressed = 1,
ZipWithoutPrediction = 2,
ZipWithPrediction = 3,
}
impl PsdChannelCompression {
pub fn new(compression: u16) -> Option<PsdChannelCompression> {
match compression {
0 => Some(PsdChannelCompression::RawData),
1 => Some(PsdChannelCompression::RleCompressed),
2 => Some(PsdChannelCompression::ZipWithoutPrediction),
3 => Some(PsdChannelCompression::ZipWithPrediction),
_ => None,
}
}
}
#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
#[allow(missing_docs)]
pub enum PsdChannelKind {
Red = 0,
Green = 1,
Blue = 2,
TransparencyMask = -1,
UserSuppliedLayerMask = -2,
RealUserSuppliedLayerMask = -3,
}
#[derive(Debug, Error)]
pub enum PsdChannelError {
#[error("Channel {channel:#?} not present")]
ChannelNotFound { channel: PsdChannelKind },
}
impl PsdChannelKind {
pub fn new(channel_id: i16) -> Option<PsdChannelKind> {
match channel_id {
0 => Some(PsdChannelKind::Red),
1 => Some(PsdChannelKind::Green),
2 => Some(PsdChannelKind::Blue),
-1 => Some(PsdChannelKind::TransparencyMask),
-2 => Some(PsdChannelKind::UserSuppliedLayerMask),
-3 => Some(PsdChannelKind::RealUserSuppliedLayerMask),
_ => None,
}
}
pub fn rgba_offset(self) -> Result<usize, String> {
match self {
PsdChannelKind::Red => Ok(0),
PsdChannelKind::Green => Ok(1),
PsdChannelKind::Blue => Ok(2),
PsdChannelKind::TransparencyMask => Ok(3),
_ => Err(format!("{:#?} is not an RGBA channel", &self)),
}
}
}
#[cfg(test)]
mod tests {
use crate::sections::layer_and_mask_information_section::layer::{
BlendMode, LayerChannels, LayerProperties,
};
use crate::PsdLayer;
use super::*;
#[test]
fn does_not_read_beyond_rle_channels_bytes() {
let layer_properties = LayerProperties {
name: "".into(),
layer_top: 0,
layer_left: 0,
layer_bottom: 0,
layer_right: 0,
visible: true,
opacity: 0,
clipping_mask: false,
psd_width: 1,
psd_height: 1,
blend_mode: BlendMode::Normal,
group_id: None,
};
let layer = PsdLayer {
channels: LayerChannels::from([(
PsdChannelKind::Red,
ChannelBytes::RleCompressed(vec![0, 0, 0]),
)]),
layer_properties,
};
let mut rgba = vec![0; (layer.width() * layer.height() * 4) as usize];
layer.insert_channel_bytes(&mut rgba, PsdChannelKind::Red, layer.red());
assert_eq!(rgba, vec![0; 4]);
}
}