rmagick-windows 2.16.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (393) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +14 -0
  3. data/.gitignore +23 -0
  4. data/.hound.yml +2 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +340 -0
  7. data/.simplecov +27 -0
  8. data/.travis.yml +60 -0
  9. data/CHANGELOG.md +915 -0
  10. data/CODE_OF_CONDUCT.md +13 -0
  11. data/CONTRIBUTING.md +50 -0
  12. data/Doxyfile +1514 -0
  13. data/Gemfile +10 -0
  14. data/LICENSE +20 -0
  15. data/README.textile +257 -0
  16. data/Rakefile +188 -0
  17. data/before_install_linux.sh +32 -0
  18. data/before_install_osx.sh +2 -0
  19. data/deprecated/RMagick.rb +6 -0
  20. data/doc/.cvsignore +1 -0
  21. data/doc/comtasks.html +287 -0
  22. data/doc/constants.html +1581 -0
  23. data/doc/css/doc.css +299 -0
  24. data/doc/css/popup.css +34 -0
  25. data/doc/css/ref.css +67 -0
  26. data/doc/draw.html +3272 -0
  27. data/doc/ex/InitialCoords.rb +22 -0
  28. data/doc/ex/NewCoordSys.rb +30 -0
  29. data/doc/ex/OrigCoordSys.rb +16 -0
  30. data/doc/ex/PreserveAspectRatio.rb +204 -0
  31. data/doc/ex/RotateScale.rb +36 -0
  32. data/doc/ex/Skew.rb +38 -0
  33. data/doc/ex/Use01.rb +15 -0
  34. data/doc/ex/Use02.rb +20 -0
  35. data/doc/ex/Use03.rb +16 -0
  36. data/doc/ex/ViewBox.rb +31 -0
  37. data/doc/ex/adaptive_threshold.rb +9 -0
  38. data/doc/ex/add_noise.rb +16 -0
  39. data/doc/ex/affine.rb +48 -0
  40. data/doc/ex/affine_transform.rb +20 -0
  41. data/doc/ex/arc.rb +49 -0
  42. data/doc/ex/arcpath.rb +32 -0
  43. data/doc/ex/arcs01.rb +28 -0
  44. data/doc/ex/arcs02.rb +59 -0
  45. data/doc/ex/average.rb +15 -0
  46. data/doc/ex/axes.rb +64 -0
  47. data/doc/ex/baseline_shift01.rb +17 -0
  48. data/doc/ex/bilevel_channel.rb +8 -0
  49. data/doc/ex/blur_image.rb +12 -0
  50. data/doc/ex/border.rb +10 -0
  51. data/doc/ex/bounding_box.rb +42 -0
  52. data/doc/ex/cbezier1.rb +41 -0
  53. data/doc/ex/cbezier2.rb +41 -0
  54. data/doc/ex/cbezier3.rb +41 -0
  55. data/doc/ex/cbezier4.rb +42 -0
  56. data/doc/ex/cbezier5.rb +42 -0
  57. data/doc/ex/cbezier6.rb +53 -0
  58. data/doc/ex/channel.rb +25 -0
  59. data/doc/ex/charcoal.rb +12 -0
  60. data/doc/ex/chop.rb +29 -0
  61. data/doc/ex/circle.rb +33 -0
  62. data/doc/ex/circle01.rb +16 -0
  63. data/doc/ex/clip_path.rb +60 -0
  64. data/doc/ex/coalesce.rb +57 -0
  65. data/doc/ex/color_fill_to_border.rb +29 -0
  66. data/doc/ex/color_floodfill.rb +28 -0
  67. data/doc/ex/color_histogram.rb +47 -0
  68. data/doc/ex/color_reset.rb +11 -0
  69. data/doc/ex/colorize.rb +16 -0
  70. data/doc/ex/colors.rb +64 -0
  71. data/doc/ex/compose_mask.rb +22 -0
  72. data/doc/ex/composite.rb +133 -0
  73. data/doc/ex/composite_layers.rb +53 -0
  74. data/doc/ex/composite_tiled.rb +21 -0
  75. data/doc/ex/contrast.rb +36 -0
  76. data/doc/ex/crop.rb +31 -0
  77. data/doc/ex/crop_with_gravity.rb +42 -0
  78. data/doc/ex/cubic01.rb +43 -0
  79. data/doc/ex/cubic02.rb +91 -0
  80. data/doc/ex/cycle_colormap.rb +21 -0
  81. data/doc/ex/dissolve.rb +12 -0
  82. data/doc/ex/drawcomp.rb +42 -0
  83. data/doc/ex/drop_shadow.rb +60 -0
  84. data/doc/ex/edge.rb +11 -0
  85. data/doc/ex/ellipse.rb +45 -0
  86. data/doc/ex/ellipse01.rb +21 -0
  87. data/doc/ex/emboss.rb +11 -0
  88. data/doc/ex/enhance.rb +28 -0
  89. data/doc/ex/equalize.rb +11 -0
  90. data/doc/ex/evenodd.rb +42 -0
  91. data/doc/ex/fill_pattern.rb +23 -0
  92. data/doc/ex/flatten_images.rb +36 -0
  93. data/doc/ex/flip.rb +11 -0
  94. data/doc/ex/flop.rb +11 -0
  95. data/doc/ex/font_styles.rb +32 -0
  96. data/doc/ex/fonts.rb +20 -0
  97. data/doc/ex/frame.rb +12 -0
  98. data/doc/ex/gaussian_blur.rb +11 -0
  99. data/doc/ex/get_multiline_type_metrics.rb +41 -0
  100. data/doc/ex/get_pixels.rb +47 -0
  101. data/doc/ex/get_type_metrics.rb +141 -0
  102. data/doc/ex/gradientfill.rb +27 -0
  103. data/doc/ex/grav.rb +45 -0
  104. data/doc/ex/gravity.rb +80 -0
  105. data/doc/ex/group.rb +26 -0
  106. data/doc/ex/hatchfill.rb +27 -0
  107. data/doc/ex/image.rb +44 -0
  108. data/doc/ex/images/Apple.miff +0 -0
  109. data/doc/ex/images/Ballerina.jpg +0 -0
  110. data/doc/ex/images/Ballerina3.jpg +0 -0
  111. data/doc/ex/images/Button_0.gif +0 -0
  112. data/doc/ex/images/Button_1.gif +0 -0
  113. data/doc/ex/images/Button_2.gif +0 -0
  114. data/doc/ex/images/Button_3.gif +0 -0
  115. data/doc/ex/images/Button_4.gif +0 -0
  116. data/doc/ex/images/Button_5.gif +0 -0
  117. data/doc/ex/images/Button_6.gif +0 -0
  118. data/doc/ex/images/Button_7.gif +0 -0
  119. data/doc/ex/images/Button_8.gif +0 -0
  120. data/doc/ex/images/Button_9.gif +0 -0
  121. data/doc/ex/images/Button_A.gif +0 -0
  122. data/doc/ex/images/Button_B.gif +0 -0
  123. data/doc/ex/images/Button_C.gif +0 -0
  124. data/doc/ex/images/Button_D.gif +0 -0
  125. data/doc/ex/images/Button_E.gif +0 -0
  126. data/doc/ex/images/Button_F.gif +0 -0
  127. data/doc/ex/images/Button_G.gif +0 -0
  128. data/doc/ex/images/Button_H.gif +0 -0
  129. data/doc/ex/images/Button_I.gif +0 -0
  130. data/doc/ex/images/Button_J.gif +0 -0
  131. data/doc/ex/images/Button_K.gif +0 -0
  132. data/doc/ex/images/Button_L.gif +0 -0
  133. data/doc/ex/images/Button_M.gif +0 -0
  134. data/doc/ex/images/Button_N.gif +0 -0
  135. data/doc/ex/images/Button_O.gif +0 -0
  136. data/doc/ex/images/Button_P.gif +0 -0
  137. data/doc/ex/images/Button_Q.gif +0 -0
  138. data/doc/ex/images/Button_R.gif +0 -0
  139. data/doc/ex/images/Button_S.gif +0 -0
  140. data/doc/ex/images/Button_T.gif +0 -0
  141. data/doc/ex/images/Button_U.gif +0 -0
  142. data/doc/ex/images/Button_V.gif +0 -0
  143. data/doc/ex/images/Button_W.gif +0 -0
  144. data/doc/ex/images/Button_X.gif +0 -0
  145. data/doc/ex/images/Button_Y.gif +0 -0
  146. data/doc/ex/images/Button_Z.gif +0 -0
  147. data/doc/ex/images/Cheetah.jpg +0 -0
  148. data/doc/ex/images/Coffee.wmf +0 -0
  149. data/doc/ex/images/Flower_Hat.jpg +0 -0
  150. data/doc/ex/images/Gold_Statue.jpg +0 -0
  151. data/doc/ex/images/Hot_Air_Balloons.jpg +0 -0
  152. data/doc/ex/images/Hot_Air_Balloons_H.jpg +0 -0
  153. data/doc/ex/images/Leaf.miff +0 -0
  154. data/doc/ex/images/No.wmf +0 -0
  155. data/doc/ex/images/Polynesia.jpg +0 -0
  156. data/doc/ex/images/Red_Rocks.jpg +0 -0
  157. data/doc/ex/images/Rocks_On_Beach.miff +0 -0
  158. data/doc/ex/images/Shorts.jpg +0 -0
  159. data/doc/ex/images/Snake.wmf +0 -0
  160. data/doc/ex/images/Violin.jpg +0 -0
  161. data/doc/ex/images/Yellow_Rose.miff +0 -0
  162. data/doc/ex/images/big-duck.gif +0 -0
  163. data/doc/ex/images/duck.gif +0 -0
  164. data/doc/ex/images/duck0.gif +0 -0
  165. data/doc/ex/images/duck1.gif +0 -0
  166. data/doc/ex/images/duck10.gif +0 -0
  167. data/doc/ex/images/duck11.gif +0 -0
  168. data/doc/ex/images/duck12.gif +0 -0
  169. data/doc/ex/images/duck13.gif +0 -0
  170. data/doc/ex/images/duck14.gif +0 -0
  171. data/doc/ex/images/duck15.gif +0 -0
  172. data/doc/ex/images/duck2.gif +0 -0
  173. data/doc/ex/images/duck3.gif +0 -0
  174. data/doc/ex/images/duck4.gif +0 -0
  175. data/doc/ex/images/duck5.gif +0 -0
  176. data/doc/ex/images/duck6.gif +0 -0
  177. data/doc/ex/images/duck7.gif +0 -0
  178. data/doc/ex/images/duck8.gif +0 -0
  179. data/doc/ex/images/duck9.gif +0 -0
  180. data/doc/ex/images/graydient230x6.gif +0 -0
  181. data/doc/ex/images/image_with_profile.jpg +0 -0
  182. data/doc/ex/images/logo400x83.gif +0 -0
  183. data/doc/ex/images/model.miff +0 -0
  184. data/doc/ex/images/notimplemented.gif +0 -0
  185. data/doc/ex/images/smile.miff +0 -0
  186. data/doc/ex/images/spin.gif +0 -0
  187. data/doc/ex/implode.rb +34 -0
  188. data/doc/ex/level.rb +11 -0
  189. data/doc/ex/level_colors.rb +11 -0
  190. data/doc/ex/line.rb +41 -0
  191. data/doc/ex/line01.rb +21 -0
  192. data/doc/ex/mask.rb +35 -0
  193. data/doc/ex/matte_fill_to_border.rb +39 -0
  194. data/doc/ex/matte_floodfill.rb +32 -0
  195. data/doc/ex/matte_replace.rb +39 -0
  196. data/doc/ex/median_filter.rb +28 -0
  197. data/doc/ex/modulate.rb +11 -0
  198. data/doc/ex/mono.rb +23 -0
  199. data/doc/ex/morph.rb +25 -0
  200. data/doc/ex/mosaic.rb +35 -0
  201. data/doc/ex/motion_blur.rb +11 -0
  202. data/doc/ex/negate.rb +11 -0
  203. data/doc/ex/negate_channel.rb +9 -0
  204. data/doc/ex/nested_rvg.rb +21 -0
  205. data/doc/ex/nonzero.rb +42 -0
  206. data/doc/ex/normalize.rb +11 -0
  207. data/doc/ex/oil_paint.rb +11 -0
  208. data/doc/ex/opacity.rb +37 -0
  209. data/doc/ex/ordered_dither.rb +11 -0
  210. data/doc/ex/path.rb +63 -0
  211. data/doc/ex/pattern1.rb +25 -0
  212. data/doc/ex/pattern2.rb +26 -0
  213. data/doc/ex/polaroid.rb +27 -0
  214. data/doc/ex/polygon.rb +23 -0
  215. data/doc/ex/polygon01.rb +21 -0
  216. data/doc/ex/polyline.rb +22 -0
  217. data/doc/ex/polyline01.rb +21 -0
  218. data/doc/ex/posterize.rb +8 -0
  219. data/doc/ex/preview.rb +8 -0
  220. data/doc/ex/qbezierpath.rb +52 -0
  221. data/doc/ex/quad01.rb +34 -0
  222. data/doc/ex/quantize-m.rb +25 -0
  223. data/doc/ex/radial_blur.rb +9 -0
  224. data/doc/ex/raise.rb +8 -0
  225. data/doc/ex/random_threshold_channel.rb +13 -0
  226. data/doc/ex/rect01.rb +14 -0
  227. data/doc/ex/rect02.rb +20 -0
  228. data/doc/ex/rectangle.rb +34 -0
  229. data/doc/ex/reduce_noise.rb +28 -0
  230. data/doc/ex/remap.rb +11 -0
  231. data/doc/ex/remap_images.rb +19 -0
  232. data/doc/ex/resize_to_fill.rb +8 -0
  233. data/doc/ex/resize_to_fit.rb +8 -0
  234. data/doc/ex/roll.rb +9 -0
  235. data/doc/ex/rotate.rb +44 -0
  236. data/doc/ex/rotate_f.rb +14 -0
  237. data/doc/ex/roundrect.rb +33 -0
  238. data/doc/ex/rubyname.rb +30 -0
  239. data/doc/ex/rvg_clippath.rb +12 -0
  240. data/doc/ex/rvg_linecap.rb +42 -0
  241. data/doc/ex/rvg_linejoin.rb +40 -0
  242. data/doc/ex/rvg_opacity.rb +18 -0
  243. data/doc/ex/rvg_pattern.rb +26 -0
  244. data/doc/ex/rvg_stroke_dasharray.rb +11 -0
  245. data/doc/ex/segment.rb +11 -0
  246. data/doc/ex/sepiatone.rb +7 -0
  247. data/doc/ex/shade.rb +11 -0
  248. data/doc/ex/shadow.rb +30 -0
  249. data/doc/ex/shave.rb +15 -0
  250. data/doc/ex/shear.rb +10 -0
  251. data/doc/ex/sketch.rb +17 -0
  252. data/doc/ex/skewx.rb +51 -0
  253. data/doc/ex/skewy.rb +47 -0
  254. data/doc/ex/smile.rb +125 -0
  255. data/doc/ex/solarize.rb +11 -0
  256. data/doc/ex/sparse_color.rb +54 -0
  257. data/doc/ex/splice.rb +8 -0
  258. data/doc/ex/spread.rb +11 -0
  259. data/doc/ex/stegano.rb +55 -0
  260. data/doc/ex/stroke_dasharray.rb +42 -0
  261. data/doc/ex/stroke_fill.rb +10 -0
  262. data/doc/ex/stroke_linecap.rb +44 -0
  263. data/doc/ex/stroke_linejoin.rb +48 -0
  264. data/doc/ex/stroke_width.rb +49 -0
  265. data/doc/ex/swirl.rb +17 -0
  266. data/doc/ex/text.rb +37 -0
  267. data/doc/ex/text01.rb +16 -0
  268. data/doc/ex/text_align.rb +36 -0
  269. data/doc/ex/text_antialias.rb +37 -0
  270. data/doc/ex/text_styles.rb +19 -0
  271. data/doc/ex/text_undercolor.rb +28 -0
  272. data/doc/ex/texture_fill_to_border.rb +34 -0
  273. data/doc/ex/texture_floodfill.rb +32 -0
  274. data/doc/ex/texturefill.rb +24 -0
  275. data/doc/ex/threshold.rb +13 -0
  276. data/doc/ex/to_blob.rb +13 -0
  277. data/doc/ex/translate.rb +39 -0
  278. data/doc/ex/transparent.rb +38 -0
  279. data/doc/ex/transpose.rb +9 -0
  280. data/doc/ex/transverse.rb +9 -0
  281. data/doc/ex/tref01.rb +24 -0
  282. data/doc/ex/triangle01.rb +15 -0
  283. data/doc/ex/trim.rb +23 -0
  284. data/doc/ex/tspan01.rb +17 -0
  285. data/doc/ex/tspan02.rb +17 -0
  286. data/doc/ex/tspan03.rb +19 -0
  287. data/doc/ex/unsharp_mask.rb +28 -0
  288. data/doc/ex/viewex.rb +33 -0
  289. data/doc/ex/vignette.rb +12 -0
  290. data/doc/ex/watermark.rb +27 -0
  291. data/doc/ex/wave.rb +9 -0
  292. data/doc/ex/wet_floor.rb +58 -0
  293. data/doc/ex/writing_mode01.rb +26 -0
  294. data/doc/ex/writing_mode02.rb +26 -0
  295. data/doc/ilist.html +2056 -0
  296. data/doc/image1.html +4680 -0
  297. data/doc/image2.html +3665 -0
  298. data/doc/image3.html +4522 -0
  299. data/doc/imageattrs.html +1638 -0
  300. data/doc/imusage.html +514 -0
  301. data/doc/index.html +416 -0
  302. data/doc/info.html +1499 -0
  303. data/doc/magick.html +565 -0
  304. data/doc/optequiv.html +2435 -0
  305. data/doc/rvg.html +975 -0
  306. data/doc/rvgclip.html +248 -0
  307. data/doc/rvggroup.html +305 -0
  308. data/doc/rvgimage.html +289 -0
  309. data/doc/rvgpattern.html +475 -0
  310. data/doc/rvgshape.html +406 -0
  311. data/doc/rvgstyle.html +270 -0
  312. data/doc/rvgtext.html +465 -0
  313. data/doc/rvgtspan.html +238 -0
  314. data/doc/rvgtut.html +530 -0
  315. data/doc/rvguse.html +145 -0
  316. data/doc/rvgxform.html +294 -0
  317. data/doc/scripts/doc.js +22 -0
  318. data/doc/scripts/stripeTables.js +23 -0
  319. data/doc/struct.html +1339 -0
  320. data/doc/usage.html +1621 -0
  321. data/examples/constitute.rb +7 -0
  322. data/examples/crop_with_gravity.rb +42 -0
  323. data/examples/demo.rb +324 -0
  324. data/examples/describe.rb +43 -0
  325. data/examples/find_similar_region.rb +34 -0
  326. data/examples/histogram.rb +321 -0
  327. data/examples/identify.rb +185 -0
  328. data/examples/image_opacity.rb +29 -0
  329. data/examples/import_export.rb +31 -0
  330. data/examples/pattern_fill.rb +38 -0
  331. data/examples/rotating_text.rb +44 -0
  332. data/examples/spinner.rb +49 -0
  333. data/examples/thumbnail.rb +64 -0
  334. data/examples/vignette.rb +78 -0
  335. data/ext/RMagick/extconf.rb +548 -0
  336. data/ext/RMagick/rmagick.c +401 -0
  337. data/ext/RMagick/rmagick.h +1287 -0
  338. data/ext/RMagick/rmdraw.c +2022 -0
  339. data/ext/RMagick/rmenum.c +1235 -0
  340. data/ext/RMagick/rmfill.c +720 -0
  341. data/ext/RMagick/rmilist.c +1270 -0
  342. data/ext/RMagick/rmimage.c +15427 -0
  343. data/ext/RMagick/rminfo.c +2590 -0
  344. data/ext/RMagick/rmmain.c +1741 -0
  345. data/ext/RMagick/rmmontage.c +519 -0
  346. data/ext/RMagick/rmpixel.c +1114 -0
  347. data/ext/RMagick/rmstruct.c +1124 -0
  348. data/ext/RMagick/rmutil.c +1754 -0
  349. data/lib/rmagick.rb +1 -0
  350. data/lib/rmagick/version.rb +6 -0
  351. data/lib/rmagick_internal.rb +1947 -0
  352. data/lib/rvg/clippath.rb +45 -0
  353. data/lib/rvg/container.rb +122 -0
  354. data/lib/rvg/deep_equal.rb +52 -0
  355. data/lib/rvg/describable.rb +47 -0
  356. data/lib/rvg/embellishable.rb +391 -0
  357. data/lib/rvg/misc.rb +723 -0
  358. data/lib/rvg/paint.rb +50 -0
  359. data/lib/rvg/pathdata.rb +126 -0
  360. data/lib/rvg/rvg.rb +283 -0
  361. data/lib/rvg/stretchable.rb +165 -0
  362. data/lib/rvg/stylable.rb +116 -0
  363. data/lib/rvg/text.rb +172 -0
  364. data/lib/rvg/transformable.rb +126 -0
  365. data/lib/rvg/units.rb +63 -0
  366. data/rmagick.gemspec +46 -0
  367. data/spec/rmagick/ImageList1_spec.rb +24 -0
  368. data/spec/rmagick/draw_spec.rb +156 -0
  369. data/spec/rmagick/image/blue_shift_spec.rb +16 -0
  370. data/spec/rmagick/image/composite_spec.rb +140 -0
  371. data/spec/rmagick/image/constitute_spec.rb +15 -0
  372. data/spec/rmagick/image/dispatch_spec.rb +18 -0
  373. data/spec/rmagick/image/from_blob_spec.rb +14 -0
  374. data/spec/rmagick/image/ping_spec.rb +14 -0
  375. data/spec/rmagick/image/properties_spec.rb +29 -0
  376. data/spec/spec_helper.rb +4 -0
  377. data/test/Image1.rb +565 -0
  378. data/test/Image2.rb +1304 -0
  379. data/test/Image3.rb +1030 -0
  380. data/test/ImageList1.rb +806 -0
  381. data/test/ImageList2.rb +385 -0
  382. data/test/Image_attributes.rb +697 -0
  383. data/test/Import_Export.rb +121 -0
  384. data/test/Info.rb +345 -0
  385. data/test/Magick.rb +321 -0
  386. data/test/Pixel.rb +116 -0
  387. data/test/Preview.rb +57 -0
  388. data/test/cmyk.icm +0 -0
  389. data/test/srgb.icm +0 -0
  390. data/test/test_all_basic.rb +38 -0
  391. data/test/tmpnam_test.rb +50 -0
  392. data/wercker.yml +10 -0
  393. metadata +509 -0
