use std::io::Cursor;
use self::file_header_section::{FileHeaderSectionError, EXPECTED_PSD_SIGNATURE};
const FILE_HEADER_SECTION_LEN: usize = 26;
pub mod file_header_section;
pub mod image_data_section;
pub mod image_resources_section;
pub mod layer_and_mask_information_section;
#[derive(Debug)]
pub struct MajorSections<'a> {
pub(crate) file_header: &'a [u8],
pub(crate) color_mode_data: &'a [u8],
pub(crate) image_resources: &'a [u8],
pub(crate) layer_and_mask: &'a [u8],
pub(crate) image_data: &'a [u8],
}
impl<'a> MajorSections<'a> {
pub fn from_bytes(bytes: &[u8]) -> Result<MajorSections, FileHeaderSectionError> {
if bytes.len() < FILE_HEADER_SECTION_LEN {
return Err(FileHeaderSectionError::IncorrectLength {
length: bytes.len(),
});
}
let mut cursor = PsdCursor::new(bytes);
let signature = cursor.peek_4();
if signature != EXPECTED_PSD_SIGNATURE {
return Err(FileHeaderSectionError::InvalidSignature {});
}
let file_header = &bytes[0..FILE_HEADER_SECTION_LEN];
cursor.read(FILE_HEADER_SECTION_LEN as u32);
let (color_start, color_end) = read_major_section_start_end(&mut cursor);
let (img_res_start, img_res_end) = read_major_section_start_end(&mut cursor);
let (layer_mask_start, layer_mask_end) = read_major_section_start_end(&mut cursor);
let image_data = &bytes[cursor.position() as usize..];
Ok(MajorSections {
file_header,
color_mode_data: &bytes[color_start..color_end],
image_resources: &bytes[img_res_start..img_res_end],
layer_and_mask: &bytes[layer_mask_start..layer_mask_end],
image_data,
})
}
}
fn read_major_section_start_end(cursor: &mut PsdCursor) -> (usize, usize) {
let start = cursor.position() as usize;
let data_len = cursor.read_u32();
cursor.read(data_len);
let end = cursor.position() as usize;
(start, end)
}
pub(crate) struct PsdCursor<'a> {
cursor: Cursor<&'a [u8]>,
}
impl<'a> PsdCursor<'a> {
pub fn new(bytes: &[u8]) -> PsdCursor {
PsdCursor {
cursor: Cursor::new(bytes),
}
}
pub fn position(&self) -> u64 {
self.cursor.position()
}
pub fn seek(&mut self, pos: u64) {
self.cursor.set_position(pos);
}
pub fn get_ref(&self) -> &[u8] {
self.cursor.get_ref()
}
pub fn read(&mut self, count: u32) -> &[u8] {
let start = self.cursor.position() as usize;
let end = start + count as usize;
let bytes = &self.cursor.get_ref()[start..end];
self.cursor.set_position(end as u64);
bytes
}
pub fn peek_u32(&self) -> u32 {
let bytes = self.peek_4();
u32_from_be_bytes(bytes)
}
pub fn peek_4(&self) -> &[u8] {
self.peek(4)
}
fn peek(&self, n: u8) -> &[u8] {
let start = self.cursor.position() as usize;
let end = start + n as usize;
let bytes = &self.cursor.get_ref()[start..end];
bytes
}
pub fn read_1(&mut self) -> &[u8] {
self.read(1)
}
pub fn read_2(&mut self) -> &[u8] {
self.read(2)
}
pub fn read_4(&mut self) -> &[u8] {
self.read(4)
}
pub fn read_6(&mut self) -> &[u8] {
self.read(6)
}
pub fn read_8(&mut self) -> &[u8] {
self.read(8)
}
pub fn read_u8(&mut self) -> u8 {
self.read_1()[0]
}
pub fn read_u16(&mut self) -> u16 {
let bytes = self.read_2();
let mut array = [0; 2];
array.copy_from_slice(bytes);
u16::from_be_bytes(array)
}
pub fn read_u32(&mut self) -> u32 {
let bytes = self.read_4();
u32_from_be_bytes(bytes)
}
pub fn read_i8(&mut self) -> i8 {
let bytes = self.read_1();
let mut array = [0; 1];
array.copy_from_slice(bytes);
i8::from_be_bytes(array)
}
pub fn read_i16(&mut self) -> i16 {
let bytes = self.read_2();
let mut array = [0; 2];
array.copy_from_slice(bytes);
i16::from_be_bytes(array)
}
pub fn read_i32(&mut self) -> i32 {
let bytes = self.read_4();
let mut array = [0; 4];
array.copy_from_slice(bytes);
i32::from_be_bytes(array)
}
pub fn read_f64(&mut self) -> f64 {
let bytes = self.read_8();
let mut array = [0; 8];
array.copy_from_slice(bytes);
f64::from_be_bytes(array)
}
pub fn read_i64(&mut self) -> i64 {
let bytes = self.read_8();
let mut array = [0; 8];
array.copy_from_slice(bytes);
i64::from_be_bytes(array)
}
pub fn read_unicode_string(&mut self) -> String {
self.read_unicode_string_padding(4)
}
pub fn read_unicode_string_padding(&mut self, padding: usize) -> String {
let length = self.read_u32() as usize;
let length_bytes = length * 2;
let data = self.read(length_bytes as u32);
let result = String::from_utf16(&u8_slice_to_u16(data).as_slice()[..length]).unwrap();
self.read_padding(4 + length_bytes, padding);
result
}
fn read_padding(&mut self, size: usize, divisor: usize) -> &[u8] {
let remainder = size % divisor;
if remainder > 0 {
let to_read = divisor - remainder;
self.read(to_read as u32)
} else {
&[] as &[u8]
}
}
pub fn read_pascal_string(&mut self) -> String {
let len = self.read_u8();
let data = self.read(len as u32);
let result = String::from_utf8_lossy(data).into_owned();
if len % 2 == 0 {
self.read_u8();
}
result
}
}
fn u8_slice_to_u16(bytes: &[u8]) -> Vec<u16> {
return Vec::from(bytes)
.chunks_exact(2)
.into_iter()
.map(|a| u16::from_be_bytes([a[0], a[1]]))
.collect();
}
fn u32_from_be_bytes(bytes: &[u8]) -> u32 {
let mut array = [0; 4];
array.copy_from_slice(bytes);
u32::from_be_bytes(array)
}