pdfrb 0.6.0 → 0.7.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +144 -0
  3. data/RELEASE.md +52 -33
  4. data/data/pdfrb/afm/Courier-Bold.afm +342 -342
  5. data/data/pdfrb/afm/Courier-BoldOblique.afm +342 -342
  6. data/data/pdfrb/afm/Courier-Oblique.afm +342 -342
  7. data/data/pdfrb/afm/Courier.afm +342 -342
  8. data/data/pdfrb/afm/Helvetica-Bold.afm +2827 -2827
  9. data/data/pdfrb/afm/Helvetica-BoldOblique.afm +2827 -2827
  10. data/data/pdfrb/afm/Helvetica-Oblique.afm +3051 -3051
  11. data/data/pdfrb/afm/Helvetica.afm +3051 -3051
  12. data/data/pdfrb/afm/Symbol.afm +213 -213
  13. data/data/pdfrb/afm/Times-Bold.afm +2588 -2588
  14. data/data/pdfrb/afm/Times-BoldItalic.afm +2384 -2384
  15. data/data/pdfrb/afm/Times-Italic.afm +2667 -2667
  16. data/data/pdfrb/afm/Times-Roman.afm +2419 -2419
  17. data/data/pdfrb/afm/ZapfDingbats.afm +225 -225
  18. data/data/pdfrb/layout/hyphenation_en.txt +408 -0
  19. data/lib/pdfrb/color/default_profile.rb +213 -0
  20. data/lib/pdfrb/color/icc_validator.rb +69 -0
  21. data/lib/pdfrb/color.rb +2 -0
  22. data/lib/pdfrb/conformance/ltv.rb +112 -0
  23. data/lib/pdfrb/conformance/pades.rb +198 -0
  24. data/lib/pdfrb/conformance/pdf_2_af.rb +185 -0
  25. data/lib/pdfrb/conformance/pdf_a.rb +123 -0
  26. data/lib/pdfrb/conformance/pdf_a4_deep.rb +94 -0
  27. data/lib/pdfrb/conformance/pdf_ua2_deep.rb +93 -0
  28. data/lib/pdfrb/conformance/pdf_ua_tagging_deep.rb +125 -0
  29. data/lib/pdfrb/conformance/pdf_vt.rb +128 -0
  30. data/lib/pdfrb/conformance/pdf_x.rb +66 -1
  31. data/lib/pdfrb/conformance/tagged_pdf.rb +182 -0
  32. data/lib/pdfrb/conformance.rb +8 -0
  33. data/lib/pdfrb/content/canvas.rb +137 -0
  34. data/lib/pdfrb/content/operators/inline_image.rb +53 -0
  35. data/lib/pdfrb/content/operators.rb +1 -0
  36. data/lib/pdfrb/content/parser.rb +82 -0
  37. data/lib/pdfrb/digital_signature/timestamp_client.rb +86 -0
  38. data/lib/pdfrb/digital_signature.rb +1 -0
  39. data/lib/pdfrb/document.rb +29 -0
  40. data/lib/pdfrb/encryption/public_key_security_handler.rb +146 -0
  41. data/lib/pdfrb/encryption/standard_security_handler.rb +98 -3
  42. data/lib/pdfrb/encryption/v5_writer.rb +108 -0
  43. data/lib/pdfrb/encryption.rb +3 -0
  44. data/lib/pdfrb/font_loader/type3.rb +65 -0
  45. data/lib/pdfrb/font_loader.rb +1 -0
  46. data/lib/pdfrb/image_loader/gif.rb +246 -0
  47. data/lib/pdfrb/image_loader/png.rb +76 -19
  48. data/lib/pdfrb/image_loader/tiff.rb +257 -0
  49. data/lib/pdfrb/image_loader.rb +2 -0
  50. data/lib/pdfrb/layout/font_fallback.rb +203 -0
  51. data/lib/pdfrb/layout/hyphenation.rb +120 -0
  52. data/lib/pdfrb/layout/justification_kashidas.rb +72 -0
  53. data/lib/pdfrb/layout/multi_cell_text_layout.rb +65 -0
  54. data/lib/pdfrb/layout/multi_page_table_box.rb +155 -0
  55. data/lib/pdfrb/layout/polygon_frame.rb +106 -0
  56. data/lib/pdfrb/layout/table_box.rb +154 -23
  57. data/lib/pdfrb/layout/text_shaper.rb +129 -0
  58. data/lib/pdfrb/layout.rb +7 -0
  59. data/lib/pdfrb/model/type/page_piece_info.rb +58 -0
  60. data/lib/pdfrb/model/type.rb +3 -0
  61. data/lib/pdfrb/source/linearization_reader.rb +76 -0
  62. data/lib/pdfrb/source/recovery.rb +65 -1
  63. data/lib/pdfrb/source/tokenizer.rb +21 -0
  64. data/lib/pdfrb/source.rb +1 -0
  65. data/lib/pdfrb/task/regenerate_appearances.rb +98 -0
  66. data/lib/pdfrb/task/thumbnail.rb +133 -0
  67. data/lib/pdfrb/task.rb +2 -0
  68. data/lib/pdfrb/version.rb +1 -1
  69. metadata +35 -3
