rmagick 2.16.0 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (441) hide show
  1. checksums.yaml +5 -5
  2. data/.devcontainer/Dockerfile +14 -0
  3. data/.devcontainer/ImageMagick6/devcontainer.json +11 -0
  4. data/.devcontainer/devcontainer.json +11 -0
  5. data/.devcontainer/setup-repo.sh +10 -0
  6. data/.devcontainer/setup-user.sh +45 -0
  7. data/.editorconfig +3 -0
  8. data/.github/ISSUE_TEMPLATE.md +17 -0
  9. data/.github/workflows/ci.yml +157 -0
  10. data/.gitignore +9 -1
  11. data/.rspec +1 -0
  12. data/.rubocop.yml +37 -340
  13. data/.rubocop_todo.yml +456 -0
  14. data/.yardopts +5 -0
  15. data/CHANGELOG.md +536 -0
  16. data/CODE_OF_CONDUCT.md +122 -7
  17. data/CONTRIBUTING.md +37 -6
  18. data/Gemfile +18 -4
  19. data/README.md +319 -0
  20. data/Rakefile +83 -98
  21. data/before_install_linux.sh +65 -28
  22. data/before_install_osx.sh +58 -2
  23. data/ext/RMagick/extconf.rb +310 -393
  24. data/ext/RMagick/{rmagick.c → rmagick.cpp} +119 -127
  25. data/ext/RMagick/rmagick.h +290 -363
  26. data/ext/RMagick/rmagick_gvl.h +224 -0
  27. data/ext/RMagick/rmdraw.cpp +1696 -0
  28. data/ext/RMagick/rmenum.cpp +796 -0
  29. data/ext/RMagick/{rmfill.c → rmfill.cpp} +287 -197
  30. data/ext/RMagick/rmilist.cpp +1275 -0
  31. data/ext/RMagick/rmimage.cpp +16459 -0
  32. data/ext/RMagick/{rminfo.c → rminfo.cpp} +738 -910
  33. data/ext/RMagick/rmkinfo.cpp +210 -0
  34. data/ext/RMagick/rmmain.cpp +1923 -0
  35. data/ext/RMagick/rmmontage.cpp +474 -0
  36. data/ext/RMagick/rmpixel.cpp +1322 -0
  37. data/ext/RMagick/{rmstruct.c → rmstruct.cpp} +104 -284
  38. data/ext/RMagick/{rmutil.c → rmutil.cpp} +500 -433
  39. data/lib/rmagick/version.rb +5 -4
  40. data/lib/rmagick.rb +2 -0
  41. data/lib/rmagick_internal.rb +397 -459
  42. data/lib/rvg/clippath.rb +3 -4
  43. data/lib/rvg/container.rb +30 -22
  44. data/lib/rvg/deep_equal.rb +11 -11
  45. data/lib/rvg/describable.rb +2 -2
  46. data/lib/rvg/embellishable.rb +67 -68
  47. data/lib/rvg/misc.rb +139 -142
  48. data/lib/rvg/paint.rb +2 -1
  49. data/lib/rvg/pathdata.rb +7 -8
  50. data/lib/rvg/rvg.rb +49 -46
  51. data/lib/rvg/stretchable.rb +22 -28
  52. data/lib/rvg/stylable.rb +12 -10
  53. data/lib/rvg/text.rb +169 -165
  54. data/lib/rvg/transformable.rb +17 -16
  55. data/lib/rvg/units.rb +5 -5
  56. data/rmagick.gemspec +7 -41
  57. data/sig/rmagick/_draw_common_methods.rbs +64 -0
  58. data/sig/rmagick/_image_common_methods.rbs +389 -0
  59. data/sig/rmagick/draw.rbs +38 -0
  60. data/sig/rmagick/draw_attribute.rbs +28 -0
  61. data/sig/rmagick/enum.rbs +814 -0
  62. data/sig/rmagick/error.rbs +11 -0
  63. data/sig/rmagick/fill.rbs +21 -0
  64. data/sig/rmagick/geometry.rbs +14 -0
  65. data/sig/rmagick/image.rbs +194 -0
  66. data/sig/rmagick/image_list.rbs +181 -0
  67. data/sig/rmagick/iptc.rbs +101 -0
  68. data/sig/rmagick/kernel_info.rbs +12 -0
  69. data/sig/rmagick/optional_method_arguments.rbs +10 -0
  70. data/sig/rmagick/pixel.rbs +46 -0
  71. data/sig/rmagick/struct.rbs +90 -0
  72. data/sig/rmagick.rbs +43 -0
  73. data/sig/rvg/clippath.rbs +34 -0
  74. data/sig/rvg/container.rbs +78 -0
  75. data/sig/rvg/deep_equal.rbs +48 -0
  76. data/sig/rvg/describable.rbs +30 -0
  77. data/sig/rvg/embellishable.rbs +226 -0
  78. data/sig/rvg/misc.rbs +145 -0
  79. data/sig/rvg/paint.rbs +55 -0
  80. data/sig/rvg/pathdata.rbs +77 -0
  81. data/sig/rvg/rvg.rbs +125 -0
  82. data/sig/rvg/stretchable.rbs +56 -0
  83. data/sig/rvg/stylable.rbs +66 -0
  84. data/sig/rvg/text.rbs +118 -0
  85. data/sig/rvg/transformable.rbs +59 -0
  86. data/sig/rvg/units.rbs +33 -0
  87. metadata +68 -428
  88. data/.hound.yml +0 -2
  89. data/.simplecov +0 -27
  90. data/.travis.yml +0 -74
  91. data/Doxyfile +0 -1514
  92. data/README.textile +0 -251
  93. data/deprecated/RMagick.rb +0 -6
  94. data/doc/.cvsignore +0 -1
  95. data/doc/comtasks.html +0 -287
  96. data/doc/constants.html +0 -1581
  97. data/doc/css/doc.css +0 -299
  98. data/doc/css/popup.css +0 -34
  99. data/doc/css/ref.css +0 -67
  100. data/doc/draw.html +0 -3272
  101. data/doc/ex/InitialCoords.rb +0 -22
  102. data/doc/ex/NewCoordSys.rb +0 -30
  103. data/doc/ex/OrigCoordSys.rb +0 -16
  104. data/doc/ex/PreserveAspectRatio.rb +0 -204
  105. data/doc/ex/RotateScale.rb +0 -36
  106. data/doc/ex/Skew.rb +0 -38
  107. data/doc/ex/Use01.rb +0 -15
  108. data/doc/ex/Use02.rb +0 -20
  109. data/doc/ex/Use03.rb +0 -16
  110. data/doc/ex/ViewBox.rb +0 -31
  111. data/doc/ex/adaptive_threshold.rb +0 -9
  112. data/doc/ex/add_noise.rb +0 -16
  113. data/doc/ex/affine.rb +0 -48
  114. data/doc/ex/affine_transform.rb +0 -20
  115. data/doc/ex/arc.rb +0 -49
  116. data/doc/ex/arcpath.rb +0 -32
  117. data/doc/ex/arcs01.rb +0 -28
  118. data/doc/ex/arcs02.rb +0 -59
  119. data/doc/ex/average.rb +0 -15
  120. data/doc/ex/axes.rb +0 -64
  121. data/doc/ex/baseline_shift01.rb +0 -17
  122. data/doc/ex/bilevel_channel.rb +0 -8
  123. data/doc/ex/blur_image.rb +0 -12
  124. data/doc/ex/border.rb +0 -10
  125. data/doc/ex/bounding_box.rb +0 -42
  126. data/doc/ex/cbezier1.rb +0 -41
  127. data/doc/ex/cbezier2.rb +0 -41
  128. data/doc/ex/cbezier3.rb +0 -41
  129. data/doc/ex/cbezier4.rb +0 -42
  130. data/doc/ex/cbezier5.rb +0 -42
  131. data/doc/ex/cbezier6.rb +0 -53
  132. data/doc/ex/channel.rb +0 -25
  133. data/doc/ex/charcoal.rb +0 -12
  134. data/doc/ex/chop.rb +0 -29
  135. data/doc/ex/circle.rb +0 -33
  136. data/doc/ex/circle01.rb +0 -16
  137. data/doc/ex/clip_path.rb +0 -60
  138. data/doc/ex/coalesce.rb +0 -57
  139. data/doc/ex/color_fill_to_border.rb +0 -29
  140. data/doc/ex/color_floodfill.rb +0 -28
  141. data/doc/ex/color_histogram.rb +0 -47
  142. data/doc/ex/color_reset.rb +0 -11
  143. data/doc/ex/colorize.rb +0 -16
  144. data/doc/ex/colors.rb +0 -64
  145. data/doc/ex/compose_mask.rb +0 -22
  146. data/doc/ex/composite.rb +0 -133
  147. data/doc/ex/composite_layers.rb +0 -53
  148. data/doc/ex/composite_tiled.rb +0 -21
  149. data/doc/ex/contrast.rb +0 -36
  150. data/doc/ex/crop.rb +0 -31
  151. data/doc/ex/crop_with_gravity.rb +0 -42
  152. data/doc/ex/cubic01.rb +0 -43
  153. data/doc/ex/cubic02.rb +0 -91
  154. data/doc/ex/cycle_colormap.rb +0 -21
  155. data/doc/ex/dissolve.rb +0 -12
  156. data/doc/ex/drawcomp.rb +0 -42
  157. data/doc/ex/drop_shadow.rb +0 -60
  158. data/doc/ex/edge.rb +0 -11
  159. data/doc/ex/ellipse.rb +0 -45
  160. data/doc/ex/ellipse01.rb +0 -21
  161. data/doc/ex/emboss.rb +0 -11
  162. data/doc/ex/enhance.rb +0 -28
  163. data/doc/ex/equalize.rb +0 -11
  164. data/doc/ex/evenodd.rb +0 -42
  165. data/doc/ex/fill_pattern.rb +0 -23
  166. data/doc/ex/flatten_images.rb +0 -36
  167. data/doc/ex/flip.rb +0 -11
  168. data/doc/ex/flop.rb +0 -11
  169. data/doc/ex/font_styles.rb +0 -32
  170. data/doc/ex/fonts.rb +0 -20
  171. data/doc/ex/frame.rb +0 -12
  172. data/doc/ex/gaussian_blur.rb +0 -11
  173. data/doc/ex/get_multiline_type_metrics.rb +0 -41
  174. data/doc/ex/get_pixels.rb +0 -47
  175. data/doc/ex/get_type_metrics.rb +0 -141
  176. data/doc/ex/gradientfill.rb +0 -27
  177. data/doc/ex/grav.rb +0 -45
  178. data/doc/ex/gravity.rb +0 -80
  179. data/doc/ex/group.rb +0 -26
  180. data/doc/ex/hatchfill.rb +0 -27
  181. data/doc/ex/image.rb +0 -44
  182. data/doc/ex/images/Apple.miff +0 -0
  183. data/doc/ex/images/Ballerina.jpg +0 -0
  184. data/doc/ex/images/Ballerina3.jpg +0 -0
  185. data/doc/ex/images/Button_0.gif +0 -0
  186. data/doc/ex/images/Button_1.gif +0 -0
  187. data/doc/ex/images/Button_2.gif +0 -0
  188. data/doc/ex/images/Button_3.gif +0 -0
  189. data/doc/ex/images/Button_4.gif +0 -0
  190. data/doc/ex/images/Button_5.gif +0 -0
  191. data/doc/ex/images/Button_6.gif +0 -0
  192. data/doc/ex/images/Button_7.gif +0 -0
  193. data/doc/ex/images/Button_8.gif +0 -0
  194. data/doc/ex/images/Button_9.gif +0 -0
  195. data/doc/ex/images/Button_A.gif +0 -0
  196. data/doc/ex/images/Button_B.gif +0 -0
  197. data/doc/ex/images/Button_C.gif +0 -0
  198. data/doc/ex/images/Button_D.gif +0 -0
  199. data/doc/ex/images/Button_E.gif +0 -0
  200. data/doc/ex/images/Button_F.gif +0 -0
  201. data/doc/ex/images/Button_G.gif +0 -0
  202. data/doc/ex/images/Button_H.gif +0 -0
  203. data/doc/ex/images/Button_I.gif +0 -0
  204. data/doc/ex/images/Button_J.gif +0 -0
  205. data/doc/ex/images/Button_K.gif +0 -0
  206. data/doc/ex/images/Button_L.gif +0 -0
  207. data/doc/ex/images/Button_M.gif +0 -0
  208. data/doc/ex/images/Button_N.gif +0 -0
  209. data/doc/ex/images/Button_O.gif +0 -0
  210. data/doc/ex/images/Button_P.gif +0 -0
  211. data/doc/ex/images/Button_Q.gif +0 -0
  212. data/doc/ex/images/Button_R.gif +0 -0
  213. data/doc/ex/images/Button_S.gif +0 -0
  214. data/doc/ex/images/Button_T.gif +0 -0
  215. data/doc/ex/images/Button_U.gif +0 -0
  216. data/doc/ex/images/Button_V.gif +0 -0
  217. data/doc/ex/images/Button_W.gif +0 -0
  218. data/doc/ex/images/Button_X.gif +0 -0
  219. data/doc/ex/images/Button_Y.gif +0 -0
  220. data/doc/ex/images/Button_Z.gif +0 -0
  221. data/doc/ex/images/Cheetah.jpg +0 -0
  222. data/doc/ex/images/Coffee.wmf +0 -0
  223. data/doc/ex/images/Flower_Hat.jpg +0 -0
  224. data/doc/ex/images/Gold_Statue.jpg +0 -0
  225. data/doc/ex/images/Hot_Air_Balloons.jpg +0 -0
  226. data/doc/ex/images/Hot_Air_Balloons_H.jpg +0 -0
  227. data/doc/ex/images/Leaf.miff +0 -0
  228. data/doc/ex/images/No.wmf +0 -0
  229. data/doc/ex/images/Polynesia.jpg +0 -0
  230. data/doc/ex/images/Red_Rocks.jpg +0 -0
  231. data/doc/ex/images/Rocks_On_Beach.miff +0 -0
  232. data/doc/ex/images/Shorts.jpg +0 -0
  233. data/doc/ex/images/Snake.wmf +0 -0
  234. data/doc/ex/images/Violin.jpg +0 -0
  235. data/doc/ex/images/Yellow_Rose.miff +0 -0
  236. data/doc/ex/images/big-duck.gif +0 -0
  237. data/doc/ex/images/duck.gif +0 -0
  238. data/doc/ex/images/duck0.gif +0 -0
  239. data/doc/ex/images/duck1.gif +0 -0
  240. data/doc/ex/images/duck10.gif +0 -0
  241. data/doc/ex/images/duck11.gif +0 -0
  242. data/doc/ex/images/duck12.gif +0 -0
  243. data/doc/ex/images/duck13.gif +0 -0
  244. data/doc/ex/images/duck14.gif +0 -0
  245. data/doc/ex/images/duck15.gif +0 -0
  246. data/doc/ex/images/duck2.gif +0 -0
  247. data/doc/ex/images/duck3.gif +0 -0
  248. data/doc/ex/images/duck4.gif +0 -0
  249. data/doc/ex/images/duck5.gif +0 -0
  250. data/doc/ex/images/duck6.gif +0 -0
  251. data/doc/ex/images/duck7.gif +0 -0
  252. data/doc/ex/images/duck8.gif +0 -0
  253. data/doc/ex/images/duck9.gif +0 -0
  254. data/doc/ex/images/graydient230x6.gif +0 -0
  255. data/doc/ex/images/image_with_profile.jpg +0 -0
  256. data/doc/ex/images/logo400x83.gif +0 -0
  257. data/doc/ex/images/model.miff +0 -0
  258. data/doc/ex/images/notimplemented.gif +0 -0
  259. data/doc/ex/images/smile.miff +0 -0
  260. data/doc/ex/images/spin.gif +0 -0
  261. data/doc/ex/implode.rb +0 -34
  262. data/doc/ex/level.rb +0 -11
  263. data/doc/ex/level_colors.rb +0 -11
  264. data/doc/ex/line.rb +0 -41
  265. data/doc/ex/line01.rb +0 -21
  266. data/doc/ex/mask.rb +0 -35
  267. data/doc/ex/matte_fill_to_border.rb +0 -39
  268. data/doc/ex/matte_floodfill.rb +0 -32
  269. data/doc/ex/matte_replace.rb +0 -39
  270. data/doc/ex/median_filter.rb +0 -28
  271. data/doc/ex/modulate.rb +0 -11
  272. data/doc/ex/mono.rb +0 -23
  273. data/doc/ex/morph.rb +0 -25
  274. data/doc/ex/mosaic.rb +0 -35
  275. data/doc/ex/motion_blur.rb +0 -11
  276. data/doc/ex/negate.rb +0 -11
  277. data/doc/ex/negate_channel.rb +0 -9
  278. data/doc/ex/nested_rvg.rb +0 -21
  279. data/doc/ex/nonzero.rb +0 -42
  280. data/doc/ex/normalize.rb +0 -11
  281. data/doc/ex/oil_paint.rb +0 -11
  282. data/doc/ex/opacity.rb +0 -37
  283. data/doc/ex/ordered_dither.rb +0 -11
  284. data/doc/ex/path.rb +0 -63
  285. data/doc/ex/pattern1.rb +0 -25
  286. data/doc/ex/pattern2.rb +0 -26
  287. data/doc/ex/polaroid.rb +0 -27
  288. data/doc/ex/polygon.rb +0 -23
  289. data/doc/ex/polygon01.rb +0 -21
  290. data/doc/ex/polyline.rb +0 -22
  291. data/doc/ex/polyline01.rb +0 -21
  292. data/doc/ex/posterize.rb +0 -8
  293. data/doc/ex/preview.rb +0 -8
  294. data/doc/ex/qbezierpath.rb +0 -52
  295. data/doc/ex/quad01.rb +0 -34
  296. data/doc/ex/quantize-m.rb +0 -25
  297. data/doc/ex/radial_blur.rb +0 -9
  298. data/doc/ex/raise.rb +0 -8
  299. data/doc/ex/random_threshold_channel.rb +0 -13
  300. data/doc/ex/rect01.rb +0 -14
  301. data/doc/ex/rect02.rb +0 -20
  302. data/doc/ex/rectangle.rb +0 -34
  303. data/doc/ex/reduce_noise.rb +0 -28
  304. data/doc/ex/remap.rb +0 -11
  305. data/doc/ex/remap_images.rb +0 -19
  306. data/doc/ex/resize_to_fill.rb +0 -8
  307. data/doc/ex/resize_to_fit.rb +0 -8
  308. data/doc/ex/roll.rb +0 -9
  309. data/doc/ex/rotate.rb +0 -44
  310. data/doc/ex/rotate_f.rb +0 -14
  311. data/doc/ex/roundrect.rb +0 -33
  312. data/doc/ex/rubyname.rb +0 -30
  313. data/doc/ex/rvg_clippath.rb +0 -12
  314. data/doc/ex/rvg_linecap.rb +0 -42
  315. data/doc/ex/rvg_linejoin.rb +0 -40
  316. data/doc/ex/rvg_opacity.rb +0 -18
  317. data/doc/ex/rvg_pattern.rb +0 -26
  318. data/doc/ex/rvg_stroke_dasharray.rb +0 -11
  319. data/doc/ex/segment.rb +0 -11
  320. data/doc/ex/sepiatone.rb +0 -7
  321. data/doc/ex/shade.rb +0 -11
  322. data/doc/ex/shadow.rb +0 -30
  323. data/doc/ex/shave.rb +0 -15
  324. data/doc/ex/shear.rb +0 -10
  325. data/doc/ex/sketch.rb +0 -17
  326. data/doc/ex/skewx.rb +0 -51
  327. data/doc/ex/skewy.rb +0 -47
  328. data/doc/ex/smile.rb +0 -125
  329. data/doc/ex/solarize.rb +0 -11
  330. data/doc/ex/sparse_color.rb +0 -54
  331. data/doc/ex/splice.rb +0 -8
  332. data/doc/ex/spread.rb +0 -11
  333. data/doc/ex/stegano.rb +0 -55
  334. data/doc/ex/stroke_dasharray.rb +0 -42
  335. data/doc/ex/stroke_fill.rb +0 -10
  336. data/doc/ex/stroke_linecap.rb +0 -44
  337. data/doc/ex/stroke_linejoin.rb +0 -48
  338. data/doc/ex/stroke_width.rb +0 -49
  339. data/doc/ex/swirl.rb +0 -17
  340. data/doc/ex/text.rb +0 -37
  341. data/doc/ex/text01.rb +0 -16
  342. data/doc/ex/text_align.rb +0 -36
  343. data/doc/ex/text_antialias.rb +0 -37
  344. data/doc/ex/text_styles.rb +0 -19
  345. data/doc/ex/text_undercolor.rb +0 -28
  346. data/doc/ex/texture_fill_to_border.rb +0 -34
  347. data/doc/ex/texture_floodfill.rb +0 -32
  348. data/doc/ex/texturefill.rb +0 -24
  349. data/doc/ex/threshold.rb +0 -13
  350. data/doc/ex/to_blob.rb +0 -13
  351. data/doc/ex/translate.rb +0 -39
  352. data/doc/ex/transparent.rb +0 -38
  353. data/doc/ex/transpose.rb +0 -9
  354. data/doc/ex/transverse.rb +0 -9
  355. data/doc/ex/tref01.rb +0 -24
  356. data/doc/ex/triangle01.rb +0 -15
  357. data/doc/ex/trim.rb +0 -23
  358. data/doc/ex/tspan01.rb +0 -17
  359. data/doc/ex/tspan02.rb +0 -17
  360. data/doc/ex/tspan03.rb +0 -19
  361. data/doc/ex/unsharp_mask.rb +0 -28
  362. data/doc/ex/viewex.rb +0 -33
  363. data/doc/ex/vignette.rb +0 -12
  364. data/doc/ex/watermark.rb +0 -27
  365. data/doc/ex/wave.rb +0 -9
  366. data/doc/ex/wet_floor.rb +0 -58
  367. data/doc/ex/writing_mode01.rb +0 -26
  368. data/doc/ex/writing_mode02.rb +0 -26
  369. data/doc/ilist.html +0 -2056
  370. data/doc/image1.html +0 -4680
  371. data/doc/image2.html +0 -3665
  372. data/doc/image3.html +0 -4522
  373. data/doc/imageattrs.html +0 -1638
  374. data/doc/imusage.html +0 -514
  375. data/doc/index.html +0 -416
  376. data/doc/info.html +0 -1499
  377. data/doc/magick.html +0 -565
  378. data/doc/optequiv.html +0 -2435
  379. data/doc/rvg.html +0 -975
  380. data/doc/rvgclip.html +0 -248
  381. data/doc/rvggroup.html +0 -305
  382. data/doc/rvgimage.html +0 -289
  383. data/doc/rvgpattern.html +0 -475
  384. data/doc/rvgshape.html +0 -406
  385. data/doc/rvgstyle.html +0 -270
  386. data/doc/rvgtext.html +0 -465
  387. data/doc/rvgtspan.html +0 -238
  388. data/doc/rvgtut.html +0 -530
  389. data/doc/rvguse.html +0 -145
  390. data/doc/rvgxform.html +0 -294
  391. data/doc/scripts/doc.js +0 -22
  392. data/doc/scripts/stripeTables.js +0 -23
  393. data/doc/struct.html +0 -1339
  394. data/doc/usage.html +0 -1621
  395. data/examples/constitute.rb +0 -7
  396. data/examples/crop_with_gravity.rb +0 -42
  397. data/examples/demo.rb +0 -324
  398. data/examples/describe.rb +0 -43
  399. data/examples/find_similar_region.rb +0 -34
  400. data/examples/histogram.rb +0 -321
  401. data/examples/identify.rb +0 -185
  402. data/examples/image_opacity.rb +0 -29
  403. data/examples/import_export.rb +0 -31
  404. data/examples/pattern_fill.rb +0 -38
  405. data/examples/rotating_text.rb +0 -44
  406. data/examples/spinner.rb +0 -49
  407. data/examples/thumbnail.rb +0 -64
  408. data/examples/vignette.rb +0 -78
  409. data/ext/RMagick/rmdraw.c +0 -2022
  410. data/ext/RMagick/rmenum.c +0 -1235
  411. data/ext/RMagick/rmilist.c +0 -1270
  412. data/ext/RMagick/rmimage.c +0 -15427
  413. data/ext/RMagick/rmmain.c +0 -1741
  414. data/ext/RMagick/rmmontage.c +0 -519
  415. data/ext/RMagick/rmpixel.c +0 -1114
  416. data/spec/rmagick/ImageList1_spec.rb +0 -24
  417. data/spec/rmagick/draw_spec.rb +0 -156
  418. data/spec/rmagick/image/blue_shift_spec.rb +0 -16
  419. data/spec/rmagick/image/composite_spec.rb +0 -140
  420. data/spec/rmagick/image/constitute_spec.rb +0 -15
  421. data/spec/rmagick/image/dispatch_spec.rb +0 -18
  422. data/spec/rmagick/image/from_blob_spec.rb +0 -14
  423. data/spec/rmagick/image/ping_spec.rb +0 -14
  424. data/spec/rmagick/image/properties_spec.rb +0 -29
  425. data/spec/spec_helper.rb +0 -4
  426. data/test/Image1.rb +0 -565
  427. data/test/Image2.rb +0 -1304
  428. data/test/Image3.rb +0 -1030
  429. data/test/ImageList1.rb +0 -806
  430. data/test/ImageList2.rb +0 -385
  431. data/test/Image_attributes.rb +0 -697
  432. data/test/Import_Export.rb +0 -121
  433. data/test/Info.rb +0 -345
  434. data/test/Magick.rb +0 -321
  435. data/test/Pixel.rb +0 -116
  436. data/test/Preview.rb +0 -57
  437. data/test/cmyk.icm +0 -0
  438. data/test/srgb.icm +0 -0
  439. data/test/test_all_basic.rb +0 -38
  440. data/test/tmpnam_test.rb +0 -50
  441. data/wercker.yml +0 -10
