image_paradise 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of image_paradise might be problematic. Click here for more details.

Files changed (649) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +38 -0
  3. data/README.md +928 -0
  4. data/USAGE.md +10 -0
  5. data/bin/black_white +10 -0
  6. data/bin/confree_generator +7 -0
  7. data/bin/create_new_image +7 -0
  8. data/bin/display_text_from_this_image +7 -0
  9. data/bin/draw_as_specified_from_the_yaml_file +7 -0
  10. data/bin/embed_the_filename_into_this_image +7 -0
  11. data/bin/image_paradise +7 -0
  12. data/bin/image_paradise_shell +7 -0
  13. data/bin/image_to_ascii +54 -0
  14. data/bin/image_to_pdf +7 -0
  15. data/bin/imageparadise_img2pdf +12 -0
  16. data/bin/img_text +14 -0
  17. data/bin/interlace +7 -0
  18. data/bin/jpg_to_pdf +12 -0
  19. data/bin/magic_card_border +8 -0
  20. data/bin/make_this_image_transparent +7 -0
  21. data/bin/morph_these_images +7 -0
  22. data/bin/optimize_this_image +7 -0
  23. data/bin/quality +7 -0
  24. data/bin/resize_by_percent +10 -0
  25. data/bin/rotate_left +7 -0
  26. data/bin/rotate_right +7 -0
  27. data/bin/round_the_corner +7 -0
  28. data/bin/ruby_montage +7 -0
  29. data/bin/transparent +15 -0
  30. data/doc/README.gen +871 -0
  31. data/doc/todo/TODO_FOR_THE_GTK_GUI.md +9 -0
  32. data/doc/todo/TODO_FOR_THE_IMAGE_PARADISE_PROJECT.md +22 -0
  33. data/doc/todo/TODO_WORK_THROUGH_THESE_LINKS.md +3 -0
  34. data/doc/todo/todo_for_the_libui_gui.md +4 -0
  35. data/image_paradise.gemspec +46 -0
  36. data/images/IMAGE_PARADISE_LOGO.png +0 -0
  37. data/lib/image_paradise/base/base.rb +293 -0
  38. data/lib/image_paradise/cfdg/1dca_pattern.cfdg +48 -0
  39. data/lib/image_paradise/cfdg/3d_coloured_cube.cfdg +95 -0
  40. data/lib/image_paradise/cfdg/a_3D_spiral.cfdg +40 -0
  41. data/lib/image_paradise/cfdg/a_chaotic_city.cfdg +156 -0
  42. data/lib/image_paradise/cfdg/a_coloured_red.cfdg +21 -0
  43. data/lib/image_paradise/cfdg/a_daisy_flower.cfdg +66 -0
  44. data/lib/image_paradise/cfdg/a_decorated_window.cfdg +74 -0
  45. data/lib/image_paradise/cfdg/a_human_profile.cfdg +303 -0
  46. data/lib/image_paradise/cfdg/a_lost_heart.cfdg +28 -0
  47. data/lib/image_paradise/cfdg/a_plant_root.cfdg +26 -0
  48. data/lib/image_paradise/cfdg/a_rather_realistic_forest.cfdg +29 -0
  49. data/lib/image_paradise/cfdg/a_shoreline_next_to_a_forest.cfdg +127 -0
  50. data/lib/image_paradise/cfdg/a_simple_mini_brain.cfdg +17 -0
  51. data/lib/image_paradise/cfdg/a_simple_star.cfdg +22 -0
  52. data/lib/image_paradise/cfdg/adorned_tree.cfdg +58 -0
  53. data/lib/image_paradise/cfdg/adsorption.cfdg +19 -0
  54. data/lib/image_paradise/cfdg/alfabet_free.cfdg +346 -0
  55. data/lib/image_paradise/cfdg/alfreebet.cfdg +229 -0
  56. data/lib/image_paradise/cfdg/algal_flora.cfdg +25 -0
  57. data/lib/image_paradise/cfdg/alien_eyeball.cfdg +15 -0
  58. data/lib/image_paradise/cfdg/alien_flower.cfdg +35 -0
  59. data/lib/image_paradise/cfdg/alphabet_circles.cfdg +38 -0
  60. data/lib/image_paradise/cfdg/alveolo.cfdg +38 -0
  61. data/lib/image_paradise/cfdg/an_icosahedron.cfdg +134 -0
  62. data/lib/image_paradise/cfdg/an_oils_surface.cfdg +48 -0
  63. data/lib/image_paradise/cfdg/ancient_map.cfdg +30 -0
  64. data/lib/image_paradise/cfdg/ancient_scripts_tile.cfdg +96 -0
  65. data/lib/image_paradise/cfdg/angelfish.cfdg +58 -0
  66. data/lib/image_paradise/cfdg/angry_yarn.cfdg +82 -0
  67. data/lib/image_paradise/cfdg/apple_tree_small.cfdg +46 -0
  68. data/lib/image_paradise/cfdg/aqua_star.cfdg +27 -0
  69. data/lib/image_paradise/cfdg/army_explosion.cfdg +25 -0
  70. data/lib/image_paradise/cfdg/arrows_in_quadcity.cfdg +143 -0
  71. data/lib/image_paradise/cfdg/artificial_intelligence.cfdg +41 -0
  72. data/lib/image_paradise/cfdg/askew.cfdg +27 -0
  73. data/lib/image_paradise/cfdg/audio_diagram_waves.cfdg +54 -0
  74. data/lib/image_paradise/cfdg/autumn_fractal.cfdg +39 -0
  75. data/lib/image_paradise/cfdg/baignoire.cfdg +33 -0
  76. data/lib/image_paradise/cfdg/barcode.cfdg +781 -0
  77. data/lib/image_paradise/cfdg/basic_polygon_shapes.cfdg +311 -0
  78. data/lib/image_paradise/cfdg/basic_spreaders.cfdg +52 -0
  79. data/lib/image_paradise/cfdg/basic_square.cfdg +8 -0
  80. data/lib/image_paradise/cfdg/bats_hiding_in_foliage.cfdg +19 -0
  81. data/lib/image_paradise/cfdg/bees.cfdg +61 -0
  82. data/lib/image_paradise/cfdg/bent_squares.cfdg +46 -0
  83. data/lib/image_paradise/cfdg/benzo_dreaming.cfdg +54 -0
  84. data/lib/image_paradise/cfdg/beta_bet.cfdg +645 -0
  85. data/lib/image_paradise/cfdg/big_bang_theory.cfdg +31 -0
  86. data/lib/image_paradise/cfdg/big_pacman.cfdg +70 -0
  87. data/lib/image_paradise/cfdg/bigger_tree.cfdg +64 -0
  88. data/lib/image_paradise/cfdg/binary_connection.cfdg +34 -0
  89. data/lib/image_paradise/cfdg/birch_line.cfdg +57 -0
  90. data/lib/image_paradise/cfdg/blacksmith_masterpiece.cfdg +3 -0
  91. data/lib/image_paradise/cfdg/blocked_rectangles.cfdg +23 -0
  92. data/lib/image_paradise/cfdg/blood_tubes.cfdg +45 -0
  93. data/lib/image_paradise/cfdg/bloom.cfdg +23 -0
  94. data/lib/image_paradise/cfdg/blown_glass_spheres.cfdg +30 -0
  95. data/lib/image_paradise/cfdg/blue_daisies_in_detail.cfdg +101 -0
  96. data/lib/image_paradise/cfdg/blue_galaxy.cfdg +20 -0
  97. data/lib/image_paradise/cfdg/blue_moon.cfdg +36 -0
  98. data/lib/image_paradise/cfdg/boa_feathers.cfdg +53 -0
  99. data/lib/image_paradise/cfdg/bomb.cfdg +75 -0
  100. data/lib/image_paradise/cfdg/boxy_continent.cfdg +111 -0
  101. data/lib/image_paradise/cfdg/bright_coloured_neurons.cfdg +53 -0
  102. data/lib/image_paradise/cfdg/brightness_flower.cfdg +31 -0
  103. data/lib/image_paradise/cfdg/btp_71_beautiful_coloured_lines.cfdg +85 -0
  104. data/lib/image_paradise/cfdg/btp_73.cfdg +76 -0
  105. data/lib/image_paradise/cfdg/bubblesun.cfdg +46 -0
  106. data/lib/image_paradise/cfdg/burning_bush.cfdg +31 -0
  107. data/lib/image_paradise/cfdg/butterflies_in_the_moonlight.cfdg +55 -0
  108. data/lib/image_paradise/cfdg/cardiod_arc.cfdg +44 -0
  109. data/lib/image_paradise/cfdg/cardioid.cfdg +41 -0
  110. data/lib/image_paradise/cfdg/caros_wallpaper.cfdg +46 -0
  111. data/lib/image_paradise/cfdg/cartoony_face_arrays.cfdg +137 -0
  112. data/lib/image_paradise/cfdg/centerfold.cfdg +12 -0
  113. data/lib/image_paradise/cfdg/chain_link_fence.cfdg +31 -0
  114. data/lib/image_paradise/cfdg/chanukah.cfdg +109 -0
  115. data/lib/image_paradise/cfdg/chaos_red_sun.cfdg +42 -0
  116. data/lib/image_paradise/cfdg/chaotic_farn.cfdg +76 -0
  117. data/lib/image_paradise/cfdg/chaotic_fractal_shell.cfdg +41 -0
  118. data/lib/image_paradise/cfdg/charleston.cfdg +182 -0
  119. data/lib/image_paradise/cfdg/ciliasun.cfdg +109 -0
  120. data/lib/image_paradise/cfdg/cipal.cfdg +65 -0
  121. data/lib/image_paradise/cfdg/circuits.cfdg +176 -0
  122. data/lib/image_paradise/cfdg/city_map.cfdg +66 -0
  123. data/lib/image_paradise/cfdg/clifford_torus.cfdg +135 -0
  124. data/lib/image_paradise/cfdg/colonize_flat_colour_pattern.cfdg +14 -0
  125. data/lib/image_paradise/cfdg/colour_blind_squid.cfdg +30 -0
  126. data/lib/image_paradise/cfdg/colour_hole.cfdg +56 -0
  127. data/lib/image_paradise/cfdg/colour_wheel.cfdg +40 -0
  128. data/lib/image_paradise/cfdg/coloured_eyes.cfdg +40 -0
  129. data/lib/image_paradise/cfdg/coloured_forest.cfdg +133 -0
  130. data/lib/image_paradise/cfdg/coloured_tree.cfdg +50 -0
  131. data/lib/image_paradise/cfdg/colourful_lives.cfdg +123 -0
  132. data/lib/image_paradise/cfdg/colourful_neuronal_network.cfdg +32 -0
  133. data/lib/image_paradise/cfdg/complex_city_plans.cfdg +75 -0
  134. data/lib/image_paradise/cfdg/complex_kritworks.cfdg +75 -0
  135. data/lib/image_paradise/cfdg/complex_snowflake.cfdg +61 -0
  136. data/lib/image_paradise/cfdg/conspiracy_theory.cfdg +104 -0
  137. data/lib/image_paradise/cfdg/constellation_grid.cfdg +29 -0
  138. data/lib/image_paradise/cfdg/cool_caterpillar.cfdg +44 -0
  139. data/lib/image_paradise/cfdg/coolcubes.cfdg +70 -0
  140. data/lib/image_paradise/cfdg/crawler_battle.cfdg +93 -0
  141. data/lib/image_paradise/cfdg/crazy_octo.cfdg +48 -0
  142. data/lib/image_paradise/cfdg/cthulhu.cfdg +166 -0
  143. data/lib/image_paradise/cfdg/cubies.cfdg +43 -0
  144. data/lib/image_paradise/cfdg/cubist_sunset.cfdg +55 -0
  145. data/lib/image_paradise/cfdg/curled_tree.cfdg +37 -0
  146. data/lib/image_paradise/cfdg/curls.cfdg +45 -0
  147. data/lib/image_paradise/cfdg/curve_stiched.cfdg +59 -0
  148. data/lib/image_paradise/cfdg/curved_tubes.cfdg +20 -0
  149. data/lib/image_paradise/cfdg/cylinder_city.cfdg +27 -0
  150. data/lib/image_paradise/cfdg/cymbal.cfdg +38 -0
  151. data/lib/image_paradise/cfdg/d_mustard.cfdg +52 -0
  152. data/lib/image_paradise/cfdg/dance_party.cfdg +81 -0
  153. data/lib/image_paradise/cfdg/dance_party_and_background.cfdg +86 -0
  154. data/lib/image_paradise/cfdg/decreasing_aperture.cfdg +16 -0
  155. data/lib/image_paradise/cfdg/delicat_twist.cfdg +13 -0
  156. data/lib/image_paradise/cfdg/demo_text.cfdg +22 -0
  157. data/lib/image_paradise/cfdg/dennis_ritchie.cfdg +294 -0
  158. data/lib/image_paradise/cfdg/diablo.cfdg +47 -0
  159. data/lib/image_paradise/cfdg/different_flowers.cfdg +60 -0
  160. data/lib/image_paradise/cfdg/different_snowflakes_shapes.cfdg +149 -0
  161. data/lib/image_paradise/cfdg/dimensions.cfdg +33 -0
  162. data/lib/image_paradise/cfdg/domino_pieces.cfdg +166 -0
  163. data/lib/image_paradise/cfdg/dong.cfdg +41 -0
  164. data/lib/image_paradise/cfdg/drip_shape.cfdg +24 -0
  165. data/lib/image_paradise/cfdg/earthday2007b.cfdg +49 -0
  166. data/lib/image_paradise/cfdg/edera_circles.cfdg +55 -0
  167. data/lib/image_paradise/cfdg/eight_queens_problem.cfdg +85 -0
  168. data/lib/image_paradise/cfdg/electro_shock.cfdg +88 -0
  169. data/lib/image_paradise/cfdg/enter_the_force_field.cfdg +56 -0
  170. data/lib/image_paradise/cfdg/escargot_fleur.cfdg +98 -0
  171. data/lib/image_paradise/cfdg/european_city.cfdg +63 -0
  172. data/lib/image_paradise/cfdg/evil_eye.cfdg +74 -0
  173. data/lib/image_paradise/cfdg/evolving_coloured_spots.cfdg +47 -0
  174. data/lib/image_paradise/cfdg/excellines_nr2.cfdg +171 -0
  175. data/lib/image_paradise/cfdg/exoplanet_settlement.cfdg +117 -0
  176. data/lib/image_paradise/cfdg/explosion.cfdg +45 -0
  177. data/lib/image_paradise/cfdg/explosion_of_a_megabyte.cfdg +73 -0
  178. data/lib/image_paradise/cfdg/eye_of_katora.cfdg +20 -0
  179. data/lib/image_paradise/cfdg/family_tree.cfdg +169 -0
  180. data/lib/image_paradise/cfdg/feathers.cfdg +17 -0
  181. data/lib/image_paradise/cfdg/ferma_drawings.cfdg +23 -0
  182. data/lib/image_paradise/cfdg/fevrier.cfdg +66 -0
  183. data/lib/image_paradise/cfdg/fibmod.cfdg +25 -0
  184. data/lib/image_paradise/cfdg/field_of_boxes.cfdg +21 -0
  185. data/lib/image_paradise/cfdg/finetre.cfdg +34 -0
  186. data/lib/image_paradise/cfdg/fireblorks.cfdg +37 -0
  187. data/lib/image_paradise/cfdg/first_branch.cfdg +18 -0
  188. data/lib/image_paradise/cfdg/fish_with_coloured_bubbles.cfdg +77 -0
  189. data/lib/image_paradise/cfdg/fishing_lure.cfdg +30 -0
  190. data/lib/image_paradise/cfdg/flake.cfdg +20 -0
  191. data/lib/image_paradise/cfdg/flaming_spiro.cfdg +10 -0
  192. data/lib/image_paradise/cfdg/fleshflower.cfdg +25 -0
  193. data/lib/image_paradise/cfdg/flourescent_fish_btp.cfdg +48 -0
  194. data/lib/image_paradise/cfdg/flow_control_shape.cfdg +45 -0
  195. data/lib/image_paradise/cfdg/flower_galaxy.cfdg +57 -0
  196. data/lib/image_paradise/cfdg/flower_house.cfdg +115 -0
  197. data/lib/image_paradise/cfdg/flower_stories.cfdg +136 -0
  198. data/lib/image_paradise/cfdg/fluctuating_heart.cfdg +87 -0
  199. data/lib/image_paradise/cfdg/fly_agaric.cfdg +22 -0
  200. data/lib/image_paradise/cfdg/forest_and_ocean.cfdg +65 -0
  201. data/lib/image_paradise/cfdg/fractal_fern.cfdg +15 -0
  202. data/lib/image_paradise/cfdg/fractal_shell.cfdg +36 -0
  203. data/lib/image_paradise/cfdg/frost_bite.cfdg +23 -0
  204. data/lib/image_paradise/cfdg/fun_with_paper.cfdg +17 -0
  205. data/lib/image_paradise/cfdg/func_plot.cfdg +59 -0
  206. data/lib/image_paradise/cfdg/funky_squiggle.cfdg +40 -0
  207. data/lib/image_paradise/cfdg/fuzzy_sun.cfdg +47 -0
  208. data/lib/image_paradise/cfdg/galaxy.cfdg +59 -0
  209. data/lib/image_paradise/cfdg/gallery.cfdg +28 -0
  210. data/lib/image_paradise/cfdg/game1_turn6.cfdg +35 -0
  211. data/lib/image_paradise/cfdg/garland.cfdg +42 -0
  212. data/lib/image_paradise/cfdg/general_polygons.cfdg +20 -0
  213. data/lib/image_paradise/cfdg/generational_birds.cfdg +118 -0
  214. data/lib/image_paradise/cfdg/ghostly_spine.cfdg +24 -0
  215. data/lib/image_paradise/cfdg/gift_wrapping.cfdg +46 -0
  216. data/lib/image_paradise/cfdg/glass_cubes.cfdg +33 -0
  217. data/lib/image_paradise/cfdg/gleaming_bush.cfdg +33 -0
  218. data/lib/image_paradise/cfdg/glowing_bush.cfdg +33 -0
  219. data/lib/image_paradise/cfdg/go_grid.cfdg +32 -0
  220. data/lib/image_paradise/cfdg/gold_tiles.cfdg +21 -0
  221. data/lib/image_paradise/cfdg/golden_rectangle.cfdg +19 -0
  222. data/lib/image_paradise/cfdg/golden_sierpinski.cfdg +49 -0
  223. data/lib/image_paradise/cfdg/golgi_stain.cfdg +74 -0
  224. data/lib/image_paradise/cfdg/gothic_bath_tiles.cfdg +14 -0
  225. data/lib/image_paradise/cfdg/grass_land.cfdg +112 -0
  226. data/lib/image_paradise/cfdg/gray_matter.cfdg +110 -0
  227. data/lib/image_paradise/cfdg/great_forest.cfdg +91 -0
  228. data/lib/image_paradise/cfdg/growth.cfdg +46 -0
  229. data/lib/image_paradise/cfdg/gumtree.cfdg +28 -0
  230. data/lib/image_paradise/cfdg/haggards_bull.cfdg +92 -0
  231. data/lib/image_paradise/cfdg/haight_ashbury.cfdg +882 -0
  232. data/lib/image_paradise/cfdg/hair_pattern.cfdg +59 -0
  233. data/lib/image_paradise/cfdg/hairy.cfdg +43 -0
  234. data/lib/image_paradise/cfdg/hairy_branch.cfdg +48 -0
  235. data/lib/image_paradise/cfdg/hands_and_feet.cfdg +49 -0
  236. data/lib/image_paradise/cfdg/happy_new_year.cfdg +3435 -0
  237. data/lib/image_paradise/cfdg/hatagu_lila_spiral.cfdg +27 -0
  238. data/lib/image_paradise/cfdg/hexaeder_triangle.cfdg +43 -0
  239. data/lib/image_paradise/cfdg/hexclouds_textures.cfdg +75 -0
  240. data/lib/image_paradise/cfdg/hextiles.cfdg +73 -0
  241. data/lib/image_paradise/cfdg/hexy_continent.cfdg +83 -0
  242. data/lib/image_paradise/cfdg/human_ballet.cfdg +215 -0
  243. data/lib/image_paradise/cfdg/human_eyes.cfdg +102 -0
  244. data/lib/image_paradise/cfdg/hydra_tail.cfdg +57 -0
  245. data/lib/image_paradise/cfdg/i_like_it_dirty.cfdg +88 -0
  246. data/lib/image_paradise/cfdg/i_pix.cfdg +679 -0
  247. data/lib/image_paradise/cfdg/imaginary_star.cfdg +55 -0
  248. data/lib/image_paradise/cfdg/imaginery_forest.cfdg +61 -0
  249. data/lib/image_paradise/cfdg/impossible_stairs.cfdg +211 -0
  250. data/lib/image_paradise/cfdg/in_the_morning.cfdg +83 -0
  251. data/lib/image_paradise/cfdg/inertial_confinement.cfdg +150 -0
  252. data/lib/image_paradise/cfdg/infected_shell.cfdg +56 -0
  253. data/lib/image_paradise/cfdg/insect_fight.cfdg +316 -0
  254. data/lib/image_paradise/cfdg/insectivore.cfdg +80 -0
  255. data/lib/image_paradise/cfdg/interference.cfdg +43 -0
  256. data/lib/image_paradise/cfdg/interference_fields.cfdg +25 -0
  257. data/lib/image_paradise/cfdg/into_the_deep.cfdg +96 -0
  258. data/lib/image_paradise/cfdg/inverted_decorations.cfdg +85 -0
  259. data/lib/image_paradise/cfdg/irregular_galaxies.cfdg +29 -0
  260. data/lib/image_paradise/cfdg/iso_blocks.cfdg +35 -0
  261. data/lib/image_paradise/cfdg/jewelry_old_style.cfdg +31 -0
  262. data/lib/image_paradise/cfdg/just_some_flowers.cfdg +127 -0
  263. data/lib/image_paradise/cfdg/kaboom.cfdg +40 -0
  264. data/lib/image_paradise/cfdg/kaleidoskop.cfdg +27 -0
  265. data/lib/image_paradise/cfdg/kama_sutra.cfdg +182 -0
  266. data/lib/image_paradise/cfdg/kitakoa_akiyoshi_illusions_roller.cfdg +40 -0
  267. data/lib/image_paradise/cfdg/koch_snowflake.cfdg +11 -0
  268. data/lib/image_paradise/cfdg/kochlea.cfdg +43 -0
  269. data/lib/image_paradise/cfdg/kreepykrawler.cfdg +48 -0
  270. data/lib/image_paradise/cfdg/kw_expanded_explosion.cfdg +46 -0
  271. data/lib/image_paradise/cfdg/lapsang_abstrait.cfdg +51 -0
  272. data/lib/image_paradise/cfdg/laser.cfdg +51 -0
  273. data/lib/image_paradise/cfdg/last_pluto_dream.cfdg +95 -0
  274. data/lib/image_paradise/cfdg/lazy_dust.cfdg +42 -0
  275. data/lib/image_paradise/cfdg/lesson_one_two_three_four.cfdg +217 -0
  276. data/lib/image_paradise/cfdg/lila_lili.cfdg +60 -0
  277. data/lib/image_paradise/cfdg/lindenmayergrassef2_pretty_flowers.cfdg +94 -0
  278. data/lib/image_paradise/cfdg/lines_from_excel.cfdg +136 -0
  279. data/lib/image_paradise/cfdg/looking_out.cfdg +51 -0
  280. data/lib/image_paradise/cfdg/looking_up_in_the_sky.cfdg +43 -0
  281. data/lib/image_paradise/cfdg/lotus_logo.cfdg +49 -0
  282. data/lib/image_paradise/cfdg/lowercased_alphabet.cfdg +565 -0
  283. data/lib/image_paradise/cfdg/luma_smiley.cfdg +563 -0
  284. data/lib/image_paradise/cfdg/maggi_stars.cfdg +11 -0
  285. data/lib/image_paradise/cfdg/mandelbrot_3.cfdg +111 -0
  286. data/lib/image_paradise/cfdg/martini.cfdg +147 -0
  287. data/lib/image_paradise/cfdg/material_studies.cfdg +172 -0
  288. data/lib/image_paradise/cfdg/math_eye.cfdg +30 -0
  289. data/lib/image_paradise/cfdg/matrix_freestyle.cfdg +127 -0
  290. data/lib/image_paradise/cfdg/maze.cfdg +211 -0
  291. data/lib/image_paradise/cfdg/meaculpo.cfdg +46 -0
  292. data/lib/image_paradise/cfdg/medieval_madness.cfdg +140 -0
  293. data/lib/image_paradise/cfdg/menage_a_trois.cfdg +77 -0
  294. data/lib/image_paradise/cfdg/micky_mouse.cfdg +75 -0
  295. data/lib/image_paradise/cfdg/mistletoe_forest.cfdg +62 -0
  296. data/lib/image_paradise/cfdg/mixed_simple_bubbles.cfdg +20 -0
  297. data/lib/image_paradise/cfdg/mod4g_starhole.cfdg +27 -0
  298. data/lib/image_paradise/cfdg/moebius.cfdg +57 -0
  299. data/lib/image_paradise/cfdg/molecules.cfdg +30 -0
  300. data/lib/image_paradise/cfdg/momos_blossom.cfdg +70 -0
  301. data/lib/image_paradise/cfdg/mona_lisa.cfdg +7937 -0
  302. data/lib/image_paradise/cfdg/more_arrows_in_quadcity.cfdg +49 -0
  303. data/lib/image_paradise/cfdg/more_cats.cfdg +1002 -0
  304. data/lib/image_paradise/cfdg/mosaic_for_2D_games.cfdg +69 -0
  305. data/lib/image_paradise/cfdg/mr_bezier.cfdg +195 -0
  306. data/lib/image_paradise/cfdg/mtree.cfdg +33 -0
  307. data/lib/image_paradise/cfdg/multiple_triangles.cfdg +13 -0
  308. data/lib/image_paradise/cfdg/mycel.cfdg +88 -0
  309. data/lib/image_paradise/cfdg/mytohexagone.cfdg +56 -0
  310. data/lib/image_paradise/cfdg/nature_is_not_like_that.cfdg +48 -0
  311. data/lib/image_paradise/cfdg/negative_flowers.cfdg +85 -0
  312. data/lib/image_paradise/cfdg/neo_town.cfdg +41 -0
  313. data/lib/image_paradise/cfdg/nesting_pattern.cfdg +34 -0
  314. data/lib/image_paradise/cfdg/neuronal_network.cfdg +94 -0
  315. data/lib/image_paradise/cfdg/neuronal_root.cfdg +46 -0
  316. data/lib/image_paradise/cfdg/night.cfdg +82 -0
  317. data/lib/image_paradise/cfdg/nightwalker.cfdg +23 -0
  318. data/lib/image_paradise/cfdg/no_xcape.cfdg +41 -0
  319. data/lib/image_paradise/cfdg/noise.cfdg +12 -0
  320. data/lib/image_paradise/cfdg/octopodi.cfdg +51 -0
  321. data/lib/image_paradise/cfdg/octopussy.cfdg +49 -0
  322. data/lib/image_paradise/cfdg/oldschool_cartoon_figure.cfdg +181 -0
  323. data/lib/image_paradise/cfdg/open_shapes.cfdg +240 -0
  324. data/lib/image_paradise/cfdg/orange_blossom.cfdg +57 -0
  325. data/lib/image_paradise/cfdg/orange_guts.cfdg +43 -0
  326. data/lib/image_paradise/cfdg/orange_monster.cfdg +42 -0
  327. data/lib/image_paradise/cfdg/organic.cfdg +30 -0
  328. data/lib/image_paradise/cfdg/ouo_happy_smiley.cfdg +45 -0
  329. data/lib/image_paradise/cfdg/output.png +0 -0
  330. data/lib/image_paradise/cfdg/pacman.cfdg +18 -0
  331. data/lib/image_paradise/cfdg/palmen.cfdg +162 -0
  332. data/lib/image_paradise/cfdg/pandoras_box.cfdg +53 -0
  333. data/lib/image_paradise/cfdg/papillon_butterfly.cfdg +28 -0
  334. data/lib/image_paradise/cfdg/patchwork.cfdg +32 -0
  335. data/lib/image_paradise/cfdg/pattern_grass.cfdg +110 -0
  336. data/lib/image_paradise/cfdg/peau_de_grenouille.cfdg +16 -0
  337. data/lib/image_paradise/cfdg/penrose_tiling.cfdg +102 -0
  338. data/lib/image_paradise/cfdg/pentagon.cfdg +68 -0
  339. data/lib/image_paradise/cfdg/pentagons.cfdg +25 -0
  340. data/lib/image_paradise/cfdg/perspective_tsunami.cfdg +20 -0
  341. data/lib/image_paradise/cfdg/phi_cloud.cfdg +23 -0
  342. data/lib/image_paradise/cfdg/picnic_birds_eye_view.cfdg +132 -0
  343. data/lib/image_paradise/cfdg/ping_pong.cfdg +29 -0
  344. data/lib/image_paradise/cfdg/pink_blossom.cfdg +58 -0
  345. data/lib/image_paradise/cfdg/piupole.cfdg +77 -0
  346. data/lib/image_paradise/cfdg/plotting.cfdg +61 -0
  347. data/lib/image_paradise/cfdg/point_onto_root.cfdg +64 -0
  348. data/lib/image_paradise/cfdg/primitive_reptile_pattern.cfdg +96 -0
  349. data/lib/image_paradise/cfdg/psycho_knot.cfdg +20 -0
  350. data/lib/image_paradise/cfdg/pyramide.cfdg +67 -0
  351. data/lib/image_paradise/cfdg/pythagoras_puzzle.cfdg +17 -0
  352. data/lib/image_paradise/cfdg/pythagorean_tree.cfdg +70 -0
  353. data/lib/image_paradise/cfdg/qimica.cfdg +64 -0
  354. data/lib/image_paradise/cfdg/quad_green_satellite.cfdg +53 -0
  355. data/lib/image_paradise/cfdg/quadcity.cfdg +24 -0
  356. data/lib/image_paradise/cfdg/quiet_wood_town.cfdg +195 -0
  357. data/lib/image_paradise/cfdg/r180.cfdg +26 -0
  358. data/lib/image_paradise/cfdg/r45.cfdg +26 -0
  359. data/lib/image_paradise/cfdg/r_square.cfdg +36 -0
  360. data/lib/image_paradise/cfdg/rads.cfdg +33 -0
  361. data/lib/image_paradise/cfdg/rainbow_black_hole.cfdg +9 -0
  362. data/lib/image_paradise/cfdg/rainbow_sun.cfdg +9 -0
  363. data/lib/image_paradise/cfdg/random_handwriting.cfdg +50 -0
  364. data/lib/image_paradise/cfdg/random_tile_shapes_jens_revisited.cfdg +146 -0
  365. data/lib/image_paradise/cfdg/rays_attack.cfdg +29 -0
  366. data/lib/image_paradise/cfdg/razpad.cfdg +20 -0
  367. data/lib/image_paradise/cfdg/rectangular_distortion.cfdg +169 -0
  368. data/lib/image_paradise/cfdg/recurse_path.cfdg +38 -0
  369. data/lib/image_paradise/cfdg/red_flurry.cfdg +64 -0
  370. data/lib/image_paradise/cfdg/red_horse_tail.cfdg +36 -0
  371. data/lib/image_paradise/cfdg/red_yellow_mosaic.cfdg +26 -0
  372. data/lib/image_paradise/cfdg/rendering_tests.cfdg +183 -0
  373. data/lib/image_paradise/cfdg/repeat_floor_tile_pattern.cfdg +153 -0
  374. data/lib/image_paradise/cfdg/repeat_tile.cfdg +160 -0
  375. data/lib/image_paradise/cfdg/retro_disc.cfdg +736 -0
  376. data/lib/image_paradise/cfdg/ring_growth_variation.cfdg +41 -0
  377. data/lib/image_paradise/cfdg/robot_nightlife.cfdg +25 -0
  378. data/lib/image_paradise/cfdg/rolled_firespiral.cfdg +34 -0
  379. data/lib/image_paradise/cfdg/rose.cfdg +44 -0
  380. data/lib/image_paradise/cfdg/round_tree.cfdg +121 -0
  381. data/lib/image_paradise/cfdg/rubiks_cube.cfdg +120 -0
  382. data/lib/image_paradise/cfdg/ruins.cfdg +19 -0
  383. data/lib/image_paradise/cfdg/sails_and_the_sea.cfdg +27 -0
  384. data/lib/image_paradise/cfdg/salt_crystals.cfdg +26 -0
  385. data/lib/image_paradise/cfdg/saturn.cfdg +105 -0
  386. data/lib/image_paradise/cfdg/scary_pot.cfdg +49 -0
  387. data/lib/image_paradise/cfdg/schematic_worm.cfdg +35 -0
  388. data/lib/image_paradise/cfdg/school_script.cfdg +359 -0
  389. data/lib/image_paradise/cfdg/seahorse.cfdg +78 -0
  390. data/lib/image_paradise/cfdg/seasons.cfdg +115 -0
  391. data/lib/image_paradise/cfdg/segmental_veins.cfdg +66 -0
  392. data/lib/image_paradise/cfdg/select_mayhem.cfdg +28 -0
  393. data/lib/image_paradise/cfdg/seven_folded_symmetry.cfdg +7 -0
  394. data/lib/image_paradise/cfdg/several_cats.cfdg +996 -0
  395. data/lib/image_paradise/cfdg/shadow_box.cfdg +49 -0
  396. data/lib/image_paradise/cfdg/shadowrun_google_maps.cfdg +66 -0
  397. data/lib/image_paradise/cfdg/shadowrun_nightline.cfdg +18 -0
  398. data/lib/image_paradise/cfdg/shards.cfdg +70 -0
  399. data/lib/image_paradise/cfdg/sheet_music.cfdg +213 -0
  400. data/lib/image_paradise/cfdg/shy_guy.cfdg +886 -0
  401. data/lib/image_paradise/cfdg/sierpinski1.cfdg +41 -0
  402. data/lib/image_paradise/cfdg/sierpinski2.cfdg +34 -0
  403. data/lib/image_paradise/cfdg/sierpinski_like_red_swirl.cfdg +46 -0
  404. data/lib/image_paradise/cfdg/sierpinsktri.cfdg +9 -0
  405. data/lib/image_paradise/cfdg/silk_flowers.cfdg +68 -0
  406. data/lib/image_paradise/cfdg/silk_scarf.cfdg +18 -0
  407. data/lib/image_paradise/cfdg/simple_cilia.cfdg +88 -0
  408. data/lib/image_paradise/cfdg/simple_circle_and_square.cfdg +7 -0
  409. data/lib/image_paradise/cfdg/simple_coloured_square.cfdg +38 -0
  410. data/lib/image_paradise/cfdg/simple_ferns.cfdg +40 -0
  411. data/lib/image_paradise/cfdg/simple_fish.cfdg +77 -0
  412. data/lib/image_paradise/cfdg/simple_orchid.cfdg +23 -0
  413. data/lib/image_paradise/cfdg/simple_rounded_colour_wheel.cfdg +10 -0
  414. data/lib/image_paradise/cfdg/simple_sheet_music.cfdg +27 -0
  415. data/lib/image_paradise/cfdg/sincos_pattern_2.cfdg +42 -0
  416. data/lib/image_paradise/cfdg/singing_birdy.cfdg +112 -0
  417. data/lib/image_paradise/cfdg/skyscraper.cfdg +85 -0
  418. data/lib/image_paradise/cfdg/small_golden_rectangle.cfdg +12 -0
  419. data/lib/image_paradise/cfdg/smells_like_layered.cfdg +43 -0
  420. data/lib/image_paradise/cfdg/snowflake.cfdg +26 -0
  421. data/lib/image_paradise/cfdg/snowstorm.cfdg +26 -0
  422. data/lib/image_paradise/cfdg/soar_on_wings.cfdg +8 -0
  423. data/lib/image_paradise/cfdg/soft_core.cfdg +26 -0
  424. data/lib/image_paradise/cfdg/soft_touch.cfdg +20 -0
  425. data/lib/image_paradise/cfdg/some_sort_of_tree.cfdg +57 -0
  426. data/lib/image_paradise/cfdg/spade_ball.cfdg +39 -0
  427. data/lib/image_paradise/cfdg/sparks.cfdg +39 -0
  428. data/lib/image_paradise/cfdg/sperm.cfdg +63 -0
  429. data/lib/image_paradise/cfdg/sphinx.cfdg +17 -0
  430. data/lib/image_paradise/cfdg/spiral_clusters.cfdg +29 -0
  431. data/lib/image_paradise/cfdg/spiral_cross.cfdg +27 -0
  432. data/lib/image_paradise/cfdg/spiral_star.cfdg +19 -0
  433. data/lib/image_paradise/cfdg/spiral_sun.cfdg +39 -0
  434. data/lib/image_paradise/cfdg/spirit.cfdg +47 -0
  435. data/lib/image_paradise/cfdg/splatter_tree.cfdg +61 -0
  436. data/lib/image_paradise/cfdg/spliced.cfdg +27 -0
  437. data/lib/image_paradise/cfdg/spring_parade.cfdg +105 -0
  438. data/lib/image_paradise/cfdg/sprinkle_explosion.cfdg +23 -0
  439. data/lib/image_paradise/cfdg/square_limit_one.cfdg +15 -0
  440. data/lib/image_paradise/cfdg/square_rose.cfdg +75 -0
  441. data/lib/image_paradise/cfdg/square_spiral4.cfdg +41 -0
  442. data/lib/image_paradise/cfdg/square_star.cfdg +39 -0
  443. data/lib/image_paradise/cfdg/squiggle.cfdg +54 -0
  444. data/lib/image_paradise/cfdg/stacked_blob.cfdg +27 -0
  445. data/lib/image_paradise/cfdg/star_explosion.cfdg +38 -0
  446. data/lib/image_paradise/cfdg/star_flower.cfdg +72 -0
  447. data/lib/image_paradise/cfdg/star_mosaic_2007.cfdg +51 -0
  448. data/lib/image_paradise/cfdg/starry_pines.cfdg +79 -0
  449. data/lib/image_paradise/cfdg/stars_tentacles.cfdg +28 -0
  450. data/lib/image_paradise/cfdg/starshape.cfdg +57 -0
  451. data/lib/image_paradise/cfdg/strange_antlers.cfdg +49 -0
  452. data/lib/image_paradise/cfdg/strange_carpet.cfdg +13 -0
  453. data/lib/image_paradise/cfdg/sunset_city.cfdg +112 -0
  454. data/lib/image_paradise/cfdg/sweep.cfdg +946 -0
  455. data/lib/image_paradise/cfdg/swimmers_sperms.cfdg +54 -0
  456. data/lib/image_paradise/cfdg/sword.cfdg +24 -0
  457. data/lib/image_paradise/cfdg/tangle.cfdg +25 -0
  458. data/lib/image_paradise/cfdg/tapestry.cfdg +40 -0
  459. data/lib/image_paradise/cfdg/tasty_loops.cfdg +97 -0
  460. data/lib/image_paradise/cfdg/tendril.cfdg +6 -0
  461. data/lib/image_paradise/cfdg/tentacle_tree.cfdg +57 -0
  462. data/lib/image_paradise/cfdg/terraforming.cfdg +87 -0
  463. data/lib/image_paradise/cfdg/test.cfdg +7 -0
  464. data/lib/image_paradise/cfdg/tetris.cfdg +123 -0
  465. data/lib/image_paradise/cfdg/textured_giraffes.cfdg +122 -0
  466. data/lib/image_paradise/cfdg/the_eye.cfdg +16 -0
  467. data/lib/image_paradise/cfdg/the_go_game.cfdg +81 -0
  468. data/lib/image_paradise/cfdg/the_secret.cfdg +52 -0
  469. data/lib/image_paradise/cfdg/the_third_eye.cfdg +42 -0
  470. data/lib/image_paradise/cfdg/thingy.cfdg +13 -0
  471. data/lib/image_paradise/cfdg/thorns.cfdg +26 -0
  472. data/lib/image_paradise/cfdg/too_many_notes.cfdg +155 -0
  473. data/lib/image_paradise/cfdg/top_down_plant_root.cfdg +43 -0
  474. data/lib/image_paradise/cfdg/top_view_tree.cfdg +79 -0
  475. data/lib/image_paradise/cfdg/transparent_heart.cfdg +31 -0
  476. data/lib/image_paradise/cfdg/tree.cfdg +68 -0
  477. data/lib/image_paradise/cfdg/tree_number_5.cfdg +28 -0
  478. data/lib/image_paradise/cfdg/tree_retro.cfdg +46 -0
  479. data/lib/image_paradise/cfdg/tree_spiral.cfdg +52 -0
  480. data/lib/image_paradise/cfdg/treematic.cfdg +42 -0
  481. data/lib/image_paradise/cfdg/tri_arc.cfdg +16 -0
  482. data/lib/image_paradise/cfdg/tri_squares.cfdg +7 -0
  483. data/lib/image_paradise/cfdg/tube_map.cfdg +112 -0
  484. data/lib/image_paradise/cfdg/turing_morphogenesis.cfdg +788 -0
  485. data/lib/image_paradise/cfdg/twisted_hex_grid.cfdg +26 -0
  486. data/lib/image_paradise/cfdg/twisty_triangel.cfdg +79 -0
  487. data/lib/image_paradise/cfdg/twizeeded.cfdg +19 -0
  488. data/lib/image_paradise/cfdg/uncontrolled_fungus.cfdg +36 -0
  489. data/lib/image_paradise/cfdg/underground.cfdg +72 -0
  490. data/lib/image_paradise/cfdg/underwater.cfdg +75 -0
  491. data/lib/image_paradise/cfdg/unicorn_boi.cfdg +20 -0
  492. data/lib/image_paradise/cfdg/unification_sign.cfdg +52 -0
  493. data/lib/image_paradise/cfdg/urban_connections.cfdg +44 -0
  494. data/lib/image_paradise/cfdg/us_flag.cfdg +109 -0
  495. data/lib/image_paradise/cfdg/v_null.cfdg +89 -0
  496. data/lib/image_paradise/cfdg/very_simple_flower.cfdg +45 -0
  497. data/lib/image_paradise/cfdg/very_simple_hexagon.cfdg +16 -0
  498. data/lib/image_paradise/cfdg/very_simple_octagon.cfg +13 -0
  499. data/lib/image_paradise/cfdg/vigorous_vine.cfdg +45 -0
  500. data/lib/image_paradise/cfdg/ville_topview.cfdg +70 -0
  501. data/lib/image_paradise/cfdg/vine.cfdg +176 -0
  502. data/lib/image_paradise/cfdg/vinyl.cfdg +12 -0
  503. data/lib/image_paradise/cfdg/violet_ribbons.cfdg +45 -0
  504. data/lib/image_paradise/cfdg/voronoi_2.cfdg +61 -0
  505. data/lib/image_paradise/cfdg/wald.cfdg +46 -0
  506. data/lib/image_paradise/cfdg/water_ink.cfdg +71 -0
  507. data/lib/image_paradise/cfdg/water_monster.cfdg +33 -0
  508. data/lib/image_paradise/cfdg/web.cfdg +53 -0
  509. data/lib/image_paradise/cfdg/weighting_demo.cfdg +16 -0
  510. data/lib/image_paradise/cfdg/weird_spots.cfdg +15 -0
  511. data/lib/image_paradise/cfdg/welcome.cfdg +109 -0
  512. data/lib/image_paradise/cfdg/where_do_you_want_to_go_today.cfdg +632 -0
  513. data/lib/image_paradise/cfdg/where_is_the_head.cfdg +28 -0
  514. data/lib/image_paradise/cfdg/where_to_go.cfdg +62 -0
  515. data/lib/image_paradise/cfdg/willow.cfdg +39 -0
  516. data/lib/image_paradise/cfdg/witch_poison.cfdg +58 -0
  517. data/lib/image_paradise/cfdg/wooden_floor.cfdg +95 -0
  518. data/lib/image_paradise/cfdg/writhing.cfdg +15 -0
  519. data/lib/image_paradise/cfdg/wrooom_cars.cfdg +124 -0
  520. data/lib/image_paradise/cfdg/xmas_code.cfdg +101 -0
  521. data/lib/image_paradise/cfdg/xmas_tree.cfdg +70 -0
  522. data/lib/image_paradise/cfdg/yellow_cactus.cfdg +52 -0
  523. data/lib/image_paradise/cfdg/yet_another_explosion.cfdg +46 -0
  524. data/lib/image_paradise/cfdg/yin_yang_taijitu_pattern.cfdg +44 -0
  525. data/lib/image_paradise/cfdg/yog.cfdg +27 -0
  526. data/lib/image_paradise/cfdg/yurbanis_m.cfdg +27 -0
  527. data/lib/image_paradise/cfdg/zen_tree.cfdg +79 -0
  528. data/lib/image_paradise/cfdg/ziggy_flowers.cfdg +44 -0
  529. data/lib/image_paradise/cfdg/zodiac.cfdg +43 -0
  530. data/lib/image_paradise/chunky_png/chunky_png.rb +54 -0
  531. data/lib/image_paradise/colours/colours.rb +46 -0
  532. data/lib/image_paradise/confree_generator/confree_generator.rb +791 -0
  533. data/lib/image_paradise/confree_generator/constants.rb +93 -0
  534. data/lib/image_paradise/constants/constants.rb +50 -0
  535. data/lib/image_paradise/constants/image_file_types.rb +26 -0
  536. data/lib/image_paradise/crop/crop.rb +429 -0
  537. data/lib/image_paradise/gm_support.rb +34 -0
  538. data/lib/image_paradise/graphs/accumulator_bar.rb +29 -0
  539. data/lib/image_paradise/graphs/area.rb +64 -0
  540. data/lib/image_paradise/graphs/bar.rb +117 -0
  541. data/lib/image_paradise/graphs/bar_conversion.rb +53 -0
  542. data/lib/image_paradise/graphs/base.rb +1392 -0
  543. data/lib/image_paradise/graphs/bezier.rb +45 -0
  544. data/lib/image_paradise/graphs/bullet.rb +115 -0
  545. data/lib/image_paradise/graphs/deprecated.rb +42 -0
  546. data/lib/image_paradise/graphs/dot.rb +129 -0
  547. data/lib/image_paradise/graphs/line.rb +328 -0
  548. data/lib/image_paradise/graphs/mini/bar.rb +42 -0
  549. data/lib/image_paradise/graphs/mini/legend.rb +109 -0
  550. data/lib/image_paradise/graphs/mini/pie.rb +42 -0
  551. data/lib/image_paradise/graphs/mini/side_bar.rb +41 -0
  552. data/lib/image_paradise/graphs/net.rb +133 -0
  553. data/lib/image_paradise/graphs/photo_bar.rb +106 -0
  554. data/lib/image_paradise/graphs/pie.rb +139 -0
  555. data/lib/image_paradise/graphs/scatter.rb +264 -0
  556. data/lib/image_paradise/graphs/scene.rb +216 -0
  557. data/lib/image_paradise/graphs/side_bar.rb +144 -0
  558. data/lib/image_paradise/graphs/side_stacked_bar.rb +116 -0
  559. data/lib/image_paradise/graphs/spider.rb +163 -0
  560. data/lib/image_paradise/graphs/stacked_area.rb +73 -0
  561. data/lib/image_paradise/graphs/stacked_bar.rb +68 -0
  562. data/lib/image_paradise/graphs/stacked_mixin.rb +30 -0
  563. data/lib/image_paradise/graphs/themes.rb +117 -0
  564. data/lib/image_paradise/graphs.rb +36 -0
  565. data/lib/image_paradise/graphviz/README.md +2 -0
  566. data/lib/image_paradise/graphviz/generate_graphviz_image.rb +276 -0
  567. data/lib/image_paradise/gui/gtk3/cfdg_widget/cfdg_widget.rb +1452 -0
  568. data/lib/image_paradise/gui/gtk3/cfdg_widget/connect_skeleton.rb +46 -0
  569. data/lib/image_paradise/gui/gtk3/image_editor/connect_skeleton.rb +126 -0
  570. data/lib/image_paradise/gui/gtk3/image_editor/image_editor.rb +2003 -0
  571. data/lib/image_paradise/identify.rb +184 -0
  572. data/lib/image_paradise/image_paradise.rb +153 -0
  573. data/lib/image_paradise/image_to_ascii/image_to_ascii.rb +187 -0
  574. data/lib/image_paradise/image_to_pdf/image_to_pdf.rb +99 -0
  575. data/lib/image_paradise/label/README.md +2 -0
  576. data/lib/image_paradise/label/simple_label.rb +206 -0
  577. data/lib/image_paradise/logo/IMGUR_LOGO.png +0 -0
  578. data/lib/image_paradise/project/project.rb +30 -0
  579. data/lib/image_paradise/requires/common_base_requires.rb +17 -0
  580. data/lib/image_paradise/requires/require_colours.rb +9 -0
  581. data/lib/image_paradise/requires/require_gtk_components.rb +8 -0
  582. data/lib/image_paradise/requires/require_image_to_ascii.rb +7 -0
  583. data/lib/image_paradise/requires/require_the_image_paradise_project.rb +42 -0
  584. data/lib/image_paradise/requires/require_toplevel_methods.rb +21 -0
  585. data/lib/image_paradise/rotate/README.md +2 -0
  586. data/lib/image_paradise/rotate/rotate.rb +124 -0
  587. data/lib/image_paradise/shell/interactive.rb +156 -0
  588. data/lib/image_paradise/svg/README.md +5 -0
  589. data/lib/image_paradise/svg/circle.rb +106 -0
  590. data/lib/image_paradise/svg/feature.rb +48 -0
  591. data/lib/image_paradise/svg/rectangle.rb +154 -0
  592. data/lib/image_paradise/svg/svg.rb +102 -0
  593. data/lib/image_paradise/toplevel_methods/add_black_border_to_this_image.rb +94 -0
  594. data/lib/image_paradise/toplevel_methods/create_animated_gif.rb +49 -0
  595. data/lib/image_paradise/toplevel_methods/crop.rb +29 -0
  596. data/lib/image_paradise/toplevel_methods/e.rb +16 -0
  597. data/lib/image_paradise/toplevel_methods/esystem.rb +19 -0
  598. data/lib/image_paradise/toplevel_methods/extract_text_from_this_image.rb +56 -0
  599. data/lib/image_paradise/toplevel_methods/file_related_code.rb +48 -0
  600. data/lib/image_paradise/toplevel_methods/flip_image_left_right.rb +59 -0
  601. data/lib/image_paradise/toplevel_methods/font_related_methods.rb +62 -0
  602. data/lib/image_paradise/toplevel_methods/greyscale_this_image.rb +76 -0
  603. data/lib/image_paradise/toplevel_methods/gui.rb +19 -0
  604. data/lib/image_paradise/toplevel_methods/help.rb +30 -0
  605. data/lib/image_paradise/toplevel_methods/interlace.rb +33 -0
  606. data/lib/image_paradise/toplevel_methods/is_an_image_file.rb +18 -0
  607. data/lib/image_paradise/toplevel_methods/make_this_image_transparent.rb +40 -0
  608. data/lib/image_paradise/toplevel_methods/menu.rb +110 -0
  609. data/lib/image_paradise/toplevel_methods/merge_these_images.rb +49 -0
  610. data/lib/image_paradise/toplevel_methods/mirror_image.rb +28 -0
  611. data/lib/image_paradise/toplevel_methods/misc.rb +1407 -0
  612. data/lib/image_paradise/toplevel_methods/negate.rb +36 -0
  613. data/lib/image_paradise/toplevel_methods/png_to_svg.rb +38 -0
  614. data/lib/image_paradise/toplevel_methods/quality.rb +34 -0
  615. data/lib/image_paradise/toplevel_methods/resized.rb +43 -0
  616. data/lib/image_paradise/toplevel_methods/roebe.rb +323 -0
  617. data/lib/image_paradise/toplevel_methods/thumbnail.rb +54 -0
  618. data/lib/image_paradise/toplevel_methods/to_png.rb +106 -0
  619. data/lib/image_paradise/toplevel_methods/wallpaper.rb +51 -0
  620. data/lib/image_paradise/toplevel_methods/write_this_text.rb +89 -0
  621. data/lib/image_paradise/utility_scripts/black_white.rb +92 -0
  622. data/lib/image_paradise/utility_scripts/create_new_image.rb +110 -0
  623. data/lib/image_paradise/utility_scripts/image_border.rb +226 -0
  624. data/lib/image_paradise/utility_scripts/image_gallery/image_gallery.rb +283 -0
  625. data/lib/image_paradise/utility_scripts/image_manipulations.rb +316 -0
  626. data/lib/image_paradise/utility_scripts/magic_card_border.rb +215 -0
  627. data/lib/image_paradise/utility_scripts/optimizer.rb +452 -0
  628. data/lib/image_paradise/utility_scripts/random_text_to_image.rb +364 -0
  629. data/lib/image_paradise/utility_scripts/text_on_image.rb +311 -0
  630. data/lib/image_paradise/utility_scripts/to_gif.rb +93 -0
  631. data/lib/image_paradise/utility_scripts/to_jpg.rb +82 -0
  632. data/lib/image_paradise/version/version.rb +19 -0
  633. data/lib/image_paradise/www/cfdg.cgi +25 -0
  634. data/lib/image_paradise/www/imagemagick/imagemagick.cgi +266 -0
  635. data/lib/image_paradise/yaml/README.md +2 -0
  636. data/lib/image_paradise/yaml/arc.yml +0 -0
  637. data/lib/image_paradise/yaml/circle.yml +6 -0
  638. data/lib/image_paradise/yaml/rectangle.yml +6 -0
  639. data/lib/image_paradise.rb +5 -0
  640. data/test/16x16_red_square_image_for_testing.png +0 -0
  641. data/test/misc/README.md +3 -0
  642. data/test/misc/testing_filling_up_with_circles.rb +65 -0
  643. data/test/testing_confree_generator.rb +8 -0
  644. data/test/testing_crop.rb +19 -0
  645. data/test/testing_image_magick_commands.rb +39 -0
  646. data/test/testing_image_paradise.rb +49 -0
  647. data/test/testing_the_svg_component.html +261 -0
  648. data/test/testing_the_svg_component.rb +106 -0
  649. metadata +760 -0