data/lib/rvg/misc.rb ADDED
@@ -0,0 +1,723 @@
1
+ # $Id: misc.rb,v 1.17 2010/03/21 01:43:01 baror Exp $
2
+ # Copyright (C) 2009 Timothy P. Hunter
3
+ module Magick
4
+ class RVG
5
+ # This is a standard deep_copy method that is used in most classes.
6
+ # Thanks to Robert Klemme.
7
+ module Duplicatable
8
+ def deep_copy(h = {})
9
+ # Prevent recursion. If we reach the
10
+ # object we started with, stop copying.
11
+ copy = h[__id__]
12
+ unless copy
13
+ h[__id__] = copy = self.class.allocate
14
+ ivars = instance_variables
15
+ ivars.each do |ivar|
16
+ ivalue = instance_variable_get(ivar)
17
+ cvalue = case
18
+ when NilClass === ivalue, Symbol === ivalue, Float === ivalue,
19
+ Fixnum === ivalue, FalseClass === ivalue, TrueClass === ivalue
20
+ ivalue
21
+ when ivalue.respond_to?(:deep_copy)
22
+ ivalue.deep_copy(h)
23
+ when ivalue.respond_to?(:dup)
24
+ ivalue.dup
25
+ else
26
+ ivalue
27
+ end
28
+ copy.instance_variable_set(ivar, cvalue)
29
+ end
30
+ copy.freeze if frozen?
31
+ end
32
+ copy
33
+ end
34
+ end # module Duplicatable
35
+
36
+ # Convert an array of method arguments to Float objects. If any
37
+ # cannot be converted, raise ArgumentError and issue a message.
38
+ def self.fmsg(*args)
39
+ "at least one argument cannot be converted to Float (got #{args.collect {|a| a.class}.join(', ')})"
40
+ end
41
+
42
+ def self.convert_to_float(*args)
43
+ allow_nil = false
44
+ if args.last == :allow_nil
45
+ allow_nil = true
46
+ args.pop
47
+ end
48
+ begin
49
+ fargs = args.collect { |a| (allow_nil && a.nil?) ? a : Float(a) }
50
+ rescue ArgumentError, TypeError
51
+ raise ArgumentError, fmsg(*args)
52
+ end
53
+ fargs
54
+ end
55
+
56
+ def self.convert_one_to_float(arg)
57
+ begin
58
+ farg = Float(arg)
59
+ rescue ArgumentError, TypeError
60
+ raise ArgumentError, "argument cannot be converted to Float (got #{arg.class})"
61
+ end
62
+ farg
63
+ end
64
+ end # class RVG
65
+ end # module Magick
66
+
67
+ module Magick
68
+ class RVG
69
+ class Utility
70
+ class TextStrategy
71
+ def initialize(context)
72
+ @ctx = context
73
+ @ctx.shadow.affine = @ctx.text_attrs.affine
74
+ end
75
+
76
+ def enquote(text)
77
+ if text.length > 2 && /\A(?:\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})\z/.match(text)
78
+ return text
79
+ elsif !text['\'']
80
+ text = '\''+text+'\''
81
+ return text
82
+ elsif !text['"']
83
+ text = '"'+text+'"'
84
+ return text
85
+ elsif !(text['{'] || text['}'])
86
+ text = '{'+text+'}'
87
+ return text
88
+ end
89
+
90
+ # escape existing braces, surround with braces
91
+ text.gsub!(/[}]/) { |b| '\\' + b }
92
+ '{' + text + '}'
93
+ end
94
+
95
+ def glyph_metrics(glyph_orientation, glyph)
96
+ gm = @ctx.shadow.get_type_metrics('a' + glyph + 'a')
97
+ gm2 = @ctx.shadow.get_type_metrics('aa')
98
+ h = (gm.ascent - gm.descent + 0.5).to_i
99
+ w = gm.width - gm2.width
100
+ if glyph_orientation == 0 || glyph_orientation == 180
101
+ [w, h]
102
+ else
103
+ [h, w]
104
+ end
105
+ end
106
+
107
+ def text_rel_coords(text)
108
+ y_rel_coords = []
109
+ x_rel_coords = []
110
+ first_word = true
111
+ words = text.split(::Magick::RVG::WORD_SEP)
112
+ words.each do |word|
113
+ unless first_word
114
+ wx, wy = get_word_spacing
115
+ x_rel_coords << wx
116
+ y_rel_coords << wy
117
+ end
118
+ first_word = false
119
+ word.split('').each do |glyph|
120
+ wx, wy = get_letter_spacing(glyph)
121
+ x_rel_coords << wx
122
+ y_rel_coords << wy
123
+ end
124
+ end
125
+ [x_rel_coords, y_rel_coords]
126
+ end
127
+
128
+ def shift_baseline(glyph_orientation, glyph)
129
+ glyph_dimensions = @ctx.shadow.get_type_metrics(glyph)
130
+ if glyph_orientation == 0 || glyph_orientation == 180
131
+ x = glyph_dimensions.width
132
+ else
133
+ x = glyph_dimensions.ascent - glyph_dimensions.descent
134
+ end
135
+ case @ctx.text_attrs.baseline_shift
136
+ when :baseline
137
+ x = 0
138
+ when :sub
139
+
140
+ when :super
141
+ x = -x
142
+ when /[-+]?(\d+)%/
143
+ m = $1 == '-' ? -1.0 : 1.0
144
+ x = (m * x * $1.to_f / 100.0)
145
+ else
146
+ x = -@ctx.text_attrs.baseline_shift
147
+ end
148
+ x
149
+ end
150
+
151
+ def render_glyph(glyph_orientation, x, y, glyph)
152
+ if glyph_orientation == 0
153
+ @ctx.gc.text(x, y, enquote(glyph))
154
+ else
155
+ @ctx.gc.push
156
+ @ctx.gc.translate(x, y)
157
+ @ctx.gc.rotate(glyph_orientation)
158
+ @ctx.gc.translate(-x, -y)
159
+ @ctx.gc.text(x, y, enquote(glyph))
160
+ @ctx.gc.pop
161
+ end
162
+ end
163
+ end # class TextStrategy
164
+
165
+ class LRTextStrategy < TextStrategy
166
+ def get_word_spacing
167
+ @word_space ||= glyph_metrics(@ctx.text_attrs.glyph_orientation_horizontal, ' ')[0]
168
+ [@word_space + @ctx.text_attrs.word_spacing, 0]
169
+ end
170
+
171
+ def get_letter_spacing(glyph)
172
+ gx, gy = glyph_metrics(@ctx.text_attrs.glyph_orientation_horizontal, glyph)
173
+ [gx+@ctx.text_attrs.letter_spacing, gy]
174
+ end
175
+
176
+ def render(x, y, text)
177
+ x_rel_coords, y_rel_coords = text_rel_coords(text)
178
+ dx = x_rel_coords.inject(0) {|sum, a| sum + a}
179
+ dy = y_rel_coords.max
180
+
181
+ # We're handling the anchoring.
182
+ @ctx.gc.push
183
+ @ctx.gc.text_anchor(Magick::StartAnchor)
184
+ if @ctx.text_attrs.text_anchor == :end
185
+ x -= dx
186
+ elsif @ctx.text_attrs.text_anchor == :middle
187
+ x -= dx / 2
188
+ end
189
+
190
+ # Align the first glyph
191
+ case @ctx.text_attrs.glyph_orientation_horizontal
192
+ when 0
193
+
194
+ when 90
195
+ y -= dy
196
+ when 180
197
+ x += x_rel_coords.shift
198
+ x_rel_coords << 0
199
+ y -= dy
200
+ when 270
201
+ x += x_rel_coords[0]
202
+ end
203
+
204
+ y += shift_baseline(@ctx.text_attrs.glyph_orientation_horizontal, text[0,1])
205
+
206
+ first_word = true
207
+ text.split(::Magick::RVG::WORD_SEP).each do |word|
208
+ unless first_word
209
+ x += x_rel_coords.shift
210
+ end
211
+ first_word = false
212
+ word.split('').each do |glyph|
213
+ render_glyph(@ctx.text_attrs.glyph_orientation_horizontal, x, y, glyph)
214
+ x += x_rel_coords.shift
215
+ end
216
+ end
217
+
218
+ @ctx.gc.pop
219
+ [dx, 0]
220
+ end
221
+ end # class LRTextStrategy
222
+
223
+ class RLTextStrategy < TextStrategy
224
+ def render(x, y, text)
225
+ fail NotImplementedError
226
+ end
227
+ end # class RLTextStrategy
228
+
229
+ class TBTextStrategy < TextStrategy
230
+ def get_word_spacing
231
+ @word_space ||= glyph_metrics(@ctx.text_attrs.glyph_orientation_vertical, ' ')[1]
232
+ [0, @word_space + @ctx.text_attrs.word_spacing]
233
+ end
234
+
235
+ def get_letter_spacing(glyph)
236
+ gx, gy = glyph_metrics(@ctx.text_attrs.glyph_orientation_vertical, glyph)
237
+ [gx, gy+@ctx.text_attrs.letter_spacing]
238
+ end
239
+
240
+ def render(x, y, text)
241
+ x_rel_coords, y_rel_coords = text_rel_coords(text)
242
+ dx = x_rel_coords.max
243
+ dy = y_rel_coords.inject(0) {|sum, a| sum + a}
244
+
245
+ # We're handling the anchoring.
246
+ @ctx.gc.push
247
+ @ctx.gc.text_anchor(Magick::StartAnchor)
248
+ if @ctx.text_attrs.text_anchor == :end
249
+ y -= dy
250
+ elsif @ctx.text_attrs.text_anchor == :middle
251
+ y -= dy / 2
252
+ end
253
+
254
+ # Align the first glyph such that its center
255
+ # is aligned on x and its top is aligned on y.
256
+
257
+ case @ctx.text_attrs.glyph_orientation_vertical
258
+ when 0
259
+ x -= x_rel_coords.max / 2
260
+ y += y_rel_coords[0]
261
+ when 90
262
+ x -= x_rel_coords.max / 2
263
+ when 180
264
+ x += x_rel_coords.max / 2
265
+ when 270
266
+ x += x_rel_coords.max / 2
267
+ y += y_rel_coords.shift
268
+ y_rel_coords << 0 # since we used an element we need to add a dummy
269
+ end
270
+
271
+ x -= shift_baseline(@ctx.text_attrs.glyph_orientation_vertical, text[0,1])
272
+
273
+ first_word = true
274
+ text.split(::Magick::RVG::WORD_SEP).each do |word|
275
+ unless first_word
276
+ y += y_rel_coords.shift
277
+ x_rel_coords.shift
278
+ end
279
+ first_word = false
280
+ word.split('').each do |glyph|
281
+ case @ctx.text_attrs.glyph_orientation_vertical.to_i
282
+ when 0, 90, 270
283
+ x_shift = (dx - x_rel_coords.shift) / 2
284
+ when 180
285
+ x_shift = -(dx - x_rel_coords.shift) / 2
286
+ end
287
+
288
+ render_glyph(@ctx.text_attrs.glyph_orientation_vertical, x+x_shift, y, glyph)
289
+ y += y_rel_coords.shift
290
+ end
291
+ end
292
+
293
+ @ctx.gc.pop
294
+ [0, dy]
295
+ end
296
+ end # class TBTextStrategy
297
+
298
+ # Handle "easy" text
299
+ class DefaultTextStrategy < TextStrategy
300
+ def render(x, y, text)
301
+ @ctx.gc.text(x, y, enquote(text))
302
+ tm = @ctx.shadow.get_type_metrics(text)
303
+ dx = case @ctx.text_attrs.text_anchor
304
+ when :start
305
+ tm.width
306
+ when :middle
307
+ tm.width / 2
308
+ when :end
309
+ 0
310
+ end
311
+ [dx, 0]
312
+ end
313
+ end # class NormalTextStrategy
314
+ end # class Utility
315
+ end # class RVG
316
+ end # module Magick
317
+
318
+ module Magick
319
+ class RVG
320
+ class Utility
321
+ class TextAttributes
322
+ public
323
+
324
+ WRITING_MODE = %w{lr-tb lr rl-tb rl tb-rl tb}
325
+
326
+ def initialize
327
+ @affine = []
328
+ @affine << Magick::AffineMatrix.new(1, 0, 0, 1, 0, 0)
329
+ @baseline_shift = []
330
+ @baseline_shift << :baseline
331
+ @glyph_orientation_horizontal = []
332
+ @glyph_orientation_horizontal << 0
333
+ @glyph_orientation_vertical = []
334
+ @glyph_orientation_vertical << 90
335
+ @letter_spacing = []
336
+ @letter_spacing << 0
337
+ @text_anchor = []
338
+ @text_anchor << :start
339
+ @word_spacing = []
340
+ @word_spacing << 0
341
+ @writing_mode = []
342
+ @writing_mode << 'lr-tb'
343
+ end
344
+
345
+ def push
346
+ @affine.push(@affine.last.dup)
347
+ @baseline_shift.push(@baseline_shift.last)
348
+ @text_anchor.push(@text_anchor.last)
349
+ @writing_mode.push(@writing_mode.last.dup)
350
+ @glyph_orientation_vertical.push(@glyph_orientation_vertical.last)
351
+ @glyph_orientation_horizontal.push(@glyph_orientation_horizontal.last)
352
+ @letter_spacing.push(@letter_spacing.last)
353
+ @word_spacing.push(@word_spacing.last)
354
+ end
355
+
356
+ def pop
357
+ @affine.pop
358
+ @baseline_shift.pop
359
+ @text_anchor.pop
360
+ @writing_mode.pop
361
+ @glyph_orientation_vertical.pop
362
+ @glyph_orientation_horizontal.pop
363
+ @letter_spacing.pop
364
+ @word_spacing.pop
365
+ end
366
+
367
+ def set_affine(sx, rx, ry, sy, tx, ty)
368
+ @affine[-1].sx = sx
369
+ @affine[-1].rx = rx
370
+ @affine[-1].ry = ry
371
+ @affine[-1].sy = sy
372
+ @affine[-1].tx = tx
373
+ @affine[-1].ty = ty
374
+ end
375
+
376
+ def affine
377
+ @affine[-1]
378
+ end
379
+
380
+ def baseline_shift
381
+ @baseline_shift[-1]
382
+ end
383
+
384
+ def baseline_shift=(value)
385
+ @baseline_shift[-1] = value
386
+ end
387
+
388
+ def text_anchor
389
+ @text_anchor[-1]
390
+ end
391
+
392
+ def text_anchor=(anchor)
393
+ @text_anchor[-1] = anchor
394
+ end
395
+
396
+ def glyph_orientation_vertical
397
+ @glyph_orientation_vertical[-1]
398
+ end
399
+
400
+ def glyph_orientation_vertical=(angle)
401
+ @glyph_orientation_vertical[-1] = angle
402
+ end
403
+
404
+ def glyph_orientation_horizontal
405
+ @glyph_orientation_horizontal[-1]
406
+ end
407
+
408
+ def glyph_orientation_horizontal=(angle)
409
+ @glyph_orientation_horizontal[-1] = angle
410
+ end
411
+
412
+ def letter_spacing
413
+ @letter_spacing[-1]
414
+ end
415
+
416
+ def letter_spacing=(value)
417
+ @letter_spacing[-1] = value
418
+ end
419
+
420
+ def non_default?
421
+ @baseline_shift[-1] != :baseline || @letter_spacing[-1] != 0 ||
422
+ @word_spacing[-1] != 0 || @writing_mode[-1][/\Alr/].nil? ||
423
+ @glyph_orientation_horizontal[-1] != 0
424
+ end
425
+
426
+ def word_spacing
427
+ @word_spacing[-1]
428
+ end
429
+
430
+ def word_spacing=(value)
431
+ @word_spacing[-1] = value
432
+ end
433
+
434
+ def writing_mode
435
+ @writing_mode[-1]
436
+ end
437
+
438
+ def writing_mode=(mode)
439
+ @writing_mode[-1] = WRITING_MODE.include?(mode) ? mode : 'lr-tb'
440
+ end
441
+ end # class TextAttributes
442
+
443
+ class GraphicContext
444
+ FONT_STRETCH = {
445
+ :normal => Magick::NormalStretch,
446
+ :ultra_condensed => Magick::UltraCondensedStretch,
447
+ :extra_condensed => Magick::ExtraCondensedStretch,
448
+ :condensed => Magick::CondensedStretch,
449
+ :semi_condensed => Magick::SemiCondensedStretch,
450
+ :semi_expanded => Magick::SemiExpandedStretch,
451
+ :expanded => Magick::ExpandedStretch,
452
+ :extra_expanded => Magick::ExtraExpandedStretch,
453
+ :ultra_expanded => Magick::UltraExpandedStretch
454
+ }
455
+
456
+ FONT_STYLE = {
457
+ :normal => Magick::NormalStyle,
458
+ :italic => Magick::ItalicStyle,
459
+ :oblique => Magick::ObliqueStyle
460
+ }
461
+
462
+ FONT_WEIGHT = {
463
+ 'normal' => Magick::NormalWeight,
464
+ 'bold' => Magick::BoldWeight,
465
+ 'bolder' => Magick::BolderWeight,
466
+ 'lighter' => Magick::LighterWeight
467
+ }
468
+
469
+ TEXT_ANCHOR = {
470
+ :start => Magick::StartAnchor,
471
+ :middle => Magick::MiddleAnchor,
472
+ :end => Magick::EndAnchor
473
+ }
474
+
475
+ ANCHOR_TO_ALIGN = {
476
+ :start => Magick::LeftAlign,
477
+ :middle => Magick::CenterAlign,
478
+ :end => Magick::RightAlign
479
+ }
480
+
481
+ TEXT_DECORATION = {
482
+ :none => Magick::NoDecoration,
483
+ :underline => Magick::UnderlineDecoration,
484
+ :overline => Magick::OverlineDecoration,
485
+ :line_through => Magick::LineThroughDecoration}
486
+
487
+ TEXT_STRATEGIES = {
488
+ 'lr-tb' => LRTextStrategy, 'lr' => LRTextStrategy,
489
+ 'rt-tb' => RLTextStrategy, 'rl' => RLTextStrategy,
490
+ 'tb-rl' => TBTextStrategy, 'tb' => TBTextStrategy
491
+ }
492
+
493
+ def self.degrees_to_radians(deg)
494
+ Math::PI * (deg % 360.0) / 180.0
495
+ end
496
+
497
+ private
498
+
499
+ def init_matrix
500
+ @rx = @ry = 0
501
+ @sx = @sy = 1
502
+ @tx = @ty = 0
503
+ end
504
+
505
+ def concat_matrix
506
+ curr = @text_attrs.affine
507
+ sx = curr.sx * @sx + curr.ry * @rx
508
+ rx = curr.rx * @sx + curr.sy * @rx
509
+ ry = curr.sx * @ry + curr.ry * @sy
510
+ sy = curr.rx * @ry + curr.sy * @sy
511
+ tx = curr.sx * @tx + curr.ry * @ty + curr.tx
512
+ ty = curr.rx * @tx + curr.sy * @ty + curr.ty
513
+ @text_attrs.set_affine(sx, rx, ry, sy, tx, ty)
514
+ init_matrix
515
+ end
516
+
517
+ public
518
+
519
+ attr_reader :gc, :text_attrs
520
+
521
+ def initialize
522
+ @gc = Magick::Draw.new
523
+ @shadow = []
524
+ @shadow << Magick::Draw.new
525
+ @text_attrs = TextAttributes.new
526
+ init_matrix
527
+ end
528
+
529
+ def method_missing(methID, *args, &block)
530
+ @gc.__send__(methID, *args, &block)
531
+ end
532
+
533
+ def affine(sx, rx, ry, sy, tx, ty)
534
+ sx, rx, ry, sy, tx, ty = Magick::RVG.convert_to_float(sx, rx, ry, sy, tx, ty)
535
+ @gc.affine(sx, rx, ry, sy, tx, ty)
536
+ @text_attrs.set_affine(sx, rx, ry, sy, tx, ty)
537
+ nil
538
+ end
539
+
540
+ def baseline_shift(value)
541
+ @text_attrs.baseline_shift = case value
542
+ when 'baseline', 'sub', 'super'
543
+ value.intern
544
+ when /[-+]?\d+%/, Numeric
545
+ value
546
+ else
547
+ :baseline
548
+ end
549
+ nil
550
+ end
551
+
552
+ def font(name)
553
+ @gc.font(name)
554
+ @shadow[-1].font = name
555
+ nil
556
+ end
557
+
558
+ def font_family(name)
559
+ @gc.font_family(name)
560
+ @shadow[-1].font_family = name
561
+ nil
562
+ end
563
+
564
+ def font_size(points)
565
+ @gc.font_size(points)
566
+ @shadow[-1].pointsize = points
567
+ nil
568
+ end
569
+
570
+ def font_stretch(stretch)
571
+ stretch = FONT_STRETCH.fetch(stretch.intern, Magick::NormalStretch)
572
+ @gc.font_stretch(stretch)
573
+ @shadow[-1].font_stretch = stretch
574
+ nil
575
+ end
576
+
577
+ def font_style(style)
578
+ style = FONT_STYLE.fetch(style.intern, Magick::NormalStyle)
579
+ @gc.font_style(style)
580
+ @shadow[-1].font_style = style
581
+ nil
582
+ end
583
+
584
+ def font_weight(weight)
585
+ # If the arg is not in the hash use it directly. Handles numeric values.
586
+ weight = FONT_WEIGHT.fetch(weight) {|key| key}
587
+ @gc.font_weight(weight)
588
+ @shadow[-1].font_weight = weight
589
+ nil
590
+ end
591
+
592
+ def glyph_orientation_horizontal(deg)
593
+ deg = Magick::RVG.convert_one_to_float(deg)
594
+ @text_attrs.glyph_orientation_horizontal = (deg % 360) / 90 * 90
595
+ nil
596
+ end
597
+
598
+ def glyph_orientation_vertical(deg)
599
+ deg = Magick::RVG.convert_one_to_float(deg)
600
+ @text_attrs.glyph_orientation_vertical = (deg % 360) / 90 * 90
601
+ nil
602
+ end
603
+
604
+ def inspect
605
+ @gc.inspect
606
+ end
607
+
608
+ def letter_spacing(value)
609
+ @text_attrs.letter_spacing = Magick::RVG.convert_one_to_float(value)
610
+ nil
611
+ end
612
+
613
+ def push
614
+ @gc.push
615
+ @shadow.push(@shadow.last.dup)
616
+ @text_attrs.push
617
+ nil
618
+ end
619
+
620
+ def pop
621
+ @gc.pop
622
+ @shadow.pop
623
+ @text_attrs.pop
624
+ nil
625
+ end
626
+
627
+ def rotate(degrees)
628
+ degrees = Magick::RVG.convert_one_to_float(degrees)
629
+ @gc.rotate(degrees)
630
+ @sx = Math.cos(GraphicContext.degrees_to_radians(degrees))
631
+ @rx = Math.sin(GraphicContext.degrees_to_radians(degrees))
632
+ @ry = -Math.sin(GraphicContext.degrees_to_radians(degrees))
633
+ @sy = Math.cos(GraphicContext.degrees_to_radians(degrees))
634
+ concat_matrix
635
+ nil
636
+ end
637
+
638
+ def scale(sx, sy)
639
+ sx, sy = Magick::RVG.convert_to_float(sx, sy)
640
+ @gc.scale(sx, sy)
641
+ @sx = sx
642
+ @sy = sy
643
+ concat_matrix
644
+ nil
645
+ end
646
+
647
+ def shadow
648
+ @shadow.last
649
+ end
650
+
651
+ def skewX(degrees)
652
+ degrees = Magick::RVG.convert_one_to_float(degrees)
653
+ @gc.skewX(degrees)
654
+ @ry = Math.tan(GraphicContext.degrees_to_radians(degrees))
655
+ concat_matrix
656
+ nil
657
+ end
658
+
659
+ def skewY(degrees)
660
+ degrees = Magick::RVG.convert_one_to_float(degrees)
661
+ @gc.skewY(degrees)
662
+ @rx = Math.tan(GraphicContext.degrees_to_radians(degrees))
663
+ concat_matrix
664
+ nil
665
+ end
666
+
667
+ def stroke_width(width)
668
+ width = Magick::RVG.convert_one_to_float(width)
669
+ @gc.stroke_width(width)
670
+ @shadow[-1].stroke_width = width
671
+ nil
672
+ end
673
+
674
+ def text(x, y, text)
675
+ return if text.length == 0
676
+ if @text_attrs.non_default?
677
+ text_renderer = TEXT_STRATEGIES[@text_attrs.writing_mode].new(self)
678
+ else
679
+ text_renderer = DefaultTextStrategy.new(self)
680
+ end
681
+
682
+ text_renderer.render(x, y, text)
683
+ end
684
+
685
+ def text_anchor(anchor)
686
+ anchor = anchor.intern
687
+ anchor_enum = TEXT_ANCHOR.fetch(anchor, Magick::StartAnchor)
688
+ @gc.text_anchor(anchor_enum)
689
+ align = ANCHOR_TO_ALIGN.fetch(anchor, Magick::LeftAlign)
690
+ @shadow[-1].align = align
691
+ @text_attrs.text_anchor = anchor
692
+ nil
693
+ end
694
+
695
+ def text_decoration(decoration)
696
+ decoration = TEXT_DECORATION.fetch(decoration.intern, Magick::NoDecoration)
697
+ @gc.decorate(decoration)
698
+ @shadow[-1].decorate = decoration
699
+ nil
700
+ end
701
+
702
+ def translate(tx, ty)
703
+ tx, ty = Magick::RVG.convert_to_float(tx, ty)
704
+ @gc.translate(tx, ty)
705
+ @tx = tx
706
+ @ty = ty
707
+ concat_matrix
708
+ nil
709
+ end
710
+
711
+ def word_spacing(value)
712
+ @text_attrs.word_spacing = Magick::RVG.convert_one_to_float(value)
713
+ nil
714
+ end
715
+
716
+ def writing_mode(mode)
717
+ @text_attrs.writing_mode = mode
718
+ nil
719
+ end
720
+ end # class GraphicContext
721
+ end # class Utility
722
+ end # class RVG
723
+ end # module Magick