1use crate::content::{OPERANDS_THRESHOLD, Operation, OperatorTrait, Stack};
4use crate::object::Object;
5use crate::object::array::Array;
6use crate::object::name::Name;
7use crate::object::number::Number;
8use crate::object::stream::Stream;
9use crate::object::string;
10use smallvec::{SmallVec, smallvec};
11
12use crate::content::macros::{op_all, op_impl, op0, op1, op2, op3, op4, op6};
13use log::warn;
14
15include!("ops_generated.rs");
16
17#[derive(Debug, Clone, PartialEq)]
20pub struct StrokeColorNamed<'a>(
21 pub SmallVec<[Number; OPERANDS_THRESHOLD]>,
22 pub Option<Name<'a>>,
23);
24
25fn scn_fn<'a>(
26 stack: &Stack<'a>,
27) -> Option<(SmallVec<[Number; OPERANDS_THRESHOLD]>, Option<Name<'a>>)> {
28 let mut nums = smallvec![];
29 let mut name = None;
30
31 for o in &stack.0 {
32 match o {
33 Object::Number(n) => nums.push(*n),
34 Object::Name(n) => name = Some(n.clone()),
35 _ => {
36 warn!("encountered unknown object {:?} when parsing scn/SCN", o);
37
38 return None;
39 }
40 }
41 }
42
43 Some((nums, name))
44}
45
46op_impl!(
47 StrokeColorNamed<'a>,
48 "SCN",
49 u8::MAX as usize,
50 |stack: &Stack<'a>| {
51 let res = scn_fn(stack);
52 res.map(|r| StrokeColorNamed(r.0, r.1))
53 }
54);
55
56#[derive(Debug, PartialEq, Clone)]
57pub struct NonStrokeColorNamed<'a>(
58 pub SmallVec<[Number; OPERANDS_THRESHOLD]>,
59 pub Option<Name<'a>>,
60);
61
62op_impl!(
63 NonStrokeColorNamed<'a>,
64 "scn",
65 u8::MAX as usize,
66 |stack: &Stack<'a>| {
67 let res = scn_fn(stack);
68 res.map(|r| NonStrokeColorNamed(r.0, r.1))
69 }
70);
71
72#[cfg(test)]
73mod tests {
74 use crate::content::ops::{
75 BeginMarkedContentWithProperties, ClosePath, EndMarkedContent, FillPathNonZero, LineTo,
76 MarkedContentPointWithProperties, MoveTo, NonStrokeColorDeviceRgb, NonStrokeColorNamed,
77 SetGraphicsState, StrokeColorNamed, Transform, TypedOperation,
78 };
79 use crate::content::{TypedIter, UntypedIter};
80 use crate::object::Object;
81 use crate::object::dict::Dict;
82 use crate::object::name::Name;
83 use crate::object::number::Number;
84 use crate::reader::Readable;
85 use smallvec::smallvec;
86
87 fn n(num: i32) -> Number {
88 Number::from_i32(num)
89 }
90
91 fn f(num: f32) -> Number {
92 Number::from_f32(num)
93 }
94
95 #[test]
96 fn basic_ops_1() {
97 let input = b"
981 0 0 -1 0 200 cm
99/g0 gs
1001 0 0 rg
101";
102
103 let expected = vec![
104 TypedOperation::Transform(Transform(n(1), n(0), n(0), n(-1), n(0), n(200))),
105 TypedOperation::SetGraphicsState(SetGraphicsState(Name::new(b"g0"))),
106 TypedOperation::NonStrokeColorDeviceRgb(NonStrokeColorDeviceRgb(n(1), n(0), n(0))),
107 ];
108
109 let elements = TypedIter::new(UntypedIter::new(input))
110 .into_iter()
111 .collect::<Vec<_>>();
112 assert_eq!(elements, expected,)
113 }
114
115 #[test]
116 fn basic_ops_2() {
117 let input = b"
11820 20 m
119180 20 l
120180.1 180.1 l
12120 180 l
122h
123f
124";
125
126 let expected = vec![
127 TypedOperation::MoveTo(MoveTo(n(20), n(20))),
128 TypedOperation::LineTo(LineTo(n(180), n(20))),
129 TypedOperation::LineTo(LineTo(f(180.1), f(180.1))),
130 TypedOperation::LineTo(LineTo(n(20), n(180))),
131 TypedOperation::ClosePath(ClosePath),
132 TypedOperation::FillPathNonZero(FillPathNonZero),
133 ];
134
135 let elements = TypedIter::new(UntypedIter::new(input))
136 .into_iter()
137 .collect::<Vec<_>>();
138 assert_eq!(elements, expected,)
139 }
140
141 #[test]
142 fn scn() {
143 let input = b"
1440.0 scn
1450.1 0.2 0.3 /DeviceRgb SCN
146";
147
148 let expected = vec![
149 TypedOperation::NonStrokeColorNamed(NonStrokeColorNamed(
150 smallvec![Number::from_i32(0)],
151 None,
152 )),
153 TypedOperation::StrokeColorNamed(StrokeColorNamed(
154 smallvec![
155 Number::from_f32(0.1),
156 Number::from_f32(0.2),
157 Number::from_f32(0.3)
158 ],
159 Some(Name::new(b"DeviceRgb")),
160 )),
161 ];
162
163 let elements = TypedIter::new(UntypedIter::new(input))
164 .into_iter()
165 .collect::<Vec<_>>();
166
167 assert_eq!(elements, expected);
168 }
169
170 #[test]
171 fn dp() {
172 let input = b"/Attribute<</ShowCenterPoint false >> DP";
173
174 let expected = vec![TypedOperation::MarkedContentPointWithProperties(
175 MarkedContentPointWithProperties(
176 Name::new(b"Attribute"),
177 Object::Dict(Dict::from_bytes(b"<</ShowCenterPoint false >>").unwrap()),
178 ),
179 )];
180
181 let elements = TypedIter::new(UntypedIter::new(input))
182 .into_iter()
183 .collect::<Vec<_>>();
184
185 assert_eq!(elements, expected);
186 }
187
188 #[test]
189 fn bdc_with_dict() {
190 let input = b"/Span << /MCID 0 /Alt (Alt)>> BDC EMC";
191
192 let expected = vec![
193 TypedOperation::BeginMarkedContentWithProperties(BeginMarkedContentWithProperties(
194 Name::new(b"Span"),
195 Object::Dict(Dict::from_bytes(b"<< /MCID 0 /Alt (Alt)>>").unwrap()),
196 )),
197 TypedOperation::EndMarkedContent(EndMarkedContent),
198 ];
199
200 let elements = TypedIter::new(UntypedIter::new(input))
201 .into_iter()
202 .collect::<Vec<_>>();
203
204 assert_eq!(elements, expected);
205 }
206
207 #[test]
208 fn bdc_with_name() {
209 let input = b"/Span /Name BDC EMC";
210
211 let expected = vec![
212 TypedOperation::BeginMarkedContentWithProperties(BeginMarkedContentWithProperties(
213 Name::new(b"Span"),
214 Object::Name(Name::new(b"Name")),
215 )),
216 TypedOperation::EndMarkedContent(EndMarkedContent),
217 ];
218
219 let elements = TypedIter::new(UntypedIter::new(input))
220 .into_iter()
221 .collect::<Vec<_>>();
222
223 assert_eq!(elements, expected);
224 }
225}