1use crate::additional_info::{write_additional_info, WriteCtx};
18use crate::helpers::{
19 clamp, from_blend_mode, has_alpha, offset_for_channel, write_data_rle,
20 write_data_zip_without_prediction, Bounds as ChannelBounds, ChannelData, ColorSpace,
21 LayerChannelData, LayerMaskFlags, MaskParams, RAW_IMAGE_DATA,
22};
23use crate::image_resources::{has_image_resource, write_image_resource, RESOURCE_IDS};
24use crate::psd::{
25 BlendMode, ChannelId, Color, ColorMode, Compression, GlobalLayerMaskInfo, Layer,
26 LayerAdditionalInfo, LayerMaskData, PatternInfo, PixelData, Psd, SectionDividerType,
27 WriteOptions,
28};
29
30#[derive(Debug, Clone)]
41pub struct PsdWriter {
42 pub buffer: Vec<u8>,
44 pub offset: usize,
46 pub temp_buffer: Option<Vec<u8>>,
48}
49
50pub fn create_writer(size: usize) -> PsdWriter {
52 PsdWriter {
53 buffer: vec![0u8; size],
54 offset: 0,
55 temp_buffer: None,
56 }
57}
58
59pub fn create_writer_default() -> PsdWriter {
61 create_writer(4096)
62}
63
64pub fn get_writer_buffer(writer: &PsdWriter) -> Vec<u8> {
66 writer.buffer[..writer.offset].to_vec()
67}
68
69pub fn get_writer_buffer_no_copy(writer: &PsdWriter) -> &[u8] {
71 &writer.buffer[..writer.offset]
72}
73
74fn resize_buffer(writer: &mut PsdWriter, size: usize) {
80 let mut new_length = writer.buffer.len();
81
82 loop {
84 new_length *= 2;
85 if size <= new_length {
86 break;
87 }
88 }
89
90 writer.buffer.resize(new_length, 0);
91}
92
93fn ensure_size(writer: &mut PsdWriter, size: usize) {
95 if size > writer.buffer.len() {
96 resize_buffer(writer, size);
97 }
98}
99
100fn add_size(writer: &mut PsdWriter, size: usize) -> usize {
102 let offset = writer.offset;
103 writer.offset += size;
104 ensure_size(writer, writer.offset);
105 offset
106}
107
108#[inline]
117fn set_bytes_be(writer: &mut PsdWriter, offset: usize, bytes: &[u8]) {
118 writer.buffer[offset..offset + bytes.len()].copy_from_slice(bytes);
119}
120
121pub fn write_uint8(writer: &mut PsdWriter, value: u8) {
127 let offset = add_size(writer, 1);
128 writer.buffer[offset] = value;
129}
130
131pub fn write_int16(writer: &mut PsdWriter, value: i16) {
133 let offset = add_size(writer, 2);
134 set_bytes_be(writer, offset, &value.to_be_bytes());
135}
136
137pub fn write_uint16(writer: &mut PsdWriter, value: u16) {
139 let offset = add_size(writer, 2);
140 set_bytes_be(writer, offset, &value.to_be_bytes());
141}
142
143pub fn write_uint16_le(writer: &mut PsdWriter, value: u16) {
145 let offset = add_size(writer, 2);
146 set_bytes_be(writer, offset, &value.to_le_bytes());
147}
148
149pub fn write_int32(writer: &mut PsdWriter, value: i32) {
151 let offset = add_size(writer, 4);
152 set_bytes_be(writer, offset, &value.to_be_bytes());
153}
154
155pub fn write_int32_le(writer: &mut PsdWriter, value: i32) {
157 let offset = add_size(writer, 4);
158 set_bytes_be(writer, offset, &value.to_le_bytes());
159}
160
161pub fn write_uint32(writer: &mut PsdWriter, value: u32) {
163 let offset = add_size(writer, 4);
164 set_bytes_be(writer, offset, &value.to_be_bytes());
165}
166
167pub fn write_float32(writer: &mut PsdWriter, value: f32) {
169 let offset = add_size(writer, 4);
170 set_bytes_be(writer, offset, &value.to_be_bytes());
171}
172
173pub fn write_float64(writer: &mut PsdWriter, value: f64) {
175 let offset = add_size(writer, 8);
176 set_bytes_be(writer, offset, &value.to_be_bytes());
177}
178
179pub fn write_fixed_point32(writer: &mut PsdWriter, value: f64) {
181 write_int32(writer, (value * (1i64 << 16) as f64) as i32);
182}
183
184pub fn write_fixed_point_path32(writer: &mut PsdWriter, value: f64) {
186 write_int32(writer, (value * (1i64 << 24) as f64) as i32);
187}
188
189pub fn write_bytes(writer: &mut PsdWriter, buffer: Option<&[u8]>) {
191 if let Some(buffer) = buffer {
192 ensure_size(writer, writer.offset + buffer.len());
193 let offset = writer.offset;
194 writer.buffer[offset..offset + buffer.len()].copy_from_slice(buffer);
195 writer.offset += buffer.len();
196 }
197}
198
199pub fn write_zeros(writer: &mut PsdWriter, count: usize) {
201 for _ in 0..count {
202 write_uint8(writer, 0);
203 }
204}
205
206pub fn write_signature(writer: &mut PsdWriter, signature: &str) {
208 if signature.len() != 4 {
209 panic!("Invalid signature: '{}'", signature);
210 }
211
212 for b in signature.bytes() {
213 write_uint8(writer, b);
214 }
215}
216
217pub fn write_ascii_string(writer: &mut PsdWriter, text: &str) {
223 for ch in text.chars() {
224 write_uint8(writer, (ch as u32) as u8);
225 }
226}
227
228pub fn write_pascal_string(writer: &mut PsdWriter, text: &str, pad_to: usize) {
230 let chars: Vec<char> = text.chars().collect();
231 let mut length = chars.len();
232 if length > 255 {
233 panic!("String too long");
234 }
235
236 write_uint8(writer, length as u8);
237
238 for &ch in &chars {
239 let code = ch as u32;
240 write_uint8(writer, if code < 128 { code as u8 } else { b'?' });
242 }
243
244 length += 1;
246 while length % pad_to != 0 {
247 write_uint8(writer, 0);
248 length += 1;
249 }
250}
251
252pub fn write_unicode_string_without_length(writer: &mut PsdWriter, text: &str) {
254 for unit in text.encode_utf16() {
255 write_uint16(writer, unit);
256 }
257}
258
259pub fn write_unicode_string_without_length_le(writer: &mut PsdWriter, text: &str) {
261 for unit in text.encode_utf16() {
262 write_uint16_le(writer, unit);
263 }
264}
265
266pub fn write_unicode_string(writer: &mut PsdWriter, text: &str) {
268 let len = text.encode_utf16().count();
269 write_uint32(writer, len as u32);
270 write_unicode_string_without_length(writer, text);
271}
272
273pub fn write_unicode_string_with_padding(writer: &mut PsdWriter, text: &str) {
275 let len = text.encode_utf16().count();
276 write_uint32(writer, (len + 1) as u32);
277
278 for unit in text.encode_utf16() {
279 write_uint16(writer, unit);
280 }
281
282 write_uint16(writer, 0);
283}
284
285pub fn write_section<F: FnOnce(&mut PsdWriter)>(
295 writer: &mut PsdWriter,
296 round: usize,
297 func: F,
298 write_total_length: bool,
299 large: bool,
300) {
301 if large {
302 write_uint32(writer, 0);
303 }
304 let offset = writer.offset;
305 write_uint32(writer, 0);
306
307 func(writer);
308
309 let mut length = writer.offset - offset - 4;
310 let mut len = length;
311
312 while len % round != 0 {
313 write_uint8(writer, 0);
314 len += 1;
315 }
316
317 if write_total_length {
318 length = len;
319 }
320
321 set_bytes_be(writer, offset, &(length as u32).to_be_bytes());
323}
324
325pub fn write_color(writer: &mut PsdWriter, color: Option<&Color>) {
331 match color {
332 None => {
333 write_uint16(writer, ColorSpace::Rgb as u16);
334 write_zeros(writer, 8);
335 }
336 Some(Color::Rgba(c)) => {
337 write_uint16(writer, ColorSpace::Rgb as u16);
339 write_uint16(writer, (c.r * 257.0).round() as u16);
340 write_uint16(writer, (c.g * 257.0).round() as u16);
341 write_uint16(writer, (c.b * 257.0).round() as u16);
342 write_uint16(writer, 0);
343 }
344 Some(Color::Rgb(c)) => {
345 write_uint16(writer, ColorSpace::Rgb as u16);
347 write_uint16(writer, (c.r * 257.0).round() as u16);
348 write_uint16(writer, (c.g * 257.0).round() as u16);
349 write_uint16(writer, (c.b * 257.0).round() as u16);
350 write_uint16(writer, 0);
351 }
352 Some(Color::Frgb(c)) => {
353 write_uint16(writer, ColorSpace::Rgb as u16);
355 write_uint16(writer, (c.fr * 255.0 * 257.0).round() as u16);
356 write_uint16(writer, (c.fg * 255.0 * 257.0).round() as u16);
357 write_uint16(writer, (c.fb * 255.0 * 257.0).round() as u16);
358 write_uint16(writer, 0);
359 }
360 Some(Color::Lab(c)) => {
361 write_uint16(writer, ColorSpace::Lab as u16);
363 write_int16(writer, (c.l * 10000.0).round() as i16);
364 write_int16(
365 writer,
366 (if c.a < 0.0 { c.a * 12800.0 } else { c.a * 12700.0 }).round() as i16,
367 );
368 write_int16(
369 writer,
370 (if c.b < 0.0 { c.b * 12800.0 } else { c.b * 12700.0 }).round() as i16,
371 );
372 write_uint16(writer, 0);
373 }
374 Some(Color::Hsb(c)) => {
375 write_uint16(writer, ColorSpace::Hsb as u16);
377 write_uint16(writer, (c.h * 0xffff as f64).round() as u16);
378 write_uint16(writer, (c.s * 0xffff as f64).round() as u16);
379 write_uint16(writer, (c.b * 0xffff as f64).round() as u16);
380 write_uint16(writer, 0);
381 }
382 Some(Color::Cmyk(c)) => {
383 write_uint16(writer, ColorSpace::Cmyk as u16);
385 write_uint16(writer, (c.c * 257.0).round() as u16);
386 write_uint16(writer, (c.m * 257.0).round() as u16);
387 write_uint16(writer, (c.y * 257.0).round() as u16);
388 write_uint16(writer, (c.k * 257.0).round() as u16);
389 }
390 Some(Color::Grayscale(c)) => {
391 write_uint16(writer, ColorSpace::Grayscale as u16);
393 write_uint16(writer, (c.k * 10000.0 / 255.0).round() as u16);
394 write_zeros(writer, 6);
395 }
396 }
397}
398
399pub fn write_pattern(writer: &mut PsdWriter, pattern: &PatternInfo) {
404 let width = pattern.bounds.w as u32;
405 let height = pattern.bounds.h as u32;
406 let pixel_data = PixelData {
407 width,
408 height,
409 data: pattern.data.clone(),
410 };
411
412 write_uint32(writer, 0); let patts_offset = writer.offset;
414
415 write_uint32(writer, 1); write_uint32(writer, ColorMode::Rgb as u32); write_int16(writer, pattern.x as i16);
419 write_int16(writer, pattern.y as i16);
420
421 write_unicode_string(writer, &format!("{}\0", pattern.name)); write_pascal_string(writer, &pattern.id, 1); write_uint32(writer, 3); write_uint32(writer, 0); let vl_offset = writer.offset;
428
429 let top = pattern.bounds.y as u32;
430 let left = pattern.bounds.x as u32;
431 let bottom = top + height;
432 let right = left + width;
433
434 write_uint32(writer, top);
435 write_uint32(writer, left);
436 write_uint32(writer, bottom);
437 write_uint32(writer, right);
438
439 write_uint32(writer, 24); for i in 0..(24 + 2) {
443 let offset: i32 = if i < 3 {
444 i
445 } else if i == 25 {
446 3
447 } else {
448 -1
449 };
450
451 if offset < 0 {
452 write_uint32(writer, 0); continue;
454 }
455
456 let mut buffer = vec![
458 0u8;
459 (width * height + 2 * height + 2 * width + 16) as usize
460 ];
461 let data = write_data_rle(&mut buffer, &pixel_data, &[offset as usize], false)
462 .expect("write_data_rle returned None for pattern channel");
463
464 write_uint32(writer, 1); write_uint32(writer, (data.len() + 4 + 16 + 2 + 1) as u32); write_uint32(writer, 8); write_uint32(writer, top);
468 write_uint32(writer, left);
469 write_uint32(writer, bottom);
470 write_uint32(writer, right);
471 write_uint16(writer, 8); write_uint8(writer, 1); write_bytes(writer, Some(&data));
474 }
475
476 let vl_length = writer.offset - vl_offset;
477 let mut patts_length = writer.offset - patts_offset;
478
479 while patts_length % 4 != 0 {
480 write_zeros(writer, 1);
481 patts_length += 1;
482 }
483
484 set_bytes_be(writer, vl_offset - 4, &(vl_length as u32).to_be_bytes());
485 set_bytes_be(writer, patts_offset - 4, &(patts_length as u32).to_be_bytes());
486}
487
488fn get_largest_layer_size(layers: Option<&[Layer]>) -> usize {
494 let mut max = 0usize;
495 let layers = match layers {
496 Some(l) => l,
497 None => return 0,
498 };
499 for layer in layers {
500 if layer.canvas.is_some() || layer.image_data.is_some() {
501 let (width, height) = get_layer_dimensions(layer.canvas.as_ref(), layer.image_data.as_ref());
502 let (w, h) = (width as usize, height as usize);
503 max = max.max(2 * h + 2 * w * h);
504 }
505 if let Some(children) = &layer.children {
506 max = max.max(get_largest_layer_size(Some(children)));
507 }
508 }
509 max
510}
511
512fn get_layer_dimensions(canvas: Option<&PixelData>, image_data: Option<&PixelData>) -> (u32, u32) {
515 if let Some(d) = image_data {
516 (d.width, d.height)
517 } else if let Some(c) = canvas {
518 (c.width, c.height)
519 } else {
520 (0, 0)
521 }
522}
523
524fn verify_bit_count(_target_children: Option<&[Layer]>) {
528 }
530
531pub fn write_psd(psd: &Psd, options: &WriteOptions) -> Vec<u8> {
534 let mut writer = create_writer_default();
535 write_psd_to_writer(&mut writer, psd, options);
536 get_writer_buffer(&writer)
537}
538
539pub fn write_psd_to_writer(writer: &mut PsdWriter, psd: &Psd, options: &WriteOptions) {
541 if !(psd.width > 0.0 && psd.height > 0.0) {
542 panic!("Invalid document size");
543 }
544
545 let psb = options.psb == Some(true);
546
547 if (psd.width > 30000.0 || psd.height > 30000.0) && !psb {
548 panic!("Document size is too large (max is 30000x30000, use PSB format instead)");
549 }
550
551 let bits_per_channel = psd.bits_per_channel.unwrap_or(8.0);
552 if bits_per_channel != 8.0 {
553 panic!("bitsPerChannel other than 8 are not supported for writing");
554 }
555
556 verify_bit_count(psd.children.as_deref());
557
558 let image_resources = psd.image_resources.clone().unwrap_or_default();
563
564 let image_data: Option<&PixelData> = psd.image_data.as_ref().or(psd.canvas.as_ref());
567
568 if let Some(id) = image_data {
569 if psd.width as u32 != id.width || psd.height as u32 != id.height {
570 panic!("Document canvas must have the same size as document");
571 }
572 }
573
574 let global_alpha = image_data.map(has_alpha).unwrap_or(false);
575
576 let max_buffer_size = get_largest_layer_size(psd.children.as_deref()).max(
577 4 * 2 * (psd.width as usize) * (psd.height as usize) + 2 * (psd.height as usize),
578 );
579 writer.temp_buffer = Some(vec![0u8; max_buffer_size]);
580
581 write_signature(writer, "8BPS");
583 write_uint16(writer, if psb { 2 } else { 1 }); write_zeros(writer, 6);
585 write_uint16(writer, if global_alpha { 4 } else { 3 }); write_uint32(writer, psd.height as u32);
587 write_uint32(writer, psd.width as u32);
588 write_uint16(writer, bits_per_channel as u16);
589 write_uint16(writer, ColorMode::Rgb as u16); let palette = psd.palette.clone();
593 write_section(
594 writer,
595 1,
596 |w| {
597 if let Some(palette) = &palette {
598 for i in 0..256 {
599 w_palette_byte(w, palette.get(i).map(|c| c.r));
600 }
601 for i in 0..256 {
602 w_palette_byte(w, palette.get(i).map(|c| c.g));
603 }
604 for i in 0..256 {
605 w_palette_byte(w, palette.get(i).map(|c| c.b));
606 }
607 }
608 },
609 false,
610 false,
611 );
612
613 let has_layer_section = psd.children.is_some();
625 let mut layers: Vec<Layer> = Vec::new();
626 add_children(&mut layers, psd.children.as_deref());
627 if layers.is_empty() && has_layer_section {
628 layers.push(Layer::default());
629 }
630
631 write_section(
639 writer,
640 1,
641 |w| {
642 for &id in RESOURCE_IDS {
643 let count = has_image_resource(id, &image_resources);
644 for i in 0..count {
645 write_signature(w, "8BIM");
646 write_uint16(w, id);
647 write_pascal_string(w, "", 2);
648 write_section(
649 w,
650 2,
651 |w| {
652 write_image_resource(id, w, &image_resources, i)
656 .expect("write_image_resource failed");
657 },
658 false,
659 false,
660 );
661 }
662 }
663 },
664 false,
665 false,
666 );
667
668 write_section(
670 writer,
671 2,
672 |w| {
673 write_layer_info(w, &layers, psd, global_alpha, options, psb);
674 write_global_layer_mask_info(w, psd.global_layer_mask_info.as_ref());
675 let mut ctx = WriteCtx::new(options, psb);
677 write_additional_info(w, &psd.additional_info, &mut ctx);
678 },
679 false,
680 psb,
681 );
682
683 let channels: Vec<usize> = if global_alpha {
685 vec![0, 1, 2, 3]
686 } else {
687 vec![0, 1, 2]
688 };
689 let width = image_data.map(|d| d.width).unwrap_or(psd.width as u32);
690 let height = image_data.map(|d| d.height).unwrap_or(psd.height as u32);
691 let mut data = PixelData {
692 width,
693 height,
694 data: vec![0u8; (width as usize) * (height as usize) * 4],
695 };
696
697 write_uint16(writer, Compression::RleCompressed as u16);
698
699 if let Some(id) = image_data {
700 data.data[..id.data.len()].copy_from_slice(&id.data);
701
702 if global_alpha {
704 let size = (data.width as usize) * (data.height as usize) * 4;
705 let p = &mut data.data;
706 let mut i = 0;
707 while i < size {
708 let pa = p[i + 3];
709 if pa != 0 && pa != 255 {
710 let a = pa as f64 / 255.0;
711 let ra = 255.0 * (1.0 - a);
712 p[i] = (p[i] as f64 * a + ra) as u8;
713 p[i + 1] = (p[i + 1] as f64 * a + ra) as u8;
714 p[i + 2] = (p[i + 2] as f64 * a + ra) as u8;
715 }
716 i += 4;
717 }
718 }
719 }
720
721 let mut temp = writer.temp_buffer.take().unwrap();
722 let rle = write_data_rle(&mut temp, &data, &channels, psb);
723 writer.temp_buffer = Some(temp);
724 write_bytes(writer, rle.as_deref());
725}
726
727fn w_palette_byte(writer: &mut PsdWriter, value: Option<f64>) {
729 write_uint8(writer, value.unwrap_or(0.0) as u8);
730}
731
732fn write_layer_info(
734 writer: &mut PsdWriter,
735 layers: &[Layer],
736 _psd: &Psd,
737 global_alpha: bool,
738 options: &WriteOptions,
739 psb: bool,
740) {
741 write_section(
742 writer,
743 4,
744 |w| {
745 write_int16(
746 w,
747 if global_alpha {
748 -(layers.len() as i16)
749 } else {
750 layers.len() as i16
751 },
752 );
753
754 let mut temp = w.temp_buffer.take().unwrap();
756 let mut layers_data: Vec<LayerChannelData> = layers
757 .iter()
758 .enumerate()
759 .map(|(i, l)| get_channels(&mut temp, l, i == 0, options, psb))
760 .collect();
761 w.temp_buffer = Some(temp);
762
763 let mut ctx = WriteCtx::new(options, psb);
765 for layer_data in &layers_data {
766 let layer = &layer_data.layer;
767 write_int32(w, layer_data.top);
768 write_int32(w, layer_data.left);
769 write_int32(w, layer_data.bottom);
770 write_int32(w, layer_data.right);
771 write_uint16(w, layer_data.channels.len() as u16);
772
773 for c in &layer_data.channels {
774 write_int16(w, c.channel_id as i16);
775 if psb {
776 write_uint32(w, 0);
777 }
778 write_uint32(w, c.length as u32);
779 }
780
781 write_signature(w, "8BIM");
782 let blend = layer.blend_mode.map(from_blend_mode).unwrap_or("norm");
783 write_signature(w, blend);
784 write_uint8(w, (clamp(layer.opacity.unwrap_or(1.0), 0.0, 1.0) * 255.0).round() as u8);
785 write_uint8(w, if layer.clipping == Some(true) { 1 } else { 0 });
786
787 let mut flags: u8 = 0x08;
788 if layer.transparency_protected == Some(true) {
789 flags |= 0x01;
790 }
791 if layer.hidden == Some(true) {
792 flags |= 0x02;
793 }
794 let info = &layer.additional_info;
795 let section_irrelevant = info.section_divider.as_ref().map_or(false, |sd| {
796 sd.divider_type != SectionDividerType::Other
797 });
798 if info.vector_mask.is_some() || section_irrelevant || info.adjustment.is_some() {
799 flags |= 0x10;
800 }
801 if layer.effects_open == Some(true) {
802 flags |= 0x20;
803 }
804
805 write_uint8(w, flags);
806 write_uint8(w, 0); write_section(
809 w,
810 1,
811 |w| {
812 write_layer_mask_data(w, info, layer_data);
813 write_layer_blending_ranges(w, info);
814 let name = info.name.clone().unwrap_or_default();
815 let name: String = name.chars().take(255).collect();
816 write_pascal_string(w, &name, 4);
817 write_additional_info(w, info, &mut ctx);
818 },
819 false,
820 false,
821 );
822 }
823
824 for layer_data in &mut layers_data {
826 for channel in &layer_data.channels {
827 write_uint16(w, channel.compression as u16);
828 if let Some(buffer) = &channel.buffer {
829 write_bytes(w, Some(buffer));
830 }
831 }
832 }
833 },
834 true,
835 psb,
836 );
837}
838
839fn write_layer_mask_data(
841 writer: &mut PsdWriter,
842 info: &LayerAdditionalInfo,
843 layer_data: &LayerChannelData,
844) {
845 let mask = info.mask.as_ref();
846 let real_mask = info.real_mask.as_ref();
847 write_section(
848 writer,
849 1,
850 |w| {
851 if mask.is_none() && real_mask.is_none() {
852 return;
853 }
854
855 let mut params: u8 = 0;
856 let mut flags: u8 = 0;
857 let mut real_flags: u8 = 0;
858
859 if let Some(mask) = mask {
860 if mask.user_mask_density.is_some() {
861 params |= MaskParams::UserMaskDensity as u8;
862 }
863 if mask.user_mask_feather.is_some() {
864 params |= MaskParams::UserMaskFeather as u8;
865 }
866 if mask.vector_mask_density.is_some() {
867 params |= MaskParams::VectorMaskDensity as u8;
868 }
869 if mask.vector_mask_feather.is_some() {
870 params |= MaskParams::VectorMaskFeather as u8;
871 }
872
873 if mask.disabled == Some(true) {
874 flags |= LayerMaskFlags::LayerMaskDisabled as u8;
875 }
876 if mask.position_relative_to_layer == Some(true) {
877 flags |= LayerMaskFlags::PositionRelativeToLayer as u8;
878 }
879 if mask.from_vector_data == Some(true) {
880 flags |= LayerMaskFlags::LayerMaskFromRenderingOtherData as u8;
881 }
882 if params != 0 {
883 flags |= LayerMaskFlags::MaskHasParametersAppliedToIt as u8;
884 }
885 }
886
887 let m = layer_data.mask.unwrap_or_default();
888 write_int32(w, m.top);
889 write_int32(w, m.left);
890 write_int32(w, m.bottom);
891 write_int32(w, m.right);
892 write_uint8(w, mask.and_then(|m| m.default_color).unwrap_or(0.0) as u8);
893 write_uint8(w, flags);
894
895 if let Some(real_mask) = real_mask {
896 if real_mask.disabled == Some(true) {
897 real_flags |= LayerMaskFlags::LayerMaskDisabled as u8;
898 }
899 if real_mask.position_relative_to_layer == Some(true) {
900 real_flags |= LayerMaskFlags::PositionRelativeToLayer as u8;
901 }
902 if real_mask.from_vector_data == Some(true) {
903 real_flags |= LayerMaskFlags::LayerMaskFromRenderingOtherData as u8;
904 }
905
906 let r = layer_data.real_mask.unwrap_or_default();
907 write_uint8(w, real_flags);
908 write_uint8(w, real_mask.default_color.unwrap_or(0.0) as u8);
909 write_int32(w, r.top);
910 write_int32(w, r.left);
911 write_int32(w, r.bottom);
912 write_int32(w, r.right);
913 }
914
915 if params != 0 {
916 if let Some(mask) = mask {
917 write_uint8(w, params);
918 if let Some(v) = mask.user_mask_density {
919 write_uint8(w, (v * 0xff as f64).round() as u8);
920 }
921 if let Some(v) = mask.user_mask_feather {
922 write_float64(w, v);
923 }
924 if let Some(v) = mask.vector_mask_density {
925 write_uint8(w, (v * 0xff as f64).round() as u8);
926 }
927 if let Some(v) = mask.vector_mask_feather {
928 write_float64(w, v);
929 }
930 }
931 }
932
933 write_zeros(w, 2);
934 },
935 false,
936 false,
937 );
938}
939
940fn write_blending_range(writer: &mut PsdWriter, range: &[f64]) {
942 write_uint8(writer, range[0] as u8);
943 write_uint8(writer, range[1] as u8);
944 write_uint8(writer, range[2] as u8);
945 write_uint8(writer, range[3] as u8);
946}
947
948fn write_layer_blending_ranges(writer: &mut PsdWriter, info: &LayerAdditionalInfo) {
950 let ranges = info.blending_ranges.clone();
951 write_section(
952 writer,
953 1,
954 |w| {
955 if let Some(ranges) = &ranges {
956 write_blending_range(w, &ranges.composite_gray_blend_source);
957 write_blending_range(w, &ranges.composite_graph_blend_destination_range);
958 for r in &ranges.ranges {
959 write_blending_range(w, &r.source_range);
960 write_blending_range(w, &r.dest_range);
961 }
962 }
963 },
964 false,
965 false,
966 );
967}
968
969fn write_global_layer_mask_info(writer: &mut PsdWriter, info: Option<&GlobalLayerMaskInfo>) {
971 let info = info.cloned();
972 write_section(
973 writer,
974 1,
975 |w| {
976 if let Some(info) = &info {
977 write_uint16(w, info.overlay_color_space as u16);
978 write_uint16(w, info.color_space1 as u16);
979 write_uint16(w, info.color_space2 as u16);
980 write_uint16(w, info.color_space3 as u16);
981 write_uint16(w, info.color_space4 as u16);
982 write_uint16(w, (info.opacity * 0xff as f64) as u16);
983 write_uint8(w, info.kind as u8);
984 write_zeros(w, 3);
985 }
986 },
987 false,
988 false,
989 );
990}
991
992fn add_children(layers: &mut Vec<Layer>, children: Option<&[Layer]>) {
994 let children = match children {
995 Some(c) => c,
996 None => return,
997 };
998
999 for c in children {
1000 if c.children.is_some() && c.canvas.is_some() {
1001 panic!("Invalid layer, cannot have both 'canvas' and 'children' properties");
1002 }
1003 if c.children.is_some() && c.image_data.is_some() {
1004 panic!("Invalid layer, cannot have both 'imageData' and 'children' properties");
1005 }
1006
1007 if c.children.is_some() {
1008 let mut open_layer = Layer::default();
1010 open_layer.additional_info.name = Some("</Layer group>".to_string());
1011 open_layer.additional_info.section_divider = Some(crate::psd::SectionDivider {
1012 divider_type: SectionDividerType::BoundingSectionDivider,
1013 key: None,
1014 sub_type: None,
1015 });
1016 layers.push(open_layer);
1017
1018 add_children(layers, c.children.as_deref());
1019
1020 let mut folder = c.clone();
1022 folder.children = None;
1023 if folder.blend_mode == Some(BlendMode::PassThrough) {
1024 folder.blend_mode = Some(BlendMode::Normal);
1025 }
1026 let key = c.blend_mode.map(from_blend_mode).unwrap_or("pass").to_string();
1027 folder.additional_info.section_divider = Some(crate::psd::SectionDivider {
1028 divider_type: if c.opened == Some(false) {
1029 SectionDividerType::ClosedFolder
1030 } else {
1031 SectionDividerType::OpenFolder
1032 },
1033 key: Some(key),
1034 sub_type: Some(0.0),
1035 });
1036 layers.push(folder);
1037 } else {
1038 layers.push(c.clone());
1039 }
1040 }
1041}
1042
1043fn get_channels(
1045 temp_buffer: &mut [u8],
1046 layer: &Layer,
1047 background: bool,
1048 options: &WriteOptions,
1049 psb: bool,
1050) -> LayerChannelData {
1051 let mut layer_data = get_layer_channels(temp_buffer, layer, background, options, psb);
1052 if let Some(mask) = &layer.additional_info.mask {
1053 get_mask_channels(temp_buffer, &mut layer_data, mask, options, psb, false);
1054 }
1055 if let Some(real_mask) = &layer.additional_info.real_mask {
1056 get_mask_channels(temp_buffer, &mut layer_data, real_mask, options, psb, true);
1057 }
1058 layer_data
1059}
1060
1061fn get_mask_channels(
1063 temp_buffer: &mut [u8],
1064 layer_data: &mut LayerChannelData,
1065 mask: &LayerMaskData,
1066 options: &WriteOptions,
1067 psb: bool,
1068 real_mask: bool,
1069) {
1070 let top = mask.top.unwrap_or(0.0) as i32;
1071 let left = mask.left.unwrap_or(0.0) as i32;
1072 let (width, height) = get_layer_dimensions(mask.canvas.as_ref(), mask.image_data.as_ref());
1073
1074 let image_data = mask.image_data.as_ref().or(mask.canvas.as_ref());
1075
1076 if let Some(id) = image_data {
1077 if id.width != width || id.height != height {
1078 panic!("Invalid imageData dimentions");
1079 }
1080 }
1081
1082 let right = left + width as i32;
1083 let bottom = top + height as i32;
1084
1085 let (buffer, compression): (Vec<u8>, Compression) = if image_data.is_none() {
1086 (Vec::new(), Compression::RleCompressed)
1087 } else if options.compress == Some(true) {
1088 (
1089 write_data_zip_without_prediction(image_data.unwrap(), &[0]).unwrap_or_default(),
1090 Compression::ZipWithoutPrediction,
1091 )
1092 } else {
1093 (
1094 write_data_rle(temp_buffer, image_data.unwrap(), &[0], psb).unwrap_or_default(),
1095 Compression::RleCompressed,
1096 )
1097 };
1098
1099 let length = 2 + buffer.len();
1100 layer_data.channels.push(ChannelData {
1101 channel_id: if real_mask {
1102 ChannelId::RealUserMask
1103 } else {
1104 ChannelId::UserMask
1105 },
1106 compression,
1107 buffer: Some(buffer),
1108 length,
1109 });
1110
1111 let bounds = ChannelBounds { top, left, right, bottom };
1112 if real_mask {
1113 layer_data.real_mask = Some(bounds);
1114 } else {
1115 layer_data.mask = Some(bounds);
1116 }
1117}
1118
1119fn crop_image_data(data: &PixelData, left: usize, top: usize, width: usize, height: usize) -> PixelData {
1121 let mut dst = vec![0u8; width * height * 4];
1122 let src = &data.data;
1123 let dw = data.width as usize;
1124 for y in 0..height {
1125 for x in 0..width {
1126 let s = ((x + left) + (y + top) * dw) * 4;
1127 let d = (x + y * width) * 4;
1128 dst[d] = src[s];
1129 dst[d + 1] = src[s + 1];
1130 dst[d + 2] = src[s + 2];
1131 dst[d + 3] = src[s + 3];
1132 }
1133 }
1134 PixelData {
1135 width: width as u32,
1136 height: height as u32,
1137 data: dst,
1138 }
1139}
1140
1141fn get_layer_channels(
1143 temp_buffer: &mut [u8],
1144 layer: &Layer,
1145 background: bool,
1146 options: &WriteOptions,
1147 psb: bool,
1148) -> LayerChannelData {
1149 let mut top = layer.top.unwrap_or(0.0) as i32;
1150 let mut left = layer.left.unwrap_or(0.0) as i32;
1151 #[allow(unused_assignments)]
1152 let mut right = layer.right.unwrap_or(0.0) as i32;
1153 #[allow(unused_assignments)]
1154 let mut bottom = layer.bottom.unwrap_or(0.0) as i32;
1155
1156 let default_channels = || {
1158 vec![
1159 ChannelData { channel_id: ChannelId::Transparency, compression: Compression::RawData, buffer: None, length: 2 },
1160 ChannelData { channel_id: ChannelId::Color0, compression: Compression::RawData, buffer: None, length: 2 },
1161 ChannelData { channel_id: ChannelId::Color1, compression: Compression::RawData, buffer: None, length: 2 },
1162 ChannelData { channel_id: ChannelId::Color2, compression: Compression::RawData, buffer: None, length: 2 },
1163 ]
1164 };
1165
1166 let (mut width, mut height) = get_layer_dimensions(layer.canvas.as_ref(), layer.image_data.as_ref());
1167
1168 if (layer.canvas.is_none() && layer.image_data.is_none()) || width == 0 || height == 0 {
1169 right = left;
1170 bottom = top;
1171 return LayerChannelData {
1172 layer: layer.clone(),
1173 channels: default_channels(),
1174 top,
1175 left,
1176 right,
1177 bottom,
1178 mask: None,
1179 real_mask: None,
1180 };
1181 }
1182
1183 right = left + width as i32;
1184 bottom = top + height as i32;
1185
1186 let mut data: PixelData = layer
1187 .image_data
1188 .clone()
1189 .or_else(|| layer.canvas.clone())
1190 .unwrap();
1191
1192 if options.trim_image_data == Some(true) {
1193 let trimmed = trim_data(&data);
1194 if trimmed.left != 0
1195 || trimmed.top != 0
1196 || trimmed.right != data.width as i32
1197 || trimmed.bottom != data.height as i32
1198 {
1199 left += trimmed.left;
1200 top += trimmed.top;
1201 right -= data.width as i32 - trimmed.right;
1202 bottom -= data.height as i32 - trimmed.bottom;
1203 width = (right - left) as u32;
1204 height = (bottom - top) as u32;
1205
1206 if width == 0 || height == 0 {
1207 return LayerChannelData {
1208 layer: layer.clone(),
1209 channels: default_channels(),
1210 top,
1211 left,
1212 right,
1213 bottom,
1214 mask: None,
1215 real_mask: None,
1216 };
1217 }
1218
1219 data = crop_image_data(
1220 &data,
1221 trimmed.left as usize,
1222 trimmed.top as usize,
1223 width as usize,
1224 height as usize,
1225 );
1226 }
1227 }
1228
1229 let mut channel_ids = vec![ChannelId::Color0, ChannelId::Color1, ChannelId::Color2];
1230
1231 if !background
1232 || options.no_background == Some(true)
1233 || layer.additional_info.mask.is_some()
1234 || has_alpha(&data)
1235 {
1236 channel_ids.insert(0, ChannelId::Transparency);
1237 }
1238
1239 let channels: Vec<ChannelData> = channel_ids
1240 .into_iter()
1241 .map(|channel_id| {
1242 let offset = offset_for_channel(channel_id, false) as usize;
1243 let (buffer, compression): (Vec<u8>, Compression) = if options.compress == Some(true) {
1244 (
1245 write_data_zip_without_prediction(&data, &[offset]).unwrap_or_default(),
1246 Compression::ZipWithoutPrediction,
1247 )
1248 } else {
1249 (
1250 write_data_rle(temp_buffer, &data, &[offset], psb).unwrap_or_default(),
1251 Compression::RleCompressed,
1252 )
1253 };
1254 let length = 2 + buffer.len();
1255 ChannelData { channel_id, compression, buffer: Some(buffer), length }
1256 })
1257 .collect();
1258
1259 let _ = RAW_IMAGE_DATA; LayerChannelData {
1262 layer: layer.clone(),
1263 channels,
1264 top,
1265 left,
1266 right,
1267 bottom,
1268 mask: None,
1269 real_mask: None,
1270 }
1271}
1272
1273fn is_row_empty(data: &PixelData, y: usize, left: usize, right: usize) -> bool {
1275 let width = data.width as usize;
1276 let start = (y * width + left) * 4 + 3;
1277 let end = start + (right - left) * 4;
1278 let mut i = start;
1279 while i < end {
1280 if data.data[i] != 0 {
1281 return false;
1282 }
1283 i += 4;
1284 }
1285 true
1286}
1287
1288fn is_col_empty(data: &PixelData, x: usize, top: usize, bottom: usize) -> bool {
1290 let width = data.width as usize;
1291 let stride = width * 4;
1292 let start = top * stride + x * 4 + 3;
1293 let mut y = top;
1294 let mut i = start;
1295 while y < bottom {
1296 if data.data[i] != 0 {
1297 return false;
1298 }
1299 y += 1;
1300 i += stride;
1301 }
1302 true
1303}
1304
1305fn trim_data(data: &PixelData) -> ChannelBounds {
1307 let mut top = 0i32;
1308 let mut left = 0i32;
1309 let mut right = data.width as i32;
1310 let mut bottom = data.height as i32;
1311
1312 while top < bottom && is_row_empty(data, top as usize, left as usize, right as usize) {
1313 top += 1;
1314 }
1315 while bottom > top && is_row_empty(data, (bottom - 1) as usize, left as usize, right as usize) {
1316 bottom -= 1;
1317 }
1318 while left < right && is_col_empty(data, left as usize, top as usize, bottom as usize) {
1319 left += 1;
1320 }
1321 while right > left && is_col_empty(data, (right - 1) as usize, top as usize, bottom as usize) {
1322 right -= 1;
1323 }
1324
1325 ChannelBounds { top, left, right, bottom }
1326}
1327
1328#[cfg(test)]
1329mod tests {
1330 use super::*;
1331 use crate::psd::{Cmyk, Grayscale, Hsb, Lab, Rgb};
1332
1333 #[test]
1334 fn scalars_big_endian() {
1335 let mut w = create_writer_default();
1336 write_uint8(&mut w, 0x12);
1337 write_uint16(&mut w, 0x1234);
1338 write_int16(&mut w, -2);
1339 write_uint32(&mut w, 0x12345678);
1340 write_int32(&mut w, -1);
1341 let buf = get_writer_buffer(&w);
1342 assert_eq!(
1343 buf,
1344 vec![
1345 0x12, 0x12, 0x34, 0xff, 0xfe, 0x12, 0x34, 0x56, 0x78, 0xff, 0xff, 0xff, 0xff, ]
1351 );
1352 }
1353
1354 #[test]
1355 fn le_variants() {
1356 let mut w = create_writer_default();
1357 write_uint16_le(&mut w, 0x1234);
1358 write_int32_le(&mut w, 0x12345678);
1359 assert_eq!(
1360 get_writer_buffer(&w),
1361 vec![0x34, 0x12, 0x78, 0x56, 0x34, 0x12]
1362 );
1363 }
1364
1365 #[test]
1366 fn floats_big_endian() {
1367 let mut w = create_writer_default();
1368 write_float32(&mut w, 1.0_f32);
1369 write_float64(&mut w, 1.0_f64);
1370 assert_eq!(
1371 get_writer_buffer(&w),
1372 vec![
1373 0x3f, 0x80, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]
1376 );
1377 }
1378
1379 #[test]
1380 fn signature_and_zeros() {
1381 let mut w = create_writer_default();
1382 write_signature(&mut w, "8BPS");
1383 write_zeros(&mut w, 3);
1384 assert_eq!(get_writer_buffer(&w), vec![b'8', b'B', b'P', b'S', 0, 0, 0]);
1385 }
1386
1387 #[test]
1388 fn pascal_string_padding() {
1389 let mut w = create_writer_default();
1392 write_pascal_string(&mut w, "ab", 4);
1393 assert_eq!(get_writer_buffer(&w), vec![2, b'a', b'b', 0]);
1394 }
1395
1396 #[test]
1397 fn pascal_string_empty_pad2() {
1398 let mut w = create_writer_default();
1400 write_pascal_string(&mut w, "", 2);
1401 assert_eq!(get_writer_buffer(&w), vec![0, 0]);
1402 }
1403
1404 #[test]
1405 fn pascal_string_non_ascii_becomes_question() {
1406 let mut w = create_writer_default();
1407 write_pascal_string(&mut w, "é", 1); assert_eq!(get_writer_buffer(&w), vec![1, b'?']);
1410 }
1411
1412 #[test]
1413 fn unicode_string_layout() {
1414 let mut w = create_writer_default();
1415 write_unicode_string(&mut w, "AB");
1416 assert_eq!(
1417 get_writer_buffer(&w),
1418 vec![
1419 0x00, 0x00, 0x00, 0x02, 0x00, b'A', 0x00, b'B', ]
1422 );
1423 }
1424
1425 #[test]
1426 fn unicode_string_with_padding_layout() {
1427 let mut w = create_writer_default();
1428 write_unicode_string_with_padding(&mut w, "A");
1429 assert_eq!(
1430 get_writer_buffer(&w),
1431 vec![
1432 0x00, 0x00, 0x00, 0x02, 0x00, b'A', 0x00, 0x00, ]
1436 );
1437 }
1438
1439 #[test]
1440 fn section_backpatch_and_rounding() {
1441 let mut w = create_writer_default();
1444 write_section(
1445 &mut w,
1446 4,
1447 |w| {
1448 write_uint8(w, 0xaa);
1449 write_uint8(w, 0xbb);
1450 write_uint8(w, 0xcc);
1451 },
1452 false,
1453 false,
1454 );
1455 assert_eq!(
1456 get_writer_buffer(&w),
1457 vec![
1458 0x00, 0x00, 0x00, 0x03, 0xaa, 0xbb, 0xcc, 0x00, ]
1462 );
1463 }
1464
1465 #[test]
1466 fn section_total_length() {
1467 let mut w = create_writer_default();
1469 write_section(
1470 &mut w,
1471 4,
1472 |w| {
1473 write_uint8(w, 0xaa);
1474 write_uint8(w, 0xbb);
1475 write_uint8(w, 0xcc);
1476 },
1477 true,
1478 false,
1479 );
1480 assert_eq!(
1481 get_writer_buffer(&w),
1482 vec![0x00, 0x00, 0x00, 0x04, 0xaa, 0xbb, 0xcc, 0x00]
1483 );
1484 }
1485
1486 #[test]
1487 fn section_large() {
1488 let mut w = create_writer_default();
1490 write_section(&mut w, 2, |w| write_uint8(w, 0x7f), false, true);
1491 assert_eq!(
1492 get_writer_buffer(&w),
1493 vec![
1494 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f, 0x00, ]
1499 );
1500 }
1501
1502 #[test]
1503 fn buffer_growth_doubling() {
1504 let mut w = create_writer(4);
1506 for i in 0..10u8 {
1507 write_uint8(&mut w, i);
1508 }
1509 assert_eq!(w.offset, 10);
1510 assert_eq!(w.buffer.len(), 16);
1511 assert_eq!(
1512 get_writer_buffer(&w),
1513 vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1514 );
1515 }
1516
1517 #[test]
1518 fn write_bytes_grows_and_appends() {
1519 let mut w = create_writer(2);
1520 write_bytes(&mut w, Some(&[1, 2, 3, 4, 5]));
1521 write_bytes(&mut w, None);
1522 assert_eq!(get_writer_buffer(&w), vec![1, 2, 3, 4, 5]);
1523 }
1524
1525 #[test]
1526 fn color_none_is_rgb_zeros() {
1527 let mut w = create_writer_default();
1528 write_color(&mut w, None);
1529 assert_eq!(
1530 get_writer_buffer(&w),
1531 vec![0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0] );
1533 }
1534
1535 #[test]
1536 fn color_rgb() {
1537 let mut w = create_writer_default();
1538 let c = Color::Rgb(Rgb {
1539 r: 255.0,
1540 g: 0.0,
1541 b: 128.0,
1542 });
1543 write_color(&mut w, Some(&c));
1544 assert_eq!(
1546 get_writer_buffer(&w),
1547 vec![
1548 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, ]
1554 );
1555 }
1556
1557 #[test]
1558 fn color_cmyk_lab_hsb_grayscale_color_space_codes() {
1559 let mut w = create_writer_default();
1560 write_color(&mut w, Some(&Color::Cmyk(Cmyk { c: 0.0, m: 0.0, y: 0.0, k: 0.0 })));
1561 write_color(&mut w, Some(&Color::Lab(Lab { l: 0.0, a: 0.0, b: 0.0 })));
1562 write_color(&mut w, Some(&Color::Hsb(Hsb { h: 0.0, s: 0.0, b: 0.0 })));
1563 write_color(&mut w, Some(&Color::Grayscale(Grayscale { k: 0.0 })));
1564 let buf = get_writer_buffer(&w);
1565 assert_eq!(&buf[0..2], &[0x00, 0x02]); assert_eq!(&buf[10..12], &[0x00, 0x07]); assert_eq!(&buf[20..22], &[0x00, 0x01]); assert_eq!(&buf[30..32], &[0x00, 0x08]); }
1571
1572 use crate::psd::{BlendMode, Layer, Psd, ReadOptions};
1578 use crate::reader::read_psd;
1579
1580 fn read_fixture(rel: &str) -> Psd {
1581 let path = format!(
1584 "{}/../../test/ag-psd/test/read/{}/src.psd",
1585 env!("CARGO_MANIFEST_DIR"),
1586 rel
1587 );
1588 let bytes = std::fs::read(&path).unwrap_or_else(|e| panic!("read {}: {}", path, e));
1589 let opts = ReadOptions { use_image_data: Some(true), ..Default::default() };
1590 read_psd(&bytes, &opts).unwrap_or_else(|e| panic!("read_psd {}: {:?}", rel, e))
1591 }
1592
1593 fn count_layers(layers: &[Layer]) -> usize {
1594 layers
1595 .iter()
1596 .map(|l| 1 + l.children.as_ref().map_or(0, |c| count_layers(c)))
1597 .sum()
1598 }
1599
1600 fn flatten(layers: &[Layer], out: &mut Vec<(String, i64, i64, i64, i64, u8, BlendMode)>) {
1604 for l in layers {
1605 out.push((
1606 l.additional_info.name.clone().unwrap_or_default(),
1607 l.top.unwrap_or(0.0) as i64,
1608 l.left.unwrap_or(0.0) as i64,
1609 l.bottom.unwrap_or(0.0) as i64,
1610 l.right.unwrap_or(0.0) as i64,
1611 (l.opacity.unwrap_or(1.0) * 255.0).round() as u8,
1612 l.blend_mode.unwrap_or(BlendMode::Normal),
1613 ));
1614 if let Some(children) = &l.children {
1615 flatten(children, out);
1616 }
1617 }
1618 }
1619
1620 fn round_trip(psd: &Psd) -> Psd {
1621 let bytes = write_psd(psd, &WriteOptions::default());
1622 let opts = ReadOptions { use_image_data: Some(true), ..Default::default() };
1623 read_psd(&bytes, &opts).expect("re-read written psd")
1624 }
1625
1626 fn assert_structural_eq(a: &Psd, b: &Psd) {
1627 assert_eq!(a.width, b.width, "width");
1628 assert_eq!(a.height, b.height, "height");
1629 assert_eq!(a.color_mode, b.color_mode, "color_mode");
1630
1631 let ca = a.children.as_deref().unwrap_or(&[]);
1632 let cb = b.children.as_deref().unwrap_or(&[]);
1633 assert_eq!(ca.len(), cb.len(), "top-level children count");
1634 assert_eq!(count_layers(ca), count_layers(cb), "total layer count");
1635
1636 let mut fa = Vec::new();
1637 let mut fb = Vec::new();
1638 flatten(ca, &mut fa);
1639 flatten(cb, &mut fb);
1640 assert_eq!(fa, fb, "per-layer name/bounds/opacity/blendMode");
1641 }
1642
1643 fn total_pixel_bytes(layers: &[Layer]) -> usize {
1645 layers
1646 .iter()
1647 .map(|l| {
1648 let own = l.image_data.as_ref().map_or(0, |d| d.data.len());
1649 own + l.children.as_ref().map_or(0, |c| total_pixel_bytes(c))
1650 })
1651 .sum()
1652 }
1653
1654 #[test]
1655 fn round_trip_layers_fixture() {
1656 let orig = read_fixture("layers");
1657 let again = round_trip(&orig);
1658 assert_structural_eq(&orig, &again);
1659
1660 let ca = orig.children.as_deref().unwrap_or(&[]);
1662 let cb = again.children.as_deref().unwrap_or(&[]);
1663 assert!(total_pixel_bytes(ca) > 0, "fixture should have layer pixels");
1664 assert_eq!(
1665 total_pixel_bytes(ca),
1666 total_pixel_bytes(cb),
1667 "layer pixel byte totals survive round trip"
1668 );
1669 }
1670
1671 #[test]
1672 fn round_trip_groups_fixture() {
1673 let orig = read_fixture("groups");
1674 let again = round_trip(&orig);
1675 assert_structural_eq(&orig, &again);
1676
1677 let ca = orig.children.as_deref().unwrap_or(&[]);
1678 let cb = again.children.as_deref().unwrap_or(&[]);
1679 assert_eq!(
1680 total_pixel_bytes(ca),
1681 total_pixel_bytes(cb),
1682 "layer pixel byte totals survive round trip"
1683 );
1684 }
1685
1686 #[test]
1687 fn round_trip_synthetic_two_solid_layers() {
1688 fn solid(w: u32, h: u32, rgba: [u8; 4]) -> PixelData {
1690 let mut data = vec![0u8; (w * h * 4) as usize];
1691 for px in data.chunks_mut(4) {
1692 px.copy_from_slice(&rgba);
1693 }
1694 PixelData { width: w, height: h, data }
1695 }
1696
1697 let mut red = Layer::default();
1698 red.additional_info.name = Some("red".to_string());
1699 red.top = Some(0.0);
1700 red.left = Some(0.0);
1701 red.bottom = Some(4.0);
1702 red.right = Some(4.0);
1703 red.opacity = Some(1.0);
1704 red.blend_mode = Some(BlendMode::Normal);
1705 red.image_data = Some(solid(4, 4, [255, 0, 0, 255]));
1706
1707 let mut blue = Layer::default();
1708 blue.additional_info.name = Some("blue".to_string());
1709 blue.top = Some(0.0);
1710 blue.left = Some(0.0);
1711 blue.bottom = Some(4.0);
1712 blue.right = Some(4.0);
1713 blue.opacity = Some(0.5);
1714 blue.blend_mode = Some(BlendMode::Multiply);
1715 blue.image_data = Some(solid(4, 4, [0, 0, 255, 200]));
1716
1717 let psd = Psd {
1718 width: 4.0,
1719 height: 4.0,
1720 color_mode: Some(ColorMode::Rgb),
1721 bits_per_channel: Some(8.0),
1722 children: Some(vec![red, blue]),
1723 ..Default::default()
1724 };
1725
1726 let again = round_trip(&psd);
1727
1728 assert_eq!(again.width, 4.0);
1729 assert_eq!(again.height, 4.0);
1730 assert_eq!(again.color_mode, Some(ColorMode::Rgb));
1731
1732 let children = again.children.as_ref().expect("children");
1733 assert_eq!(children.len(), 2, "two layers survive");
1734
1735 let red_back = &children[0];
1736 assert_eq!(red_back.additional_info.name.as_deref(), Some("red"));
1737 assert_eq!(red_back.blend_mode, Some(BlendMode::Normal));
1738 assert_eq!(red_back.opacity.map(|o| (o * 255.0).round() as u8), Some(255));
1739 assert_eq!(red_back.bottom, Some(4.0));
1740 assert_eq!(red_back.right, Some(4.0));
1741 let rd = red_back.image_data.as_ref().expect("red image data");
1743 assert_eq!(&rd.data[0..4], &[255, 0, 0, 255]);
1744
1745 let blue_back = &children[1];
1746 assert_eq!(blue_back.additional_info.name.as_deref(), Some("blue"));
1747 assert_eq!(blue_back.blend_mode, Some(BlendMode::Multiply));
1748 assert_eq!(blue_back.opacity.map(|o| (o * 255.0).round() as u8), Some(128));
1749 let bd = blue_back.image_data.as_ref().expect("blue image data");
1750 assert_eq!(&bd.data[0..4], &[0, 0, 255, 200]);
1751 }
1752}