@@ -0,0 +1,408 @@
1
+ .ab1
2
+ ab2c
3
+ a2ble
4
+ .a1
5
+ a2b
6
+ ac1c
7
+ ad2d
8
+ ag2
9
+ al1s
10
+ an3c
11
+ a3p2
12
+ ar1d
13
+ ar1t
14
+ as1c
15
+ as1s
16
+ at1c
17
+ au1
18
+ a1v
19
+ a3y
20
+ be2s4
21
+ 1ba
22
+ 2b1
23
+ be2
24
+ bi2z
25
+ 1b2
26
+ bo2
27
+ bp1
28
+ bs1
29
+ b5t2
30
+ b5u2
31
+ 1ca
32
+ c2h2
33
+ ci2
34
+ 1c2
35
+ ck1
36
+ co3
37
+ con1
38
+ cp1
39
+ cs2
40
+ cu2
41
+ cy1
42
+ 1da
43
+ dd2
44
+ de2
45
+ 1d2
46
+ d4f3
47
+ d5i6
48
+ dg2
49
+ d1i4
50
+ d5le
51
+ d3o2
52
+ ds4
53
+ 1ea
54
+ ea2
55
+ e1b
56
+ e2c1
57
+ e1d
58
+ e4ed
59
+ e1f
60
+ e1g
61
+ e1h
62
+ ei2
63
+ e3j
64
+ e1k
65
+ e1l
66
+ e2m1
67
+ e1n
68
+ eo2
69
+ ep2
70
+ e1q
71
+ e1r
72
+ e4s1
73
+ e1t
74
+ eu2
75
+ e1v
76
+ e1w
77
+ e1x
78
+ ey1
79
+ e1z
80
+ 1fa
81
+ fb1
82
+ fe2
83
+ 1f2
84
+ ff2
85
+ 4f3i
86
+ fi2
87
+ 4f5l
88
+ 1f2
89
+ fo1
90
+ f4p1
91
+ fr2
92
+ 1ga
93
+ g2a
94
+ 1g2
95
+ gd1
96
+ ge3
97
+ g2gel
98
+ g4g3
99
+ gi2
100
+ 1g2
101
+ go1
102
+ g4p1
103
+ g3ra
104
+ 1ha
105
+ he2
106
+ 1h2
107
+ hi2
108
+ 1h2
109
+ ho2
110
+ hp1
111
+ hs2
112
+ hu2
113
+ hy1
114
+ 4i1a
115
+ 2i1b
116
+ i1c4
117
+ 2i1d
118
+ i1e
119
+ 4if
120
+ i1g2
121
+ 4ih
122
+ ii2
123
+ i1j4
124
+ i1k2
125
+ i1l2
126
+ 2im
127
+ 2in
128
+ 4i1o
129
+ i1p4
130
+ i1q
131
+ ir2
132
+ 4is
133
+ i1t4
134
+ i1u
135
+ 2iv
136
+ i1w
137
+ iw4
138
+ ix2
139
+ i1y
140
+ iz2
141
+ 1ja
142
+ 1je
143
+ 1ji
144
+ 1jo
145
+ 1ju
146
+ 1ka
147
+ kb1
148
+ 1kc
149
+ 1kd
150
+ ke2
151
+ 1k2
152
+ kf1
153
+ kg1
154
+ k2h
155
+ 1ki
156
+ 1kj
157
+ kk1
158
+ 1kl
159
+ km1
160
+ 1kn
161
+ ko1
162
+ kp1
163
+ 1kr
164
+ ks2
165
+ 1ku
166
+ 1kv
167
+ 1kw
168
+ 1la
169
+ lb1
170
+ lc1
171
+ ld2
172
+ le2
173
+ 1l2
174
+ lf1
175
+ lg2
176
+ 1li
177
+ 1lj
178
+ 1lk1
179
+ 1ll2
180
+ 1lm1
181
+ 1ln1
182
+ 1lo
183
+ 1lp1
184
+ 1lq
185
+ 1lr
186
+ 1ls
187
+ 1lt1
188
+ 1lu
189
+ 1lv
190
+ 1lw
191
+ 1lx
192
+ 1ly
193
+ 1lz
194
+ 4ma
195
+ 1m2b1
196
+ me2
197
+ m1f1
198
+ m4g3
199
+ mi2
200
+ 4m1l
201
+ 1mo
202
+ 1mp
203
+ m2s1
204
+ mu2
205
+ my1
206
+ 1na
207
+ nb1
208
+ nc2
209
+ nd2
210
+ ne2
211
+ 1n2
212
+ nf1
213
+ n2g3
214
+ 1ni
215
+ 1nj
216
+ 1nk1
217
+ n1l2
218
+ 1nm1
219
+ 1nn
220
+ 1no
221
+ n1p1
222
+ n1q
223
+ 1nr
224
+ ns2
225
+ nt1
226
+ 1nu
227
+ 1nv
228
+ nw1
229
+ ny1
230
+ 1ob
231
+ oc2
232
+ o1d4
233
+ o1f
234
+ og2
235
+ oh2
236
+ oi2
237
+ o1j
238
+ o1k
239
+ ol2
240
+ om1
241
+ on4
242
+ op2
243
+ o1q
244
+ o1r
245
+ o4s3
246
+ o1t
247
+ ou2
248
+ o1v
249
+ ow2
250
+ ox1
251
+ o1y
252
+ oz2
253
+ 1pa
254
+ 1p2b
255
+ pe2
256
+ 1p2
257
+ pf1
258
+ 4ph
259
+ p2h2
260
+ 4p1l
261
+ 1p2
262
+ po1
263
+ p2p
264
+ p1p1
265
+ p4p3
266
+ ps2
267
+ p1t2
268
+ 4q
269
+ 1qu
270
+ 1ra
271
+ 1r2b1
272
+ r1c
273
+ rd2
274
+ re2
275
+ r1d4
276
+ 1re
277
+ r1f4
278
+ r1g
279
+ r1h4
280
+ ri2
281
+ 4r1l
282
+ 1rm1
283
+ 1rn1
284
+ ro2
285
+ r1p4
286
+ r1r4
287
+ 1rs2
288
+ rt1
289
+ r1t4
290
+ r1u
291
+ ru2
292
+ r1v
293
+ r1w4
294
+ 1sa
295
+ 1s2b1
296
+ s1c
297
+ s1d
298
+ se2
299
+ s1e
300
+ s1f
301
+ s1g
302
+ sh2
303
+ si2
304
+ 1s2
305
+ s1k1
306
+ sl1
307
+ s1l1
308
+ sm2
309
+ s1m1
310
+ sn1
311
+ 1so
312
+ s1p
313
+ s1q
314
+ 1sr1
315
+ s1s1
316
+ s1t1
317
+ st1
318
+ su2
319
+ s1w
320
+ sy2
321
+ 4ta
322
+ 1t2b
323
+ tc2
324
+ t1d4
325
+ te2
326
+ t1e
327
+ t1f
328
+ t1g4
329
+ th1
330
+ 1ti
331
+ t1j
332
+ t1k
333
+ 1tl1
334
+ 1tn1
335
+ to2
336
+ t1p
337
+ t1q
338
+ t1r4
339
+ t1s1
340
+ t1t1
341
+ tu2
342
+ t1u
343
+ t1v
344
+ tw1
345
+ 1ua
346
+ ub1
347
+ u1c4
348
+ u1d
349
+ 4uf
350
+ u1g2
351
+ 4uh
352
+ ui2
353
+ u1j4
354
+ u1k2
355
+ u1l2
356
+ 4un
357
+ u1p4
358
+ u1q
359
+ ur2
360
+ 4us
361
+ u1t4
362
+ u1u
363
+ 4uv
364
+ u1w
365
+ ux1
366
+ u1y
367
+ uz2
368
+ 1va
369
+ 1v2b1
370
+ vc1
371
+ ve2
372
+ 1v2
373
+ v1f1
374
+ vi2
375
+ v1l
376
+ v1o
377
+ v1p1
378
+ 1vs2
379
+ vu1
380
+ 1wa
381
+ 1w2b
382
+ we2
383
+ wh1
384
+ 1wi
385
+ 1w2
386
+ wl1
387
+ wn1
388
+ 1wo
389
+ 1w2
390
+ 1wr
391
+ 1wu
392
+ 1xa
393
+ 1xe
394
+ 1xi
395
+ 1xo
396
+ 1xu
397
+ 1ya
398
+ 1ye
399
+ yi2
400
+ 1yo
401
+ 1yu
402
+ 4za
403
+ 1z2b1
404
+ ze2
405
+ 1z2
406
+ zi2
407
+ zo2
408
+ zu2
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+
5
+ module Pdfrb
6
+ module Color
7
+ # Default sRGB ICC profile accessor. Builds a usable sRGB v4
8
+ # ICC profile (header + tag table + tagged elements) that real
9
+ # PDF readers can consume for ICCBased color spaces. The profile
10
+ # includes:
11
+ #
12
+ # * desc — profile description (sRGB by pdfrb)
13
+ # * wtpt — D50 media white point
14
+ # * rXYZ, gXYZ, bXYZ — sRGB colorant matrix (D50-adapted)
15
+ # * rTRC, gTRC, bTRC — gamma 2.2 tone reproduction curves
16
+ #
17
+ # Tagged-element types follow ICC.1:2022 §10 (multiLocalizedUnicodeType
18
+ # for desc, XYZType for colorants, curveType for TRCs).
19
+ module DefaultProfile
20
+ SRGB_SIGNATURE = "acsp".b
21
+ ICC_VERSION_V4 = [0x04, 0x40, 0x00, 0x00].freeze
22
+
23
+ module_function
24
+
25
+ # Returns the sRGB ICC profile bytes (~ 600 bytes). Includes
26
+ # the structural header + tag table + tagged elements needed
27
+ # for a real ICCBased color space.
28
+ def srgb_bytes
29
+ tags = build_srgb_tags
30
+ tag_table = build_tag_table(tags)
31
+ header = build_srgb_header(tag_table.bytesize + tags_total_size(tags))
32
+ profile = header + tag_table
33
+ tags.each_value { |tag_bytes| profile << tag_bytes }
34
+ # Compute MD5 ProfileID over the on-disk profile (sans the
35
+ # existing ID slot, which we'll patch in). ICC.1:2022 §7.1.
36
+ profile = patch_profile_id(profile)
37
+ profile.force_encoding(Encoding::BINARY)
38
+ end
39
+
40
+ # Build an ICCBased color space array referencing a new stream
41
+ # containing the sRGB profile bytes. Returns
42
+ # [:ICCBased, ref] suitable for /ColorSpace resources.
43
+ def srgb_color_space(document)
44
+ bytes = srgb_bytes
45
+ stream = document.add(
46
+ { N: 3, Length: bytes.bytesize },
47
+ type: Pdfrb::Model::Cos::Stream
48
+ )
49
+ stream.stream = bytes
50
+ [:ICCBased, Pdfrb::Model::Reference.new(stream.oid, stream.gen)]
51
+ end
52
+
53
+ # ---- Header construction ----
54
+
55
+ def build_srgb_header(tag_section_size)
56
+ header = +""
57
+ header << ([0] * 4).pack("C*") # Profile size placeholder
58
+ header << ([0] * 4).pack("C*") # Preferred CMM
59
+ header << ICC_VERSION_V4.pack("C*") # Version 4.4
60
+ header << "mntr" # Device class
61
+ header << "RGB " # Color space
62
+ header << "XYZ " # PCS
63
+ header << date_bytes # Date
64
+ header << SRGB_SIGNATURE # 'acsp'
65
+ header << "APPL" # Primary platform
66
+ header << ([0] * 4).pack("C*") # Profile flags
67
+ header << ([0] * 4).pack("C*") # Device manufacturer
68
+ header << ([0] * 4).pack("C*") # Device model
69
+ header << ([0] * 8).pack("C*") # Device attributes
70
+ header << ([0] * 4).pack("C*") # Rendering intent (perceptual)
71
+ header << d50_illuminant_bytes # PCS illuminant (D50)
72
+ header << ([0] * 4).pack("C*") # Profile creator
73
+ header << ([0] * 16).pack("C*") # Profile ID (MD5, patched later)
74
+ header << ([0] * 28).pack("C*") # Reserved
75
+
76
+ total_size = header.bytesize + tag_section_size
77
+ header[0, 4] = [total_size].pack("N")
78
+ header
79
+ end
80
+
81
+ def date_bytes
82
+ [0x07, 0xE8, 0x00, 0x01, 0x00, 0x01,
83
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].pack("C*")
84
+ end
85
+
86
+ def d50_illuminant_bytes
87
+ # D50 X=0.9642, Y=1.0, Z=0.8249 in s15Fixed16.
88
+ [0x00, 0x00, 0xF6, 0xD6, 0x00, 0x01, 0x00, 0x00,
89
+ 0x00, 0x00, 0xD3, 0x2D].pack("C*")
90
+ end
91
+
92
+ # ---- Tag table + tagged elements ----
93
+
94
+ # Returns a Hash of { tag_signature => tag_bytes } in the
95
+ # order they should appear after the tag table.
96
+ def build_srgb_tags
97
+ {
98
+ "desc" => desc_tag_bytes("sRGB by pdfrb"),
99
+ "wtpt" => xyz_tag_bytes(d50_xyz),
100
+ "rXYZ" => xyz_tag_bytes(srgb_r_xyz),
101
+ "gXYZ" => xyz_tag_bytes(srgb_g_xyz),
102
+ "bXYZ" => xyz_tag_bytes(srgb_b_xyz),
103
+ "rTRC" => curve_tag_bytes,
104
+ "gTRC" => curve_tag_bytes,
105
+ "bTRC" => curve_tag_bytes,
106
+ }
107
+ end
108
+
109
+ def build_tag_table(tags)
110
+ out = +""
111
+ count = tags.length
112
+ out << [count].pack("N")
113
+
114
+ # Compute offsets: tag table is 4 + count*12 bytes; each tag
115
+ # element is appended after the table in order.
116
+ offset = 4 + (count * 12)
117
+ tags.each do |sig, bytes|
118
+ out << sig
119
+ out << [offset].pack("N")
120
+ out << [bytes.bytesize].pack("N")
121
+ offset += bytes.bytesize
122
+ end
123
+ out
124
+ end
125
+
126
+ def tags_total_size(tags)
127
+ tags.values.sum(&:bytesize)
128
+ end
129
+
130
+ # ---- Tag element builders ----
131
+
132
+ # multiLocalizedUnicodeType (mluc) for desc, per ICC.10.13.
133
+ def desc_tag_bytes(text)
134
+ utf16 = text.encode("UTF-16BE").bytes
135
+ body = +""
136
+ body << "mluc" # type signature
137
+ body << ([0] * 4).pack("C*") # reserved
138
+ body << [1].pack("N") # number of records
139
+ body << [12].pack("N") # record size in bytes
140
+ body << "enUS" # language + country
141
+ body << [utf16.length].pack("N") # string length in bytes
142
+ body << [28].pack("N") # string offset (from tag start)
143
+ body << utf16.pack("C*")
144
+ body
145
+ end
146
+
147
+ # XYZType for colorants and white points, per ICC.10.22.
148
+ def xyz_tag_bytes(xyz_triplet)
149
+ body = +""
150
+ body << "XYZ " # type signature
151
+ body << ([0] * 4).pack("C*") # reserved
152
+ xyz_triplet.each { |v| body << s15fixed16(v) }
153
+ body
154
+ end
155
+
156
+ # curveType with a single gamma value, per ICC.10.16.
157
+ # 2.2 is the canonical sRGB approximation (real sRGB uses a
158
+ # piecewise curve, but a single 2.2 gamma is acceptable for
159
+ # most rendering).
160
+ def curve_tag_bytes
161
+ body = +""
162
+ body << "curv" # type signature
163
+ body << ([0] * 4).pack("C*") # reserved
164
+ body << [0].pack("N") # count = 0 → gamma follows in u8Fixed8
165
+ body << u8fixed8(2.2)
166
+ body
167
+ end
168
+
169
+ # Encode a Float as ICC s15Fixed16 (signed 16.16).
170
+ def s15fixed16(value)
171
+ v = (value * 65536.0).round.to_i
172
+ [v].pack("N")
173
+ end
174
+
175
+ # Encode a Float as ICC u8Fixed8 (unsigned 8.8).
176
+ def u8fixed8(value)
177
+ v = (value * 256.0).round.to_i
178
+ [v].pack("n")
179
+ end
180
+
181
+ # ---- sRGB colorants (D50-adapted, per ICC.1:2022 Annex A) ----
182
+
183
+ def d50_xyz
184
+ [0.9642, 1.0000, 0.8249]
185
+ end
186
+
187
+ def srgb_r_xyz
188
+ [0.4360, 0.2225, 0.0139]
189
+ end
190
+
191
+ def srgb_g_xyz
192
+ [0.3851, 0.7169, 0.0971]
193
+ end
194
+
195
+ def srgb_b_xyz
196
+ [0.1431, 0.0606, 0.7141]
197
+ end
198
+
199
+ # ---- Profile ID (MD5) ----
200
+
201
+ # Patch the Profile ID (offset 84..99) with the MD5 of the
202
+ # profile bytes computed with the ID slot zeroed (per ICC.1
203
+ # §7.1.1).
204
+ def patch_profile_id(profile)
205
+ copy = profile.b
206
+ copy[84, 16] = ([0] * 16).pack("C*")
207
+ md5 = Digest::MD5.digest(copy)
208
+ copy[84, 16] = md5
209
+ copy
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Color
5
+ # Validates an ICC profile binary against the structural rules in
6
+ # ICC.1:2022 §7. The validator checks:
7
+ # * Profile size >= 128 (header) + 4 (tag count)
8
+ # * 'acsp' signature at offset 36
9
+ # * Profile version is 2.x, 4.x, or 5.x
10
+ # * Device class is one of the known classes
11
+ # * Color space is one of the known spaces
12
+ # * Tag table offsets don't exceed the file size
13
+ #
14
+ # Returns an Array of Violation strings (empty if valid).
15
+ module ICCValidator
16
+ VALID_VERSIONS = [(2.0..2.99), (4.0..4.99), (5.0..5.99)].freeze
17
+ VALID_DEVICE_CLASSES = %w[
18
+ scnr mntr prtr link spac abst nmcl nkpr
19
+ ].freeze
20
+ VALID_COLOR_SPACES = %w[
21
+ XYZ Lab Luv YCbCr Yxy RGB GRAY HSV HLS CMYK CMY 2CLR 3CLR
22
+ 4CLR 5CLR 6CLR 7CLR 8CLR 9CLR ACLR BCLR CCLR DCLR ECLR FCLR
23
+ ].freeze
24
+
25
+ module_function
26
+
27
+ def validate(profile_bytes)
28
+ violations = []
29
+ unless profile_bytes.is_a?(::String) && profile_bytes.bytesize >= 132
30
+ violations << "ICC profile too small (need >= 132 bytes, got #{profile_bytes&.bytesize})"
31
+ return violations
32
+ end
33
+
34
+ unless profile_bytes.byteslice(36, 4) == "acsp"
35
+ violations << "ICC profile signature at offset 36 is not 'acsp'"
36
+ end
37
+
38
+ version_hi = profile_bytes.getbyte(8)
39
+ version_lo = profile_bytes.getbyte(9)
40
+ version = (version_hi * 1.0) + (version_lo / 16.0 / 10.0)
41
+ unless VALID_VERSIONS.any? { |range| range.cover?(version) }
42
+ violations << "ICC profile version #{version} not in 2.x/4.x/5.x"
43
+ end
44
+
45
+ device_class = profile_bytes.byteslice(12, 4).to_s.strip
46
+ unless VALID_DEVICE_CLASSES.include?(device_class)
47
+ violations << "ICC device class '#{device_class}' is not recognised"
48
+ end
49
+
50
+ color_space = profile_bytes.byteslice(16, 4).to_s.strip
51
+ unless VALID_COLOR_SPACES.include?(color_space)
52
+ violations << "ICC color space '#{color_space}' is not recognised"
53
+ end
54
+
55
+ # Tag table sanity check
56
+ tag_count = profile_bytes.unpack1("N", offset: 128)
57
+ if tag_count > 256
58
+ violations << "ICC tag count #{tag_count} looks bogus (max 256)"
59
+ end
60
+
61
+ violations
62
+ end
63
+
64
+ def valid?(profile_bytes)
65
+ validate(profile_bytes).empty?
66
+ end
67
+ end
68
+ end
69
+ end
data/lib/pdfrb/color.rb CHANGED
@@ -8,5 +8,7 @@ module Pdfrb
8
8
  module Color
9
9
  autoload :ICCProfile, "pdfrb/color/icc_profile"
10
10
  autoload :ColorSpace, "pdfrb/color/color_space"
11
+ autoload :DefaultProfile, "pdfrb/color/default_profile"
12
+ autoload :ICCValidator, "pdfrb/color/icc_validator"
11
13
  end
12
14
  end