1use crate::reader::{
36 read_ascii_string, read_bytes, read_float32, read_float64, read_int32, read_int32_le,
37 read_signature, read_uint32, read_uint8, read_unicode_string,
38 read_unicode_string_with_length_le, PsdReader, ReadError, ReadResult,
39};
40use crate::writer::{
41 write_bytes, write_float64, write_int32, write_int32_le, write_signature,
42 write_uint32, write_uint8, write_unicode_string, write_unicode_string_with_padding,
43 write_unicode_string_without_length_le, PsdWriter,
44};
45
46pub const UNITS_MAP: &[(&str, &str)] = &[
54 ("#Ang", "Angle"),
55 ("#Rsl", "Density"),
56 ("#Rlt", "Distance"),
57 ("#Nne", "None"),
58 ("#Prc", "Percent"),
59 ("#Pxl", "Pixels"),
60 ("#Mlm", "Millimeters"),
61 ("#Pnt", "Points"),
62 ("RrPi", "Picas"),
63 ("RrIn", "Inches"),
64 ("RrCm", "Centimeters"),
65];
66
67pub fn units_name_from_code(code: &str) -> Option<&'static str> {
69 UNITS_MAP
70 .iter()
71 .find(|(c, _)| *c == code)
72 .map(|(_, name)| *name)
73}
74
75pub fn units_code_from_name(name: &str) -> Option<&'static str> {
77 UNITS_MAP
78 .iter()
79 .find(|(_, n)| *n == name)
80 .map(|(code, _)| *code)
81}
82
83#[derive(Debug, Clone, PartialEq)]
92pub struct UnitDoubleValue {
93 pub units: String,
94 pub value: f64,
95}
96
97#[derive(Debug, Clone, PartialEq, Eq)]
99pub struct LargeInteger {
100 pub low: u32,
101 pub high: u32,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq)]
106pub struct ClassStructure {
107 pub name: String,
108 pub class_id: String,
109}
110
111#[derive(Debug, Clone, PartialEq)]
113pub struct ObjectArrayItem {
114 pub type_: String,
115 pub values: Vec<f64>,
116}
117
118#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct PathValue {
121 pub sig: String,
122 pub path: String,
123}
124
125#[derive(Debug, Clone, PartialEq)]
131pub enum ReferenceItem {
132 Property(String),
134 Class(ClassStructure),
136 Enumerated(String),
138 Offset(u32),
140 Identifier(i32),
142 Index(i32),
144 Name(String),
146}
147
148#[derive(Debug, Clone, PartialEq)]
150pub enum DescriptorValue {
151 Reference(Vec<ReferenceItem>),
153 Descriptor(Descriptor),
155 List(Vec<DescriptorValue>),
157 Double(f64),
159 UnitDouble(UnitDoubleValue),
161 Text(String),
163 Enum(String),
165 Integer(i32),
167 LargeInteger(LargeInteger),
169 Boolean(bool),
171 Class(ClassStructure),
173 Alias(String),
175 RawData(Vec<u8>),
177 ObjectArray(Vec<ObjectArrayItem>),
179 Path(PathValue),
181}
182
183impl DescriptorValue {
184 pub fn os_type(&self) -> &'static str {
190 match self {
191 DescriptorValue::Reference(_) => "obj ",
192 DescriptorValue::Descriptor(_) => "Objc",
193 DescriptorValue::List(_) => "VlLs",
194 DescriptorValue::Double(_) => "doub",
195 DescriptorValue::UnitDouble(_) => "UntF",
196 DescriptorValue::Text(_) => "TEXT",
197 DescriptorValue::Enum(_) => "enum",
198 DescriptorValue::Integer(_) => "long",
199 DescriptorValue::LargeInteger(_) => "comp",
200 DescriptorValue::Boolean(_) => "bool",
201 DescriptorValue::Class(_) => "type",
202 DescriptorValue::Alias(_) => "alis",
203 DescriptorValue::RawData(_) => "tdta",
204 DescriptorValue::ObjectArray(_) => "ObAr",
205 DescriptorValue::Path(_) => "Pth ",
206 }
207 }
208}
209
210#[derive(Debug, Clone, PartialEq, Default)]
215pub struct Descriptor {
216 pub name: String,
217 pub class_id: String,
218 pub items: Vec<(String, DescriptorValue)>,
219}
220
221impl Descriptor {
222 pub fn new(name: impl Into<String>, class_id: impl Into<String>) -> Descriptor {
223 Descriptor {
224 name: name.into(),
225 class_id: class_id.into(),
226 items: Vec::new(),
227 }
228 }
229
230 pub fn set(&mut self, key: impl Into<String>, value: DescriptorValue) -> &mut Self {
232 self.items.push((key.into(), value));
233 self
234 }
235
236 pub fn get(&self, key: &str) -> Option<&DescriptorValue> {
238 self.items.iter().find(|(k, _)| k == key).map(|(_, v)| v)
239 }
240}
241
242use crate::psd::{Cmyk, Color, Frgb, Grayscale, Hsb, Lab, Rgb, Units, UnitsValue};
252
253pub fn units_to_str(u: Units) -> &'static str {
255 match u {
256 Units::Pixels => "Pixels",
257 Units::Points => "Points",
258 Units::Picas => "Picas",
259 Units::Millimeters => "Millimeters",
260 Units::Centimeters => "Centimeters",
261 Units::Inches => "Inches",
262 Units::None => "None",
263 Units::Density => "Density",
264 }
265}
266
267pub fn units_from_str(s: &str) -> ReadResult<Units> {
269 Ok(match s {
270 "Pixels" => Units::Pixels,
271 "Points" => Units::Points,
272 "Picas" => Units::Picas,
273 "Millimeters" => Units::Millimeters,
274 "Centimeters" => Units::Centimeters,
275 "Inches" => Units::Inches,
276 "None" => Units::None,
277 "Density" => Units::Density,
278 other => {
279 return Err(ReadError::StrictViolation(format!("Invalid units: {other}")));
280 }
281 })
282}
283
284pub fn units_angle(value: f64) -> DescriptorValue {
286 DescriptorValue::UnitDouble(UnitDoubleValue {
287 units: "Angle".to_string(),
288 value,
289 })
290}
291
292pub fn units_value(x: Option<&UnitsValue>) -> DescriptorValue {
294 match x {
295 None => DescriptorValue::UnitDouble(UnitDoubleValue {
296 units: "Pixels".to_string(),
297 value: 0.0,
298 }),
299 Some(v) => DescriptorValue::UnitDouble(UnitDoubleValue {
300 units: units_to_str(v.units).to_string(),
301 value: v.value,
302 }),
303 }
304}
305
306pub fn parse_units(v: &DescriptorValue) -> ReadResult<UnitsValue> {
308 match v {
309 DescriptorValue::UnitDouble(u) => Ok(UnitsValue {
310 units: units_from_str(&u.units)?,
311 value: u.value,
312 }),
313 other => Err(ReadError::StrictViolation(format!(
314 "Invalid units value: {other:?}"
315 ))),
316 }
317}
318
319pub fn parse_units_or_number(v: &DescriptorValue) -> ReadResult<UnitsValue> {
321 match v {
322 DescriptorValue::UnitDouble(u) => Ok(UnitsValue {
323 units: units_from_str(&u.units)?,
324 value: u.value,
325 }),
326 DescriptorValue::Double(d) => Ok(UnitsValue {
327 units: Units::Pixels,
328 value: *d,
329 }),
330 DescriptorValue::Integer(i) => Ok(UnitsValue {
331 units: Units::Pixels,
332 value: *i as f64,
333 }),
334 other => Err(ReadError::StrictViolation(format!(
335 "Invalid units-or-number value: {other:?}"
336 ))),
337 }
338}
339
340pub fn parse_angle(v: &DescriptorValue) -> ReadResult<f64> {
342 match v {
343 DescriptorValue::UnitDouble(u) if u.units == "Angle" => Ok(u.value),
344 DescriptorValue::UnitDouble(u) => {
345 Err(ReadError::StrictViolation(format!("Invalid units: {}", u.units)))
346 }
347 _ => Ok(0.0),
348 }
349}
350
351pub fn parse_percent(v: &DescriptorValue) -> ReadResult<f64> {
353 match v {
354 DescriptorValue::UnitDouble(u) if u.units == "Percent" => Ok(u.value / 100.0),
355 DescriptorValue::UnitDouble(u) => {
356 Err(ReadError::StrictViolation(format!("Invalid units: {}", u.units)))
357 }
358 _ => Ok(1.0),
359 }
360}
361
362pub fn parse_percent_or_angle(v: &DescriptorValue) -> ReadResult<f64> {
364 match v {
365 DescriptorValue::UnitDouble(u) if u.units == "Percent" => Ok(u.value / 100.0),
366 DescriptorValue::UnitDouble(u) if u.units == "Angle" => Ok(u.value / 360.0),
367 DescriptorValue::UnitDouble(u) => {
368 Err(ReadError::StrictViolation(format!("Invalid units: {}", u.units)))
369 }
370 _ => Ok(1.0),
371 }
372}
373
374fn color_double(d: &Descriptor, key: &str) -> f64 {
376 match d.get(key) {
377 Some(DescriptorValue::Double(v)) => *v,
378 Some(DescriptorValue::Integer(v)) => *v as f64,
379 _ => 0.0,
380 }
381}
382
383pub fn parse_color(d: &Descriptor) -> ReadResult<Color> {
385 if let Some(h) = d.get("H ") {
386 let h = parse_percent_or_angle(h)?;
387 Ok(Color::Hsb(Hsb {
388 h,
389 s: color_double(d, "Strt"),
390 b: color_double(d, "Brgh"),
391 }))
392 } else if d.get("Rd ").is_some() {
393 Ok(Color::Rgb(Rgb {
394 r: color_double(d, "Rd "),
395 g: color_double(d, "Grn "),
396 b: color_double(d, "Bl "),
397 }))
398 } else if d.get("Cyn ").is_some() {
399 Ok(Color::Cmyk(Cmyk {
400 c: color_double(d, "Cyn "),
401 m: color_double(d, "Mgnt"),
402 y: color_double(d, "Ylw "),
403 k: color_double(d, "Blck"),
404 }))
405 } else if d.get("Gry ").is_some() {
406 Ok(Color::Grayscale(Grayscale {
407 k: color_double(d, "Gry "),
408 }))
409 } else if d.get("Lmnc").is_some() {
410 Ok(Color::Lab(Lab {
411 l: color_double(d, "Lmnc"),
412 a: color_double(d, "A "),
413 b: color_double(d, "B "),
414 }))
415 } else if d.get("redFloat").is_some() {
416 Ok(Color::Frgb(Frgb {
417 fr: color_double(d, "redFloat"),
418 fg: color_double(d, "greenFloat"),
419 fb: color_double(d, "blueFloat"),
420 }))
421 } else {
422 Err(ReadError::StrictViolation(
423 "Unsupported color descriptor".to_string(),
424 ))
425 }
426}
427
428pub fn serialize_color(color: Option<&Color>) -> Descriptor {
430 let mut d;
431 match color {
432 None => {
433 d = Descriptor::new("", "RGBC");
434 d.set("Rd ", DescriptorValue::Double(0.0));
435 d.set("Grn ", DescriptorValue::Double(0.0));
436 d.set("Bl ", DescriptorValue::Double(0.0));
437 }
438 Some(Color::Rgb(c)) => {
439 d = Descriptor::new("", "RGBC");
440 d.set("Rd ", DescriptorValue::Double(c.r));
441 d.set("Grn ", DescriptorValue::Double(c.g));
442 d.set("Bl ", DescriptorValue::Double(c.b));
443 }
444 Some(Color::Rgba(c)) => {
445 d = Descriptor::new("", "RGBC");
447 d.set("Rd ", DescriptorValue::Double(c.r));
448 d.set("Grn ", DescriptorValue::Double(c.g));
449 d.set("Bl ", DescriptorValue::Double(c.b));
450 }
451 Some(Color::Frgb(c)) => {
452 d = Descriptor::new("", "RGBC");
453 d.set("redFloat", DescriptorValue::Double(c.fr));
454 d.set("greenFloat", DescriptorValue::Double(c.fg));
455 d.set("blueFloat", DescriptorValue::Double(c.fb));
456 }
457 Some(Color::Hsb(c)) => {
458 d = Descriptor::new("", "HSBC");
459 d.set("H ", units_angle(c.h * 360.0));
460 d.set("Strt", DescriptorValue::Double(c.s));
461 d.set("Brgh", DescriptorValue::Double(c.b));
462 }
463 Some(Color::Cmyk(c)) => {
464 d = Descriptor::new("", "CMYC");
465 d.set("Cyn ", DescriptorValue::Double(c.c));
466 d.set("Mgnt", DescriptorValue::Double(c.m));
467 d.set("Ylw ", DescriptorValue::Double(c.y));
468 d.set("Blck", DescriptorValue::Double(c.k));
469 }
470 Some(Color::Lab(c)) => {
471 d = Descriptor::new("", "LABC");
472 d.set("Lmnc", DescriptorValue::Double(c.l));
473 d.set("A ", DescriptorValue::Double(c.a));
474 d.set("B ", DescriptorValue::Double(c.b));
475 }
476 Some(Color::Grayscale(c)) => {
477 d = Descriptor::new("", "GRYC");
478 d.set("Gry ", DescriptorValue::Double(c.k));
479 }
480 }
481 d
482}
483
484pub fn read_ascii_string_or_class_id(reader: &mut PsdReader) -> ReadResult<String> {
491 let length = read_int32(reader)?;
492 let len = if length == 0 { 4 } else { length as usize };
493 read_ascii_string(reader, len)
494}
495
496pub fn write_ascii_string_or_class_id(writer: &mut PsdWriter, value: &str) {
502 let char_count = value.chars().count();
503 if char_count == 4 && value != "warp" && value != "time" && value != "hold" && value != "list"
504 {
505 write_int32(writer, 0);
507 write_signature(writer, value);
508 } else {
509 write_int32(writer, char_count as i32);
511 for ch in value.chars() {
512 write_uint8(writer, (ch as u32) as u8);
513 }
514 }
515}
516
517pub fn read_class_structure(reader: &mut PsdReader) -> ReadResult<ClassStructure> {
523 let name = read_unicode_string(reader)?;
524 let class_id = read_ascii_string_or_class_id(reader)?;
525 Ok(ClassStructure { name, class_id })
526}
527
528pub fn write_class_structure(writer: &mut PsdWriter, name: &str, class_id: &str) {
530 write_unicode_string(writer, name);
531 write_ascii_string_or_class_id(writer, class_id);
532}
533
534pub fn read_reference_structure(reader: &mut PsdReader) -> ReadResult<Vec<ReferenceItem>> {
540 let items_count = read_int32(reader)?;
541 let mut items = Vec::new();
542
543 for _ in 0..items_count {
544 let type_ = read_signature(reader)?;
545
546 match type_.as_str() {
547 "prop" => {
548 read_class_structure(reader)?;
550 let key_id = read_ascii_string_or_class_id(reader)?;
551 items.push(ReferenceItem::Property(key_id));
552 }
553 "Clss" => {
554 items.push(ReferenceItem::Class(read_class_structure(reader)?));
556 }
557 "Enmr" => {
558 read_class_structure(reader)?;
560 let type_id = read_ascii_string_or_class_id(reader)?;
561 let value = read_ascii_string_or_class_id(reader)?;
562 items.push(ReferenceItem::Enumerated(format!("{}.{}", type_id, value)));
563 }
564 "rele" => {
565 read_class_structure(reader)?;
567 items.push(ReferenceItem::Offset(read_uint32(reader)?));
568 }
569 "Idnt" => {
570 items.push(ReferenceItem::Identifier(read_int32(reader)?));
572 }
573 "indx" => {
574 items.push(ReferenceItem::Index(read_int32(reader)?));
576 }
577 "name" => {
578 read_class_structure(reader)?;
580 items.push(ReferenceItem::Name(read_unicode_string(reader)?));
581 }
582 other => {
583 return Err(ReadError::StrictViolation(format!(
584 "Invalid descriptor reference type: {}",
585 other
586 )));
587 }
588 }
589 }
590
591 Ok(items)
592}
593
594pub fn write_reference_structure(writer: &mut PsdWriter, items: &[ReferenceItem]) {
601 write_int32(writer, items.len() as i32);
602
603 for item in items {
604 match item {
605 ReferenceItem::Enumerated(value) => {
606 write_signature(writer, "Enmr");
607 let mut parts = value.splitn(2, '.');
608 let type_id = parts.next().unwrap_or("");
609 let enum_value = parts.next().unwrap_or("");
610 write_class_structure(writer, "\0", type_id);
611 write_ascii_string_or_class_id(writer, type_id);
612 write_ascii_string_or_class_id(writer, enum_value);
613 }
614 ReferenceItem::Name(value) => {
615 write_signature(writer, "name");
616 write_class_structure(writer, "\0", "Lyr ");
617 write_unicode_string(writer, &format!("{}\0", value));
618 }
619 other => {
620 panic!("Invalid descriptor reference type for writing: {:?}", other);
621 }
622 }
623 }
624}
625
626pub fn read_os_type(reader: &mut PsdReader, type_: &str) -> ReadResult<DescriptorValue> {
632 match type_ {
633 "obj " => Ok(DescriptorValue::Reference(read_reference_structure(reader)?)),
634 "Objc" | "GlbO" => Ok(DescriptorValue::Descriptor(read_descriptor_structure(
635 reader,
636 )?)),
637 "VlLs" => {
638 let length = read_int32(reader)?;
639 let mut items = Vec::new();
640 for _ in 0..length {
641 let item_type = read_signature(reader)?;
642 items.push(read_os_type(reader, &item_type)?);
643 }
644 Ok(DescriptorValue::List(items))
645 }
646 "doub" => Ok(DescriptorValue::Double(read_float64(reader)?)),
647 "UntF" => {
648 let units_code = read_signature(reader)?;
649 let value = read_float64(reader)?;
650 let units = units_name_from_code(&units_code)
651 .ok_or_else(|| ReadError::StrictViolation(format!("Invalid units: {}", units_code)))?;
652 Ok(DescriptorValue::UnitDouble(UnitDoubleValue {
653 units: units.to_string(),
654 value,
655 }))
656 }
657 "UnFl" => {
658 let units_code = read_signature(reader)?;
659 let value = read_float32(reader)? as f64;
660 let units = units_name_from_code(&units_code)
661 .ok_or_else(|| ReadError::StrictViolation(format!("Invalid units: {}", units_code)))?;
662 Ok(DescriptorValue::UnitDouble(UnitDoubleValue {
663 units: units.to_string(),
664 value,
665 }))
666 }
667 "TEXT" => Ok(DescriptorValue::Text(read_unicode_string(reader)?)),
668 "enum" => {
669 let enum_type = read_ascii_string_or_class_id(reader)?;
670 let value = read_ascii_string_or_class_id(reader)?;
671 Ok(DescriptorValue::Enum(format!("{}.{}", enum_type, value)))
672 }
673 "long" => Ok(DescriptorValue::Integer(read_int32(reader)?)),
674 "comp" => {
675 let low = read_uint32(reader)?;
676 let high = read_uint32(reader)?;
677 Ok(DescriptorValue::LargeInteger(LargeInteger { low, high }))
678 }
679 "bool" => Ok(DescriptorValue::Boolean(read_uint8(reader)? != 0)),
680 "type" | "GlbC" => Ok(DescriptorValue::Class(read_class_structure(reader)?)),
681 "alis" => {
682 let length = read_int32(reader)?;
683 Ok(DescriptorValue::Alias(read_ascii_string(
684 reader,
685 length as usize,
686 )?))
687 }
688 "tdta" => {
689 let length = read_int32(reader)?;
690 Ok(DescriptorValue::RawData(read_bytes(reader, length as usize)?))
691 }
692 "ObAr" => {
693 let _version = read_int32(reader)?; let _name = read_unicode_string(reader)?; let _type = read_ascii_string_or_class_id(reader)?; let length = read_int32(reader)?;
697 let mut items = Vec::new();
698
699 for _ in 0..length {
700 let type1 = read_ascii_string_or_class_id(reader)?; let _unfl = read_signature(reader)?; let _units = read_signature(reader)?; let values_count = read_int32(reader)?;
704 let mut values = Vec::new();
705 for _ in 0..values_count {
706 values.push(read_float64(reader)?);
707 }
708 items.push(ObjectArrayItem {
709 type_: type1,
710 values,
711 });
712 }
713
714 Ok(DescriptorValue::ObjectArray(items))
715 }
716 "Pth " => {
717 let _length = read_int32(reader)?; let sig = read_signature(reader)?;
719 let _path_size = read_int32_le(reader)?; let chars_count = read_int32_le(reader)?;
721 let path = read_unicode_string_with_length_le(reader, chars_count as usize)?;
722 Ok(DescriptorValue::Path(PathValue { sig, path }))
723 }
724 other => Err(ReadError::StrictViolation(format!(
725 "Invalid TySh descriptor OSType: {} at {:x}",
726 other, reader.offset
727 ))),
728 }
729}
730
731fn ob_ar_type_for_key(key: &str) -> Option<&'static str> {
733 match key {
734 "meshPoints" => Some("rationalPoint"),
735 "quiltSliceX" => Some("UntF"),
736 "quiltSliceY" => Some("UntF"),
737 _ => None,
738 }
739}
740
741pub fn write_os_type(writer: &mut PsdWriter, value: &DescriptorValue, key: &str) {
746 match value {
747 DescriptorValue::Reference(items) => {
748 write_reference_structure(writer, items);
749 }
750 DescriptorValue::Descriptor(desc) => {
751 write_descriptor_structure(writer, desc);
752 }
753 DescriptorValue::List(items) => {
754 write_int32(writer, items.len() as i32);
755 for item in items {
756 write_signature(writer, item.os_type());
757 write_os_type(writer, item, &format!("{}[]", key));
758 }
759 }
760 DescriptorValue::Double(v) => {
761 write_float64(writer, *v);
762 }
763 DescriptorValue::UnitDouble(u) => {
764 let code = units_code_from_name(&u.units)
765 .unwrap_or_else(|| panic!("Invalid units: {} in {}", u.units, key));
766 write_signature(writer, code);
767 write_float64(writer, u.value);
768 }
769 DescriptorValue::Text(v) => {
770 write_unicode_string_with_padding(writer, v);
771 }
772 DescriptorValue::Enum(v) => {
773 let mut parts = v.splitn(2, '.');
774 let type_ = parts.next().unwrap_or("");
775 let val = parts.next().unwrap_or("");
776 write_ascii_string_or_class_id(writer, type_);
777 write_ascii_string_or_class_id(writer, val);
778 }
779 DescriptorValue::Integer(v) => {
780 write_int32(writer, *v);
781 }
782 DescriptorValue::LargeInteger(li) => {
783 write_uint32(writer, li.low);
786 write_uint32(writer, li.high);
787 }
788 DescriptorValue::Boolean(v) => {
789 write_uint8(writer, if *v { 1 } else { 0 });
790 }
791 DescriptorValue::Class(c) => {
792 write_class_structure(writer, &c.name, &c.class_id);
795 }
796 DescriptorValue::Alias(s) => {
797 write_int32(writer, s.chars().count() as i32);
799 for ch in s.chars() {
800 write_uint8(writer, (ch as u32) as u8);
801 }
802 }
803 DescriptorValue::RawData(bytes) => {
804 write_int32(writer, bytes.len() as i32);
805 write_bytes(writer, Some(bytes));
806 }
807 DescriptorValue::ObjectArray(items) => {
808 write_int32(writer, 16); write_unicode_string_with_padding(writer, ""); let type_ = ob_ar_type_for_key(key)
811 .unwrap_or_else(|| panic!("Not implemented ObArType for: {}", key));
812 write_ascii_string_or_class_id(writer, type_);
813 write_int32(writer, items.len() as i32);
814
815 for item in items {
816 write_ascii_string_or_class_id(writer, &item.type_); write_signature(writer, "UnFl");
818 write_signature(writer, "#Pxl");
819 write_int32(writer, item.values.len() as i32);
820 for v in &item.values {
821 write_float64(writer, *v);
822 }
823 }
824 }
825 DescriptorValue::Path(p) => {
826 let length = 4 + 4 + 4 + p.path.chars().count() as i32 * 2;
827 write_int32(writer, length);
828 write_signature(writer, &p.sig);
829 write_int32_le(writer, length);
830 write_int32_le(writer, p.path.chars().count() as i32);
831 write_unicode_string_without_length_le(writer, &p.path);
832 }
833 }
834}
835
836pub fn read_descriptor_structure(reader: &mut PsdReader) -> ReadResult<Descriptor> {
845 let class = read_class_structure(reader)?;
846 let mut desc = Descriptor {
847 name: class.name,
848 class_id: class.class_id,
849 items: Vec::new(),
850 };
851
852 let items_count = read_uint32(reader)?;
853 for _ in 0..items_count {
854 let key = read_ascii_string_or_class_id(reader)?;
855 let type_ = read_signature(reader)?;
856 let data = read_os_type(reader, &type_)?;
857 desc.items.push((key, data));
858 }
859
860 Ok(desc)
861}
862
863pub fn write_descriptor_structure(writer: &mut PsdWriter, desc: &Descriptor) {
868 write_unicode_string_with_padding(writer, &desc.name);
869 write_ascii_string_or_class_id(writer, &desc.class_id);
870
871 write_uint32(writer, desc.items.len() as u32);
872
873 for (key, value) in &desc.items {
874 write_ascii_string_or_class_id(writer, key);
875 write_signature(writer, value.os_type());
876 write_os_type(writer, value, key);
877 }
878}
879
880pub fn read_descriptor(reader: &mut PsdReader) -> ReadResult<Descriptor> {
887 read_descriptor_structure(reader)
888}
889
890pub fn write_descriptor(writer: &mut PsdWriter, desc: &Descriptor) {
892 write_descriptor_structure(writer, desc);
893}
894
895pub fn read_version_and_descriptor(reader: &mut PsdReader) -> ReadResult<Descriptor> {
903 let version = read_uint32(reader)?;
904 if version != 16 {
905 return Err(ReadError::StrictViolation(format!(
906 "Invalid descriptor version: {}",
907 version
908 )));
909 }
910 read_descriptor_structure(reader)
911}
912
913pub fn write_version_and_descriptor(writer: &mut PsdWriter, desc: &Descriptor) {
915 write_uint32(writer, 16); write_descriptor_structure(writer, desc);
917}
918
919#[cfg(test)]
920mod tests {
921 use super::*;
922 use crate::writer::{create_writer, get_writer_buffer};
923
924 fn build_sample() -> Descriptor {
925 let mut nested = Descriptor::new("", "Pnt ");
926 nested.set("Hrzn", DescriptorValue::Double(12.5));
927 nested.set("Vrtc", DescriptorValue::Double(-7.0));
928
929 let list = DescriptorValue::List(vec![
930 DescriptorValue::Integer(1),
931 DescriptorValue::Integer(2),
932 DescriptorValue::Integer(3),
933 ]);
934
935 let mut desc = Descriptor::new("layer name", "TxLr");
936 desc.set("Txt ", DescriptorValue::Text("Héllo 𝕎orld".to_string()));
938 desc.set("dbl ", DescriptorValue::Double(3.5));
939 desc.set(
940 "Opct",
941 DescriptorValue::UnitDouble(UnitDoubleValue {
942 units: "Percent".to_string(),
943 value: 75.0,
944 }),
945 );
946 desc.set("Ornt", DescriptorValue::Enum("Ornt.Hrzn".to_string()));
947 desc.set("long", DescriptorValue::Integer(-42));
948 desc.set("bool", DescriptorValue::Boolean(true));
949 desc.set("Objc", DescriptorValue::Descriptor(nested));
950 desc.set("VlLs", list);
951 desc
952 }
953
954 #[test]
955 fn round_trip_descriptor() {
956 let desc = build_sample();
957
958 let mut writer = create_writer(256);
959 write_descriptor(&mut writer, &desc);
960 let bytes = get_writer_buffer(&writer);
961
962 let mut reader = PsdReader::new(&bytes, None, None);
963 let read = read_descriptor(&mut reader).expect("read");
964
965 assert_eq!(read.name, "layer name");
966 assert_eq!(read.class_id, "TxLr");
967 assert_eq!(read, desc);
968 assert_eq!(reader.offset, bytes.len());
970 }
971
972 #[test]
973 fn round_trip_version_and_descriptor() {
974 let desc = build_sample();
975
976 let mut writer = create_writer(256);
977 write_version_and_descriptor(&mut writer, &desc);
978 let bytes = get_writer_buffer(&writer);
979
980 let mut reader = PsdReader::new(&bytes, None, None);
981 let read = read_version_and_descriptor(&mut reader).expect("read");
982 assert_eq!(read, desc);
983 }
984
985 #[test]
986 fn field_order_preserved() {
987 let desc = build_sample();
988 let expected_keys: Vec<&str> = desc.items.iter().map(|(k, _)| k.as_str()).collect();
989
990 let mut writer = create_writer(256);
991 write_descriptor(&mut writer, &desc);
992 let bytes = get_writer_buffer(&writer);
993
994 let mut reader = PsdReader::new(&bytes, None, None);
995 let read = read_descriptor(&mut reader).expect("read");
996 let read_keys: Vec<&str> = read.items.iter().map(|(k, _)| k.as_str()).collect();
997
998 assert_eq!(read_keys, expected_keys);
999 }
1000
1001 #[test]
1002 fn unit_float_round_trip() {
1003 let value = UnitDoubleValue {
1005 units: "Pixels".to_string(),
1006 value: 10.0,
1007 };
1008 let mut writer = create_writer(64);
1009 write_signature(&mut writer, "#Pxl");
1011 write_float64(&mut writer, value.value);
1012 let bytes = get_writer_buffer(&writer);
1013 let mut reader = PsdReader::new(&bytes, None, None);
1014 let v = read_os_type(&mut reader, "UntF").expect("read untf");
1015 assert_eq!(v, DescriptorValue::UnitDouble(value));
1016 }
1017
1018 #[test]
1019 fn ascii_string_or_class_id_encoding() {
1020 let mut w1 = create_writer(32);
1022 write_ascii_string_or_class_id(&mut w1, "TxLr");
1023 let b1 = get_writer_buffer(&w1);
1024 assert_eq!(&b1[0..4], &[0, 0, 0, 0]);
1025 assert_eq!(&b1[4..8], b"TxLr");
1026
1027 let mut w2 = create_writer(32);
1029 write_ascii_string_or_class_id(&mut w2, "list");
1030 let b2 = get_writer_buffer(&w2);
1031 assert_eq!(&b2[0..4], &[0, 0, 0, 4]);
1032 assert_eq!(&b2[4..8], b"list");
1033
1034 for s in ["TxLr", "list", "longerKey"] {
1036 let mut w = create_writer(32);
1037 write_ascii_string_or_class_id(&mut w, s);
1038 let b = get_writer_buffer(&w);
1039 let mut r = PsdReader::new(&b, None, None);
1040 assert_eq!(read_ascii_string_or_class_id(&mut r).unwrap(), s);
1041 }
1042 }
1043
1044 #[test]
1045 fn raw_data_and_large_integer_round_trip() {
1046 let mut desc = Descriptor::new("", "test");
1047 desc.set("data", DescriptorValue::RawData(vec![1, 2, 3, 4, 5]));
1048 desc.set(
1049 "big ",
1050 DescriptorValue::LargeInteger(LargeInteger {
1051 low: 0xDEAD_BEEF,
1052 high: 0x1234_5678,
1053 }),
1054 );
1055
1056 let mut writer = create_writer(64);
1057 write_descriptor(&mut writer, &desc);
1058 let bytes = get_writer_buffer(&writer);
1059 let mut reader = PsdReader::new(&bytes, None, None);
1060 let read = read_descriptor(&mut reader).expect("read");
1061 assert_eq!(read, desc);
1062 }
1063
1064 #[test]
1065 fn units_table_complete() {
1066 assert_eq!(UNITS_MAP.len(), 11);
1068 for (code, name) in UNITS_MAP {
1069 assert_eq!(units_name_from_code(code), Some(*name));
1070 assert_eq!(units_code_from_name(name), Some(*code));
1071 }
1072 }
1073}