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
@@ -0,0 +1,1754 @@
1
+ /**************************************************************************//**
2
+ * Utility functions for RMagick.
3
+ *
4
+ * Copyright © 2002 - 2009 by Timothy P. Hunter
5
+ *
6
+ * Changes since Nov. 2009 copyright © by Benjamin Thomas and Omer Bar-or
7
+ *
8
+ * @file rmutil.c
9
+ * @version $Id: rmutil.c,v 1.182 2009/12/21 10:34:58 baror Exp $
10
+ * @author Tim Hunter
11
+ ******************************************************************************/
12
+
13
+ #include "rmagick.h"
14
+ #include <errno.h>
15
+
16
+ static void handle_exception(ExceptionInfo *, Image *, ErrorRetention);
17
+
18
+
19
+ /**
20
+ * ImageMagick safe version of malloc.
21
+ *
22
+ * No Ruby usage (internal function)
23
+ *
24
+ * Notes:
25
+ * - Use when managing memory that ImageMagick may have allocated or may free.
26
+ * - If malloc fails, it raises an exception.
27
+ * - magick_safe_malloc and magick_safe_realloc prevent exceptions caused by
28
+ * integer overflow. Added in 6.3.5-9 but backwards compatible with prior
29
+ * releases.
30
+ *
31
+ * @param count the number of quantum elements to allocate
32
+ * @param quantum the number of bytes in each quantum
33
+ * @return a pointer to a block of memory that is at least count*quantum
34
+ */
35
+ void *
36
+ magick_safe_malloc(const size_t count, const size_t quantum)
37
+ {
38
+ void *ptr;
39
+
40
+ ptr = AcquireQuantumMemory(count, quantum);
41
+ if (!ptr)
42
+ {
43
+ rb_raise(rb_eNoMemError, "not enough memory to continue");
44
+ }
45
+ return ptr;
46
+ }
47
+
48
+
49
+ /**
50
+ * ImageMagick version of malloc.
51
+ *
52
+ * No Ruby usage (internal function)
53
+ *
54
+ * @param size the size of memory to allocate
55
+ * @return pointer to a block of memory
56
+ */
57
+ void *
58
+ magick_malloc(const size_t size)
59
+ {
60
+ void *ptr;
61
+ ptr = AcquireMagickMemory(size);
62
+ if (!ptr)
63
+ {
64
+ rb_raise(rb_eNoMemError, "not enough memory to continue");
65
+ }
66
+
67
+ return ptr;
68
+ }
69
+
70
+
71
+ /**
72
+ * ImageMagick version of free.
73
+ *
74
+ * No Ruby usage (internal function)
75
+ *
76
+ * @param ptr pointer to the existing block of memory
77
+ */
78
+ void
79
+ magick_free(void *ptr)
80
+ {
81
+ (void) RelinquishMagickMemory(ptr);
82
+ }
83
+
84
+
85
+ /**
86
+ * ImageMagick safe version of realloc.
87
+ *
88
+ * No Ruby usage (internal function)
89
+ *
90
+ * Notes:
91
+ * - Use when managing memory that ImageMagick may have allocated or may free.
92
+ * - If malloc fails, it raises an exception.
93
+ * - magick_safe_malloc and magick_safe_realloc prevent exceptions caused by
94
+ * integer overflow. Added in 6.3.5-9 but backwards compatible with prior
95
+ * releases.
96
+ *
97
+ * @param memory the existing block of memory
98
+ * @param count the number of quantum elements to allocate
99
+ * @param quantum the number of bytes in each quantum
100
+ * @return a pointer to a block of memory that is at least count*quantum in size
101
+ */
102
+ void *
103
+ magick_safe_realloc(void *memory, const size_t count, const size_t quantum)
104
+ {
105
+ void *v;
106
+ v = ResizeQuantumMemory(memory, count, quantum);
107
+ if (!v)
108
+ {
109
+ rb_raise(rb_eNoMemError, "not enough memory to continue");
110
+ }
111
+ return v;
112
+ }
113
+
114
+
115
+ /**
116
+ * ImageMagick version of realloc.
117
+ *
118
+ * No Ruby usage (internal function)
119
+ *
120
+ * @param ptr pointer to the existing block of memory
121
+ * @param size the new size of memory to allocate
122
+ * @return pointer to a block of memory
123
+ */
124
+ void *
125
+ magick_realloc(void *ptr, const size_t size)
126
+ {
127
+ void *v;
128
+ v = ResizeMagickMemory(ptr, size);
129
+ if (!v)
130
+ {
131
+ rb_raise(rb_eNoMemError, "not enough memory to continue");
132
+ }
133
+ return v;
134
+ }
135
+
136
+
137
+ /**
138
+ * Make a copy of a string in malloc'd memory.
139
+ *
140
+ * No Ruby usage (internal function)
141
+ *
142
+ * Notes:
143
+ * - Any existing string pointed to by *new_str is freed.
144
+ * - CloneString asserts if no memory. No need to check its return value.
145
+ *
146
+ * @param new_str pointer to the new string
147
+ * @param str the string to copy
148
+ */
149
+ void
150
+ magick_clone_string(char **new_str, const char *str)
151
+ {
152
+ (void) CloneString(new_str, str);
153
+ }
154
+
155
+
156
+ /**
157
+ * Compare s1 and s2 ignoring case.
158
+ *
159
+ * No Ruby usage (internal function)
160
+ *
161
+ * @param s1 the first string
162
+ * @param s2 the second string
163
+ * @return same as strcmp(3)
164
+ */
165
+ int
166
+ rm_strcasecmp(const char *s1, const char *s2)
167
+ {
168
+ while (*s1 && *s2)
169
+ {
170
+ if (toupper(*s1) != toupper(*s2))
171
+ {
172
+ break;
173
+ }
174
+ s1 += 1;
175
+ s2 += 1;
176
+ }
177
+ return (int)(*s1 - *s2);
178
+ }
179
+
180
+
181
+ /**
182
+ * Compare s1 and s2 ignoring case.
183
+ *
184
+ * No Ruby usage (internal function)
185
+ *
186
+ * @param s1 the first string
187
+ * @param s2 the second string
188
+ * @param n number of characters to compare
189
+ * @return same as strcmp(3)
190
+ */
191
+ int
192
+ rm_strncasecmp(const char *s1, const char *s2, size_t n)
193
+ {
194
+ if (n == 0)
195
+ {
196
+ return 0;
197
+ }
198
+ while (toupper(*s1) == toupper(*s2))
199
+ {
200
+ if (--n == 0 || *s1 == '\0')
201
+ {
202
+ return 0;
203
+ }
204
+ s1 += 1;
205
+ s2 += 1;
206
+ }
207
+ return (int)(*s1 - *s2);
208
+ }
209
+
210
+
211
+ /**
212
+ * Raise exception if array too short.
213
+ *
214
+ * No Ruby usage (internal function)
215
+ *
216
+ * @param ary the array
217
+ * @param len the minimum length
218
+ * @throw IndexError
219
+ */
220
+ void
221
+ rm_check_ary_len(VALUE ary, long len)
222
+ {
223
+ if (RARRAY_LEN(ary) < len)
224
+ {
225
+ rb_raise(rb_eIndexError, "not enough elements in array - expecting %ld, got %ld",
226
+ len, (long)RARRAY_LEN(ary));
227
+ }
228
+ }
229
+
230
+
231
+ /**
232
+ * Raise an error if the image has been destroyed.
233
+ *
234
+ * No Ruby usage (internal function)
235
+ *
236
+ * @param obj the image
237
+ * @return the C image structure for the image
238
+ * @throw DestroyedImageError
239
+ */
240
+ Image *
241
+ rm_check_destroyed(VALUE obj)
242
+ {
243
+ Image *image;
244
+
245
+ Data_Get_Struct(obj, Image, image);
246
+ if (!image)
247
+ {
248
+ rb_raise(Class_DestroyedImageError, "destroyed image");
249
+ }
250
+
251
+ return image;
252
+ }
253
+
254
+
255
+ /**
256
+ * Raise an error if the image has been destroyed or is frozen.
257
+ *
258
+ * No Ruby usage (internal function)
259
+ *
260
+ * @param obj the image
261
+ * @return the C image structure for the image
262
+ */
263
+ Image *
264
+ rm_check_frozen(VALUE obj)
265
+ {
266
+ Image *image = rm_check_destroyed(obj);
267
+ rb_check_frozen(obj);
268
+ return image;
269
+ }
270
+
271
+
272
+ /**
273
+ * Overrides freeze in classes that can't be frozen.
274
+ *
275
+ * No Ruby usage (internal function)
276
+ *
277
+ * @param obj the object of the class to override
278
+ * @return 0
279
+ * @throw TypeError
280
+ */
281
+ VALUE
282
+ rm_no_freeze(VALUE obj)
283
+ {
284
+ rb_raise(rb_eTypeError, "can't freeze %s", rb_class2name(CLASS_OF(obj)));
285
+ return (VALUE)0;
286
+ }
287
+
288
+
289
+ /**
290
+ * Return obj.to_s, or obj if obj is already a string.
291
+ *
292
+ * No Ruby usage (internal function)
293
+ *
294
+ * @param obj a Ruby object
295
+ * @return a String representation of obj
296
+ */
297
+ VALUE
298
+ rm_to_s(VALUE obj)
299
+ {
300
+
301
+ if (TYPE(obj) != T_STRING)
302
+ {
303
+ return rb_funcall(obj, rm_ID_to_s, 0);
304
+ }
305
+ return obj;
306
+ }
307
+
308
+
309
+ /**
310
+ * Supply our own version of the "obsolete" rb_str2cstr.
311
+ *
312
+ * No Ruby usage (internal function)
313
+ *
314
+ * @param str the Ruby string
315
+ * @param len pointer to a long in which to store the number of characters
316
+ * @return a C string version of str
317
+ */
318
+ char *
319
+ rm_str2cstr(VALUE str, long *len)
320
+ {
321
+ StringValue(str);
322
+ if (len)
323
+ {
324
+ *len = RSTRING_LEN(str);
325
+ }
326
+ return RSTRING_PTR(str);
327
+ }
328
+
329
+
330
+ /**
331
+ * Try to convert the argument to a double, raise an exception if fail.
332
+ *
333
+ * No Ruby usage (internal function)
334
+ *
335
+ * @param arg the argument
336
+ * @return arg
337
+ */
338
+ static VALUE
339
+ arg_is_number(VALUE arg)
340
+ {
341
+ double d;
342
+ d = NUM2DBL(arg);
343
+ d = d; // satisfy icc
344
+ return arg;
345
+ }
346
+
347
+
348
+ /**
349
+ * Called when `rb_str_to_str' raises an exception.
350
+ *
351
+ * No Ruby usage (internal function)
352
+ *
353
+ * @param arg the argument
354
+ * @return 0
355
+ * @throw TypeError
356
+ */
357
+ static VALUE
358
+ rescue_not_str(VALUE arg)
359
+ {
360
+ rb_raise(rb_eTypeError, "argument must be a number or a string in the form 'NN%%' (%s given)",
361
+ rb_class2name(CLASS_OF(arg)));
362
+ return (VALUE)0;
363
+ }
364
+
365
+
366
+ /**
367
+ * Return a double between 0.0 and max (the second argument), inclusive. If the
368
+ * argument is a number convert to a Float object, otherwise it's supposed to be
369
+ * a string in the form * "NN%". Convert to a number and then to a Float.
370
+ *
371
+ * No Ruby usage (internal function)
372
+ *
373
+ * @param arg the argument
374
+ * @param max the maximum allowed value
375
+ * @return a double
376
+ */
377
+ double
378
+ rm_percentage(VALUE arg, double max)
379
+ {
380
+ double pct;
381
+ long pct_long;
382
+ char *pct_str, *end;
383
+ int not_num;
384
+
385
+ // Try to convert the argument to a number. If failure, sets not_num to non-zero.
386
+ (void) rb_protect(arg_is_number, arg, &not_num);
387
+
388
+ if (not_num)
389
+ {
390
+ arg = rb_rescue(rb_str_to_str, arg, rescue_not_str, arg);
391
+ pct_str = StringValuePtr(arg);
392
+ errno = 0;
393
+ pct_long = strtol(pct_str, &end, 10);
394
+ if (errno == ERANGE)
395
+ {
396
+ rb_raise(rb_eRangeError, "`%s' out of range", pct_str);
397
+ }
398
+ if (*end != '\0' && *end != '%')
399
+ {
400
+ rb_raise(rb_eArgError, "expected percentage, got `%s'", pct_str);
401
+ }
402
+
403
+ if (*end == '%' && pct_long != 0)
404
+ {
405
+ pct = (((double)pct_long) / 100.0) * max;
406
+ }
407
+ else
408
+ {
409
+ pct = (double) pct_long;
410
+ }
411
+ if (pct < 0.0)
412
+ {
413
+ rb_raise(rb_eArgError, "percentages may not be negative (got `%s')", pct_str);
414
+ }
415
+ }
416
+ else
417
+ {
418
+ pct = NUM2DBL(arg);
419
+ if (pct < 0.0)
420
+ {
421
+ rb_raise(rb_eArgError, "percentages may not be negative (got `%g')", pct);
422
+ }
423
+ }
424
+
425
+ return pct;
426
+ }
427
+
428
+
429
+ /**
430
+ * Return 0 if rb_num2dbl doesn't raise an exception.
431
+ *
432
+ * No Ruby usage (internal function)
433
+ *
434
+ * @param obj the object to convert to a double
435
+ * @return 0
436
+ */
437
+ static VALUE
438
+ check_num2dbl(VALUE obj)
439
+ {
440
+ (void) rb_num2dbl(obj);
441
+ return INT2FIX(1);
442
+ }
443
+
444
+
445
+ /**
446
+ * Called if rb_num2dbl raises an exception.
447
+ *
448
+ * No Ruby usage (internal function)
449
+ *
450
+ * @param ignored a Ruby object (unused)
451
+ * @return 0
452
+ */
453
+ static VALUE
454
+ rescue_not_dbl(VALUE ignored)
455
+ {
456
+ ignored = ignored; // defeat gcc message
457
+ return INT2FIX(0);
458
+ }
459
+
460
+
461
+ /**
462
+ * Return 1 if the object can be converted to a double, 0 otherwise.
463
+ *
464
+ * No Ruby usage (internal function)
465
+ *
466
+ * @param obj the object
467
+ * @return 1 or 0
468
+ */
469
+ int
470
+ rm_check_num2dbl(VALUE obj)
471
+ {
472
+ return FIX2INT(rb_rescue(check_num2dbl, obj, rescue_not_dbl, (VALUE)0));
473
+ }
474
+
475
+
476
+ /**
477
+ * Given a string in the form NN% return the corresponding double.
478
+ *
479
+ * No Ruby usage (internal function)
480
+ *
481
+ * @param str the string
482
+ * @return a double
483
+ */
484
+ double
485
+ rm_str_to_pct(VALUE str)
486
+ {
487
+ long pct;
488
+ char *pct_str, *end;
489
+
490
+ str = rb_rescue(rb_str_to_str, str, rescue_not_str, str);
491
+ pct_str = StringValuePtr(str);
492
+ errno = 0;
493
+ pct = strtol(pct_str, &end, 10);
494
+
495
+ if (errno == ERANGE)
496
+ {
497
+ rb_raise(rb_eRangeError, "`%s' out of range", pct_str);
498
+ }
499
+ if (*end != '%')
500
+ {
501
+ rb_raise(rb_eArgError, "expected percentage, got `%s'", pct_str);
502
+ }
503
+ if (pct < 0L)
504
+ {
505
+ rb_raise(rb_eArgError, "percentages may not be negative (got `%s')", pct_str);
506
+ }
507
+
508
+ return pct / 100.0;
509
+ }
510
+
511
+
512
+ /**
513
+ * If the argument is a number, convert it to a double. Otherwise it's supposed
514
+ * to be a string in the form 'NN%'. Return a percentage of QuantumRange.
515
+ *
516
+ * No Ruby usage (internal function)
517
+ *
518
+ * @param fuzz_arg the fuzz argument
519
+ * @return a double
520
+ * @see Image_fuzz
521
+ * @see Image_fuzz_eq
522
+ */
523
+ double
524
+ rm_fuzz_to_dbl(VALUE fuzz_arg)
525
+ {
526
+ double fuzz;
527
+ char *fuzz_str, *end;
528
+ int not_num;
529
+
530
+ // Try to convert the argument to a number. If failure, sets not_num to non-zero.
531
+ (void) rb_protect(arg_is_number, fuzz_arg, &not_num);
532
+
533
+ if (not_num)
534
+ {
535
+ // Convert to string, issue error message if failure.
536
+ fuzz_arg = rb_rescue(rb_str_to_str, fuzz_arg, rescue_not_str, fuzz_arg);
537
+ fuzz_str = StringValuePtr(fuzz_arg);
538
+ errno = 0;
539
+ fuzz = strtod(fuzz_str, &end);
540
+ if (errno == ERANGE)
541
+ {
542
+ rb_raise(rb_eRangeError, "`%s' out of range", fuzz_str);
543
+ }
544
+ if(*end == '%')
545
+ {
546
+ if (fuzz < 0.0)
547
+ {
548
+ rb_raise(rb_eArgError, "percentages may not be negative (got `%s')", fuzz_str);
549
+ }
550
+ fuzz = (fuzz * QuantumRange) / 100.0;
551
+ }
552
+ else if(*end != '\0')
553
+ {
554
+ rb_raise(rb_eArgError, "expected percentage, got `%s'", fuzz_str);
555
+ }
556
+ }
557
+ else
558
+ {
559
+ fuzz = NUM2DBL(fuzz_arg);
560
+ if (fuzz < 0.0)
561
+ {
562
+ rb_raise(rb_eArgError, "fuzz may not be negative (got `%g')", fuzz);
563
+ }
564
+ }
565
+
566
+ return fuzz;
567
+ }
568
+
569
+
570
+ /**
571
+ * Convert a application-supplied number to a Quantum. If the object is a Float,
572
+ * truncate it before converting.
573
+ *
574
+ * No Ruby usage (internal function)
575
+ *
576
+ * Notes:
577
+ * - Ruby says that 2147483647.5 doesn't fit into an unsigned long. If you
578
+ * truncate it, it works.
579
+ * - Should use this only when the input value is possibly subject to this
580
+ * problem.
581
+ *
582
+ * @param obj the application-supplied number
583
+ * @return a Quantum
584
+ */
585
+ Quantum
586
+ rm_app2quantum(VALUE obj)
587
+ {
588
+ VALUE v = obj;
589
+
590
+ if (TYPE(obj) == T_FLOAT)
591
+ {
592
+ v = rb_funcall(obj, rm_ID_to_i, 0);
593
+ }
594
+
595
+ RB_GC_GUARD(v);
596
+
597
+ return NUM2QUANTUM(v);
598
+ }
599
+
600
+
601
+ /**
602
+ * Send the "cur_image" method to the object. If 'img' is an ImageList, then
603
+ * cur_image is self[\@scene]. If 'img' is an image, then cur_image is simply
604
+ * 'self'.
605
+ *
606
+ * No Ruby usage (internal function)
607
+ *
608
+ * @param img the object
609
+ * @return the return value from "cur_image"
610
+ */
611
+ VALUE
612
+ rm_cur_image(VALUE img)
613
+ {
614
+ return rb_funcall(img, rm_ID_cur_image, 0);
615
+ }
616
+
617
+
618
+ /**
619
+ * Map the color intensity to a named color.
620
+ *
621
+ * No Ruby usage (internal function)
622
+ *
623
+ * @param image the image
624
+ * @param color the color intensity as a PixelPacket
625
+ * @return the named color as a String
626
+ * @see rm_pixelpacket_to_color_name_info
627
+ */
628
+ VALUE
629
+ rm_pixelpacket_to_color_name(Image *image, PixelPacket *color)
630
+ {
631
+ char name[MaxTextExtent];
632
+ ExceptionInfo *exception;
633
+
634
+ exception = AcquireExceptionInfo();
635
+
636
+ (void) QueryColorname(image, color, X11Compliance, name, exception);
637
+ CHECK_EXCEPTION()
638
+ (void) DestroyExceptionInfo(exception);
639
+
640
+ return rb_str_new2(name);
641
+ }
642
+
643
+
644
+ /**
645
+ * Map the color intensity to a named color.
646
+ *
647
+ * No Ruby usage (internal function)
648
+ *
649
+ * Notes:
650
+ * - Simply create an Image from the Info, call QueryColorname, and then
651
+ * destroy the Image.
652
+ * - If the Info structure is NULL, creates a new one.
653
+ * - The default depth is always used, and the matte value is set to False,
654
+ * which means "don't use the alpha channel".
655
+ *
656
+ * @param info the info
657
+ * @param color the color intensity as a PixelPacket
658
+ * @return the named color as a String
659
+ * @see rm_pixelpacket_to_color_name
660
+ */
661
+ VALUE
662
+ rm_pixelpacket_to_color_name_info(Info *info, PixelPacket *color)
663
+ {
664
+ Image *image;
665
+ Info *my_info;
666
+ VALUE color_name;
667
+
668
+ my_info = info ? info : CloneImageInfo(NULL);
669
+
670
+ image = AcquireImage(info);
671
+ image->matte = MagickFalse;
672
+ color_name = rm_pixelpacket_to_color_name(image, color);
673
+ (void) DestroyImage(image);
674
+ if (!info)
675
+ {
676
+ (void) DestroyImageInfo(my_info);
677
+ }
678
+
679
+ RB_GC_GUARD(color_name);
680
+
681
+ return color_name;
682
+ }
683
+
684
+
685
+ /**
686
+ * Write a temporary copy of the image to the IM registry.
687
+ *
688
+ * No Ruby usage (internal function)
689
+ *
690
+ * Notes:
691
+ * - The `temp_name' argument must point to an char array of size
692
+ * MaxTextExtent.
693
+ *
694
+ * @param image the image
695
+ * @param temp_name the temporary name to use
696
+ * @return the "filename" of the registered image
697
+ */
698
+ void
699
+ rm_write_temp_image(Image *image, char *temp_name)
700
+ {
701
+
702
+ #define TMPNAM_CLASS_VAR "@@_tmpnam_"
703
+
704
+ MagickBooleanType okay;
705
+ ExceptionInfo *exception;
706
+ VALUE id_value;
707
+ int id;
708
+
709
+ exception = AcquireExceptionInfo();
710
+
711
+
712
+ // 'id' is always the value of its previous use
713
+ if (rb_cvar_defined(Module_Magick, rb_intern(TMPNAM_CLASS_VAR)) == Qtrue)
714
+ {
715
+ id_value = rb_cv_get(Module_Magick, TMPNAM_CLASS_VAR);
716
+ id = FIX2INT(id_value);
717
+ }
718
+ else
719
+ {
720
+ id = 0;
721
+ rb_cv_set(Module_Magick, TMPNAM_CLASS_VAR, INT2FIX(id));
722
+ }
723
+
724
+ id += 1;
725
+ rb_cv_set(Module_Magick, TMPNAM_CLASS_VAR, INT2FIX(id));
726
+ sprintf(temp_name, "mpri:%d", id);
727
+
728
+ // Omit "mpri:" from filename to form the key
729
+ okay = SetImageRegistry(ImageRegistryType, temp_name+5, image, exception);
730
+ CHECK_EXCEPTION()
731
+ DestroyExceptionInfo(exception);
732
+ if (!okay)
733
+ {
734
+ rb_raise(rb_eRuntimeError, "SetImageRegistry failed.");
735
+ }
736
+
737
+ RB_GC_GUARD(id_value);
738
+ }
739
+
740
+
741
+ /**
742
+ * Delete the temporary image from the registry.
743
+ *
744
+ * No Ruby usage (internal function)
745
+ *
746
+ * @param temp_name the name of temporary image in the registry.
747
+ */
748
+ void
749
+ rm_delete_temp_image(char *temp_name)
750
+ {
751
+ MagickBooleanType okay = DeleteImageRegistry(temp_name+5);
752
+
753
+ if (!okay)
754
+ {
755
+ rb_warn("DeleteImageRegistry failed for `%s'", temp_name);
756
+ }
757
+ }
758
+
759
+
760
+ /**
761
+ * Raise NotImplementedError.
762
+ *
763
+ * No Ruby usage (internal function)
764
+ *
765
+ * Notes:
766
+ * - Called when a xMagick API is not available.
767
+ * - Replaces Ruby's rb_notimplement function.
768
+ *
769
+ * @throw NotImpError
770
+ */
771
+ void
772
+ rm_not_implemented(void)
773
+ {
774
+
775
+ rb_raise(rb_eNotImpError, "the `%s' method is not supported by ImageMagick "
776
+ MagickLibVersionText, rb_id2name(THIS_FUNC()));
777
+ }
778
+
779
+
780
+ /**
781
+ * Create a new ImageMagickError object and raise an exception.
782
+ *
783
+ * No Ruby usage (internal function)
784
+ *
785
+ * Notes:
786
+ * - This funky technique allows me to safely add additional information to
787
+ * the ImageMagickError object in both 1.6.8 and 1.8.0.
788
+ *
789
+ * @param msg the error mesage
790
+ * @param loc the location of the error
791
+ * @throw ImageMagickError
792
+ * @see www.ruby_talk.org/36408.
793
+ */
794
+ void
795
+ rm_magick_error(const char *msg, const char *loc)
796
+ {
797
+ VALUE exc, mesg, extra;
798
+
799
+ mesg = rb_str_new2(msg);
800
+ extra = loc ? rb_str_new2(loc) : Qnil;
801
+
802
+ exc = rb_funcall(Class_ImageMagickError, rm_ID_new, 2, mesg, extra);
803
+ (void) rb_funcall(rb_cObject, rb_intern("raise"), 1, exc);
804
+
805
+ RB_GC_GUARD(exc);
806
+ RB_GC_GUARD(mesg);
807
+ RB_GC_GUARD(extra);
808
+ }
809
+
810
+
811
+ /**
812
+ * Initialize a new ImageMagickError object - store the "loc" string in the
813
+ * \@magick_location instance variable.
814
+ *
815
+ * Ruby usage:
816
+ * - @verbatim ImageMagickError#initialize(msg) @endverbatim
817
+ * - @verbatim ImageMagickError#initialize(msg, loc) @endverbatim
818
+ *
819
+ * Notes:
820
+ * - Default loc is nil
821
+ *
822
+ * @param argc number of input arguments
823
+ * @param argv array of input arguments
824
+ * @param self this object
825
+ * @return self
826
+ */
827
+ VALUE
828
+ ImageMagickError_initialize(int argc, VALUE *argv, VALUE self)
829
+ {
830
+ VALUE super_argv[1] = {(VALUE)0};
831
+ int super_argc = 0;
832
+ VALUE extra = Qnil;
833
+
834
+ switch(argc)
835
+ {
836
+ case 2:
837
+ extra = argv[1];
838
+ case 1:
839
+ super_argv[0] = argv[0];
840
+ super_argc = 1;
841
+ case 0:
842
+ break;
843
+ default:
844
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 2)", argc);
845
+ }
846
+
847
+ (void) rb_call_super(super_argc, (const VALUE *)super_argv);
848
+ (void) rb_iv_set(self, "@"MAGICK_LOC, extra);
849
+
850
+ RB_GC_GUARD(extra);
851
+
852
+ return self;
853
+ }
854
+
855
+
856
+ /**
857
+ * Backport GetImageProperty for pre-6.3.1 versions of ImageMagick.
858
+ *
859
+ * No Ruby usage (internal function)
860
+ *
861
+ * @param img the image
862
+ * @param property the property name
863
+ * @return the property value
864
+ */
865
+ const char *
866
+ rm_get_property(const Image *img, const char *property)
867
+ {
868
+ return GetImageProperty(img, property);
869
+ }
870
+
871
+
872
+ /**
873
+ * Backport SetImageProperty for pre-6.3.1 versions of ImageMagick.
874
+ *
875
+ * No Ruby usage (internal function)
876
+ *
877
+ * @param image the image
878
+ * @param property the property name
879
+ * @param value the property value
880
+ * @return true if successful, otherwise false
881
+ */
882
+ MagickBooleanType
883
+ rm_set_property(Image *image, const char *property, const char *value)
884
+ {
885
+ return SetImageProperty(image, property, value);
886
+ }
887
+
888
+
889
+ /**
890
+ * If a "user" option is present in the Info, assign its value to a "user"
891
+ * artifact in each image.
892
+ *
893
+ * No Ruby usage (internal function)
894
+ *
895
+ * @param images a list of images
896
+ * @param info the info
897
+ */
898
+ void rm_set_user_artifact(Image *images, Info *info)
899
+ {
900
+ #if defined(HAVE_SETIMAGEARTIFACT)
901
+ Image *image;
902
+ const char *value;
903
+
904
+ value = GetImageOption(info, "user");
905
+ if (value)
906
+ {
907
+ image = GetFirstImageInList(images);
908
+ while (image)
909
+ {
910
+ (void) SetImageArtifact(image, "user", value);
911
+ image = GetNextImageInList(image);
912
+ }
913
+ }
914
+ #else
915
+ images = images;
916
+ info = info;
917
+ #endif
918
+ }
919
+
920
+
921
+ /**
922
+ * Collect optional method arguments via Magick::OptionalMethodArguments.
923
+ *
924
+ * No Ruby usage (internal function)
925
+ *
926
+ * Notes:
927
+ * - Creates an instance of Magick::OptionalMethodArguments, then yields to a
928
+ * block in the context of the instance.
929
+ *
930
+ * @param img the image
931
+ */
932
+ void
933
+ rm_get_optional_arguments(VALUE img)
934
+ {
935
+ VALUE optional_method_arguments;
936
+ VALUE opt_args;
937
+ VALUE argv[1];
938
+
939
+ // opt_args = Magick::OptionalMethodArguments.new(img)
940
+ // opt_args.instance_eval { block }
941
+ if (rb_block_given_p())
942
+ {
943
+ optional_method_arguments = rb_const_get_from(Module_Magick, rb_intern("OptionalMethodArguments"));
944
+ argv[0] = img;
945
+ opt_args = rb_class_new_instance(1, argv, optional_method_arguments);
946
+ (void) rb_obj_instance_eval(0, NULL, opt_args);
947
+ }
948
+
949
+ RB_GC_GUARD(optional_method_arguments);
950
+ RB_GC_GUARD(opt_args);
951
+
952
+ return;
953
+ }
954
+
955
+
956
+ #if defined(HAVE_SETIMAGEARTIFACT)
957
+ /**
958
+ * Copy image options from the Info structure to the Image structure.
959
+ *
960
+ * No Ruby usage (internal function)
961
+ *
962
+ * @param image the Image structure to modify
963
+ * @param info the Info structure
964
+ */
965
+ static void copy_options(Image *image, Info *info)
966
+ {
967
+ char property[MaxTextExtent];
968
+ const char *value, *option;
969
+
970
+ ResetImageOptionIterator(info);
971
+ for (option = GetNextImageOption(info); option; option = GetNextImageOption(info))
972
+ {
973
+ value = GetImageOption(info,option);
974
+ if (value)
975
+ {
976
+ strncpy(property, value, MaxTextExtent);
977
+ property[MaxTextExtent-1] = '\0';
978
+ (void) SetImageArtifact(image, property, value);
979
+ }
980
+ }
981
+ }
982
+ #endif
983
+
984
+
985
+ /**
986
+ * Propagate ImageInfo values to the Image
987
+ *
988
+ * No Ruby usage (internal function)
989
+ *
990
+ * @param image the Image structure to modify
991
+ * @param info the Info structure
992
+ * @see SyncImageSettings in mogrify.c in ImageMagick
993
+ */
994
+ void rm_sync_image_options(Image *image, Info *info)
995
+ {
996
+ MagickStatusType flags;
997
+ GeometryInfo geometry_info;
998
+ const char *option;
999
+
1000
+ // The option strings will be set only when their attribute values were
1001
+ // set in the optional argument block.
1002
+ option = GetImageOption(info,"background");
1003
+ if (option)
1004
+ {
1005
+ image->background_color = info->background_color;
1006
+ }
1007
+
1008
+ option = GetImageOption(info,"bordercolor");
1009
+ if (option)
1010
+ {
1011
+ image->border_color = info->border_color;
1012
+ }
1013
+
1014
+ if (info->colorspace != UndefinedColorspace)
1015
+ {
1016
+ image->colorspace = info->colorspace;
1017
+ }
1018
+
1019
+ if (info->compression != UndefinedCompression)
1020
+ {
1021
+ image->compression = info->compression;
1022
+ }
1023
+
1024
+ option = GetImageOption(info, "delay");
1025
+ if (option)
1026
+ {
1027
+ image->delay = strtoul(option, NULL, 0);
1028
+ }
1029
+
1030
+ if (info->density)
1031
+ {
1032
+ flags = ParseGeometry(info->density, &geometry_info);
1033
+ image->x_resolution = geometry_info.rho;
1034
+ image->y_resolution = geometry_info.sigma;
1035
+ if ((flags & SigmaValue) == 0)
1036
+ {
1037
+ image->y_resolution = image->x_resolution;
1038
+ }
1039
+ }
1040
+
1041
+ if (info->depth != 0)
1042
+ {
1043
+ image->depth = info->depth;
1044
+ }
1045
+
1046
+ option = GetImageOption(info, "dispose");
1047
+ if (option)
1048
+ {
1049
+ image->dispose = rm_dispose_to_enum(option);
1050
+ }
1051
+
1052
+ if (info->extract)
1053
+ {
1054
+ ParseAbsoluteGeometry(info->extract, &image->extract_info);
1055
+ }
1056
+
1057
+ if (info->fuzz != 0.0)
1058
+ {
1059
+ image->fuzz = info->fuzz;
1060
+ }
1061
+
1062
+ option = GetImageOption(info, "gravity");
1063
+ if (option)
1064
+ {
1065
+ image->gravity = rm_gravity_to_enum(option);
1066
+ }
1067
+
1068
+ if (info->interlace != NoInterlace)
1069
+ {
1070
+ image->interlace = info->interlace;
1071
+ }
1072
+
1073
+ option = GetImageOption(info,"mattecolor");
1074
+ if (option)
1075
+ {
1076
+ image->matte_color = info->matte_color;
1077
+ }
1078
+
1079
+ if (info->orientation != UndefinedOrientation)
1080
+ {
1081
+ image->orientation = info->orientation;
1082
+ }
1083
+
1084
+ if (info->page)
1085
+ {
1086
+ (void)ParseAbsoluteGeometry(info->page, &image->page);
1087
+ }
1088
+
1089
+ if (info->quality != 0UL)
1090
+ {
1091
+ image->quality = info->quality;
1092
+ }
1093
+
1094
+ option = GetImageOption(info, "scene");
1095
+ if (option)
1096
+ {
1097
+ image->scene = info->scene;
1098
+ }
1099
+
1100
+ option = GetImageOption(info, "tile-offset");
1101
+ if (option)
1102
+ {
1103
+ (void)ParseAbsoluteGeometry(option, &image->tile_offset);
1104
+ }
1105
+
1106
+ option = GetImageOption(info, "transparent");
1107
+ if (option)
1108
+ {
1109
+ image->transparent_color = info->transparent_color;
1110
+ }
1111
+
1112
+ #if defined(HAVE_ST_TYPE)
1113
+ if (info->type != UndefinedType)
1114
+ {
1115
+ image->type = info->type;
1116
+ }
1117
+ #endif
1118
+
1119
+ if (info->units != UndefinedResolution)
1120
+ {
1121
+ if (image->units != info->units)
1122
+ {
1123
+ switch (image->units)
1124
+ {
1125
+ case PixelsPerInchResolution:
1126
+ {
1127
+ if (info->units == PixelsPerCentimeterResolution)
1128
+ {
1129
+ image->x_resolution /= 2.54;
1130
+ image->y_resolution /= 2.54;
1131
+ }
1132
+ break;
1133
+ }
1134
+ case PixelsPerCentimeterResolution:
1135
+ {
1136
+ if (info->units == PixelsPerInchResolution)
1137
+ {
1138
+ image->x_resolution *= 2.54;
1139
+ image->y_resolution *= 2.54;
1140
+ }
1141
+ break;
1142
+ }
1143
+ default:
1144
+ break;
1145
+ }
1146
+ }
1147
+
1148
+ image->units = info->units;
1149
+ }
1150
+
1151
+ #if defined(HAVE_SETIMAGEARTIFACT)
1152
+ copy_options(image, info);
1153
+ #endif
1154
+ }
1155
+
1156
+
1157
+ /**
1158
+ * Replicate old (ImageMagick < 6.3.2) EXIF:* functionality using
1159
+ * GetImageProperty by returning the exif entries as a single string, separated
1160
+ * by \n's. Do this so that RMagick.rb works no matter which version of
1161
+ * ImageMagick is in use.
1162
+ *
1163
+ * No Ruby usage (internal function)
1164
+ *
1165
+ * @param image the image
1166
+ * @return string representation of exif properties
1167
+ * @see magick/identify.c in ImageMagick
1168
+ */
1169
+ VALUE
1170
+ rm_exif_by_entry(Image *image)
1171
+ {
1172
+ const char *property, *value;
1173
+ char *str;
1174
+ size_t len = 0, property_l, value_l;
1175
+ VALUE v;
1176
+
1177
+ (void) GetImageProperty(image, "exif:*");
1178
+ ResetImagePropertyIterator(image);
1179
+ property = GetNextImageProperty(image);
1180
+
1181
+ // Measure the exif properties and values
1182
+ while (property)
1183
+ {
1184
+ // ignore properties that don't start with "exif:"
1185
+ property_l = strlen(property);
1186
+ if (property_l > 5 && rm_strncasecmp(property, "exif:", 5) == 0)
1187
+ {
1188
+ if (len > 0)
1189
+ {
1190
+ len += 1; // there will be a \n between property=value entries
1191
+ }
1192
+ len += property_l - 5;
1193
+ value = GetImageProperty(image,property);
1194
+ if (value)
1195
+ {
1196
+ // add 1 for the = between property and value
1197
+ len += 1 + strlen(value);
1198
+ }
1199
+ }
1200
+ property = GetNextImageProperty(image);
1201
+ }
1202
+
1203
+ if (len == 0)
1204
+ {
1205
+ return Qnil;
1206
+ }
1207
+ str = xmalloc(len);
1208
+ len = 0;
1209
+
1210
+ // Copy the exif properties and values into the string.
1211
+ ResetImagePropertyIterator(image);
1212
+ property = GetNextImageProperty(image);
1213
+
1214
+ while (property)
1215
+ {
1216
+ property_l = strlen(property);
1217
+ if (property_l > 5 && rm_strncasecmp(property, "exif:", 5) == 0)
1218
+ {
1219
+ if (len > 0)
1220
+ {
1221
+ str[len++] = '\n';
1222
+ }
1223
+ memcpy(str+len, property+5, property_l-5);
1224
+ len += property_l - 5;
1225
+ value = GetImageProperty(image,property);
1226
+ if (value)
1227
+ {
1228
+ value_l = strlen(value);
1229
+ str[len++] = '=';
1230
+ memcpy(str+len, value, value_l);
1231
+ len += value_l;
1232
+ }
1233
+ }
1234
+ property = GetNextImageProperty(image);
1235
+ }
1236
+
1237
+ v = rb_str_new(str, len);
1238
+ xfree(str);
1239
+
1240
+ RB_GC_GUARD(v);
1241
+
1242
+ return v;
1243
+ }
1244
+
1245
+
1246
+ /**
1247
+ * Replicate old (ImageMagick < 6.3.2) EXIF:! functionality using
1248
+ * GetImageProperty by returning the exif entries as a single string, separated
1249
+ * by \n's. Do this so that RMagick.rb works no matter which version of
1250
+ * ImageMagick is in use.
1251
+ *
1252
+ * No Ruby usage (internal function)
1253
+ *
1254
+ * @param image the image
1255
+ * @return string representation of exif properties
1256
+ * @see magick/identify.c in ImageMagick
1257
+ */
1258
+ VALUE
1259
+ rm_exif_by_number(Image *image)
1260
+ {
1261
+ const char *property, *value;
1262
+ char *str;
1263
+ size_t len = 0, property_l, value_l;
1264
+ VALUE v;
1265
+
1266
+ (void) GetImageProperty(image, "exif:!");
1267
+ ResetImagePropertyIterator(image);
1268
+ property = GetNextImageProperty(image);
1269
+
1270
+ // Measure the exif properties and values
1271
+ while (property)
1272
+ {
1273
+ // ignore properties that don't start with "#"
1274
+ property_l = strlen(property);
1275
+ if (property_l > 1 && property[0] == '#')
1276
+ {
1277
+ if (len > 0)
1278
+ {
1279
+ len += 1; // there will be a \n between property=value entries
1280
+ }
1281
+ len += property_l;
1282
+ value = GetImageProperty(image,property);
1283
+ if (value)
1284
+ {
1285
+ // add 1 for the = between property and value
1286
+ len += 1 + strlen(value);
1287
+ }
1288
+ }
1289
+ property = GetNextImageProperty(image);
1290
+ }
1291
+
1292
+ if (len == 0)
1293
+ {
1294
+ return Qnil;
1295
+ }
1296
+ str = xmalloc(len);
1297
+ len = 0;
1298
+
1299
+ // Copy the exif properties and values into the string.
1300
+ ResetImagePropertyIterator(image);
1301
+ property = GetNextImageProperty(image);
1302
+
1303
+ while (property)
1304
+ {
1305
+ property_l = strlen(property);
1306
+ if (property_l > 1 && property[0] == '#')
1307
+ {
1308
+ if (len > 0)
1309
+ {
1310
+ str[len++] = '\n';
1311
+ }
1312
+ memcpy(str+len, property, property_l);
1313
+ len += property_l;
1314
+ value = GetImageProperty(image,property);
1315
+ if (value)
1316
+ {
1317
+ value_l = strlen(value);
1318
+ str[len++] = '=';
1319
+ memcpy(str+len, value, value_l);
1320
+ len += value_l;
1321
+ }
1322
+ }
1323
+ property = GetNextImageProperty(image);
1324
+ }
1325
+
1326
+ v = rb_str_new(str, len);
1327
+ xfree(str);
1328
+
1329
+ RB_GC_GUARD(v);
1330
+
1331
+ return v;
1332
+ }
1333
+
1334
+
1335
+ /**
1336
+ * Get the values from a Geometry object and return them in C variables.
1337
+ *
1338
+ * No Ruby usage (internal function)
1339
+ *
1340
+ * Notes:
1341
+ * - No return value: modifies x, y, width, height, and flag
1342
+ *
1343
+ * @param geom the Geometry object
1344
+ * @param x pointer to the x position of the start of the rectangle
1345
+ * @param y pointer to the y position of the start of the rectangle
1346
+ * @param width pointer to the width of the rectangle
1347
+ * @param height pointer to the height of the rectangle
1348
+ * @param flag pointer to the Geometry's flag
1349
+ */
1350
+ void
1351
+ rm_get_geometry(
1352
+ VALUE geom,
1353
+ long *x,
1354
+ long *y,
1355
+ unsigned long *width,
1356
+ unsigned long *height,
1357
+ int *flag)
1358
+ {
1359
+ VALUE v;
1360
+
1361
+ v = rb_funcall(geom, rm_ID_x, 0);
1362
+ *x = NUM2LONG(v);
1363
+ v = rb_funcall(geom, rm_ID_y, 0);
1364
+ *y = NUM2LONG(v);
1365
+ v = rb_funcall(geom, rm_ID_width, 0);
1366
+ *width = NUM2ULONG(v);
1367
+ v = rb_funcall(geom, rm_ID_height, 0);
1368
+ *height = NUM2ULONG(v);
1369
+
1370
+ // Getting the flag field is a bit more difficult since it's
1371
+ // supposed to be an instance of the GeometryValue Enum class. We
1372
+ // may not know the VALUE for the GeometryValue class, and we
1373
+ // need to check that the flag field is an instance of that class.
1374
+ if (flag)
1375
+ {
1376
+ MagickEnum *magick_enum;
1377
+
1378
+ v = rb_funcall(geom, rm_ID_flag, 0);
1379
+ if (!Class_GeometryValue)
1380
+ {
1381
+ Class_GeometryValue = rb_const_get(Module_Magick, rm_ID_GeometryValue);
1382
+ }
1383
+ if (CLASS_OF(v) != Class_GeometryValue)
1384
+ {
1385
+ rb_raise(rb_eTypeError, "wrong enumeration type - expected %s, got %s"
1386
+ , rb_class2name(Class_GeometryValue),rb_class2name(CLASS_OF(v)));
1387
+ }
1388
+ Data_Get_Struct(v, MagickEnum, magick_enum);
1389
+ *flag = magick_enum->val;
1390
+ }
1391
+
1392
+ }
1393
+
1394
+
1395
+ /**
1396
+ * Clone an image, handle errors.
1397
+ *
1398
+ * No Ruby usage (internal function)
1399
+ *
1400
+ * Notes:
1401
+ * - Don't trace creation - the clone may not be used as an Image object. Let
1402
+ * the caller do the trace if desired.
1403
+ *
1404
+ * @param image the image to clone
1405
+ * @return the cloned image
1406
+ */
1407
+ Image *
1408
+ rm_clone_image(Image *image)
1409
+ {
1410
+ Image *clone;
1411
+ ExceptionInfo *exception;
1412
+
1413
+ exception = AcquireExceptionInfo();
1414
+ clone = CloneImage(image, 0, 0, MagickTrue, exception);
1415
+ if (!clone)
1416
+ {
1417
+ rb_raise(rb_eNoMemError, "not enough memory to continue");
1418
+ }
1419
+ rm_check_exception(exception, clone, DestroyOnError);
1420
+ (void) DestroyExceptionInfo(exception);
1421
+
1422
+ return clone;
1423
+ }
1424
+
1425
+
1426
+ /**
1427
+ * SetImage(Info)ProgressMonitor exit.
1428
+ *
1429
+ * No Ruby usage (internal function)
1430
+ *
1431
+ * Notes:
1432
+ * - ImageMagick's "tag" argument is unused. We pass along the method name
1433
+ * instead.
1434
+ *
1435
+ * @param tag ImageMagick argument (unused)
1436
+ * @param of the offset type
1437
+ * @param sp the size type
1438
+ * @param client_data pointer to the progress method to call
1439
+ * @return true if calling client_data returns a non-nil value, otherwise false
1440
+ */
1441
+ MagickBooleanType
1442
+ rm_progress_monitor(
1443
+ const char *tag,
1444
+ const MagickOffsetType of,
1445
+ const MagickSizeType sp,
1446
+ void *client_data)
1447
+ {
1448
+ VALUE rval;
1449
+ VALUE method, offset, span;
1450
+
1451
+ tag = tag; // defeat gcc message
1452
+
1453
+ #if defined(HAVE_LONG_LONG) // defined in Ruby's defines.h
1454
+ offset = rb_ll2inum(of);
1455
+ span = rb_ull2inum(sp);
1456
+ #else
1457
+ offset = rb_int2big((long)of);
1458
+ span = rb_uint2big((unsigned long)sp);
1459
+ #endif
1460
+
1461
+ method = rb_str_new2(rb_id2name(THIS_FUNC()));
1462
+
1463
+ rval = rb_funcall((VALUE)client_data, rm_ID_call, 3, method, offset, span);
1464
+
1465
+ RB_GC_GUARD(rval);
1466
+ RB_GC_GUARD(method);
1467
+ RB_GC_GUARD(offset);
1468
+ RB_GC_GUARD(span);
1469
+
1470
+ return RTEST(rval) ? MagickTrue : MagickFalse;
1471
+ }
1472
+
1473
+
1474
+ /**
1475
+ * Remove the ImageMagick links between images in an scene sequence.
1476
+ *
1477
+ * No Ruby usage (internal function)
1478
+ *
1479
+ * Notes:
1480
+ * - The images remain grouped via the ImageList
1481
+ *
1482
+ * @param image the image
1483
+ */
1484
+ void
1485
+ rm_split(Image *image)
1486
+ {
1487
+
1488
+ if (!image)
1489
+ {
1490
+ rb_bug("RMagick FATAL: split called with NULL argument.");
1491
+ }
1492
+ while (image)
1493
+ {
1494
+ (void) RemoveFirstImageFromList(&image);
1495
+ }
1496
+ }
1497
+
1498
+
1499
+ /**
1500
+ * If an ExceptionInfo struct in a list of images indicates a warning, issue a
1501
+ * warning message. If an ExceptionInfo struct indicates an error, raise an
1502
+ * exception and optionally destroy the images.
1503
+ *
1504
+ * No Ruby usage (internal function)
1505
+ *
1506
+ * @param imglist the list of images
1507
+ * @param retention retention strategy in case of an error (either RetainOnError
1508
+ * or DestroyOnError)
1509
+ */
1510
+ void
1511
+ rm_check_image_exception(Image *imglist, ErrorRetention retention)
1512
+ {
1513
+ ExceptionInfo *exception;
1514
+ Image *badboy = NULL;
1515
+ Image *image;
1516
+
1517
+ if (imglist == NULL)
1518
+ {
1519
+ return;
1520
+ }
1521
+
1522
+ exception = AcquireExceptionInfo();
1523
+
1524
+ // Find the image with the highest severity
1525
+ image = GetFirstImageInList(imglist);
1526
+ while (image)
1527
+ {
1528
+ if (image->exception.severity != UndefinedException)
1529
+ {
1530
+ if (!badboy || image->exception.severity > badboy->exception.severity)
1531
+ {
1532
+ badboy = image;
1533
+ InheritException(exception, &badboy->exception);
1534
+ }
1535
+
1536
+ ClearMagickException(&image->exception);
1537
+ }
1538
+ image = GetNextImageInList(image);
1539
+ }
1540
+
1541
+ if (badboy)
1542
+ {
1543
+ rm_check_exception(exception, imglist, retention);
1544
+ }
1545
+
1546
+ (void) DestroyExceptionInfo(exception);
1547
+ }
1548
+
1549
+
1550
+ /**
1551
+ * Call handle_exception if there is an exception to handle.
1552
+ *
1553
+ * No Ruby usage (internal function)
1554
+ *
1555
+ * @param exception information about the exception
1556
+ * @param imglist the images that caused the exception
1557
+ * @param retention retention strategy in case of an error (either RetainOnError
1558
+ * or DestroyOnError)
1559
+ */
1560
+ void
1561
+ rm_check_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
1562
+ {
1563
+ if (exception->severity == UndefinedException)
1564
+ {
1565
+ return;
1566
+ }
1567
+
1568
+ handle_exception(exception, imglist, retention);
1569
+ }
1570
+
1571
+
1572
+
1573
+ /**
1574
+ * Called from ImageMagick for a warning.
1575
+ *
1576
+ * No Ruby usage (internal function)
1577
+ *
1578
+ * @param severity information about the severity of the warning (ignored)
1579
+ * @param reason the reason for the warning
1580
+ * @param description description of the warning
1581
+ */
1582
+ void
1583
+ rm_warning_handler(const ExceptionType severity, const char *reason, const char *description)
1584
+ {
1585
+ ExceptionType dummy;
1586
+
1587
+ rb_warning("RMagick: %s: `%s'", reason, description);
1588
+ dummy = severity;
1589
+ dummy = dummy;
1590
+ }
1591
+
1592
+
1593
+ /**
1594
+ * Called from ImageMagick for a error.
1595
+ *
1596
+ * No Ruby usage (internal function)
1597
+ *
1598
+ * @param severity information about the severity of the error (ignored)
1599
+ * @param reason the reason for the error
1600
+ * @param description description of the error
1601
+ */
1602
+ void
1603
+ rm_error_handler(const ExceptionType severity, const char *reason, const char *description)
1604
+ {
1605
+ char msg[500];
1606
+ int len;
1607
+ ExceptionType dummy;
1608
+
1609
+ memset(msg, 0, sizeof(msg));
1610
+ #if defined(HAVE_SNPRINTF)
1611
+ len = snprintf(msg, sizeof(msg), "%s: `%s'", reason, description);
1612
+ #else
1613
+ len = sprintf(msg, "%.250s: `%.240s'", reason, description);
1614
+ #endif
1615
+ msg[len] = '\0';
1616
+
1617
+ rm_magick_error(msg, NULL);
1618
+ dummy = severity;
1619
+ dummy = dummy;
1620
+ }
1621
+
1622
+
1623
+ /**
1624
+ * Called from ImageMagick for a fatal error.
1625
+ *
1626
+ * No Ruby usage (internal function)
1627
+ *
1628
+ * @param severity information about the severity of the error
1629
+ * @param reason the reason for the error
1630
+ * @param description description of the error (ignored)
1631
+ * @throw FatalImageMagickError
1632
+ */
1633
+ void
1634
+ rm_fatal_error_handler(const ExceptionType severity, const char *reason, const char *description)
1635
+ {
1636
+ rb_raise(Class_FatalImageMagickError, "%s", GetLocaleExceptionMessage(severity, reason));
1637
+ description = description;
1638
+ }
1639
+
1640
+
1641
+ /**
1642
+ * Called when rm_check_exception determines that we need to either issue a
1643
+ * warning message or raise an exception. This function allocates a bunch of
1644
+ * stack so we don't call it unless we have to.
1645
+ *
1646
+ * No Ruby usage (internal function)
1647
+ *
1648
+ * @param exception information about the exception
1649
+ * @param imglist the images that caused the exception
1650
+ * @param retention retention strategy in case of an error (either RetainOnError
1651
+ * or DestroyOnError)
1652
+ */
1653
+ static void
1654
+ handle_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
1655
+ {
1656
+
1657
+ char reason[500];
1658
+ char desc[500];
1659
+ char msg[sizeof(reason)+sizeof(desc)+20];
1660
+
1661
+ memset(msg, 0, sizeof(msg));
1662
+
1663
+
1664
+ // Handle simple warning
1665
+ if (exception->severity < ErrorException)
1666
+ {
1667
+ #if defined(HAVE_SNPRINTF)
1668
+ snprintf(msg, sizeof(msg)-1, "RMagick: %s%s%s",
1669
+ #else
1670
+ sprintf(msg, "RMagick: %.500s%s%.500s",
1671
+ #endif
1672
+ GetLocaleExceptionMessage(exception->severity, exception->reason),
1673
+ exception->description ? ": " : "",
1674
+ exception->description ? GetLocaleExceptionMessage(exception->severity, exception->description) : "");
1675
+ msg[sizeof(msg)-1] = '\0';
1676
+ rb_warning("%s", msg);
1677
+
1678
+ // Caller deletes ExceptionInfo...
1679
+
1680
+ return;
1681
+ }
1682
+
1683
+ // Raise an exception. We're not coming back...
1684
+
1685
+
1686
+ // Newly-created images should be destroyed, images that are part
1687
+ // of image objects should be retained but split.
1688
+ if (imglist)
1689
+ {
1690
+ if (retention == DestroyOnError)
1691
+ {
1692
+ (void) DestroyImageList(imglist);
1693
+ imglist = NULL;
1694
+ }
1695
+ else
1696
+ {
1697
+ rm_split(imglist);
1698
+ }
1699
+ }
1700
+
1701
+
1702
+ // Clone the ExceptionInfo with all arguments on the stack.
1703
+ memset(reason, 0, sizeof(reason));
1704
+ memset(desc, 0, sizeof(desc));
1705
+
1706
+ if (exception->reason)
1707
+ {
1708
+ strncpy(reason, exception->reason, sizeof(reason)-1);
1709
+ reason[sizeof(reason)-1] = '\0';
1710
+ }
1711
+ if (exception->description)
1712
+ {
1713
+ strncpy(desc, exception->description, sizeof(desc)-1);
1714
+ desc[sizeof(desc)-1] = '\0';
1715
+ }
1716
+
1717
+
1718
+ #if defined(HAVE_SNPRINTF)
1719
+ snprintf(msg, sizeof(msg)-1, "%s%s%s",
1720
+ GetLocaleExceptionMessage(exception->severity, reason),
1721
+ desc[0] ? ": " : "",
1722
+ desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
1723
+ #else
1724
+ sprintf(msg, "%.*s%s%.*s",
1725
+ sizeof(reason)-1, GetLocaleExceptionMessage(exception->severity, reason),
1726
+ desc[0] ? ": " : "",
1727
+ sizeof(desc)-1, desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
1728
+ #endif
1729
+
1730
+ msg[sizeof(msg)-1] = '\0';
1731
+
1732
+ (void) DestroyExceptionInfo(exception);
1733
+ rm_magick_error(msg, NULL);
1734
+
1735
+ }
1736
+
1737
+
1738
+ /**
1739
+ * RMagick expected a result. If it got NULL instead raise an exception.
1740
+ *
1741
+ * No Ruby usage (internal function)
1742
+ *
1743
+ * @param image the expected result
1744
+ * @throw RuntimeError
1745
+ */
1746
+ void
1747
+ rm_ensure_result(Image *image)
1748
+ {
1749
+ if (!image)
1750
+ {
1751
+ rb_raise(rb_eRuntimeError, MagickPackageName " library function failed to return a result.");
1752
+ }
1753
+ }
1754
+