pdf-labels 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/History.txt +8 -0
  2. data/LICENCE +38 -0
  3. data/Manifest.txt +141 -0
  4. data/README.txt +72 -0
  5. data/Rakefile +30 -0
  6. data/lib/alias.rb +8 -0
  7. data/lib/glabel_template.rb +36 -0
  8. data/lib/label.rb +52 -0
  9. data/lib/layout.rb +13 -0
  10. data/lib/length_node.rb +47 -0
  11. data/lib/markup.rb +25 -0
  12. data/lib/pdf_label_page.rb +171 -0
  13. data/lib/pdf_labels.rb +6 -0
  14. data/lib/template.rb +37 -0
  15. data/templates/avery-iso-templates.xml +222 -0
  16. data/templates/avery-other-templates.xml +21 -0
  17. data/templates/avery-us-templates.xml +599 -0
  18. data/templates/glabels-2.0.dtd +329 -0
  19. data/templates/misc-iso-templates.xml +434 -0
  20. data/templates/misc-other-templates.xml +21 -0
  21. data/templates/misc-us-templates.xml +183 -0
  22. data/templates/paper-sizes.xml +37 -0
  23. data/templates/zweckform-iso-templates.xml +197 -0
  24. data/test/test_pdf_label_page.rb +91 -0
  25. data/vendor/color.rb +87 -0
  26. data/vendor/color/cmyk.rb +182 -0
  27. data/vendor/color/css.rb +27 -0
  28. data/vendor/color/grayscale.rb +135 -0
  29. data/vendor/color/hsl.rb +130 -0
  30. data/vendor/color/palette.rb +15 -0
  31. data/vendor/color/palette/gimp.rb +107 -0
  32. data/vendor/color/palette/monocontrast.rb +180 -0
  33. data/vendor/color/rgb-colors.rb +189 -0
  34. data/vendor/color/rgb.rb +311 -0
  35. data/vendor/color/rgb/metallic.rb +28 -0
  36. data/vendor/color/yiq.rb +78 -0
  37. data/vendor/pdf/charts.rb +13 -0
  38. data/vendor/pdf/charts/stddev.rb +433 -0
  39. data/vendor/pdf/grid.rb +135 -0
  40. data/vendor/pdf/math.rb +108 -0
  41. data/vendor/pdf/pagenumbers.rb +288 -0
  42. data/vendor/pdf/quickref.rb +331 -0
  43. data/vendor/pdf/simpletable.rb +947 -0
  44. data/vendor/pdf/techbook.rb +901 -0
  45. data/vendor/pdf/writer.rb +2801 -0
  46. data/vendor/pdf/writer/arc4.rb +63 -0
  47. data/vendor/pdf/writer/fontmetrics.rb +202 -0
  48. data/vendor/pdf/writer/fonts/Courier-Bold.afm +342 -0
  49. data/vendor/pdf/writer/fonts/Courier-BoldOblique.afm +342 -0
  50. data/vendor/pdf/writer/fonts/Courier-Oblique.afm +342 -0
  51. data/vendor/pdf/writer/fonts/Courier.afm +342 -0
  52. data/vendor/pdf/writer/fonts/Helvetica-Bold.afm +2827 -0
  53. data/vendor/pdf/writer/fonts/Helvetica-BoldOblique.afm +2827 -0
  54. data/vendor/pdf/writer/fonts/Helvetica-Oblique.afm +3051 -0
  55. data/vendor/pdf/writer/fonts/Helvetica.afm +3051 -0
  56. data/vendor/pdf/writer/fonts/Symbol.afm +213 -0
  57. data/vendor/pdf/writer/fonts/Times-Bold.afm +2588 -0
  58. data/vendor/pdf/writer/fonts/Times-BoldItalic.afm +2384 -0
  59. data/vendor/pdf/writer/fonts/Times-Italic.afm +2667 -0
  60. data/vendor/pdf/writer/fonts/Times-Roman.afm +2419 -0
  61. data/vendor/pdf/writer/fonts/ZapfDingbats.afm +225 -0
  62. data/vendor/pdf/writer/graphics.rb +813 -0
  63. data/vendor/pdf/writer/graphics/imageinfo.rb +365 -0
  64. data/vendor/pdf/writer/lang.rb +44 -0
  65. data/vendor/pdf/writer/lang/en.rb +104 -0
  66. data/vendor/pdf/writer/object.rb +23 -0
  67. data/vendor/pdf/writer/object/action.rb +40 -0
  68. data/vendor/pdf/writer/object/annotation.rb +42 -0
  69. data/vendor/pdf/writer/object/catalog.rb +39 -0
  70. data/vendor/pdf/writer/object/contents.rb +69 -0
  71. data/vendor/pdf/writer/object/destination.rb +40 -0
  72. data/vendor/pdf/writer/object/encryption.rb +53 -0
  73. data/vendor/pdf/writer/object/font.rb +68 -0
  74. data/vendor/pdf/writer/object/fontdescriptor.rb +34 -0
  75. data/vendor/pdf/writer/object/fontencoding.rb +40 -0
  76. data/vendor/pdf/writer/object/image.rb +308 -0
  77. data/vendor/pdf/writer/object/info.rb +79 -0
  78. data/vendor/pdf/writer/object/outline.rb +30 -0
  79. data/vendor/pdf/writer/object/outlines.rb +30 -0
  80. data/vendor/pdf/writer/object/page.rb +195 -0
  81. data/vendor/pdf/writer/object/pages.rb +115 -0
  82. data/vendor/pdf/writer/object/procset.rb +46 -0
  83. data/vendor/pdf/writer/object/viewerpreferences.rb +74 -0
  84. data/vendor/pdf/writer/ohash.rb +58 -0
  85. data/vendor/pdf/writer/oreader.rb +25 -0
  86. data/vendor/pdf/writer/state.rb +48 -0
  87. data/vendor/pdf/writer/strokestyle.rb +140 -0
  88. data/vendor/transaction/simple.rb +693 -0
  89. data/vendor/transaction/simple/group.rb +133 -0
  90. data/vendor/transaction/simple/threadsafe.rb +52 -0
  91. data/vendor/transaction/simple/threadsafe/group.rb +23 -0
  92. data/vendor/xml-mapping/ChangeLog +128 -0
  93. data/vendor/xml-mapping/LICENSE +56 -0
  94. data/vendor/xml-mapping/README +386 -0
  95. data/vendor/xml-mapping/README_XPATH +175 -0
  96. data/vendor/xml-mapping/Rakefile +214 -0
  97. data/vendor/xml-mapping/TODO.txt +32 -0
  98. data/vendor/xml-mapping/doc/xpath_impl_notes.txt +119 -0
  99. data/vendor/xml-mapping/examples/company.rb +34 -0
  100. data/vendor/xml-mapping/examples/company.xml +26 -0
  101. data/vendor/xml-mapping/examples/company_usage.intin.rb +19 -0
  102. data/vendor/xml-mapping/examples/company_usage.intout +39 -0
  103. data/vendor/xml-mapping/examples/order.rb +61 -0
  104. data/vendor/xml-mapping/examples/order.xml +54 -0
  105. data/vendor/xml-mapping/examples/order_signature_enhanced.rb +7 -0
  106. data/vendor/xml-mapping/examples/order_signature_enhanced.xml +9 -0
  107. data/vendor/xml-mapping/examples/order_signature_enhanced_usage.intin.rb +12 -0
  108. data/vendor/xml-mapping/examples/order_signature_enhanced_usage.intout +16 -0
  109. data/vendor/xml-mapping/examples/order_usage.intin.rb +73 -0
  110. data/vendor/xml-mapping/examples/order_usage.intout +147 -0
  111. data/vendor/xml-mapping/examples/time_augm.intin.rb +19 -0
  112. data/vendor/xml-mapping/examples/time_augm.intout +23 -0
  113. data/vendor/xml-mapping/examples/time_node.rb +27 -0
  114. data/vendor/xml-mapping/examples/xpath_create_new.intin.rb +85 -0
  115. data/vendor/xml-mapping/examples/xpath_create_new.intout +181 -0
  116. data/vendor/xml-mapping/examples/xpath_docvsroot.intin.rb +30 -0
  117. data/vendor/xml-mapping/examples/xpath_docvsroot.intout +34 -0
  118. data/vendor/xml-mapping/examples/xpath_ensure_created.intin.rb +62 -0
  119. data/vendor/xml-mapping/examples/xpath_ensure_created.intout +114 -0
  120. data/vendor/xml-mapping/examples/xpath_pathological.intin.rb +42 -0
  121. data/vendor/xml-mapping/examples/xpath_pathological.intout +56 -0
  122. data/vendor/xml-mapping/examples/xpath_usage.intin.rb +51 -0
  123. data/vendor/xml-mapping/examples/xpath_usage.intout +57 -0
  124. data/vendor/xml-mapping/install.rb +40 -0
  125. data/vendor/xml-mapping/lib/xml/mapping.rb +14 -0
  126. data/vendor/xml-mapping/lib/xml/mapping/base.rb +571 -0
  127. data/vendor/xml-mapping/lib/xml/mapping/standard_nodes.rb +343 -0
  128. data/vendor/xml-mapping/lib/xml/mapping/version.rb +8 -0
  129. data/vendor/xml-mapping/lib/xml/xxpath.rb +354 -0
  130. data/vendor/xml-mapping/test/all_tests.rb +6 -0
  131. data/vendor/xml-mapping/test/company.rb +56 -0
  132. data/vendor/xml-mapping/test/documents_folders.rb +33 -0
  133. data/vendor/xml-mapping/test/fixtures/bookmarks1.xml +24 -0
  134. data/vendor/xml-mapping/test/fixtures/company1.xml +85 -0
  135. data/vendor/xml-mapping/test/fixtures/documents_folders.xml +71 -0
  136. data/vendor/xml-mapping/test/fixtures/documents_folders2.xml +30 -0
  137. data/vendor/xml-mapping/test/multiple_mappings.rb +80 -0
  138. data/vendor/xml-mapping/test/tests_init.rb +2 -0
  139. data/vendor/xml-mapping/test/xml_mapping_adv_test.rb +84 -0
  140. data/vendor/xml-mapping/test/xml_mapping_test.rb +201 -0
  141. data/vendor/xml-mapping/test/xpath_test.rb +273 -0
  142. metadata +191 -0
