rmagick-windows 2.16.1

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 (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