@@ -0,0 +1,1392 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ begin
6
+ require 'rmagick'
7
+ rescue LoadError; end
8
+
9
+ require 'bigdecimal'
10
+
11
+ require_relative '../graphs/deprecated.rb'
12
+
13
+ # =========================================================================== #
14
+ # = Gruff. Graphs.
15
+ #
16
+ # Author::
17
+ #
18
+ # Geoffrey Grosenbach boss@topfunky.com
19
+ #
20
+ # Originally Created::
21
+ #
22
+ # October 23, 2005
23
+ #
24
+ # Extra thanks to Tim Hunter for writing RMagick, and also contributions by
25
+ # Jarkko Laine, Mike Perham, Andreas Schwarz, Alun Eyre, Guillaume Theoret,
26
+ # David Stokar, Paul Rogers, Dave Woodward, Frank Oxener, Kevin Clark, Cies
27
+ # Breijs, Richard Cowin, and a cast of thousands.
28
+ #
29
+ # See Gruff::Base#theme= for setting themes.
30
+ # =========================================================================== #
31
+ module ImageParadise
32
+
33
+ module Gruff
34
+
35
+ class Base
36
+
37
+ begin
38
+ include Magick
39
+ rescue NameError; end
40
+
41
+ include Deprecated
42
+
43
+ # ========================================================================= #
44
+ # === DEBUG
45
+ #
46
+ # Draw extra lines showing where the margins and text centers are
47
+ # ========================================================================= #
48
+ DEBUG = false
49
+
50
+ # ========================================================================= #
51
+ # Used for navigating the array of data to plot
52
+ # ========================================================================= #
53
+ DATA_LABEL_INDEX = 0
54
+ DATA_VALUES_INDEX = 1
55
+ DATA_COLOR_INDEX = 2
56
+
57
+ # ========================================================================= #
58
+ # === DATA_VALUES_X_INDEX
59
+ # ========================================================================= #
60
+ DATA_VALUES_X_INDEX = 3
61
+
62
+ # ========================================================================= #
63
+ # === LEGEND_MARGIN
64
+ #
65
+ # Space around text elements. Mostly used for vertical spacing
66
+ # ========================================================================= #
67
+ LEGEND_MARGIN = TITLE_MARGIN = 20.0
68
+
69
+ # ========================================================================= #
70
+ # === LABEL_MARGIN
71
+ # ========================================================================= #
72
+ LABEL_MARGIN = 10.0
73
+
74
+ # ========================================================================= #
75
+ # === DEFAULT_MARGIN
76
+ # ========================================================================= #
77
+ DEFAULT_MARGIN = 20.0
78
+
79
+ # ========================================================================= #
80
+ # === DEFAULT_TARGET_WIDTH
81
+ # ========================================================================= #
82
+ DEFAULT_TARGET_WIDTH = 800
83
+
84
+ # ========================================================================= #
85
+ # === THOUSAND_SEPARATOR
86
+ # ========================================================================= #
87
+ THOUSAND_SEPARATOR = ','
88
+
89
+ # ========================================================================= #
90
+ # Blank space above the graph
91
+ # ========================================================================= #
92
+ attr_accessor :top_margin
93
+
94
+ # ========================================================================= #
95
+ # Blank space below the graph
96
+ # ========================================================================= #
97
+ attr_accessor :bottom_margin
98
+
99
+ # ========================================================================= #
100
+ # Blank space to the right of the graph
101
+ # ========================================================================= #
102
+ attr_accessor :right_margin
103
+
104
+ # ========================================================================= #
105
+ # Blank space to the left of the graph
106
+ # ========================================================================= #
107
+ attr_accessor :left_margin
108
+
109
+ # ========================================================================= #
110
+ # Blank space below the title
111
+ # ========================================================================= #
112
+ attr_accessor :title_margin
113
+
114
+ # ========================================================================= #
115
+ # Blank space below the legend
116
+ # ========================================================================= #
117
+ attr_accessor :legend_margin
118
+
119
+ # ========================================================================= #
120
+ # A hash of names for the individual columns, where the key is the array
121
+ # index for the column this label represents.
122
+ #
123
+ # Not all columns need to be named.
124
+ #
125
+ # Example: 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008
126
+ # ========================================================================= #
127
+ attr_accessor :labels
128
+
129
+ # ========================================================================= #
130
+ # Used internally for spacing.
131
+ #
132
+ # By default, labels are centered over the point they represent.
133
+ # ========================================================================= #
134
+ attr_accessor :center_labels_over_point
135
+
136
+ # ========================================================================= #
137
+ # Used internally for horizontal graph types.
138
+ # ========================================================================= #
139
+ attr_accessor :has_left_labels
140
+
141
+ # ========================================================================= #
142
+ # A label for the bottom of the graph
143
+ # ========================================================================= #
144
+ attr_accessor :x_axis_label
145
+
146
+ # ========================================================================= #
147
+ # A label for the left side of the graph
148
+ # ========================================================================= #
149
+ attr_accessor :y_axis_label
150
+
151
+ # ========================================================================= #
152
+ # attr_accessor :x_axis_increment
153
+ # ========================================================================= #
154
+
155
+ # ========================================================================= #
156
+ # Manually set increment of the horizontal marking lines
157
+ # ========================================================================= #
158
+ attr_accessor :y_axis_increment
159
+
160
+ # ========================================================================= #
161
+ # Height of staggering between labels (Bar graph only)
162
+ # ========================================================================= #
163
+ attr_accessor :label_stagger_height
164
+
165
+ # ========================================================================= #
166
+ # Truncates labels if longer than max specified
167
+ # ========================================================================= #
168
+ attr_accessor :label_max_size
169
+
170
+ # ========================================================================= #
171
+ # How truncated labels visually appear if they exceed label_max_size
172
+ # :absolute - does not show trailing dots to indicate truncation. This is
173
+ # the default.
174
+ # :trailing_dots - shows trailing dots to indicate truncation (note
175
+ # that label_max_size must be greater than 3).
176
+ # ========================================================================= #
177
+ attr_accessor :label_truncation_style
178
+
179
+ # ========================================================================= #
180
+ # Get or set the list of colors that will be used to draw the bars or lines.
181
+ # ========================================================================= #
182
+ attr_accessor :colors
183
+
184
+ # ========================================================================= #
185
+ # The large title of the graph displayed at the top
186
+ # ========================================================================= #
187
+ attr_accessor :title
188
+
189
+ # Font used for titles, labels, etc. Works best if you provide the full
190
+ # path to the TTF font file. RMagick must be built with the Freetype
191
+ # libraries for this to work properly.
192
+ #
193
+ # Tries to find Bitstream Vera (Vera.ttf) in the location specified by
194
+ # ENV['MAGICK_FONT_PATH']. Uses default RMagick font otherwise.
195
+ #
196
+ # The font= method below fulfills the role of the writer, so we only need
197
+ # a reader here.
198
+ attr_reader :font
199
+
200
+ # Same as font but for the title.
201
+ attr_reader :title_font
202
+
203
+ # ========================================================================= #
204
+ # Specifies whether to draw the title bolded or not.
205
+ # ========================================================================= #
206
+ attr_accessor :bold_title
207
+
208
+ attr_accessor :font_color
209
+
210
+ # Prevent drawing of line markers
211
+ attr_accessor :hide_line_markers
212
+
213
+ # Prevent drawing of the legend
214
+ attr_accessor :hide_legend
215
+
216
+ # ========================================================================= #
217
+ # Prevent drawing of the title
218
+ # ========================================================================= #
219
+ attr_accessor :hide_title
220
+
221
+ # ========================================================================= #
222
+ # Prevent drawing of line numbers
223
+ # ========================================================================= #
224
+ attr_accessor :hide_line_numbers
225
+
226
+ # ========================================================================= #
227
+ # Message shown when there is no data. Fits up to 20 characters. Defaults
228
+ # to "No Data."
229
+ # ========================================================================= #
230
+ attr_accessor :no_data_message
231
+
232
+ # The font size of the large title at the top of the graph
233
+ attr_accessor :title_font_size
234
+
235
+ # Optionally set the size of the font. Based on an 800x600px graph.
236
+ # Default is 20.
237
+ #
238
+ # Will be scaled down if the graph is smaller than 800px wide.
239
+ attr_accessor :legend_font_size
240
+
241
+ # Display the legend under the graph
242
+ attr_accessor :legend_at_bottom
243
+
244
+ # The font size of the labels around the graph
245
+ attr_accessor :marker_font_size
246
+
247
+ # The color of the auxiliary lines
248
+ attr_accessor :marker_color
249
+ attr_accessor :marker_shadow_color
250
+
251
+ # The number of horizontal lines shown for reference
252
+ attr_accessor :marker_count
253
+
254
+ # ========================================================================= #
255
+ # You can manually set a minimum value instead of having the values
256
+ # guessed for you.
257
+ #
258
+ # Set it after you have given all your data to the graph object.
259
+ # ========================================================================= #
260
+ attr_accessor :minimum_value
261
+
262
+ # ========================================================================= #
263
+ # You can manually set a maximum value, such as a percentage-based graph
264
+ # that always goes to 100.
265
+ #
266
+ # If you use this, you must set it after you have given all your data to
267
+ # the graph object.
268
+ # ========================================================================= #
269
+ attr_accessor :maximum_value
270
+
271
+ # ========================================================================= #
272
+ # Set to true if you want the data sets sorted with largest avg values
273
+ # drawn first.
274
+ # ========================================================================= #
275
+ attr_accessor :sort
276
+
277
+ # ========================================================================= #
278
+ # Set to true if you want the data sets drawn with largest avg values
279
+ # drawn first. This does not affect the legend.
280
+ # ========================================================================= #
281
+ attr_accessor :sorted_drawing
282
+
283
+ # ========================================================================= #
284
+ # Experimental
285
+ # ========================================================================= #
286
+ attr_accessor :additional_line_values
287
+
288
+ # Experimental
289
+ attr_accessor :stacked
290
+
291
+ # Optionally set the size of the colored box by each item in the legend.
292
+ # Default is 20.0
293
+ #
294
+ # Will be scaled down if graph is smaller than 800px wide.
295
+ attr_accessor :legend_box_size
296
+
297
+ # ========================================================================= #
298
+ # Output the values for the bars on a bar graph
299
+ # Default is false
300
+ # ========================================================================= #
301
+ attr_accessor :show_labels_for_bar_values
302
+
303
+ # ========================================================================= #
304
+ # Set the number output format for labels using sprintf
305
+ # Default is "%.2f"
306
+ # ========================================================================= #
307
+ attr_accessor :label_formatting
308
+
309
+ # ========================================================================= #
310
+ # With Side Bars use the data label for the marker value to the left of
311
+ # the bar Default is false
312
+ # ========================================================================= #
313
+ attr_accessor :use_data_label
314
+
315
+ # ========================================================================= #
316
+ # === initialize
317
+ #
318
+ # If one numerical argument is given, the graph is drawn at 4/3 ratio
319
+ # according to the given width (800 results in 800x600, 400 gives 400x300,
320
+ # etc.).
321
+ #
322
+ # Or, send a geometry string for other ratios ('800x400', '400x225').
323
+ #
324
+ # Looks for Bitstream Vera as the default font. Expects an environment
325
+ # var of MAGICK_FONT_PATH to be set. (Uses RMagick's default font
326
+ # otherwise.)
327
+ # ========================================================================= #
328
+ def initialize(
329
+ target_width = DEFAULT_TARGET_WIDTH
330
+ )
331
+ if Numeric === target_width
332
+ @columns = target_width.to_f
333
+ @rows = target_width.to_f * 0.75
334
+ else
335
+ geometric_width, geometric_height = target_width.split('x')
336
+ @columns = geometric_width.to_f
337
+ @rows = geometric_height.to_f
338
+ end
339
+ initialize_ivars
340
+ reset_themes
341
+ self.theme = Themes::KEYNOTE
342
+ end
343
+
344
+ # ======================================================================= #
345
+ # Set instance variables for this object.
346
+ #
347
+ # Subclasses can override this, call super, then set values separately.
348
+ #
349
+ # This makes it possible to set defaults in a subclass but still allow
350
+ # developers to change this values in their program.
351
+ # ======================================================================= #
352
+ def initialize_ivars
353
+ @increment = 1
354
+ # Internal for calculations
355
+ @raw_columns = 800.0
356
+ @raw_rows = 800.0 * (@rows/@columns)
357
+ @column_count = 0
358
+ @marker_count = nil
359
+ @maximum_value = @minimum_value = nil
360
+ @has_data = false
361
+ @data = Array.new
362
+ @labels = Hash.new
363
+ @labels_seen = Hash.new
364
+ @sort = false
365
+ @title = nil
366
+
367
+ @scale = @columns / @raw_columns
368
+
369
+ vera_font_path = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH'])
370
+ @font = File.exist?(vera_font_path) ? vera_font_path : nil
371
+ @bold_title = true
372
+
373
+ @marker_font_size = 21.0
374
+ @legend_font_size = 20.0
375
+ @title_font_size = 36.0
376
+
377
+ @top_margin = @bottom_margin = @left_margin = @right_margin = DEFAULT_MARGIN
378
+ @legend_margin = LEGEND_MARGIN
379
+ @title_margin = TITLE_MARGIN
380
+
381
+ @legend_box_size = 20.0
382
+
383
+ @no_data_message = 'No Data'
384
+
385
+ @hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = @legend_at_bottom = @show_labels_for_bar_values = false
386
+ @center_labels_over_point = true
387
+ @has_left_labels = false
388
+ @label_stagger_height = 0
389
+ @label_max_size = 0
390
+ @label_truncation_style = :absolute
391
+
392
+ @additional_line_values = []
393
+ @additional_line_colors = []
394
+ @theme_options = {}
395
+
396
+ @x_axis_label = @y_axis_label = nil
397
+ @y_axis_increment = nil
398
+ @stacked = nil
399
+ @norm_data = nil
400
+ @sorted_drawing = false
401
+ end; alias reset initialize_ivars # === reset
402
+
403
+ # ======================================================================= #
404
+ # === margins=
405
+ #
406
+ # Sets the top, bottom, left and right margins to +margin+.
407
+ # ======================================================================= #
408
+ def margins=(margin)
409
+ @top_margin = @left_margin = @right_margin = @bottom_margin = margin
410
+ end
411
+
412
+ # ======================================================================= #
413
+ # === font=
414
+ #
415
+ # Sets the font for graph text to the font at +font_path+.
416
+ # ======================================================================= #
417
+ def font=(font_path)
418
+ @font = font_path
419
+ @d.font = @font
420
+ end
421
+
422
+ # Sets the title font to the font at +font_path+
423
+ def title_font=(font_path)
424
+ @title_font = font_path
425
+ end
426
+
427
+ # ======================================================================= #
428
+ # === add_color
429
+ #
430
+ # Add a color to the list of available colors for lines.
431
+ #
432
+ # Example:
433
+ # add_color('#c0e9d3')
434
+ # ======================================================================= #
435
+ def add_color(colorname)
436
+ @colors << colorname
437
+ end
438
+
439
+ # ======================================================================= #
440
+ # Replace the entire color list with a new array of colors. Also
441
+ # aliased as the colors= setter method.
442
+ #
443
+ # If you specify fewer colors than the number of datasets you intend
444
+ # to draw, 'increment_color' will cycle through the array, reusing
445
+ # colors as needed.
446
+ #
447
+ # Note that (as with the 'theme' method), you should set up your color
448
+ # list before you send your data (via the 'data' method). Calls to the
449
+ # 'data' method made prior to this call will use whatever color scheme
450
+ # was in place at the time data was called.
451
+ #
452
+ # Example:
453
+ # replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
454
+ # ======================================================================= #
455
+ def replace_colors(color_list=[])
456
+ @colors = color_list
457
+ @color_index = 0
458
+ end
459
+
460
+ # ======================================================================= #
461
+ # === theme=
462
+ #
463
+ # You can set a theme manually. Assign a hash to this method before you
464
+ # send your data.
465
+ #
466
+ # graph.theme = {
467
+ # :colors => %w(orange purple green white red),
468
+ # :marker_color => 'blue',
469
+ # :background_colors => ['black', 'grey', :top_bottom]
470
+ # }
471
+ #
472
+ # :background_image => 'squirrel.png' is also possible.
473
+ #
474
+ # (Or hopefully something better looking than that.)
475
+ #
476
+ # ======================================================================= #
477
+ def theme=(options)
478
+ reset_themes
479
+
480
+ defaults = {
481
+ :colors => %w(black white),
482
+ :additional_line_colors => [],
483
+ :marker_color => 'white',
484
+ :marker_shadow_color => nil,
485
+ :font_color => 'black',
486
+ :background_colors => nil,
487
+ :background_image => nil
488
+ }
489
+ @theme_options = defaults.merge options
490
+
491
+ @colors = @theme_options[:colors]
492
+ @marker_color = @theme_options[:marker_color]
493
+ @marker_shadow_color = @theme_options[:marker_shadow_color]
494
+ @font_color = @theme_options[:font_color] || @marker_color
495
+ @additional_line_colors = @theme_options[:additional_line_colors]
496
+
497
+ render_background
498
+ end
499
+
500
+ # === theme_keynote
501
+ def theme_keynote
502
+ self.theme = Themes::KEYNOTE
503
+ end
504
+
505
+ def theme_37signals
506
+ self.theme = Themes::THIRTYSEVEN_SIGNALS
507
+ end
508
+
509
+ def theme_rails_keynote
510
+ self.theme = Themes::RAILS_KEYNOTE
511
+ end
512
+
513
+ # === theme_odeo
514
+ def theme_odeo
515
+ self.theme = Themes::ODEO
516
+ end
517
+
518
+ # === theme_pastel
519
+ def theme_pastel
520
+ self.theme = Themes::PASTEL
521
+ end
522
+
523
+ def theme_greyscale
524
+ self.theme = Themes::GREYSCALE
525
+ end
526
+
527
+ # ======================================================================= #
528
+ # === data
529
+ #
530
+ # Parameters are an array where the first element is the name of the
531
+ # dataset and the value is an array of values to plot.
532
+ #
533
+ # Can be called multiple times with different datasets for a
534
+ # multi-valued graph.
535
+ #
536
+ # If the color argument is nil, the next color from the default theme will
537
+ # be used.
538
+ #
539
+ # NOTE: If you want to use a preset theme, you must set it before
540
+ # calling data().
541
+ #
542
+ # Example:
543
+ #
544
+ # data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
545
+ #
546
+ # ======================================================================= #
547
+ def data(name, data_points = [], color = nil)
548
+ data_points = Array(data_points) # We have to make sure that the data points are an Array.
549
+ # ===================================================================== #
550
+ # Next, we can append onto the @data variable.
551
+ # ===================================================================== #
552
+ @data << [name, data_points, color]
553
+ # ===================================================================== #
554
+ # Set column count if this is larger than previous counts.
555
+ # ===================================================================== #
556
+ @column_count = (data_points.length > @column_count) ? data_points.length : @column_count
557
+ # ===================================================================== #
558
+ # Pre-normalize.
559
+ # ===================================================================== #
560
+ data_points.each { |data_point|
561
+ next if data_point.nil?
562
+ # =================================================================== #
563
+ # Chop off '.' if we have a String.
564
+ # =================================================================== #
565
+ if data_point.is_a? String
566
+ data_point = data_point.dup
567
+ data_point.delete!('.') if data_point.include? '.'
568
+ data_point = data_point.to_f
569
+ end
570
+ # Setup max/min so spread starts at the low end of the data points
571
+ if @maximum_value.nil? && @minimum_value.nil?
572
+ @maximum_value = @minimum_value = data_point
573
+ end
574
+ # TODO Doesn't work with stacked bar graphs
575
+ # Original: @maximum_value = larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value
576
+ @maximum_value = larger_than_max?(data_point) ? data_point : @maximum_value
577
+ @has_data = true if @maximum_value >= 0
578
+ @minimum_value = less_than_min?(data_point) ? data_point : @minimum_value
579
+ @has_data = true if @minimum_value < 0
580
+ }
581
+ end
582
+
583
+ # ======================================================================= #
584
+ # === write
585
+ #
586
+ # Writes the graph to a file. Defaults to 'graph.png'
587
+ #
588
+ # Example:
589
+ # write('graphs/my_pretty_graph.png')
590
+ # ======================================================================= #
591
+ def write(filename = 'graph.png')
592
+ draw
593
+ @base_image.write(filename)
594
+ end
595
+
596
+ # ======================================================================= #
597
+ # === to_blob
598
+ #
599
+ # Return the graph as a rendered binary blob.
600
+ # ======================================================================= #
601
+ def to_blob(fileformat = 'PNG')
602
+ draw
603
+ @base_image.to_blob {
604
+ self.format = fileformat
605
+ }
606
+ end
607
+
608
+ protected
609
+
610
+ # ======================================================================= #
611
+ # === draw
612
+ #
613
+ # Overridden by subclasses to do the actual plotting of the graph.
614
+ #
615
+ # Subclasses should start by calling super() for this method.
616
+ # ======================================================================= #
617
+ def draw
618
+ # ===================================================================== #
619
+ # Maybe should be done in one of the following functions for more
620
+ # granularity.
621
+ # ===================================================================== #
622
+ unless @has_data
623
+ draw_no_data
624
+ return
625
+ end
626
+
627
+ setup_data
628
+ setup_drawing
629
+
630
+ debug {
631
+ # Outer margin
632
+ @d.rectangle(@left_margin, @top_margin,
633
+ @raw_columns - @right_margin, @raw_rows - @bottom_margin)
634
+ # Graph area box
635
+ @d.rectangle(@graph_left, @graph_top, @graph_right, @graph_bottom)
636
+ }
637
+
638
+ draw_legend
639
+ draw_line_markers
640
+ draw_axis_labels
641
+ draw_title
642
+ end
643
+
644
+ # ======================================================================= #
645
+ # === setup_data
646
+ #
647
+ # Perform data manipulation before calculating chart measurements
648
+ # ======================================================================= #
649
+ def setup_data # :nodoc:
650
+ if @y_axis_increment && !@hide_line_markers
651
+ @maximum_value = [@y_axis_increment, @maximum_value, (@maximum_value.to_f / @y_axis_increment).round * @y_axis_increment].max
652
+ @minimum_value = [@minimum_value, (@minimum_value.to_f / @y_axis_increment).round * @y_axis_increment].min
653
+ end
654
+ make_stacked if @stacked
655
+ end
656
+
657
+ # ======================================================================= #
658
+ # Calculates size of drawable area and generates normalized data.
659
+ #
660
+ # * line markers
661
+ # * legend
662
+ # * title
663
+ # ======================================================================= #
664
+ def setup_drawing
665
+ calculate_spread
666
+ sort_data if @sort # Sort data with avg largest values set first (for display)
667
+ set_colors
668
+ normalize
669
+ setup_graph_measurements
670
+ sort_norm_data if @sorted_drawing # Sort norm_data with avg largest values set first (for display)
671
+ end
672
+
673
+ # === normalize
674
+ #
675
+ # Make copy of data with values scaled between 0-100
676
+ def normalize(force = false)
677
+ if @norm_data.nil? || force
678
+ @norm_data = []
679
+ return unless @has_data
680
+
681
+ @data.each do |data_row|
682
+ norm_data_points = []
683
+ data_row[DATA_VALUES_INDEX].each do |data_point|
684
+ if data_point.nil?
685
+ norm_data_points << nil
686
+ else
687
+ norm_data_points << ((data_point.to_f - @minimum_value.to_f) / @spread)
688
+ end
689
+ end
690
+ if @show_labels_for_bar_values
691
+ @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX], data_row[DATA_VALUES_INDEX]]
692
+ else
693
+ @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX]]
694
+ end
695
+ end
696
+ end
697
+ end
698
+
699
+ # ======================================================================= #
700
+ # === calculate_spread
701
+ # ======================================================================= #
702
+ def calculate_spread # :nodoc:
703
+ @spread = @maximum_value.to_f - @minimum_value.to_f
704
+ @spread = @spread > 0 ? @spread : 1
705
+ end
706
+
707
+ # ======================================================================= #
708
+ # === setup_graph_measurements
709
+ #
710
+ # Calculates size of drawable area, general font dimensions, etc.
711
+ # ======================================================================= #
712
+ def setup_graph_measurements
713
+ @marker_caps_height = @hide_line_markers ? 0 :
714
+ calculate_caps_height(@marker_font_size)
715
+ @title_caps_height = (@hide_title || @title.nil?) ? 0 :
716
+ calculate_caps_height(@title_font_size) * @title.lines.to_a.size
717
+ @legend_caps_height = @hide_legend ? 0 :
718
+ calculate_caps_height(@legend_font_size)
719
+
720
+ if @hide_line_markers
721
+ (@graph_left,
722
+ @graph_right_margin,
723
+ @graph_bottom_margin) = [@left_margin, @right_margin, @bottom_margin]
724
+ else
725
+ if @has_left_labels
726
+ longest_left_label_width = calculate_width(@marker_font_size,
727
+ labels.values.inject('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
728
+ else
729
+ longest_left_label_width = calculate_width(@marker_font_size,
730
+ label(@maximum_value.to_f, @increment))
731
+ end
732
+ # =================================================================== #
733
+ # Shift graph if left line numbers are hidden
734
+ # =================================================================== #
735
+ line_number_width = @hide_line_numbers && !@has_left_labels ?
736
+ 0.0 :
737
+ (longest_left_label_width + LABEL_MARGIN * 2)
738
+
739
+ @graph_left = @left_margin +
740
+ line_number_width +
741
+ (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
742
+
743
+ # =================================================================== #
744
+ # Make space for half the width of the rightmost column label.
745
+ # Might be greater than the number of columns if between-style
746
+ # bar markers are used.
747
+ # =================================================================== #
748
+ last_label = @labels.keys.sort.last.to_i
749
+ extra_room_for_long_label = (last_label >= (@column_count-1) && @center_labels_over_point) ?
750
+ calculate_width(@marker_font_size, @labels[last_label]) / 2.0 :
751
+ 0
752
+ @graph_right_margin = @right_margin + extra_room_for_long_label
753
+
754
+ @graph_bottom_margin = @bottom_margin +
755
+ @marker_caps_height + LABEL_MARGIN
756
+ end
757
+
758
+ @graph_right = @raw_columns - @graph_right_margin
759
+ @graph_width = @raw_columns - @graph_left - @graph_right_margin
760
+
761
+ # When @hide title, leave a title_margin space for aesthetics.
762
+ # Same with @hide_legend
763
+ @graph_top = @legend_at_bottom ? @top_margin : (@top_margin +
764
+ (@hide_title ? title_margin : @title_caps_height + title_margin) +
765
+ (@hide_legend ? legend_margin : @legend_caps_height + legend_margin))
766
+
767
+ x_axis_label_height = @x_axis_label.nil? ? 0.0 :
768
+ @marker_caps_height + LABEL_MARGIN
769
+ # FIXME: Consider chart types other than bar
770
+ @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height - @label_stagger_height
771
+ @graph_height = @graph_bottom - @graph_top
772
+ end
773
+
774
+ # ======================================================================= #
775
+ # === draw_axis_labels
776
+ #
777
+ # Draw the optional labels for the x axis and y axis.
778
+ # ======================================================================= #
779
+ def draw_axis_labels
780
+ unless @x_axis_label.nil?
781
+ # X Axis
782
+ # Centered vertically and horizontally by setting the
783
+ # height to 1.0 and the width to the width of the graph.
784
+ x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN * 2 + @marker_caps_height
785
+
786
+ # TODO Center between graph area
787
+ @d.fill = @font_color
788
+ @d.font = @font if @font
789
+ @d.stroke('transparent')
790
+ @d.pointsize = scale_fontsize(@marker_font_size)
791
+ @d.gravity = NorthGravity
792
+ @d = @d.annotate_scaled(@base_image,
793
+ @raw_columns, 1.0,
794
+ 0.0, x_axis_label_y_coordinate,
795
+ @x_axis_label, @scale)
796
+ debug { @d.line 0.0, x_axis_label_y_coordinate, @raw_columns, x_axis_label_y_coordinate }
797
+ end
798
+
799
+ unless @y_axis_label.nil?
800
+ # Y Axis, rotated vertically
801
+ @d.rotation = -90.0
802
+ @d.gravity = CenterGravity
803
+ @d = @d.annotate_scaled(@base_image,
804
+ 1.0, @raw_rows,
805
+ @left_margin + @marker_caps_height / 2.0, 0.0,
806
+ @y_axis_label, @scale)
807
+ @d.rotation = 90.0
808
+ end
809
+ end
810
+
811
+ # ======================================================================= #
812
+ # === draw_line_markers
813
+ #
814
+ # Draws horizontal background lines and labels
815
+ # ======================================================================= #
816
+ def draw_line_markers
817
+ return if @hide_line_markers
818
+
819
+ @d = @d.stroke_antialias false
820
+
821
+ if @y_axis_increment.nil?
822
+ # Try to use a number of horizontal lines that will come out even.
823
+ #
824
+ # TODO Do the same for larger numbers...100, 75, 50, 25
825
+ if @marker_count.nil?
826
+ (3..7).each do |lines|
827
+ if @spread % lines == 0.0
828
+ @marker_count = lines
829
+ break
830
+ end
831
+ end
832
+ @marker_count ||= 4
833
+ end
834
+ @increment = (@spread > 0 && @marker_count > 0) ? significant(@spread / @marker_count) : 1
835
+ else
836
+ # TODO Make this work for negative values
837
+ @marker_count = (@spread / @y_axis_increment).to_i
838
+ @increment = @y_axis_increment
839
+ end
840
+ @increment_scaled = @graph_height.to_f / (@spread / @increment)
841
+
842
+ # Draw horizontal line markers and annotate with numbers
843
+ (0..@marker_count).each do |index|
844
+ y = @graph_top + @graph_height - index.to_f * @increment_scaled
845
+
846
+ @d = @d.fill(@marker_color)
847
+
848
+ # FIXME(uwe): Workaround for Issue #66
849
+ # https://github.com/topfunky/gruff/issues/66
850
+ # https://github.com/rmagick/rmagick/issues/82
851
+ # Remove if the issue gets fixed.
852
+ y += 0.001 unless defined?(JRUBY_VERSION)
853
+ # EMXIF
854
+
855
+ @d = @d.line(@graph_left, y, @graph_right, y)
856
+ #If the user specified a marker shadow color, draw a shadow just below it
857
+ unless @marker_shadow_color.nil?
858
+ @d = @d.fill(@marker_shadow_color)
859
+ @d = @d.line(@graph_left, y + 1, @graph_right, y + 1)
860
+ end
861
+
862
+ marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) +
863
+ BigDecimal(@minimum_value.to_s)
864
+
865
+ unless @hide_line_numbers
866
+ @d.fill = @font_color
867
+ @d.font = @font if @font
868
+ @d.stroke('transparent')
869
+ @d.pointsize = scale_fontsize(@marker_font_size)
870
+ @d.gravity = EastGravity
871
+
872
+ # Vertically center with 1.0 for the height
873
+ @d = @d.annotate_scaled(@base_image,
874
+ @graph_left - LABEL_MARGIN, 1.0,
875
+ 0.0, y,
876
+ label(marker_label, @increment), @scale)
877
+ end
878
+ end
879
+
880
+ # # Submitted by a contibutor...the utility escapes me
881
+ # i = 0
882
+ # @additional_line_values.each do |value|
883
+ # @increment_scaled = @graph_height.to_f / (@maximum_value.to_f / value)
884
+ #
885
+ # y = @graph_top + @graph_height - @increment_scaled
886
+ #
887
+ # @d = @d.stroke(@additional_line_colors[i])
888
+ # @d = @d.line(@graph_left, y, @graph_right, y)
889
+ #
890
+ #
891
+ # @d.fill = @additional_line_colors[i]
892
+ # @d.font = @font if @font
893
+ # @d.stroke('transparent')
894
+ # @d.pointsize = scale_fontsize(@marker_font_size)
895
+ # @d.gravity = EastGravity
896
+ # @d = @d.annotate_scaled( @base_image,
897
+ # 100, 20,
898
+ # -10, y - (@marker_font_size/2.0),
899
+ # "", @scale)
900
+ # i += 1
901
+ # end
902
+
903
+ @d = @d.stroke_antialias true
904
+ end
905
+
906
+ # ======================================================================= #
907
+ # === sum
908
+ #
909
+ # Return the sum of values in an array.
910
+ #
911
+ # Duplicated to not conflict with active_support in Rails.
912
+ # ======================================================================= #
913
+ def sum(arr)
914
+ arr.inject(0) { |i, m| m + i }
915
+ end
916
+
917
+ ##
918
+ # Return a calculation of center
919
+
920
+ def center(size)
921
+ (@raw_columns - size) / 2
922
+ end
923
+
924
+ ##
925
+ # Draws a legend with the names of the datasets matched
926
+ # to the colors used to draw them.
927
+
928
+ def draw_legend
929
+ return if @hide_legend
930
+
931
+ @legend_labels = @data.collect { |item| item[DATA_LABEL_INDEX] }
932
+
933
+ legend_square_width = @legend_box_size # small square with color of this item
934
+
935
+ # May fix legend drawing problem at small sizes
936
+ @d.font = @font if @font
937
+ @d.pointsize = @legend_font_size
938
+
939
+ label_widths = [[]] # Used to calculate line wrap
940
+ @legend_labels.each do |label|
941
+ metrics = @d.get_type_metrics(@base_image, label.to_s)
942
+ label_width = metrics.width + legend_square_width * 2.7
943
+ label_widths.last.push label_width
944
+
945
+ if sum(label_widths.last) > (@raw_columns * 0.9)
946
+ label_widths.push [label_widths.last.pop]
947
+ end
948
+ end
949
+
950
+ current_x_offset = center(sum(label_widths.first))
951
+ current_y_offset = @legend_at_bottom ? @graph_height + title_margin : (@hide_title ?
952
+ @top_margin + title_margin :
953
+ @top_margin + title_margin + @title_caps_height)
954
+
955
+ @legend_labels.each_with_index do |legend_label, index|
956
+
957
+ # Draw label
958
+ @d.fill = @font_color
959
+ @d.font = @font if @font
960
+ @d.pointsize = scale_fontsize(@legend_font_size)
961
+ @d.stroke('transparent')
962
+ @d.font_weight = NormalWeight
963
+ @d.gravity = WestGravity
964
+ @d = @d.annotate_scaled(@base_image,
965
+ @raw_columns, 1.0,
966
+ current_x_offset + (legend_square_width * 1.7), current_y_offset,
967
+ legend_label.to_s, @scale)
968
+
969
+ # Now draw box with color of this dataset
970
+ @d = @d.stroke('transparent')
971
+ @d = @d.fill @data[index][DATA_COLOR_INDEX]
972
+ @d = @d.rectangle(current_x_offset,
973
+ current_y_offset - legend_square_width / 2.0,
974
+ current_x_offset + legend_square_width,
975
+ current_y_offset + legend_square_width / 2.0)
976
+
977
+ @d.pointsize = @legend_font_size
978
+ metrics = @d.get_type_metrics(@base_image, legend_label.to_s)
979
+ current_string_offset = metrics.width + (legend_square_width * 2.7)
980
+
981
+ # Handle wrapping
982
+ label_widths.first.shift
983
+ if label_widths.first.empty?
984
+ debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
985
+
986
+ label_widths.shift
987
+ current_x_offset = center(sum(label_widths.first)) unless label_widths.empty?
988
+ line_height = [@legend_caps_height, legend_square_width].max + legend_margin
989
+ if label_widths.length > 0
990
+ # Wrap to next line and shrink available graph dimensions
991
+ current_y_offset += line_height
992
+ @graph_top += line_height
993
+ @graph_height = @graph_bottom - @graph_top
994
+ end
995
+ else
996
+ current_x_offset += current_string_offset
997
+ end
998
+ end
999
+ @color_index = 0
1000
+ end
1001
+
1002
+ # Draws a title on the graph.
1003
+ def draw_title
1004
+ return if (@hide_title || @title.nil?)
1005
+
1006
+ @d.fill = @font_color
1007
+ @d.font = @title_font || @font if @title_font || @font
1008
+ @d.stroke('transparent')
1009
+ @d.pointsize = scale_fontsize(@title_font_size)
1010
+ @d.font_weight = if @bold_title then BoldWeight else NormalWeight end
1011
+ @d.gravity = NorthGravity
1012
+ @d = @d.annotate_scaled(@base_image,
1013
+ @raw_columns, 1.0,
1014
+ 0, @top_margin,
1015
+ @title, @scale)
1016
+ end
1017
+
1018
+ # Draws column labels below graph, centered over x_offset
1019
+ #--
1020
+ # TODO Allow WestGravity as an option
1021
+ def draw_label(x_offset, index)
1022
+ return if @hide_line_markers
1023
+
1024
+ if !@labels[index].nil? && @labels_seen[index].nil?
1025
+ y_offset = @graph_bottom + LABEL_MARGIN
1026
+
1027
+ # TESTME
1028
+ # FIXME: Consider chart types other than bar
1029
+ # TODO: See if index.odd? is the best stragegy
1030
+ y_offset += @label_stagger_height if index.odd?
1031
+
1032
+ label_text = @labels[index]
1033
+
1034
+ # TESTME
1035
+ # FIXME: Consider chart types other than bar
1036
+ if label_text.size > @label_max_size
1037
+ if @label_truncation_style == :trailing_dots
1038
+ if @label_max_size > 3
1039
+ # 4 because '...' takes up 3 chars
1040
+ label_text = "#{label_text[0 .. (@label_max_size - 4)]}..."
1041
+ end
1042
+ else # @label_truncation_style is :absolute (default)
1043
+ label_text = label_text[0 .. (@label_max_size - 1)]
1044
+ end
1045
+
1046
+ end
1047
+
1048
+ if x_offset >= @graph_left && x_offset <= @graph_right
1049
+ @d.fill = @font_color
1050
+ @d.font = @font if @font
1051
+ @d.stroke('transparent')
1052
+ @d.font_weight = NormalWeight
1053
+ @d.pointsize = scale_fontsize(@marker_font_size)
1054
+ @d.gravity = NorthGravity
1055
+ @d = @d.annotate_scaled(@base_image,
1056
+ 1.0, 1.0,
1057
+ x_offset, y_offset,
1058
+ label_text, @scale)
1059
+ end
1060
+ @labels_seen[index] = 1
1061
+ debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
1062
+ end
1063
+ end
1064
+
1065
+ # Draws the data value over the data point in bar graphs
1066
+ def draw_value_label(x_offset, y_offset, data_point, bar_value=false)
1067
+ return if @hide_line_markers && !bar_value
1068
+
1069
+ #y_offset = @graph_bottom + LABEL_MARGIN
1070
+
1071
+ @d.fill = @font_color
1072
+ @d.font = @font if @font
1073
+ @d.stroke('transparent')
1074
+ @d.font_weight = NormalWeight
1075
+ @d.pointsize = scale_fontsize(@marker_font_size)
1076
+ @d.gravity = NorthGravity
1077
+ @d = @d.annotate_scaled(@base_image,
1078
+ 1.0, 1.0,
1079
+ x_offset, y_offset,
1080
+ data_point.to_s, @scale)
1081
+
1082
+ debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
1083
+ end
1084
+
1085
+ # Shows an error message because you have no data.
1086
+ def draw_no_data
1087
+ @d.fill = @font_color
1088
+ @d.font = @font if @font
1089
+ @d.stroke('transparent')
1090
+ @d.font_weight = NormalWeight
1091
+ @d.pointsize = scale_fontsize(80)
1092
+ @d.gravity = CenterGravity
1093
+ @d = @d.annotate_scaled(@base_image,
1094
+ @raw_columns, @raw_rows/2.0,
1095
+ 0, 10,
1096
+ @no_data_message, @scale)
1097
+ end
1098
+
1099
+ # Finds the best background to render based on the provided theme options.
1100
+ #
1101
+ # Creates a @base_image to draw on.
1102
+ def render_background
1103
+ case @theme_options[:background_colors]
1104
+ when Array
1105
+ @base_image = render_gradiated_background(@theme_options[:background_colors][0], @theme_options[:background_colors][1], @theme_options[:background_direction])
1106
+ when String
1107
+ @base_image = render_solid_background(@theme_options[:background_colors])
1108
+ else
1109
+ @base_image = render_image_background(*@theme_options[:background_image])
1110
+ end
1111
+ end
1112
+
1113
+ # Make a new image at the current size with a solid +color+.
1114
+ def render_solid_background(color)
1115
+ Image.new(@columns, @rows) {
1116
+ self.background_color = color
1117
+ }
1118
+ end
1119
+
1120
+ # Use with a theme definition method to draw a gradiated background.
1121
+ def render_gradiated_background(top_color, bottom_color, direct = :top_bottom)
1122
+ case direct
1123
+ when :bottom_top
1124
+ gradient_fill = GradientFill.new(0, 0, 100, 0, bottom_color, top_color)
1125
+ when :left_right
1126
+ gradient_fill = GradientFill.new(0, 0, 0, 100, top_color, bottom_color)
1127
+ when :right_left
1128
+ gradient_fill = GradientFill.new(0, 0, 0, 100, bottom_color, top_color)
1129
+ when :topleft_bottomright
1130
+ gradient_fill = GradientFill.new(0, 100, 100, 0, top_color, bottom_color)
1131
+ when :topright_bottomleft
1132
+ gradient_fill = GradientFill.new(0, 0, 100, 100, bottom_color, top_color)
1133
+ else
1134
+ gradient_fill = GradientFill.new(0, 0, 100, 0, top_color, bottom_color)
1135
+ end
1136
+ Image.new(@columns, @rows, gradient_fill)
1137
+ end
1138
+
1139
+ # Use with a theme to use an image (800x600 original) background.
1140
+ def render_image_background(image_path)
1141
+ image = Image.read(image_path)
1142
+ if @scale != 1.0
1143
+ image[0].resize!(@scale) # TODO Resize with new scale (crop if necessary for wide graph)
1144
+ end
1145
+ image[0]
1146
+ end
1147
+
1148
+ # Use with a theme to make a transparent background
1149
+ def render_transparent_background
1150
+ Image.new(@columns, @rows) do
1151
+ self.background_color = 'transparent'
1152
+ end
1153
+ end
1154
+
1155
+ # Resets everything to defaults (except data).
1156
+ def reset_themes
1157
+ @color_index = 0
1158
+ @labels_seen = {}
1159
+ @theme_options = {}
1160
+
1161
+ @d = Draw.new
1162
+ # Scale down from 800x600 used to calculate drawing.
1163
+ @d = @d.scale(@scale, @scale)
1164
+ end
1165
+
1166
+ def scale(value) # :nodoc:
1167
+ value * @scale
1168
+ end
1169
+
1170
+ # Return a comparable fontsize for the current graph.
1171
+ def scale_fontsize(value)
1172
+ value * @scale
1173
+ end
1174
+
1175
+ def clip_value_if_greater_than(value, max_value) # :nodoc:
1176
+ (value > max_value) ? max_value : value
1177
+ end
1178
+
1179
+ # Overridden by subclasses such as stacked bar.
1180
+ def larger_than_max?(data_point) # :nodoc:
1181
+ data_point > @maximum_value
1182
+ end
1183
+
1184
+ def less_than_min?(data_point) # :nodoc:
1185
+ data_point < @minimum_value
1186
+ end
1187
+
1188
+ def significant(i) # :nodoc:
1189
+ return 1.0 if i == 0 # Keep from going into infinite loop
1190
+ inc = BigDecimal(i.to_s)
1191
+ factor = BigDecimal('1.0')
1192
+ while inc < 10
1193
+ inc *= 10
1194
+ factor /= 10
1195
+ end
1196
+
1197
+ while inc > 100
1198
+ inc /= 10
1199
+ factor *= 10
1200
+ end
1201
+
1202
+ res = inc.floor * factor
1203
+ if res.to_i.to_f == res
1204
+ res.to_i
1205
+ else
1206
+ res
1207
+ end
1208
+ end
1209
+
1210
+ # Sort with largest overall summed value at front of array.
1211
+ def sort_data
1212
+ @data = @data.sort_by { |a| -a[DATA_VALUES_INDEX].inject(0) { |sum, num| sum + num.to_f } }
1213
+ end
1214
+
1215
+ # Set the color for each data set unless it was gived in the data(...) call.
1216
+ def set_colors
1217
+ @data.each { |a| a[DATA_COLOR_INDEX] ||= increment_color }
1218
+ end
1219
+
1220
+ # === sort_norm_data
1221
+ #
1222
+ # Sort with largest overall summed value at front of array so it
1223
+ # shows up correctly in the drawn graph.
1224
+ def sort_norm_data
1225
+ @norm_data =
1226
+ @norm_data.sort_by { |a| -a[DATA_VALUES_INDEX].inject(0) { |sum, num| sum + num.to_f } }
1227
+ end
1228
+
1229
+ # Used by StackedBar and child classes.
1230
+ #
1231
+ # May need to be moved to the StackedBar class.
1232
+ def get_maximum_by_stack
1233
+ # Get sum of each stack
1234
+ max_hash = {}
1235
+ @data.each do |data_set|
1236
+ data_set[DATA_VALUES_INDEX].each_with_index do |data_point, i|
1237
+ max_hash[i] = 0.0 unless max_hash[i]
1238
+ max_hash[i] += data_point.to_f
1239
+ end
1240
+ end
1241
+
1242
+ # @maximum_value = 0
1243
+ max_hash.keys.each do |key|
1244
+ @maximum_value = max_hash[key] if max_hash[key] > @maximum_value
1245
+ end
1246
+ @minimum_value = 0
1247
+ end
1248
+
1249
+ # === make_stacked
1250
+ def make_stacked
1251
+ stacked_values = Array.new(@column_count, 0)
1252
+ @data.each do |value_set|
1253
+ value_set[DATA_VALUES_INDEX].each_with_index do |value, index|
1254
+ stacked_values[index] += value
1255
+ end
1256
+ value_set[DATA_VALUES_INDEX] = stacked_values.dup
1257
+ end
1258
+ end
1259
+
1260
+ private
1261
+
1262
+ # ========================================================================= #
1263
+ # === debug
1264
+ #
1265
+ # Takes a block and draws it if DEBUG is true.
1266
+ #
1267
+ # Example:
1268
+ # debug { @d.rectangle x1, y1, x2, y2 }
1269
+ # ========================================================================= #
1270
+ def debug
1271
+ if DEBUG
1272
+ @d = @d.fill 'transparent'
1273
+ @d = @d.stroke 'turquoise'
1274
+ @d = yield
1275
+ end
1276
+ end
1277
+
1278
+ # ========================================================================= #
1279
+ # === increment_colour
1280
+ #
1281
+ # Returns the next color in your color list.
1282
+ # ========================================================================= #
1283
+ def increment_colour
1284
+ @color_index = (@color_index + 1) % @colors.length
1285
+ @colors[@color_index - 1]
1286
+ end; alias increment_color increment_colour # === increment_colour
1287
+
1288
+ # ========================================================================= #
1289
+ # === label
1290
+ #
1291
+ # Return a formatted string representing a number value that should be
1292
+ # printed as a label.
1293
+ # ========================================================================= #
1294
+ def label(value, increment)
1295
+ label = if increment
1296
+ if increment >= 10 || (increment * 1) == (increment * 1).to_i.to_f
1297
+ sprintf('%0i', value)
1298
+ elsif increment >= 1.0 || (increment * 10) == (increment * 10).to_i.to_f
1299
+ sprintf('%0.1f', value)
1300
+ elsif increment >= 0.1 || (increment * 100) == (increment * 100).to_i.to_f
1301
+ sprintf('%0.2f', value)
1302
+ elsif increment >= 0.01 || (increment * 1000) == (increment * 1000).to_i.to_f
1303
+ sprintf('%0.3f', value)
1304
+ elsif increment >= 0.001 || (increment * 10000) == (increment * 10000).to_i.to_f
1305
+ sprintf('%0.4f', value)
1306
+ else
1307
+ value.to_s
1308
+ end
1309
+ elsif (@spread.to_f % (@marker_count.to_f==0 ? 1 : @marker_count.to_f) == 0) || !@y_axis_increment.nil?
1310
+ value.to_i.to_s
1311
+ elsif @spread > 10.0
1312
+ sprintf('%0i', value)
1313
+ elsif @spread >= 3.0
1314
+ sprintf('%0.2f', value)
1315
+ else
1316
+ value.to_s
1317
+ end
1318
+
1319
+ parts = label.split('.')
1320
+ parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{THOUSAND_SEPARATOR}")
1321
+ parts.join('.')
1322
+ end
1323
+
1324
+ # === calculate_caps_height
1325
+ #
1326
+ # Returns the height of the capital letter 'X' for the current font and
1327
+ # size.
1328
+ #
1329
+ # Not scaled since it deals with dimensions that the regular scaling will
1330
+ # handle.
1331
+ def calculate_caps_height(font_size)
1332
+ @d.pointsize = font_size
1333
+ @d.font = @font if @font
1334
+ @d.get_type_metrics(@base_image, 'X').height
1335
+ end
1336
+
1337
+ # === calculate_width
1338
+ #
1339
+ # Returns the width of a string at this pointsize.
1340
+ #
1341
+ # Not scaled since it deals with dimensions that the regular
1342
+ # scaling will handle.
1343
+ def calculate_width(font_size, text)
1344
+ return 0 if text.nil?
1345
+ @d.pointsize = font_size
1346
+ @d.font = @font if @font
1347
+ @d.get_type_metrics(@base_image, text.to_s).width
1348
+ end
1349
+
1350
+ # === deg2rad
1351
+ #
1352
+ # Used for degree => radian conversions
1353
+ def deg2rad(angle)
1354
+ angle * (Math::PI/180.0)
1355
+ end
1356
+
1357
+ end # Gruff::Base
1358
+
1359
+ class IncorrectNumberOfDatasetsException < StandardError
1360
+ end
1361
+
1362
+ end; end # Gruff
1363
+
1364
+ # Extend Rmagick part.
1365
+ module Magick
1366
+
1367
+ class Draw
1368
+
1369
+ # === annotate_scaled
1370
+ #
1371
+ # Additional method to scale annotation text since Draw.scale doesn't.
1372
+ def annotate_scaled(img, width, height, x, y, text, scale)
1373
+ scaled_width = (width * scale) >= 1 ? (width * scale) : 1
1374
+ scaled_height = (height * scale) >= 1 ? (height * scale) : 1
1375
+ self.annotate(img,
1376
+ scaled_width, scaled_height,
1377
+ x * scale, y * scale,
1378
+ text.gsub('%', '%%'))
1379
+ end
1380
+
1381
+ end; end # Magick
1382
+
1383
+ class String
1384
+
1385
+ # === commify
1386
+ #
1387
+ # Taken from http://codesnippets.joyent.com/posts/show/330
1388
+ def commify(delimiter=',')
1389
+ self.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
1390
+ end
1391
+
1392
+ end