@@ -0,0 +1,311 @@
1
+ #--
2
+ # Colour management with Ruby.
3
+ #
4
+ # Copyright 2005 Austin Ziegler
5
+ # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: rgb.rb,v 1.6 2005/08/08 02:44:17 austin Exp $
10
+ #++
11
+
12
+ # An RGB colour object.
13
+ class Color::RGB
14
+ # The format of a DeviceRGB colour for PDF. In color-tools 2.0 this will
15
+ # be removed from this package and added back as a modification by the
16
+ # PDF::Writer package.
17
+ PDF_FORMAT_STR = "%.3f %.3f %.3f %s"
18
+
19
+ class << self
20
+ # Creates an RGB colour object from percentages 0..100.
21
+ #
22
+ # Color::RGB.from_percentage(10, 20 30)
23
+ def from_percentage(r = 0, g = 0, b = 0)
24
+ from_fraction(r / 100.0, g / 100.0, b / 100.0)
25
+ end
26
+
27
+ # Creates an RGB colour object from fractional values 0..1.
28
+ #
29
+ # Color::RGB.from_fraction(.3, .2, .1)
30
+ def from_fraction(r = 0.0, g = 0.0, b = 0.0)
31
+ colour = Color::RGB.new
32
+ colour.r = r
33
+ colour.g = g
34
+ colour.b = b
35
+ colour
36
+ end
37
+
38
+ # Creates an RGB colour object from an HTML colour descriptor (e.g.,
39
+ # <tt>"fed"</tt> or <tt>"#cabbed;"</tt>.
40
+ #
41
+ # Color::RGB.from_html("fed")
42
+ # Color::RGB.from_html("#fed")
43
+ # Color::RGB.from_html("#cabbed")
44
+ # Color::RGB.from_html("cabbed")
45
+ def from_html(html_colour)
46
+ html_colour = html_colour.gsub(%r{[#;]}, '')
47
+ case html_colour.size
48
+ when 3
49
+ colours = html_colour.scan(%r{[0-9A-Fa-f]}).map { |el| (el * 2).to_i(16) }
50
+ when 6
51
+ colours = html_colour.scan(%r<[0-9A-Fa-f]{2}>).map { |el| el.to_i(16) }
52
+ else
53
+ raise ArgumentError
54
+ end
55
+
56
+ Color::RGB.new(*colours)
57
+ end
58
+ end
59
+
60
+ # Compares the other colour to this one. The other colour will be
61
+ # converted to RGB before comparison, so the comparison between a RGB
62
+ # colour and a non-RGB colour will be approximate and based on the other
63
+ # colour's default #to_rgb conversion. If there is no #to_rgb
64
+ # conversion, this will raise an exception. This will report that two
65
+ # RGB colours are equivalent if all component values are within 1e-4
66
+ # (0.0001) of each other.
67
+ def ==(other)
68
+ other = other.to_rgb
69
+ other.kind_of?(Color::RGB) and
70
+ ((@r - other.r).abs <= 1e-4) and
71
+ ((@g - other.g).abs <= 1e-4) and
72
+ ((@b - other.b).abs <= 1e-4)
73
+ end
74
+
75
+ # Creates an RGB colour object from the standard range 0..255.
76
+ #
77
+ # Color::RGB.new(32, 64, 128)
78
+ # Color::RGB.new(0x20, 0x40, 0x80)
79
+ def initialize(r = 0, g = 0, b = 0)
80
+ @r = r / 255.0
81
+ @g = g / 255.0
82
+ @b = b / 255.0
83
+ end
84
+
85
+ # Present the colour as a DeviceRGB fill colour string for PDF. This
86
+ # will be removed from the default package in color-tools 2.0.
87
+ def pdf_fill
88
+ PDF_FORMAT_STR % [ @r, @g, @b, "rg" ]
89
+ end
90
+
91
+ # Present the colour as a DeviceRGB stroke colour string for PDF. This
92
+ # will be removed from the default package in color-tools 2.0.
93
+ def pdf_stroke
94
+ PDF_FORMAT_STR % [ @r, @g, @b, "RG" ]
95
+ end
96
+
97
+ # Present the colour as an HTML/CSS colour string.
98
+ def html
99
+ r = (@r * 255).round
100
+ r = 255 if r > 255
101
+
102
+ g = (@g * 255).round
103
+ g = 255 if g > 255
104
+
105
+ b = (@b * 255).round
106
+ b = 255 if b > 255
107
+
108
+ "#%02x%02x%02x" % [ r, g, b ]
109
+ end
110
+
111
+ # Converts the RGB colour to CMYK. Most colour experts strongly suggest
112
+ # that this is not a good idea (some even suggesting that it's a very
113
+ # bad idea). CMYK represents additive percentages of inks on white
114
+ # paper, whereas RGB represents mixed colour intensities on a black
115
+ # screen.
116
+ #
117
+ # However, the colour conversion can be done. The basic method is
118
+ # multi-step:
119
+ #
120
+ # 1. Convert the R, G, and B components to C, M, and Y components.
121
+ # c = 1.0 � r
122
+ # m = 1.0 � g
123
+ # y = 1.0 � b
124
+ # 2. Compute the minimum amount of black (K) required to smooth the
125
+ # colour in inks.
126
+ # k = min(c, m, y)
127
+ # 3. Perform undercolour removal on the C, M, and Y components of the
128
+ # colours because less of each colour is needed for each bit of
129
+ # black. Also, regenerate the black (K) based on the undercolour
130
+ # removal so that the colour is more accurately represented in ink.
131
+ # c = min(1.0, max(0.0, c � UCR(k)))
132
+ # m = min(1.0, max(0.0, m � UCR(k)))
133
+ # y = min(1.0, max(0.0, y � UCR(k)))
134
+ # k = min(1.0, max(0.0, BG(k)))
135
+ #
136
+ # The undercolour removal function and the black generation functions
137
+ # return a value based on the brightness of the RGB colour.
138
+ def to_cmyk
139
+ c = 1.0 - @r.to_f
140
+ m = 1.0 - @g.to_f
141
+ y = 1.0 - @b.to_f
142
+
143
+ k = [c, m, y].min
144
+ k = k - (k * brightness)
145
+
146
+ c = [1.0, [0.0, c - k].max].min
147
+ m = [1.0, [0.0, m - k].max].min
148
+ y = [1.0, [0.0, y - k].max].min
149
+ k = [1.0, [0.0, k].max].min
150
+
151
+ Color::CMYK.from_fraction(c, m, y, k)
152
+ end
153
+
154
+ def to_rgb(ignored = nil)
155
+ self
156
+ end
157
+
158
+ # Returns the YIQ (NTSC) colour encoding of the RGB value.
159
+ def to_yiq
160
+ y = (@r * 0.299) + (@g * 0.587) + (@b * 0.114)
161
+ i = (@r * 0.596) + (@g * -0.275) + (@b * -0.321)
162
+ q = (@r * 0.212) + (@g * -0.523) + (@b * 0.311)
163
+ Color::YIQ.from_fraction(y, i, q)
164
+ end
165
+
166
+ # Returns the HSL colour encoding of the RGB value.
167
+ def to_hsl
168
+ min = [ @r, @g, @b ].min
169
+ max = [ @r, @g, @b ].max
170
+ delta = (max - min).to_f
171
+
172
+ lum = (max + min) / 2.0
173
+
174
+ if delta <= 1e-5 # close to 0.0, so it's a grey
175
+ hue = 0
176
+ sat = 0
177
+ else
178
+ if (lum - 0.5) <= 1e-5
179
+ sat = delta / (max + min).to_f
180
+ else
181
+ sat = delta / (2 - max - min).to_f
182
+ end
183
+
184
+ if @r == max
185
+ hue = (@g - @b) / delta.to_f
186
+ elsif @g == max
187
+ hue = (2.0 + @b - @r) / delta.to_f
188
+ elsif (@b - max) <= 1e-5
189
+ hue = (4.0 + @r - @g) / delta.to_f
190
+ end
191
+ hue /= 6.0
192
+
193
+ hue += 1 if hue < 0
194
+ hue -= 1 if hue > 1
195
+ end
196
+ Color::HSL.from_fraction(hue, sat, lum)
197
+ end
198
+
199
+ # Mix the RGB hue with White so that the RGB hue is the specified
200
+ # percentage of the resulting colour. Strictly speaking, this isn't a
201
+ # darken_by operation.
202
+ def lighten_by(percent)
203
+ mix_with(White, percent)
204
+ end
205
+
206
+ # Mix the RGB hue with Black so that the RGB hue is the specified
207
+ # percentage of the resulting colour. Strictly speaking, this isn't a
208
+ # darken_by operation.
209
+ def darken_by(percent)
210
+ mix_with(Black, percent)
211
+ end
212
+
213
+ # Mix the mask colour (which must be an RGB object) with the current
214
+ # colour at the stated opacity percentage (0..100).
215
+ def mix_with(mask, opacity)
216
+ opacity /= 100.0
217
+ rgb = self.dup
218
+
219
+ rgb.r = (@r * opacity) + (mask.r * (1 - opacity))
220
+ rgb.g = (@g * opacity) + (mask.g * (1 - opacity))
221
+ rgb.b = (@b * opacity) + (mask.b * (1 - opacity))
222
+
223
+ rgb
224
+ end
225
+
226
+ # Returns the brightness value for a colour, a number between 0..1.
227
+ # Based on the Y value of YIQ encoding, representing luminosity, or
228
+ # perceived brightness.
229
+ #
230
+ # This may be modified in a future version of color-tools to use the
231
+ # luminosity value of HSL.
232
+ def brightness
233
+ to_yiq.y
234
+ end
235
+ def to_grayscale
236
+ Color::GrayScale.from_fraction(to_hsl.l)
237
+ end
238
+
239
+ alias to_greyscale to_grayscale
240
+
241
+ # Returns a new colour with the brightness adjusted by the specified
242
+ # percentage. Negative percentages will darken the colour; positive
243
+ # percentages will brighten the colour.
244
+ #
245
+ # Color::RGB::DarkBlue.adjust_brightness(10)
246
+ # Color::RGB::DarkBlue.adjust_brightness(-10)
247
+ def adjust_brightness(percent)
248
+ percent /= 100.0
249
+ percent += 1.0
250
+ percent = [ percent, 2.0 ].min
251
+ percent = [ 0.0, percent ].max
252
+
253
+ hsl = to_hsl
254
+ hsl.l *= percent
255
+ hsl.to_rgb
256
+ end
257
+
258
+ # Returns a new colour with the saturation adjusted by the specified
259
+ # percentage. Negative percentages will reduce the saturation; positive
260
+ # percentages will increase the saturation.
261
+ #
262
+ # Color::RGB::DarkBlue.adjust_saturation(10)
263
+ # Color::RGB::DarkBlue.adjust_saturation(-10)
264
+ def adjust_saturation(percent)
265
+ percent /= 100.0
266
+ percent += 1.0
267
+ percent = [ percent, 2.0 ].min
268
+ percent = [ 0.0, percent ].max
269
+
270
+ hsl = to_hsl
271
+ hsl.s *= percent
272
+ hsl.to_rgb
273
+ end
274
+
275
+ # Returns a new colour with the hue adjusted by the specified
276
+ # percentage. Negative percentages will reduce the hue; positive
277
+ # percentages will increase the hue.
278
+ #
279
+ # Color::RGB::DarkBlue.adjust_hue(10)
280
+ # Color::RGB::DarkBlue.adjust_hue(-10)
281
+ def adjust_hue(percent)
282
+ percent /= 100.0
283
+ percent += 1.0
284
+ percent = [ percent, 2.0 ].min
285
+ percent = [ 0.0, percent ].max
286
+
287
+ hsl = to_hsl
288
+ hsl.h *= percent
289
+ hsl.to_rgb
290
+ end
291
+
292
+ attr_accessor :r, :g, :b
293
+ remove_method :r=, :g=, :b= ;
294
+ def r=(rr) #:nodoc:
295
+ rr = 1.0 if rr > 1
296
+ rr = 0.0 if rr < 0
297
+ @r = rr
298
+ end
299
+ def g=(gg) #:nodoc:
300
+ gg = 1.0 if gg > 1
301
+ gg = 0.0 if gg < 0
302
+ @g = gg
303
+ end
304
+ def b=(bb) #:nodoc:
305
+ bb = 1.0 if bb > 1
306
+ bb = 0.0 if bb < 0
307
+ @b = bb
308
+ end
309
+ end
310
+
311
+ require 'color/rgb-colors'
@@ -0,0 +1,28 @@
1
+ #--
2
+ # Colour management with Ruby.
3
+ #
4
+ # Copyright 2005 Austin Ziegler
5
+ # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: metallic.rb,v 1.1 2005/08/05 23:07:20 austin Exp $
10
+ #++
11
+
12
+ # This namespace contains some RGB metallic colours suggested by Jim Freeze.
13
+ module Color::RGB::Metallic
14
+ Aluminum = Color::RGB.new(0x99, 0x99, 0x99)
15
+ CoolCopper = Color::RGB.new(0xd9, 0x87, 0x19)
16
+ Copper = Color::RGB.new(0xb8, 0x73, 0x33)
17
+ Iron = Color::RGB.new(0x4c, 0x4c, 0x4c)
18
+ Lead = Color::RGB.new(0x19, 0x19, 0x19)
19
+ Magnesium = Color::RGB.new(0xb3, 0xb3, 0xb3)
20
+ Mercury = Color::RGB.new(0xe6, 0xe6, 0xe6)
21
+ Nickel = Color::RGB.new(0x80, 0x80, 0x80)
22
+ PolySilicon = Color::RGB.new(0x60, 0x00, 0x00)
23
+ Poly = PolySilicon
24
+ Silver = Color::RGB.new(0xcc, 0xcc, 0xcc)
25
+ Steel = Color::RGB.new(0x66, 0x66, 0x66)
26
+ Tin = Color::RGB.new(0x7f, 0x7f, 0x7f)
27
+ Tungsten = Color::RGB.new(0x33, 0x33, 0x33)
28
+ end
@@ -0,0 +1,78 @@
1
+ #--
2
+ # Colour management with Ruby.
3
+ #
4
+ # Copyright 2005 Austin Ziegler
5
+ # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: yiq.rb,v 1.3 2005/08/08 02:44:17 austin Exp $
10
+ #++
11
+
12
+ # A colour object representing YIQ (NTSC) colour encoding.
13
+ class Color::YIQ
14
+ # Creates a YIQ colour object from fractional values 0 .. 1.
15
+ #
16
+ # Color::YIQ.new(0.3, 0.2, 0.1)
17
+ def self.from_fraction(y = 0, i = 0, q = 0)
18
+ color = Color::YIQ.new
19
+ color.y = y
20
+ color.i = i
21
+ color.q = q
22
+ color
23
+ end
24
+
25
+ # Creates a YIQ colour object from percentages 0 .. 100.
26
+ #
27
+ # Color::YIQ.new(10, 20, 30)
28
+ def initialize(y = 0, i = 0, q = 0)
29
+ @y = y / 100.0
30
+ @i = i / 100.0
31
+ @q = q / 100.0
32
+ end
33
+
34
+ # Compares the other colour to this one. The other colour will be
35
+ # converted to YIQ before comparison, so the comparison between a YIQ
36
+ # colour and a non-YIQ colour will be approximate and based on the other
37
+ # colour's #to_yiq conversion. If there is no #to_yiq conversion, this
38
+ # will raise an exception. This will report that two YIQ values are
39
+ # equivalent if all component colours are within 1e-4 (0.0001) of each
40
+ # other.
41
+ def ==(other)
42
+ other = other.to_yiq
43
+ other.kind_of?(Color::YIQ) and
44
+ ((@y - other.y).abs <= 1e-4) and
45
+ ((@i - other.i).abs <= 1e-4) and
46
+ ((@q - other.q).abs <= 1e-4)
47
+ end
48
+
49
+ def to_yiq
50
+ self
51
+ end
52
+
53
+ def brightness
54
+ @y
55
+ end
56
+ def to_grayscale
57
+ Color::GrayScale.new(@y)
58
+ end
59
+ alias to_greyscale to_grayscale
60
+
61
+ attr_accessor :y, :i, :q
62
+ remove_method :y=, :i=, :q=
63
+ def y=(yy) #:nodoc:
64
+ yy = 1.0 if yy > 1
65
+ yy = 0.0 if yy < 0
66
+ @y = yy
67
+ end
68
+ def i=(ii) #:nodoc:
69
+ ii = 1.0 if ii > 1
70
+ ii = 0.0 if ii < 0
71
+ @i = ii
72
+ end
73
+ def q=(qq) #:nodoc:
74
+ qq = 1.0 if qq > 1
75
+ qq = 0.0 if qq < 0
76
+ @q = qq
77
+ end
78
+ end
@@ -0,0 +1,13 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: charts.rb,v 1.2 2005/05/16 03:59:21 austin Exp $
10
+ #++
11
+ # A namespace for charts that can be drawn on PDF::Writer canvases.
12
+ module PDF::Charts
13
+ end
@@ -0,0 +1,433 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: stddev.rb,v 1.12 2005/10/12 14:41:40 austin Exp $
10
+ #++
11
+ require 'pdf/writer'
12
+ require 'pdf/charts'
13
+ require 'ostruct'
14
+
15
+ # Creates a standard deviation chart. This is a type of chart that is
16
+ # effective for the display of survey results or other data that can
17
+ # easily be measured in terms of the average and the standard deviation
18
+ # from that average.
19
+ #
20
+ # The scale of responses is the vertical scale; the average data points
21
+ # and standard deviation values are the horizontal scale.
22
+ class PDF::Charts::StdDev
23
+ VERSION = '1.1.4'
24
+
25
+ # A data element.
26
+ DataPoint = Struct.new(:label, :average, :stddev)
27
+
28
+ # A label for displaying the scale (vertical) of data in the dataset or
29
+ # the data set identifiers.
30
+ class Label
31
+ def initialize
32
+ yield self if block_given?
33
+ end
34
+
35
+ # The height of the label, in PDF user units. Ignored for scale
36
+ # labels.
37
+ attr_accessor :height
38
+ # The background color of the label. Ignored for scale labels.
39
+ attr_accessor :background_color
40
+ # The text color of the label.
41
+ attr_accessor :text_color
42
+ # The text size, in points, of the label.
43
+ attr_accessor :text_size
44
+ # The padding of the label. Only used for scale labels.
45
+ attr_accessor :pad
46
+ # The decimal precision of the label. Only used for scale labels.
47
+ attr_accessor :decimal_precision
48
+ end
49
+
50
+ # The scale of the dataset.
51
+ class Scale
52
+ def initialize(args = { })
53
+ @range = args[:range]
54
+ @step = args[:step]
55
+ @style = args[:style]
56
+ @show_labels = false
57
+
58
+ yield self if block_given?
59
+
60
+ raise TypeError, PDF::Lange[:charts_stddev_scale_norange] if @range.nil?
61
+ raise TypeError, PDF::Lange[:charts_stddev_scale_nostep] if @step.nil?
62
+ end
63
+
64
+ # Range of the scale. This should be a Range object.
65
+ attr_accessor :range
66
+ # The lower end of the range of the scale. The scale range may be
67
+ # modified by changing this value.
68
+ attr_accessor :first
69
+ remove_method :first, :first= ;
70
+ def first #:nodoc:
71
+ @range.first
72
+ end
73
+ def first=(ff) #:nodoc:
74
+ @range = (ff..@range.last)
75
+ end
76
+ # The upper end of the range of the scale. The scale range may be
77
+ # modified by changing this value.
78
+ attr_accessor :last
79
+ remove_method :last, :last= ;
80
+ def last #:nodoc:
81
+ @range.last
82
+ end
83
+ def last=(ll) #:nodoc:
84
+ @range = (@range.first..ll)
85
+ end
86
+ # Defines the step of the scale. Each step represents a vertical
87
+ # position on the chart.
88
+ attr_accessor :step
89
+ # Defines the line style for the scale on the chart. If this is unset
90
+ # (+nil+), there will be no horizontal marks across the chart for the
91
+ # steps of the scale.
92
+ attr_accessor :style
93
+ # Shows the scale labels if +true+.
94
+ attr_accessor :show_labels
95
+ # Defines the label options.
96
+ attr_accessor :label
97
+ end
98
+
99
+ # This is any line that will be drawn; this is a combination of the line
100
+ # style (which must be a PDF::Writer::StrokeStyle object) and a color.
101
+ class Marker
102
+ def initialize
103
+ yield self if block_given?
104
+ end
105
+
106
+ # The stroke style of the marker.
107
+ attr_accessor :style
108
+ # The stroke color of the marker.
109
+ attr_accessor :color
110
+ end
111
+
112
+ def initialize
113
+ @data = []
114
+
115
+ @scale = Scale.new do |scale|
116
+ scale.range = 0..6
117
+ scale.step = 1
118
+ scale.style = PDF::Writer::StrokeStyle.new(0.25)
119
+ scale.show_labels = false
120
+ scale.label = Label.new do |label|
121
+ label.text_size = 8
122
+ label.text_color = Color::RGB::Black
123
+ label.pad = 2
124
+ label.decimal_precision = 1
125
+ end
126
+ end
127
+ @leading_gap = 10
128
+ @show_labels = true
129
+ @label = Label.new do |label|
130
+ label.height = 25
131
+ label.background_color = Color::RGB::Black
132
+ label.text_color = Color::RGB::White
133
+ label.text_size = 12
134
+ end
135
+
136
+ @outer_borders = Marker.new do |marker|
137
+ marker.style = PDF::Writer::StrokeStyle.new(1.5)
138
+ marker.color = Color::RGB::Black
139
+ end
140
+ @inner_borders = nil
141
+
142
+ @dot = Marker.new do |marker|
143
+ marker.style = PDF::Writer::StrokeStyle.new(5)
144
+ marker.color = Color::RGB::Black
145
+ end
146
+ @bar = Marker.new do |marker|
147
+ marker.style = PDF::Writer::StrokeStyle.new(0.5)
148
+ marker.color = Color::RGB::Black
149
+ end
150
+ @upper_crossbar = Marker.new do |marker|
151
+ marker.style = PDF::Writer::StrokeStyle.new(1)
152
+ marker.color = Color::RGB::Black
153
+ end
154
+ @lower_crossbar = Marker.new do |marker|
155
+ marker.style = PDF::Writer::StrokeStyle.new(1)
156
+ marker.color = Color::RGB::Black
157
+ end
158
+
159
+ @height = 200
160
+ @maximum_width = 500
161
+ @datapoint_width = 35
162
+
163
+ yield self if block_given?
164
+ end
165
+
166
+ # The data used to generate the standard deviation chart. This is an
167
+ # array of DataPoint objects, each containing a +label+, an +average+,
168
+ # and the +stddev+ (standard deviation) from that average.
169
+ attr_reader :data
170
+ # The scale of the chart. All values must be within this range. This
171
+ # will be a Scale object. It defaults to a scale of 0..6 with a step of
172
+ # 1.
173
+ attr_accessor :scale
174
+
175
+ # The minimum gap between the chart and the bottom of the page, in
176
+ # PDF user units.
177
+ attr_accessor :leading_gap
178
+
179
+ # This will be +true+ if labels are to be displayed.
180
+ attr_accessor :show_labels
181
+ # The label style of the labels if they are displayed. This must be a
182
+ # PDF::Charts::StdDev::Label object.
183
+ attr_accessor :label
184
+
185
+ # The inner border style. If +nil+, no inner borders are drawn. This is
186
+ # a PDF::Charts::StdDev::Marker object.
187
+ attr_accessor :inner_borders
188
+ # The outer border style. If +nil+, no inner borders are drawn. This is
189
+ # a PDF::Charts::StdDev::Marker object.
190
+ attr_accessor :outer_borders
191
+
192
+ # The dot marker. A filled circle will be drawn with this information.
193
+ # If +nil+, the dot will not be drawn. This is a
194
+ # PDF::Charts::StdDev::Marker object.
195
+ attr_accessor :dot
196
+ # The standard deviation bar. A line will be drawn through the dot
197
+ # marker (if drawn) from the upper to lower standard deviation.
198
+ # If +nil+, the line will not be drawn. This is a
199
+ # PDF::Charts::StdDev::Marker object.
200
+ attr_accessor :bar
201
+ # The upper crossbar. A line will be drawn across the top of the
202
+ # standard deviation bar to the width of the dot marker. If #dot is
203
+ # +nil+, then the line will be twice as wide as it is thick. If +nil+,
204
+ # the upper crossbar will not be drawn. This is a
205
+ # PDF::Charts::StdDev::Marker object.
206
+ attr_accessor :upper_crossbar
207
+ # The lower crossbar. A line will be drawn across the bottom of the
208
+ # standard deviation bar to the width of the dot marker. If #dot is
209
+ # +nil+, then the line will be twice as wide as it is thick. If +nil+,
210
+ # the lower crossbar will not be drawn. This is a
211
+ # PDF::Charts::StdDev::Marker object.
212
+ attr_accessor :lower_crossbar
213
+
214
+ # The height of the chart in PDF user units. Default 200 units.
215
+ attr_accessor :height
216
+ # The maximum width of the chart in PDF user units. Default 500 units.
217
+ attr_accessor :maximum_width
218
+ # The width of a single datapoint.
219
+ attr_accessor :datapoint_width
220
+
221
+ # Draw the standard deviation chart on the supplied PDF document.
222
+ def render_on(pdf)
223
+ raise TypeError, PDF::Writer::Lang[:charts_stddev_data_empty] if @data.empty?
224
+ data = @data.dup
225
+ leftover_data = nil
226
+
227
+ loop do
228
+ # Set up the scale information.
229
+ scale = []
230
+
231
+ (@scale.first + @scale.step).step(@scale.last, @scale.step) do |ii|
232
+ scale << "%01.#{@scale.label.decimal_precision}f" % ii
233
+ end
234
+
235
+ scales = PDF::Writer::OHash.new
236
+ scale.each_with_index do |gg, ii|
237
+ scales[ii] = OpenStruct.new
238
+ scales[ii].value = gg
239
+ end
240
+
241
+ # Add information about the scales' locations to the scales
242
+ # hash. Note that the count is one smaller than it should be, so we're
243
+ # increasing it. The first scale is the bottom of the chart.
244
+ scale_count = scale.size + 1
245
+
246
+ label_height_adjuster = 0
247
+ label_height_adjuster = @label.height if @show_labels
248
+
249
+ chart_area_height = @height - label_height_adjuster
250
+ scale_height = chart_area_height / scale_count.to_f
251
+
252
+ scales.each_key do |index|
253
+ this_height = scale_height * (index + 1) + @label.height
254
+ scales[index].line_height = this_height
255
+ if @scale.show_labels
256
+ scales[index].label_height = this_height -
257
+ (@scale.label.text_size / 3.0)
258
+ end
259
+ end
260
+
261
+ # How many sections do we need in this chart, and how wide will it
262
+ # need to be?
263
+ chunk_width = @datapoint_width
264
+ num_chunks = data.size
265
+ widest_scale_label = 0
266
+
267
+ if @scale.show_labels
268
+ scales.each_value do |scale|
269
+ this_width = pdf.text_width(scale.value, @scale.label.text_size)
270
+ widest_scale_label = this_width if this_width > widest_scale_label
271
+ end
272
+ end
273
+
274
+ chart_width = chunk_width * num_chunks
275
+ total_width = chart_width + widest_scale_label + @scale.label.pad
276
+
277
+ # What happens if the projected width of the chart is too big?
278
+ # Figure out how to break the chart in pieces.
279
+ if total_width > @maximum_width
280
+ max_column_count = 0
281
+ base_width = widest_scale_label + @scale.label.pad
282
+ (1..(num_chunks + 1)).each do |ii|
283
+ if (base_width + (ii * chunk_width)) > @maximum_width
284
+ break
285
+ else
286
+ max_column_count += 1
287
+ end
288
+ end
289
+
290
+ leftover_data = data.slice!(max_column_count, -1)
291
+
292
+ num_chunks = data.size
293
+ chart_width = chunk_width * num_chunks
294
+ total_width = chart_width + widest_scale_label + @scale.label.pad
295
+ end
296
+
297
+ chart_y = pdf.y - @height + @leading_gap
298
+ chart_y += (@outer_borders.style.width * 2.0) if @outer_borders
299
+
300
+ if chart_y < pdf.bottom_margin
301
+ pdf.start_new_page
302
+ chart_y = pdf.y - @height
303
+ chart_y += (@outer_borders.style.width * 2.0) if @outer_borders
304
+ end
305
+
306
+ chart_x = pdf.absolute_x_middle - (total_width / 2.0) + widest_scale_label
307
+
308
+ # Add labels, if needed.
309
+ if @show_labels
310
+ pdf.save_state
311
+ pdf.fill_color! @label.background_color
312
+ # Draw a rectangle for each label
313
+ num_chunks.times do |ii|
314
+ this_x = chart_x + ii * chunk_width
315
+ pdf.rectangle(this_x, chart_y, chunk_width, @label.height).fill
316
+ end
317
+
318
+ # Add a border above the label rectangle.
319
+ if @outer_borders
320
+ pdf.stroke_style! @outer_borders.style
321
+ pdf.line(chart_x, chart_y + @label.height, chart_x + chart_width, chart_y + @label.height).stroke
322
+ end
323
+ pdf.fill_color! @label.text_color
324
+
325
+ data.each_with_index do |datum, ii|
326
+ label = datum.label.to_s
327
+ label_width = pdf.text_width(label, @label.text_size)
328
+ this_x = chart_x + (ii * chunk_width) + (chunk_width / 2.0) - (label_width / 2.0)
329
+ this_y = chart_y + (@label.height / 2.0) - (@label.text_size / 3.0)
330
+ pdf.add_text(this_x, this_y, label, @label.text_size)
331
+ end
332
+ pdf.restore_state
333
+ end
334
+
335
+ if @inner_borders
336
+ pdf.save_state
337
+ pdf.stroke_color! @inner_borders.color
338
+ pdf.stroke_style! @inner_borders.style
339
+ (num_chunks - 1).times do |ii|
340
+ this_x = chart_x + (ii * chunk_width) + chunk_width
341
+ pdf.line(this_x, chart_y, this_x, chart_y + @height).stroke
342
+ end
343
+ pdf.restore_state
344
+ end
345
+
346
+ pdf.save_state
347
+ if @outer_borders
348
+ pdf.stroke_color! @outer_borders.color
349
+ pdf.stroke_style! @outer_borders.style
350
+ pdf.rectangle(chart_x, chart_y, chart_width, @height).stroke
351
+ end
352
+
353
+ if @scale.style
354
+ pdf.save_state
355
+ pdf.stroke_style! @scale.style
356
+ scales.each_value do |scale|
357
+ this_y = chart_y + scale.line_height
358
+ pdf.line(chart_x, this_y, chart_x + chart_width, this_y).stroke
359
+ end
360
+ pdf.restore_state
361
+ end
362
+
363
+ if @scale.show_labels
364
+ pdf.save_state
365
+ scales.each_value do |scale|
366
+ this_y = chart_y + scale.label_height
367
+ label_width = pdf.text_width(scale.value, @scale.label.text_size)
368
+ this_x = chart_x - label_width - @scale.label.pad
369
+ pdf.fill_color! @scale.label.text_color
370
+ pdf.add_text(this_x, this_y, scale.value, @scale.label.text_size)
371
+ end
372
+ pdf.restore_state
373
+ end
374
+
375
+ data.each_with_index do |datum, ii|
376
+ avg_height = datum.average * scale_height
377
+ stddev_height = datum.stddev * scale_height
378
+ this_y = chart_y + label_height_adjuster + avg_height
379
+ this_x = chart_x + (ii * chunk_width) + (chunk_width / 2.0)
380
+ line_top_y = this_y + (stddev_height / 2.0)
381
+ line_bot_y = this_y - (stddev_height / 2.0)
382
+
383
+ # Plot the dot
384
+ if @dot
385
+ pdf.stroke_color! @dot.color
386
+ pdf.stroke_style! @dot.style
387
+ pdf.circle_at(this_x, this_y, (@dot.style.width / 2.0)).fill
388
+ end
389
+
390
+ # Plot the bar
391
+ if @bar
392
+ pdf.stroke_color! @bar.color
393
+ pdf.stroke_style! @bar.style
394
+ pdf.line(this_x, line_top_y, this_x, line_bot_y).stroke
395
+ end
396
+
397
+ # Plot the crossbars
398
+ if @upper_crossbar
399
+ if @dot
400
+ cb_width = @dot.style.width
401
+ else
402
+ cb_width = @upper_crossbar.style.width
403
+ end
404
+ pdf.stroke_color! @upper_crossbar.color
405
+ pdf.stroke_style! @upper_crossbar.style
406
+ pdf.line(this_x - cb_width, line_top_y, this_x + cb_width, line_top_y).stroke
407
+ end
408
+ if @lower_crossbar
409
+ if @dot
410
+ cb_width = @dot.style.width
411
+ else
412
+ cb_width = @lower_crossbar.style.width
413
+ end
414
+ pdf.stroke_color! @lower_crossbar.color
415
+ pdf.stroke_style! @lower_crossbar.style
416
+
417
+ pdf.line(this_x - cb_width, line_bot_y, this_x + cb_width, line_bot_y).stroke
418
+ end
419
+ end
420
+
421
+ pdf.restore_state
422
+
423
+ pdf.y = chart_y
424
+
425
+ break if leftover_data.nil?
426
+
427
+ data = leftover_data
428
+ leftover_data = nil
429
+ end
430
+
431
+ pdf.y
432
+ end
433
+ end