use std::collections::HashMap;
use std::ops::{Deref, Range};
use failure::{Error, Fail};
use crate::psd_channel::IntoRgba;
use crate::psd_channel::PsdChannelCompression;
use crate::psd_channel::PsdChannelError;
use crate::psd_channel::PsdChannelKind;
use crate::sections::image_data_section::ChannelBytes;
#[derive(Debug, Clone)]
pub struct LayerProperties {
pub(super) name: String,
pub(crate) layer_top: i32,
pub(crate) layer_left: i32,
pub(crate) layer_bottom: i32,
pub(crate) layer_right: i32,
pub(crate) psd_width: u32,
pub(crate) psd_height: u32,
pub(crate) group_id: Option<u32>,
}
impl LayerProperties {
pub fn new(
name: String,
layer_top: i32,
layer_left: i32,
layer_bottom: i32,
layer_right: i32,
psd_width: u32,
psd_height: u32,
group_id: Option<u32>,
) -> Self {
LayerProperties {
name,
layer_top,
layer_left,
layer_bottom,
layer_right,
psd_width,
psd_height,
group_id,
}
}
pub fn from_layer_record(
name: String,
layer_record: &LayerRecord,
psd_width: u32,
psd_height: u32,
group_id: Option<u32>,
) -> Self {
Self::new(
name,
layer_record.top,
layer_record.left,
layer_record.bottom,
layer_record.right,
psd_width,
psd_height,
group_id,
)
}
pub fn name(&self) -> &str {
&self.name
}
pub fn width(&self) -> u16 {
(self.layer_right - self.layer_left) as u16 + 1
}
pub fn height(&self) -> u16 {
(self.layer_bottom - self.layer_top) as u16 + 1
}
pub fn parent_id(&self) -> Option<u32> {
self.group_id
}
}
#[derive(Debug, Clone)]
pub struct PsdGroup {
pub(in crate) id: u32,
pub(in crate) contained_layers: Range<usize>,
pub(in crate) layer_properties: LayerProperties,
}
impl PsdGroup {
pub fn new(
name: String,
id: u32,
contained_layers: Range<usize>,
layer_record: &LayerRecord,
psd_width: u32,
psd_height: u32,
group_id: Option<u32>,
) -> Self {
let layer_properties =
LayerProperties::from_layer_record(name, layer_record, psd_width, psd_height, group_id);
PsdGroup {
id,
contained_layers,
layer_properties,
}
}
pub fn id(&self) -> u32 {
self.id
}
}
impl Deref for PsdGroup {
type Target = LayerProperties;
fn deref(&self) -> &Self::Target {
&self.layer_properties
}
}
pub type LayerChannels = HashMap<PsdChannelKind, ChannelBytes>;
#[derive(Debug, Clone)]
pub struct PsdLayer {
pub(super) channels: LayerChannels,
pub(in crate) layer_properties: LayerProperties,
}
#[derive(Debug, Fail)]
pub enum PsdLayerError {
#[fail(
display = r#"Could not combine Red, Green, Blue and Alpha.
This layer is missing channel: {:#?}"#,
channel
)]
MissingChannels { channel: PsdChannelKind },
}
impl PsdLayer {
pub fn new(
layer_record: &LayerRecord,
psd_width: u32,
psd_height: u32,
group_id: Option<u32>,
channels: LayerChannels,
) -> PsdLayer {
PsdLayer {
layer_properties: LayerProperties::from_layer_record(
layer_record.name.clone(),
layer_record,
psd_width,
psd_height,
group_id,
),
channels,
}
}
pub fn compression(&self, channel: PsdChannelKind) -> Result<PsdChannelCompression, Error> {
match self.channels.get(&channel) {
Some(channel) => match channel {
ChannelBytes::RawData(_) => Ok(PsdChannelCompression::RawData),
ChannelBytes::RleCompressed(_) => Ok(PsdChannelCompression::RleCompressed),
},
None => Err(PsdChannelError::ChannelNotFound { channel }.into()),
}
}
pub fn rgba(&self) -> Result<Vec<u8>, Error> {
let rgba = self.generate_rgba()?;
Ok(rgba)
}
fn get_channel(&self, channel: PsdChannelKind) -> Option<&ChannelBytes> {
self.channels.get(&channel)
}
}
impl Deref for PsdLayer {
type Target = LayerProperties;
fn deref(&self) -> &Self::Target {
&self.layer_properties
}
}
#[derive(Debug, Clone)]
pub(super) enum GroupDivider {
Other = 0,
OpenFolder = 1,
CloseFolder = 2,
BoundingSection = 3,
}
impl GroupDivider {
pub(super) fn match_divider(divider: i32) -> Option<GroupDivider> {
match divider {
0 => Some(GroupDivider::Other),
1 => Some(GroupDivider::OpenFolder),
2 => Some(GroupDivider::CloseFolder),
3 => Some(GroupDivider::BoundingSection),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct LayerRecord {
pub(super) name: String,
pub(super) channel_data_lengths: Vec<(PsdChannelKind, u32)>,
pub(super) top: i32,
pub(super) left: i32,
pub(super) bottom: i32,
pub(super) right: i32,
pub(super) divider_type: Option<GroupDivider>,
}
impl LayerRecord {
pub fn height(&self) -> i32 {
(self.bottom - self.top) + 1
}
}
impl IntoRgba for PsdLayer {
fn rgba_idx(&self, idx: usize) -> usize {
let left_in_layer = idx % self.width() as usize;
let left_in_psd = self.layer_properties.layer_left as usize + left_in_layer;
let top_in_psd = idx / self.width() as usize + self.layer_properties.layer_top as usize;
(top_in_psd * self.layer_properties.psd_width as usize) + left_in_psd
}
fn red(&self) -> &ChannelBytes {
self.get_channel(PsdChannelKind::Red).unwrap()
}
fn green(&self) -> Option<&ChannelBytes> {
self.get_channel(PsdChannelKind::Green)
}
fn blue(&self) -> Option<&ChannelBytes> {
self.get_channel(PsdChannelKind::Blue)
}
fn alpha(&self) -> Option<&ChannelBytes> {
self.get_channel(PsdChannelKind::TransparencyMask)
}
fn psd_width(&self) -> u32 {
self.layer_properties.psd_width
}
fn psd_height(&self) -> u32 {
self.layer_properties.psd_height
}
}