@@ -0,0 +1,1275 @@
1
+ /**************************************************************************//**
2
+ * ImageList class method definitions 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 rmilist.cpp
9
+ * @version $Id: rmilist.cpp,v 1.94 2009/12/20 02:33:33 baror Exp $
10
+ * @author Tim Hunter
11
+ ******************************************************************************/
12
+
13
+ #include "rmagick.h"
14
+
15
+ static Image *clone_imagelist(Image *);
16
+ static Image *images_from_imagelist(VALUE);
17
+ static long imagelist_length(VALUE);
18
+ static long check_imagelist_length(VALUE);
19
+ static void imagelist_push(VALUE, VALUE);
20
+ static VALUE ImageList_new(void);
21
+
22
+
23
+ DEFINE_GVL_STUB3(AppendImages, const Image *, const MagickBooleanType, ExceptionInfo *);
24
+ DEFINE_GVL_STUB5(CloneImage, const Image *, const size_t, const size_t, const MagickBooleanType, ExceptionInfo *);
25
+ DEFINE_GVL_STUB2(CloneImageList, const Image *, ExceptionInfo *);
26
+ DEFINE_GVL_STUB2(CoalesceImages, const Image *, ExceptionInfo *);
27
+ DEFINE_GVL_STUB2(DisposeImages, const Image *, ExceptionInfo *);
28
+ DEFINE_GVL_STUB3(EvaluateImages, const Image *, const MagickEvaluateOperator, ExceptionInfo *);
29
+ DEFINE_GVL_STUB4(ImagesToBlob, const ImageInfo *, Image *, size_t *, ExceptionInfo *);
30
+ DEFINE_GVL_STUB3(MergeImageLayers, Image *, const LayerMethod, ExceptionInfo *);
31
+ DEFINE_GVL_STUB3(MontageImages, const Image *, const MontageInfo *, ExceptionInfo *);
32
+ DEFINE_GVL_STUB3(MorphImages, const Image *, const size_t, ExceptionInfo *);
33
+ DEFINE_GVL_STUB2(OptimizeImageLayers, const Image *, ExceptionInfo *);
34
+ DEFINE_GVL_STUB2(OptimizePlusImageLayers, const Image *, ExceptionInfo *);
35
+ #if defined(IMAGEMAGICK_7)
36
+ DEFINE_GVL_STUB3(AnimateImages, const ImageInfo *, Image *, ExceptionInfo *);
37
+ DEFINE_GVL_STUB3(CombineImages, const Image *, const ColorspaceType, ExceptionInfo *);
38
+ DEFINE_GVL_STUB3(CompareImagesLayers, const Image *, const LayerMethod, ExceptionInfo *);
39
+ DEFINE_GVL_STUB3(QuantizeImages, const QuantizeInfo *, Image *, ExceptionInfo *);
40
+ DEFINE_GVL_STUB4(RemapImages, const QuantizeInfo *, Image *, const Image *, ExceptionInfo *);
41
+ DEFINE_GVL_STUB3(WriteImage, const ImageInfo *, Image *, ExceptionInfo *);
42
+ #else
43
+ DEFINE_GVL_STUB2(AnimateImages, const ImageInfo *, Image *);
44
+ DEFINE_GVL_STUB3(CombineImages, const Image *, const ChannelType, ExceptionInfo *);
45
+ DEFINE_GVL_STUB3(CompareImageLayers, const Image *, const ImageLayerMethod, ExceptionInfo *);
46
+ DEFINE_GVL_STUB2(DeconstructImages, const Image *, ExceptionInfo *);
47
+ DEFINE_GVL_STUB2(QuantizeImages, const QuantizeInfo *, Image *);
48
+ DEFINE_GVL_STUB3(RemapImages, const QuantizeInfo *, Image *, const Image *);
49
+ DEFINE_GVL_STUB2(WriteImage, const ImageInfo *, Image *);
50
+ #endif
51
+
52
+ DEFINE_GVL_VOID_STUB6(CompositeLayers, Image *, const CompositeOperator, Image *, const ssize_t, const ssize_t, ExceptionInfo *);
53
+ DEFINE_GVL_VOID_STUB2(OptimizeImageTransparency, const Image *, ExceptionInfo *);
54
+ DEFINE_GVL_VOID_STUB2(RemoveDuplicateLayers, Image **, ExceptionInfo *);
55
+ DEFINE_GVL_VOID_STUB2(RemoveZeroDelayLayers, Image **, ExceptionInfo *);
56
+
57
+
58
+ /**
59
+ * Repeatedly display the images in the images array to an XWindow screen. The
60
+ * +delay+ argument is the number of 1/100ths of a second (0 to 65535) to delay
61
+ * between images.
62
+ *
63
+ * @overload animate
64
+ *
65
+ * @overload animate(delay)
66
+ * @param delay [Numeric] the length of time between each image in an animation
67
+ * @yield [info]
68
+ * @yieldparam info [Magick::Image::Info]
69
+ *
70
+ * @return [Magick::ImageList] self
71
+ */
72
+
73
+ VALUE
74
+ ImageList_animate(int argc, VALUE *argv, VALUE self)
75
+ {
76
+ Image *images;
77
+ Info *info;
78
+ VALUE info_obj;
79
+ unsigned int delay;
80
+ #if defined(IMAGEMAGICK_7)
81
+ ExceptionInfo *exception;
82
+ #endif
83
+
84
+ if (argc == 1)
85
+ {
86
+ delay = NUM2UINT(argv[0]);
87
+ }
88
+ if (argc > 1)
89
+ {
90
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc);
91
+ }
92
+
93
+ // Create a new Info object to use with this call
94
+ info_obj = rm_info_new();
95
+
96
+ // Convert the images array to an images sequence.
97
+ images = images_from_imagelist(self);
98
+
99
+ if (argc == 1)
100
+ {
101
+ Image *img;
102
+
103
+ for (img = images; img; img = GetNextImageInList(img))
104
+ {
105
+ img->delay = delay;
106
+ }
107
+ }
108
+
109
+ TypedData_Get_Struct(info_obj, Info, &rm_info_data_type, info);
110
+ #if defined(IMAGEMAGICK_7)
111
+ exception = AcquireExceptionInfo();
112
+ GVL_STRUCT_TYPE(AnimateImages) args = { info, images, exception };
113
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(AnimateImages), &args);
114
+ rm_split(images);
115
+ CHECK_EXCEPTION();
116
+ DestroyExceptionInfo(exception);
117
+ #else
118
+ GVL_STRUCT_TYPE(AnimateImages) args = { info, images };
119
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(AnimateImages), &args);
120
+ rm_split(images);
121
+ rm_check_image_exception(images, RetainOnError);
122
+ #endif
123
+
124
+ RB_GC_GUARD(info_obj);
125
+
126
+ return self;
127
+ }
128
+
129
+
130
+ /**
131
+ * Append all the images
132
+ *
133
+ * @param stack_arg [Magick::ImageList] the stack of images
134
+ * @return [Magick::Image] a frame object for the result
135
+ */
136
+ VALUE
137
+ ImageList_append(VALUE self, VALUE stack_arg)
138
+ {
139
+ Image *images, *new_image;
140
+ MagickBooleanType stack;
141
+ ExceptionInfo *exception;
142
+
143
+ // Convert the image array to an image sequence.
144
+ images = images_from_imagelist(self);
145
+
146
+ // If stack == true, stack rectangular images top-to-bottom,
147
+ // otherwise left-to-right.
148
+ stack = (MagickBooleanType)RTEST(stack_arg);
149
+
150
+ exception = AcquireExceptionInfo();
151
+ GVL_STRUCT_TYPE(AppendImages) args = { images, stack, exception };
152
+ new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(AppendImages), &args);
153
+ rm_split(images);
154
+ rm_check_exception(exception, new_image, DestroyOnError);
155
+ DestroyExceptionInfo(exception);
156
+
157
+ return rm_image_new(new_image);
158
+ }
159
+
160
+
161
+ /**
162
+ * Average all images together
163
+ *
164
+ * @return [Magick::Image] a frame object for the averaged image
165
+ */
166
+ VALUE
167
+ ImageList_average(VALUE self)
168
+ {
169
+ Image *images, *new_image;
170
+ ExceptionInfo *exception;
171
+
172
+ // Convert the images array to an images sequence.
173
+ images = images_from_imagelist(self);
174
+
175
+ exception = AcquireExceptionInfo();
176
+ GVL_STRUCT_TYPE(EvaluateImages) args = { images, MeanEvaluateOperator, exception };
177
+ new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(EvaluateImages), &args);
178
+ rm_split(images);
179
+ rm_check_exception(exception, new_image, DestroyOnError);
180
+ DestroyExceptionInfo(exception);
181
+
182
+ return rm_image_new(new_image);
183
+ }
184
+
185
+
186
+ /**
187
+ * Composites a set of images while respecting any page offsets and disposal methods.
188
+ *
189
+ * - Respects the delay, matte, and start_loop fields in each image.
190
+ *
191
+ * @return [Magick::ImageList] a new image with the coalesced image sequence return stored in the
192
+ * images array
193
+ */
194
+ VALUE
195
+ ImageList_coalesce(VALUE self)
196
+ {
197
+ Image *images, *new_images;
198
+ ExceptionInfo *exception;
199
+
200
+ // Convert the image array to an image sequence.
201
+ images = images_from_imagelist(self);
202
+
203
+ exception = AcquireExceptionInfo();
204
+ GVL_STRUCT_TYPE(CoalesceImages) args = { images, exception };
205
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CoalesceImages), &args);
206
+ rm_split(images);
207
+ rm_check_exception(exception, new_images, DestroyOnError);
208
+ DestroyExceptionInfo(exception);
209
+
210
+ return rm_imagelist_from_images(new_images);
211
+ }
212
+
213
+
214
+ /**
215
+ * Combines the images using the specified colorspace.
216
+ *
217
+ * @overload combine
218
+ *
219
+ * @overload combine(colorspace)
220
+ * @param colorspace [Magick::ColorspaceType] the colorspace
221
+ *
222
+ * @return [Magick::Image] a new image
223
+ */
224
+ VALUE ImageList_combine(int argc, VALUE *argv, VALUE self)
225
+ {
226
+ #if defined(IMAGEMAGICK_6)
227
+ ChannelType channel;
228
+ ColorspaceType old_colorspace;
229
+ #endif
230
+ ColorspaceType colorspace;
231
+ long len;
232
+ Image *images, *new_image;
233
+ ExceptionInfo *exception;
234
+
235
+ len = check_imagelist_length(self);
236
+
237
+ switch (argc)
238
+ {
239
+ case 1:
240
+ VALUE_TO_ENUM(argv[0], colorspace, ColorspaceType);
241
+ break;
242
+ case 0:
243
+ colorspace = sRGBColorspace;
244
+ break;
245
+ default:
246
+ rb_raise(rb_eArgError, "wrong number of arguments (expected 1, got %d)", argc);
247
+ break;
248
+ }
249
+
250
+ #if defined(IMAGEMAGICK_7)
251
+ if (len > 5)
252
+ {
253
+ rb_raise(rb_eArgError, "invalid number of images in this image list");
254
+ }
255
+ if (len == 5 && colorspace != CMYKColorspace)
256
+ {
257
+ rb_raise(rb_eArgError, "invalid number of images in this image list");
258
+ }
259
+ #else
260
+ channel = RedChannel;
261
+ switch (len)
262
+ {
263
+ case 5:
264
+ if (colorspace == CMYKColorspace)
265
+ channel = (ChannelType)(channel | AlphaChannel);
266
+ else
267
+ rb_raise(rb_eArgError, "invalid number of images in this image list");
268
+ case 4:
269
+ if (colorspace == CMYKColorspace)
270
+ channel = (ChannelType)(channel | IndexChannel);
271
+ else
272
+ channel = (ChannelType)(channel | AlphaChannel);
273
+ case 3:
274
+ channel = (ChannelType)(channel | GreenChannel);
275
+ channel = (ChannelType)(channel | BlueChannel);
276
+ break;
277
+ case 2:
278
+ channel = (ChannelType)(channel | AlphaChannel);
279
+ break;
280
+ case 1:
281
+ break;
282
+ default:
283
+ rb_raise(rb_eArgError, "invalid number of images in this image list");
284
+ break;
285
+ }
286
+ #endif
287
+
288
+ images = images_from_imagelist(self);
289
+ exception = AcquireExceptionInfo();
290
+ #if defined(IMAGEMAGICK_6)
291
+ old_colorspace = images->colorspace;
292
+ SetImageColorspace(images, colorspace);
293
+ GVL_STRUCT_TYPE(CombineImages) args = { images, channel, exception };
294
+ #else
295
+ GVL_STRUCT_TYPE(CombineImages) args = { images, colorspace, exception };
296
+ #endif
297
+ new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CombineImages), &args);
298
+
299
+ rm_split(images);
300
+ #if defined(IMAGEMAGICK_6)
301
+ images->colorspace = old_colorspace;
302
+ #endif
303
+ rm_check_exception(exception, new_image, DestroyOnError);
304
+ DestroyExceptionInfo(exception);
305
+
306
+ return rm_image_new(new_image);
307
+ }
308
+
309
+
310
+ /**
311
+ * An image from source images is composited over an image from receiver's list until one list is finished.
312
+ *
313
+ * @overload composite_layers(images)
314
+ * @param images [Magick::ImageList] the source images
315
+ *
316
+ * @overload composite_layers(images, composite_op)
317
+ * - Default operator is {Magick::OverCompositeOp}
318
+ * @param images [Magick::ImageList] the source images
319
+ * @param composite_op [Magick::CompositeOperator] the operator
320
+ *
321
+ * @return [Magick::ImageList] a new imagelist
322
+ */
323
+ VALUE
324
+ ImageList_composite_layers(int argc, VALUE *argv, VALUE self)
325
+ {
326
+ VALUE source_images;
327
+ Image *dest, *source, *new_images;
328
+ RectangleInfo geometry;
329
+ CompositeOperator composite_op = OverCompositeOp;
330
+ ExceptionInfo *exception;
331
+
332
+ switch (argc)
333
+ {
334
+ case 2:
335
+ VALUE_TO_ENUM(argv[1], composite_op, CompositeOperator);
336
+ case 1:
337
+ source_images = argv[0];
338
+ break;
339
+ default:
340
+ rb_raise(rb_eArgError, "wrong number of arguments (expected 1 or 2, got %d)", argc);
341
+ break;
342
+ }
343
+
344
+ // Convert ImageLists to image sequences.
345
+ dest = images_from_imagelist(self);
346
+ new_images = clone_imagelist(dest);
347
+ rm_split(dest);
348
+
349
+ source = images_from_imagelist(source_images);
350
+
351
+ SetGeometry(new_images, &geometry);
352
+ ParseAbsoluteGeometry(new_images->geometry, &geometry);
353
+
354
+ geometry.width = source->page.width != 0 ? source->page.width : source->columns;
355
+ geometry.height = source->page.height != 0 ? source->page.height : source->rows;
356
+ GravityAdjustGeometry(new_images->page.width != 0 ? new_images->page.width : new_images->columns,
357
+ new_images->page.height != 0 ? new_images->page.height : new_images->rows,
358
+ new_images->gravity, &geometry);
359
+
360
+ exception = AcquireExceptionInfo();
361
+ GVL_STRUCT_TYPE(CompositeLayers) args = { new_images, composite_op, source, geometry.x, geometry.y, exception };
362
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CompositeLayers), &args);
363
+ rm_split(source);
364
+ rm_check_exception(exception, new_images, DestroyOnError);
365
+ DestroyExceptionInfo(exception);
366
+
367
+ RB_GC_GUARD(source_images);
368
+
369
+ return rm_imagelist_from_images(new_images);
370
+ }
371
+
372
+
373
+ /**
374
+ * Compare each image with the next in a sequence and returns the maximum
375
+ * bounding region of any pixel differences it discovers.
376
+ *
377
+ * @return [Magick::ImageList] a new imagelist
378
+ */
379
+ VALUE
380
+ ImageList_deconstruct(VALUE self)
381
+ {
382
+ Image *new_images, *images;
383
+ ExceptionInfo *exception;
384
+
385
+ images = images_from_imagelist(self);
386
+ exception = AcquireExceptionInfo();
387
+ #if defined(IMAGEMAGICK_7)
388
+ GVL_STRUCT_TYPE(CompareImagesLayers) args = { images, CompareAnyLayer, exception };
389
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CompareImagesLayers), &args);
390
+ #else
391
+ GVL_STRUCT_TYPE(DeconstructImages) args = { images, exception };
392
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(DeconstructImages), &args);
393
+ #endif
394
+ rm_split(images);
395
+ rm_check_exception(exception, new_images, DestroyOnError);
396
+ DestroyExceptionInfo(exception);
397
+
398
+ return rm_imagelist_from_images(new_images);
399
+ }
400
+
401
+
402
+ /**
403
+ * Display all the images to an X window screen.
404
+ *
405
+ * @yield [info]
406
+ * @yieldparam info [Magick::Image::Info]
407
+ * @return [Magick::ImageList] self
408
+ */
409
+ VALUE
410
+ ImageList_display(VALUE self)
411
+ {
412
+ Image *images;
413
+ Info *info;
414
+ VALUE info_obj;
415
+ #if defined(IMAGEMAGICK_7)
416
+ ExceptionInfo *exception;
417
+ #endif
418
+
419
+ // Create a new Info object to use with this call
420
+ info_obj = rm_info_new();
421
+ TypedData_Get_Struct(info_obj, Info, &rm_info_data_type, info);
422
+
423
+ // Convert the images array to an images sequence.
424
+ images = images_from_imagelist(self);
425
+ #if defined(IMAGEMAGICK_7)
426
+ exception = AcquireExceptionInfo();
427
+ DisplayImages(info, images, exception);
428
+ rm_split(images);
429
+ CHECK_EXCEPTION();
430
+ DestroyExceptionInfo(exception);
431
+ #else
432
+ DisplayImages(info, images);
433
+ rm_split(images);
434
+ rm_check_image_exception(images, RetainOnError);
435
+ #endif
436
+
437
+ RB_GC_GUARD(info_obj);
438
+
439
+ return self;
440
+ }
441
+
442
+
443
+ /**
444
+ * Merge all the images into a single image.
445
+ *
446
+ * @return [Magick::ImageList] the new image
447
+ */
448
+ VALUE
449
+ ImageList_flatten_images(VALUE self)
450
+ {
451
+ Image *images, *new_image;
452
+ ExceptionInfo *exception;
453
+
454
+ images = images_from_imagelist(self);
455
+ exception = AcquireExceptionInfo();
456
+
457
+ GVL_STRUCT_TYPE(MergeImageLayers) args = { images, FlattenLayer, exception };
458
+ new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MergeImageLayers), &args);
459
+
460
+ rm_split(images);
461
+ rm_check_exception(exception, new_image, DestroyOnError);
462
+ DestroyExceptionInfo(exception);
463
+
464
+ return rm_image_new(new_image);
465
+ }
466
+
467
+
468
+ /**
469
+ * Tile one or more thumbnails across an image canvas.
470
+ *
471
+ * @overload montage
472
+ *
473
+ * @overload montage
474
+ * Creates {Magick::ImageList::Montage} object, yields to block
475
+ * if present in {Magick::ImageList::Montage} object's scope.
476
+ * @yield [opt]
477
+ * @yieldparam opt [Magick::ImageList::Montage]
478
+ *
479
+ * @return [Magick::ImageList] a new image list
480
+ */
481
+ VALUE
482
+ ImageList_montage(VALUE self)
483
+ {
484
+ VALUE montage_obj;
485
+ Montage *montage;
486
+ Image *new_images, *images;
487
+ ExceptionInfo *exception;
488
+
489
+ // Create a new instance of the Magick::ImageList::Montage class
490
+ montage_obj = rm_montage_new();
491
+ if (rb_block_given_p())
492
+ {
493
+ rb_yield(montage_obj);
494
+ }
495
+
496
+ TypedData_Get_Struct(montage_obj, Montage, &rm_montage_data_type, montage);
497
+
498
+ images = images_from_imagelist(self);
499
+
500
+ for (Image *image = images; image; image = GetNextImageInList(image))
501
+ {
502
+ if (montage->compose != UndefinedCompositeOp)
503
+ {
504
+ image->compose = montage->compose;
505
+ }
506
+ image->background_color = montage->info->background_color;
507
+ image->border_color = montage->info->border_color;
508
+ image->matte_color = montage->info->matte_color;
509
+ image->gravity = montage->info->gravity;
510
+ }
511
+
512
+ exception = AcquireExceptionInfo();
513
+
514
+ // MontageImage can return more than one image.
515
+ GVL_STRUCT_TYPE(MontageImages) args = { images, montage->info, exception };
516
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MontageImages), &args);
517
+ rm_split(images);
518
+ rm_check_exception(exception, new_images, DestroyOnError);
519
+ DestroyExceptionInfo(exception);
520
+
521
+ RB_GC_GUARD(montage_obj);
522
+
523
+ return rm_imagelist_from_images(new_images);
524
+ }
525
+
526
+
527
+ /**
528
+ * Requires a minimum of two images. The first image is transformed into the
529
+ * second by a number of intervening images as specified by "nimages".
530
+ *
531
+ * @note Sets +@scenes+ to 0
532
+ * @param nimages [Numeric] the number of images
533
+ * @return [Magick::ImageList] a new image list with the images array set to the morph sequence.
534
+ */
535
+ VALUE
536
+ ImageList_morph(VALUE self, VALUE nimages)
537
+ {
538
+ Image *images, *new_images;
539
+ ExceptionInfo *exception;
540
+ size_t number_images;
541
+
542
+
543
+ // Use a signed long so we can test for a negative argument.
544
+ if (NUM2LONG(nimages) <= 0)
545
+ {
546
+ rb_raise(rb_eArgError, "number of intervening images must be > 0");
547
+ }
548
+
549
+ number_images = NUM2LONG(nimages);
550
+ images = images_from_imagelist(self);
551
+ exception = AcquireExceptionInfo();
552
+ GVL_STRUCT_TYPE(MorphImages) args = { images, number_images, exception };
553
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MorphImages), &args);
554
+ rm_split(images);
555
+ rm_check_exception(exception, new_images, DestroyOnError);
556
+ DestroyExceptionInfo(exception);
557
+
558
+ return rm_imagelist_from_images(new_images);
559
+ }
560
+
561
+
562
+ /**
563
+ * Merge all the images into a single image.
564
+ *
565
+ * @return [Magick::Image] the new image
566
+ */
567
+ VALUE
568
+ ImageList_mosaic(VALUE self)
569
+ {
570
+ Image *images, *new_image;
571
+ ExceptionInfo *exception;
572
+
573
+ images = images_from_imagelist(self);
574
+
575
+ exception = AcquireExceptionInfo();
576
+ GVL_STRUCT_TYPE(MergeImageLayers) args = { images, MosaicLayer, exception };
577
+ new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MergeImageLayers), &args);
578
+
579
+ rm_split(images);
580
+ rm_check_exception(exception, new_image, DestroyOnError);
581
+ DestroyExceptionInfo(exception);
582
+
583
+ return rm_image_new(new_image);
584
+ }
585
+
586
+
587
+ /**
588
+ * Optimizes or compares the images in the list.
589
+ * Equivalent to the -layers option in ImageMagick's mogrify command.
590
+ *
591
+ * @param method [Magick::LayerMethod] the method to use
592
+ * @return [Magick::ImageList] a new imagelist
593
+ */
594
+ VALUE
595
+ ImageList_optimize_layers(VALUE self, VALUE method)
596
+ {
597
+ Image *images, *new_images, *new_images2;
598
+ LayerMethod mthd;
599
+ ExceptionInfo *exception;
600
+ QuantizeInfo quantize_info;
601
+
602
+ new_images2 = NULL; // defeat "unused variable" message
603
+
604
+ VALUE_TO_ENUM(method, mthd, LayerMethod);
605
+ images = images_from_imagelist(self);
606
+
607
+ exception = AcquireExceptionInfo();
608
+ switch (mthd)
609
+ {
610
+ case CoalesceLayer:
611
+ {
612
+ GVL_STRUCT_TYPE(CoalesceImages) args = { images, exception };
613
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CoalesceImages), &args);
614
+ }
615
+ break;
616
+ case DisposeLayer:
617
+ {
618
+ GVL_STRUCT_TYPE(DisposeImages) args = { images, exception };
619
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(DisposeImages), &args);
620
+ }
621
+ break;
622
+ case OptimizeTransLayer:
623
+ {
624
+ new_images = clone_imagelist(images);
625
+ GVL_STRUCT_TYPE(OptimizeImageTransparency) args = { new_images, exception };
626
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(OptimizeImageTransparency), &args);
627
+ }
628
+ break;
629
+ case RemoveDupsLayer:
630
+ {
631
+ new_images = clone_imagelist(images);
632
+ GVL_STRUCT_TYPE(RemoveDuplicateLayers) args = { &new_images, exception };
633
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(RemoveDuplicateLayers), &args);
634
+ }
635
+ break;
636
+ case RemoveZeroLayer:
637
+ {
638
+ new_images = clone_imagelist(images);
639
+ GVL_STRUCT_TYPE(RemoveZeroDelayLayers) args = { &new_images, exception };
640
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(RemoveZeroDelayLayers), &args);
641
+ }
642
+ break;
643
+ case CompositeLayer:
644
+ rm_split(images);
645
+ DestroyExceptionInfo(exception);
646
+ rb_raise(rb_eNotImpError, "Magick::CompositeLayer is not supported. Use the composite_layers method instead.");
647
+ break;
648
+ // In 6.3.4-ish, OptimizeImageLayer replaced OptimizeLayer
649
+ case OptimizeImageLayer:
650
+ {
651
+ GVL_STRUCT_TYPE(OptimizeImageLayers) args = { images, exception };
652
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(OptimizeImageLayers), &args);
653
+ }
654
+ break;
655
+ // and OptimizeLayer became a "General Purpose, GIF Animation Optimizer" (ref. mogrify.c)
656
+ case OptimizeLayer:
657
+ {
658
+ GVL_STRUCT_TYPE(CoalesceImages) args_CoalesceImages = { images, exception };
659
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CoalesceImages), &args_CoalesceImages);
660
+ rm_split(images);
661
+ rm_check_exception(exception, new_images, DestroyOnError);
662
+
663
+ GVL_STRUCT_TYPE(OptimizeImageLayers) args_OptimizeImageLayers = { new_images, exception };
664
+ new_images2 = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(OptimizeImageLayers), &args_OptimizeImageLayers);
665
+ DestroyImageList(new_images);
666
+ rm_check_exception(exception, new_images2, DestroyOnError);
667
+
668
+ new_images = new_images2;
669
+ GVL_STRUCT_TYPE(OptimizeImageTransparency) args_OptimizeImageTransparency = { new_images, exception };
670
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(OptimizeImageTransparency), &args_OptimizeImageTransparency);
671
+ rm_check_exception(exception, new_images, DestroyOnError);
672
+ // mogrify supports -dither here. We don't.
673
+ GetQuantizeInfo(&quantize_info);
674
+ #if defined(IMAGEMAGICK_7)
675
+ GVL_STRUCT_TYPE(RemapImages) args_RemapImages = { &quantize_info, new_images, NULL, exception };
676
+ #else
677
+ GVL_STRUCT_TYPE(RemapImages) args_RemapImages = { &quantize_info, new_images, NULL };
678
+ #endif
679
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(RemapImages), &args_RemapImages);
680
+
681
+ }
682
+ break;
683
+ case OptimizePlusLayer:
684
+ {
685
+ GVL_STRUCT_TYPE(OptimizePlusImageLayers) args = { images, exception };
686
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(OptimizePlusImageLayers), &args);
687
+ }
688
+ break;
689
+ case CompareAnyLayer:
690
+ case CompareClearLayer:
691
+ case CompareOverlayLayer:
692
+ {
693
+ #if defined(IMAGEMAGICK_7)
694
+ GVL_STRUCT_TYPE(CompareImagesLayers) args = { images, mthd, exception };
695
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CompareImagesLayers), &args);
696
+ #else
697
+ GVL_STRUCT_TYPE(CompareImageLayers) args = { images, mthd, exception };
698
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CompareImageLayers), &args);
699
+ #endif
700
+ }
701
+ break;
702
+ case MosaicLayer:
703
+ {
704
+ GVL_STRUCT_TYPE(MergeImageLayers) args = { images, mthd, exception };
705
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MergeImageLayers), &args);
706
+ }
707
+ break;
708
+ case FlattenLayer:
709
+ {
710
+ GVL_STRUCT_TYPE(MergeImageLayers) args = { images, mthd, exception };
711
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MergeImageLayers), &args);
712
+ }
713
+ break;
714
+ case MergeLayer:
715
+ {
716
+ GVL_STRUCT_TYPE(MergeImageLayers) args = { images, mthd, exception };
717
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MergeImageLayers), &args);
718
+ }
719
+ break;
720
+ case TrimBoundsLayer:
721
+ {
722
+ GVL_STRUCT_TYPE(MergeImageLayers) args = { images, mthd, exception };
723
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(MergeImageLayers), &args);
724
+ }
725
+ break;
726
+ default:
727
+ rm_split(images);
728
+ DestroyExceptionInfo(exception);
729
+ rb_raise(rb_eArgError, "undefined layer method");
730
+ break;
731
+ }
732
+
733
+ rm_split(images);
734
+ rm_check_exception(exception, new_images, DestroyOnError);
735
+ DestroyExceptionInfo(exception);
736
+
737
+ return rm_imagelist_from_images(new_images);
738
+ }
739
+
740
+
741
+ /**
742
+ * Create a new ImageList object with no images.
743
+ *
744
+ * No Ruby usage (internal function)
745
+ *
746
+ * Notes:
747
+ * - this simply calls ImageList.new() in RMagick.rb
748
+ *
749
+ * @return a new imagelist
750
+ */
751
+ static VALUE
752
+ ImageList_new(void)
753
+ {
754
+ return rb_funcall(Class_ImageList, rm_ID_new, 0);
755
+ }
756
+
757
+
758
+ /**
759
+ * Construct a new imagelist object from a list of images.
760
+ *
761
+ * No Ruby usage (internal function)
762
+ *
763
+ * Notes:
764
+ * - Sets \@scene to 0.
765
+ *
766
+ * @param images the images
767
+ * @return a new imagelist
768
+ * @see images_from_imagelist
769
+ */
770
+ VALUE
771
+ rm_imagelist_from_images(Image *images)
772
+ {
773
+ VALUE new_imagelist;
774
+
775
+ rm_ensure_result(images);
776
+
777
+ new_imagelist = ImageList_new();
778
+
779
+ while (images)
780
+ {
781
+ Image *image;
782
+
783
+ image = RemoveFirstImageFromList(&images);
784
+ imagelist_push(new_imagelist, rm_image_new(image));
785
+ }
786
+
787
+ rb_iv_set(new_imagelist, "@scene", INT2FIX(0));
788
+
789
+ RB_GC_GUARD(new_imagelist);
790
+
791
+ return new_imagelist;
792
+ }
793
+
794
+
795
+ /**
796
+ * Convert an array of Image *s to an ImageMagick scene sequence (i.e. a
797
+ * doubly-linked list of Images).
798
+ *
799
+ * No Ruby usage (internal function)
800
+ *
801
+ * @param imagelist the imagelist
802
+ * @return a pointer to the head of the scene sequence list
803
+ * @see rm_imagelist_from_images
804
+ */
805
+ static Image *
806
+ images_from_imagelist(VALUE imagelist)
807
+ {
808
+ long x, len;
809
+ Image *head = NULL;
810
+ VALUE images, t;
811
+
812
+ len = check_imagelist_length(imagelist);
813
+
814
+ images = rb_iv_get(imagelist, "@images");
815
+ for (x = 0; x < len; x++)
816
+ {
817
+ Image *image;
818
+
819
+ t = rb_ary_entry(images, x);
820
+ image = rm_check_destroyed(t);
821
+ // avoid a loop in this linked imagelist, issue #202
822
+ if (head == image || GetPreviousImageInList(image) != NULL)
823
+ {
824
+ image = rm_clone_image(image);
825
+
826
+ // Wrap raw ImageMagick object by Ruby object to destroy using Ruby's GC.
827
+ rm_image_new(image);
828
+ }
829
+ AppendImageToList(&head, image);
830
+ }
831
+
832
+ RB_GC_GUARD(images);
833
+ RB_GC_GUARD(t);
834
+
835
+ return head;
836
+ }
837
+
838
+
839
+ /**
840
+ * return the # of images in an imagelist.
841
+ *
842
+ * No Ruby usage (internal function)
843
+ *
844
+ * @param imagelist the imagelist
845
+ * @return the number of images
846
+ */
847
+ static long
848
+ imagelist_length(VALUE imagelist)
849
+ {
850
+ VALUE images = rb_iv_get(imagelist, "@images");
851
+ if (!RB_TYPE_P(images, T_ARRAY))
852
+ {
853
+ rb_raise(Class_ImageMagickError, "@images is not of type Array");
854
+ }
855
+
856
+ RB_GC_GUARD(images);
857
+
858
+ return RARRAY_LEN(images);
859
+ }
860
+
861
+
862
+ /**
863
+ * Raise exception if imagelist is emtpy.
864
+ *
865
+ * No Ruby usage (internal function)
866
+ *
867
+ * @param imagelist the imagelist
868
+ * @return the number of images
869
+ * @throw ArgError
870
+ */
871
+ static long
872
+ check_imagelist_length(VALUE imagelist)
873
+ {
874
+ long len = imagelist_length(imagelist);
875
+
876
+ if (len == 0)
877
+ {
878
+ rb_raise(rb_eArgError, "no images in this image list");
879
+ }
880
+
881
+ return len;
882
+ }
883
+
884
+
885
+ /**
886
+ * Push an image onto the end of the imagelist.
887
+ *
888
+ * No Ruby usage (internal function)
889
+ *
890
+ * @param imagelist the imagelist
891
+ * @param image the image
892
+ */
893
+ static void
894
+ imagelist_push(VALUE imagelist, VALUE image)
895
+ {
896
+ rb_check_frozen(imagelist);
897
+ rb_funcall(imagelist, rm_ID_push, 1, image);
898
+ }
899
+
900
+
901
+ /**
902
+ * Clone a list of images, handle errors.
903
+ *
904
+ * No Ruby usage (internal function)
905
+ *
906
+ * @param images the images
907
+ * @return a new array of images
908
+ */
909
+ static Image *
910
+ clone_imagelist(Image *images)
911
+ {
912
+ Image *new_imagelist = NULL, *image;
913
+ ExceptionInfo *exception;
914
+
915
+ exception = AcquireExceptionInfo();
916
+
917
+ image = GetFirstImageInList(images);
918
+ while (image)
919
+ {
920
+ Image *clone;
921
+
922
+ GVL_STRUCT_TYPE(CloneImage) args = { image, 0, 0, MagickTrue, exception };
923
+ clone = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CloneImage), &args);
924
+ rm_check_exception(exception, new_imagelist, DestroyOnError);
925
+ AppendImageToList(&new_imagelist, clone);
926
+ image = GetNextImageInList(image);
927
+ }
928
+
929
+ DestroyExceptionInfo(exception);
930
+ return new_imagelist;
931
+ }
932
+
933
+
934
+ /**
935
+ * Analyzes the colors within a set of reference images and chooses a fixed number of colors to represent the set.
936
+ * The goal of the algorithm is to minimize the difference between the input and output images while minimizing the processing time.
937
+ *
938
+ * @overload quantize(number_colors = 256, colorspace = Magick::RGBColorsapce, dither = true, tree_depth = 0, measure_error = false)
939
+ * @param number_colors [Numeric] the maximum number of colors to use in the output images.
940
+ * @param colorspace [Magick::ColorspaceType] the colorspace to quantize in.
941
+ * @param dither [Magick::DitherMethod, Boolean] a DitherMethod value or true if you want apply dither.
942
+ * @param tree_depth [Numeric] specify the tree depth to use while quantizing.
943
+ * @param measure_error [Boolean] calculate quantization errors when quantizing the image.
944
+ * @return [Magick::ImageList] a new ImageList with quantized images
945
+ * @note Sets +@scene+ to the same value as +self.scene+
946
+ */
947
+ VALUE
948
+ ImageList_quantize(int argc, VALUE *argv, VALUE self)
949
+ {
950
+ Image *images, *new_images;
951
+ Image *new_image;
952
+ QuantizeInfo quantize_info;
953
+ ExceptionInfo *exception;
954
+ VALUE new_imagelist, scene;
955
+
956
+ GetQuantizeInfo(&quantize_info);
957
+
958
+ switch (argc)
959
+ {
960
+ case 5:
961
+ quantize_info.measure_error = (MagickBooleanType) RTEST(argv[4]);
962
+ case 4:
963
+ quantize_info.tree_depth = (unsigned long)NUM2INT(argv[3]);
964
+ case 3:
965
+ #if defined(IMAGEMAGICK_7)
966
+ if (rb_obj_is_kind_of(argv[2], Class_DitherMethod))
967
+ {
968
+ VALUE_TO_ENUM(argv[2], quantize_info.dither_method, DitherMethod);
969
+ }
970
+ else
971
+ {
972
+ quantize_info.dither_method = RTEST(argv[2]) ? UndefinedDitherMethod : NoDitherMethod;
973
+ }
974
+ #else
975
+ if (rb_obj_is_kind_of(argv[2], Class_DitherMethod))
976
+ {
977
+ VALUE_TO_ENUM(argv[2], quantize_info.dither_method, DitherMethod);
978
+ quantize_info.dither = (MagickBooleanType)(quantize_info.dither_method != NoDitherMethod);
979
+ }
980
+ else
981
+ {
982
+ quantize_info.dither = (MagickBooleanType) RTEST(argv[2]);
983
+ }
984
+ #endif
985
+ case 2:
986
+ VALUE_TO_ENUM(argv[1], quantize_info.colorspace, ColorspaceType);
987
+ case 1:
988
+ quantize_info.number_colors = NUM2ULONG(argv[0]);
989
+ case 0:
990
+ break;
991
+ default:
992
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 5)", argc);
993
+ break;
994
+ }
995
+
996
+
997
+ // Convert image array to image sequence, clone image sequence.
998
+ images = images_from_imagelist(self);
999
+ exception = AcquireExceptionInfo();
1000
+ GVL_STRUCT_TYPE(CloneImageList) args_CloneImageList = { images, exception };
1001
+ new_images = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CloneImageList), &args_CloneImageList);
1002
+ rm_split(images);
1003
+ rm_check_exception(exception, new_images, DestroyOnError);
1004
+
1005
+ rm_ensure_result(new_images);
1006
+
1007
+ #if defined(IMAGEMAGICK_7)
1008
+ GVL_STRUCT_TYPE(QuantizeImages) args_QuantizeImages = { &quantize_info, new_images, exception };
1009
+ #else
1010
+ GVL_STRUCT_TYPE(QuantizeImages) args_QuantizeImages = { &quantize_info, new_images };
1011
+ #endif
1012
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(QuantizeImages), &args_QuantizeImages);
1013
+ rm_check_exception(exception, new_images, DestroyOnError);
1014
+ DestroyExceptionInfo(exception);
1015
+
1016
+ // Create new ImageList object, convert mapped image sequence to images,
1017
+ // append to images array.
1018
+ new_imagelist = ImageList_new();
1019
+ while ((new_image = RemoveFirstImageFromList(&new_images)))
1020
+ {
1021
+ imagelist_push(new_imagelist, rm_image_new(new_image));
1022
+ }
1023
+
1024
+ // Set @scene in new ImageList object to same value as in self.
1025
+ scene = rb_iv_get(self, "@scene");
1026
+ rb_iv_set(new_imagelist, "@scene", scene);
1027
+
1028
+ RB_GC_GUARD(new_imagelist);
1029
+ RB_GC_GUARD(scene);
1030
+
1031
+ return new_imagelist;
1032
+ }
1033
+
1034
+
1035
+ /**
1036
+ * Reduce the colors used in the image list to the set of colors in +remap_image+.
1037
+ *
1038
+ * @overload remap(remap_image = nil, dither_method = Magick::RiemersmaDitherMethod)
1039
+ * @param remap_image [Magick::Image, Magick::ImageList] Either an imagelist or an image. If an
1040
+ * imagelist, uses the current image.
1041
+ * @param dither_method [Magick::DitherMethod] a DitherMethod value.
1042
+ * @return [Magick::ImageList] self
1043
+ * @note Modifies images in-place.
1044
+ */
1045
+ VALUE
1046
+ ImageList_remap(int argc, VALUE *argv, VALUE self)
1047
+ {
1048
+ Image *images, *remap_image = NULL;
1049
+ QuantizeInfo quantize_info;
1050
+ #if defined(IMAGEMAGICK_7)
1051
+ ExceptionInfo *exception;
1052
+ #endif
1053
+
1054
+ if (argc > 0 && argv[0] != Qnil)
1055
+ {
1056
+ VALUE t = rm_cur_image(argv[0]);
1057
+ remap_image = rm_check_destroyed(t);
1058
+ RB_GC_GUARD(t);
1059
+ }
1060
+
1061
+ GetQuantizeInfo(&quantize_info);
1062
+
1063
+ if (argc > 1)
1064
+ {
1065
+ VALUE_TO_ENUM(argv[1], quantize_info.dither_method, DitherMethod);
1066
+ #if defined(IMAGEMAGICK_6)
1067
+ quantize_info.dither = MagickTrue;
1068
+ #endif
1069
+ }
1070
+ if (argc > 2)
1071
+ {
1072
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc);
1073
+ }
1074
+
1075
+ images = images_from_imagelist(self);
1076
+
1077
+ #if defined(IMAGEMAGICK_7)
1078
+ exception = AcquireExceptionInfo();
1079
+ GVL_STRUCT_TYPE(RemapImages) args = { &quantize_info, images, remap_image, exception };
1080
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(RemapImages), &args);
1081
+ rm_split(images);
1082
+ CHECK_EXCEPTION();
1083
+ DestroyExceptionInfo(exception);
1084
+ #else
1085
+ GVL_STRUCT_TYPE(RemapImages) args = { &quantize_info, images, remap_image };
1086
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(RemapImages), &args);
1087
+ rm_split(images);
1088
+ rm_check_image_exception(images, RetainOnError);
1089
+ #endif
1090
+
1091
+ return self;
1092
+ }
1093
+
1094
+
1095
+ /**
1096
+ * Return the imagelist as a blob (a String).
1097
+ *
1098
+ * @overload to_blob
1099
+ *
1100
+ * @overload to_blob
1101
+ * Runs an info parm block if present - the user can specify the image format and depth
1102
+ * @yield [info]
1103
+ * @yieldparam info [Magick::Image::Info]
1104
+ *
1105
+ * @return [String] the blob
1106
+ */
1107
+ VALUE
1108
+ ImageList_to_blob(VALUE self)
1109
+ {
1110
+ Image *images, *image;
1111
+ Info *info;
1112
+ VALUE info_obj;
1113
+ VALUE blob_str;
1114
+ void *blob = NULL;
1115
+ size_t length = 0;
1116
+ ExceptionInfo *exception;
1117
+
1118
+ info_obj = rm_info_new();
1119
+ TypedData_Get_Struct(info_obj, Info, &rm_info_data_type, info);
1120
+
1121
+ // Convert the images array to an images sequence.
1122
+ images = images_from_imagelist(self);
1123
+
1124
+ exception = AcquireExceptionInfo();
1125
+ SetImageInfo(info, MagickTrue, exception);
1126
+ rm_check_exception(exception, images, RetainOnError);
1127
+
1128
+ if (*info->magick != '\0')
1129
+ {
1130
+ Image *img;
1131
+ for (img = images; img; img = GetNextImageInList(img))
1132
+ {
1133
+ strlcpy(img->magick, info->magick, sizeof(img->magick));
1134
+ }
1135
+ }
1136
+
1137
+ for (image = images; image; image = GetNextImageInList(image))
1138
+ {
1139
+ rm_sync_image_options(image, info);
1140
+ }
1141
+
1142
+ // Unconditionally request multi-images support. The worst that
1143
+ // can happen is that there's only one image or the format
1144
+ // doesn't support multi-image files.
1145
+ info->adjoin = MagickTrue;
1146
+ GVL_STRUCT_TYPE(ImagesToBlob) args = { info, images, &length, exception };
1147
+ blob = CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ImagesToBlob), &args);
1148
+ if (blob && exception->severity >= ErrorException)
1149
+ {
1150
+ magick_free((void*)blob);
1151
+ blob = NULL;
1152
+ length = 0;
1153
+ }
1154
+ rm_split(images);
1155
+ CHECK_EXCEPTION();
1156
+ DestroyExceptionInfo(exception);
1157
+
1158
+
1159
+ if (length == 0 || !blob)
1160
+ {
1161
+ return Qnil;
1162
+ }
1163
+
1164
+ blob_str = rb_str_new((const char *)blob, (long)length);
1165
+ magick_free((void*)blob);
1166
+
1167
+ RB_GC_GUARD(info_obj);
1168
+ RB_GC_GUARD(blob_str);
1169
+
1170
+ return blob_str;
1171
+ }
1172
+
1173
+
1174
+ /**
1175
+ * Write all the images to the specified file. If the file format supports
1176
+ * multi-image files, and the 'images' array contains more than one image, then
1177
+ * the images will be written as a single multi-image file. Otherwise each image
1178
+ * will be written to a separate file.
1179
+ *
1180
+ * @yield [info]
1181
+ * @yieldparam info [Magick::Image::Info]
1182
+ * @param file [File, String] the file
1183
+ */
1184
+ VALUE
1185
+ ImageList_write(VALUE self, VALUE file)
1186
+ {
1187
+ Image *images, *img;
1188
+ Info *info;
1189
+ const MagickInfo *m;
1190
+ VALUE info_obj;
1191
+ unsigned long scene;
1192
+ ExceptionInfo *exception;
1193
+
1194
+ info_obj = rm_info_new();
1195
+ TypedData_Get_Struct(info_obj, Info, &rm_info_data_type, info);
1196
+
1197
+
1198
+ if (TYPE(file) == T_FILE)
1199
+ {
1200
+ rb_io_t *fptr;
1201
+
1202
+ // Ensure file is open - raise error if not
1203
+ GetOpenFile(file, fptr);
1204
+ rb_io_check_writable(fptr);
1205
+
1206
+ add_format_prefix(info, rm_io_path(file));
1207
+ #if defined(_WIN32)
1208
+ SetImageInfoFile(info, NULL);
1209
+ #else
1210
+ SetImageInfoFile(info, rb_io_stdio_file(fptr));
1211
+ #endif
1212
+ }
1213
+ else
1214
+ {
1215
+ add_format_prefix(info, file);
1216
+ SetImageInfoFile(info, NULL);
1217
+ }
1218
+
1219
+ // Convert the images array to an images sequence.
1220
+ images = images_from_imagelist(self);
1221
+
1222
+ // Copy the filename into each image. Set a scene number to be used if
1223
+ // writing multiple files. (Ref: ImageMagick's utilities/convert.c
1224
+ for (scene = 0, img = images; img; img = GetNextImageInList(img))
1225
+ {
1226
+ img->scene = scene++;
1227
+ strlcpy(img->filename, info->filename, sizeof(img->filename));
1228
+ }
1229
+
1230
+ // Find out if the format supports multi-images files.
1231
+ exception = AcquireExceptionInfo();
1232
+ SetImageInfo(info, MagickTrue, exception);
1233
+ rm_check_exception(exception, images, RetainOnError);
1234
+
1235
+ m = GetMagickInfo(info->magick, exception);
1236
+ rm_check_exception(exception, images, RetainOnError);
1237
+ #if defined(IMAGEMAGICK_6)
1238
+ DestroyExceptionInfo(exception);
1239
+ #endif
1240
+
1241
+ // Tell WriteImage if we want a multi-images file.
1242
+ if (imagelist_length(self) > 1L && m && GetMagickAdjoin(m))
1243
+ {
1244
+ info->adjoin = MagickTrue;
1245
+ }
1246
+
1247
+ for (img = images; img; img = GetNextImageInList(img))
1248
+ {
1249
+ rm_sync_image_options(img, info);
1250
+ #if defined(IMAGEMAGICK_7)
1251
+ GVL_STRUCT_TYPE(WriteImage) args = { info, img, exception };
1252
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(WriteImage), &args);
1253
+ rm_check_exception(exception, img, RetainOnError);
1254
+ #else
1255
+ GVL_STRUCT_TYPE(WriteImage) args = { info, img };
1256
+ CALL_FUNC_WITHOUT_GVL(GVL_FUNC(WriteImage), &args);
1257
+ // images will be split before raising an exception
1258
+ rm_check_image_exception(images, RetainOnError);
1259
+ #endif
1260
+ if (info->adjoin)
1261
+ {
1262
+ break;
1263
+ }
1264
+ }
1265
+
1266
+ #if defined(IMAGEMAGICK_7)
1267
+ DestroyExceptionInfo(exception);
1268
+ #endif
1269
+
1270
+ rm_split(images);
1271
+
1272
+ RB_GC_GUARD(info_obj);
1273
+
1274
+ return self;
1275
+ }