image_paradise 0.4.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (650) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +38 -0
  3. data/README.md +1015 -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/rename_this_file_based_on_metadata_information +7 -0
  25. data/bin/resize_by_percent +10 -0
  26. data/bin/rotate_left +7 -0
  27. data/bin/rotate_right +7 -0
  28. data/bin/round_the_corner +7 -0
  29. data/bin/ruby_montage +7 -0
  30. data/bin/transparent +15 -0
  31. data/doc/README.gen +936 -0
  32. data/doc/todo/TODO_FOR_THE_GTK_GUI.md +9 -0
  33. data/doc/todo/TODO_FOR_THE_IMAGE_PARADISE_PROJECT.md +20 -0
  34. data/doc/todo/TODO_WORK_THROUGH_THESE_LINKS.md +3 -0
  35. data/doc/todo/todo_for_the_libui_gui.md +6 -0
  36. data/image_paradise.gemspec +46 -0
  37. data/images/IMAGE_PARADISE_LOGO.png +0 -0
  38. data/lib/image_paradise/base/base.rb +324 -0
  39. data/lib/image_paradise/cfdg/1dca_pattern.cfdg +48 -0
  40. data/lib/image_paradise/cfdg/3d_coloured_cube.cfdg +95 -0
  41. data/lib/image_paradise/cfdg/a_3D_spiral.cfdg +40 -0
  42. data/lib/image_paradise/cfdg/a_chaotic_city.cfdg +156 -0
  43. data/lib/image_paradise/cfdg/a_coloured_red.cfdg +21 -0
  44. data/lib/image_paradise/cfdg/a_daisy_flower.cfdg +66 -0
  45. data/lib/image_paradise/cfdg/a_decorated_window.cfdg +74 -0
  46. data/lib/image_paradise/cfdg/a_human_profile.cfdg +303 -0
  47. data/lib/image_paradise/cfdg/a_lost_heart.cfdg +28 -0
  48. data/lib/image_paradise/cfdg/a_plant_root.cfdg +26 -0
  49. data/lib/image_paradise/cfdg/a_rather_realistic_forest.cfdg +29 -0
  50. data/lib/image_paradise/cfdg/a_shoreline_next_to_a_forest.cfdg +127 -0
  51. data/lib/image_paradise/cfdg/a_simple_mini_brain.cfdg +17 -0
  52. data/lib/image_paradise/cfdg/a_simple_star.cfdg +22 -0
  53. data/lib/image_paradise/cfdg/adorned_tree.cfdg +58 -0
  54. data/lib/image_paradise/cfdg/adsorption.cfdg +19 -0
  55. data/lib/image_paradise/cfdg/alfabet_free.cfdg +346 -0
  56. data/lib/image_paradise/cfdg/alfreebet.cfdg +229 -0
  57. data/lib/image_paradise/cfdg/algal_flora.cfdg +25 -0
  58. data/lib/image_paradise/cfdg/alien_eyeball.cfdg +15 -0
  59. data/lib/image_paradise/cfdg/alien_flower.cfdg +35 -0
  60. data/lib/image_paradise/cfdg/alphabet_circles.cfdg +38 -0
  61. data/lib/image_paradise/cfdg/alveolo.cfdg +38 -0
  62. data/lib/image_paradise/cfdg/an_icosahedron.cfdg +134 -0
  63. data/lib/image_paradise/cfdg/an_oils_surface.cfdg +48 -0
  64. data/lib/image_paradise/cfdg/ancient_map.cfdg +30 -0
  65. data/lib/image_paradise/cfdg/ancient_scripts_tile.cfdg +96 -0
  66. data/lib/image_paradise/cfdg/angelfish.cfdg +58 -0
  67. data/lib/image_paradise/cfdg/angry_yarn.cfdg +82 -0
  68. data/lib/image_paradise/cfdg/apple_tree_small.cfdg +46 -0
  69. data/lib/image_paradise/cfdg/aqua_star.cfdg +27 -0
  70. data/lib/image_paradise/cfdg/army_explosion.cfdg +25 -0
  71. data/lib/image_paradise/cfdg/arrows_in_quadcity.cfdg +143 -0
  72. data/lib/image_paradise/cfdg/artificial_intelligence.cfdg +41 -0
  73. data/lib/image_paradise/cfdg/askew.cfdg +27 -0
  74. data/lib/image_paradise/cfdg/audio_diagram_waves.cfdg +54 -0
  75. data/lib/image_paradise/cfdg/autumn_fractal.cfdg +39 -0
  76. data/lib/image_paradise/cfdg/baignoire.cfdg +33 -0
  77. data/lib/image_paradise/cfdg/barcode.cfdg +781 -0
  78. data/lib/image_paradise/cfdg/basic_polygon_shapes.cfdg +311 -0
  79. data/lib/image_paradise/cfdg/basic_spreaders.cfdg +52 -0
  80. data/lib/image_paradise/cfdg/basic_square.cfdg +8 -0
  81. data/lib/image_paradise/cfdg/bats_hiding_in_foliage.cfdg +19 -0
  82. data/lib/image_paradise/cfdg/bees.cfdg +61 -0
  83. data/lib/image_paradise/cfdg/bent_squares.cfdg +46 -0
  84. data/lib/image_paradise/cfdg/benzo_dreaming.cfdg +54 -0
  85. data/lib/image_paradise/cfdg/beta_bet.cfdg +645 -0
  86. data/lib/image_paradise/cfdg/big_bang_theory.cfdg +31 -0
  87. data/lib/image_paradise/cfdg/big_pacman.cfdg +70 -0
  88. data/lib/image_paradise/cfdg/bigger_tree.cfdg +64 -0
  89. data/lib/image_paradise/cfdg/binary_connection.cfdg +34 -0
  90. data/lib/image_paradise/cfdg/birch_line.cfdg +57 -0
  91. data/lib/image_paradise/cfdg/blacksmith_masterpiece.cfdg +3 -0
  92. data/lib/image_paradise/cfdg/blocked_rectangles.cfdg +23 -0
  93. data/lib/image_paradise/cfdg/blood_tubes.cfdg +45 -0
  94. data/lib/image_paradise/cfdg/bloom.cfdg +23 -0
  95. data/lib/image_paradise/cfdg/blown_glass_spheres.cfdg +30 -0
  96. data/lib/image_paradise/cfdg/blue_daisies_in_detail.cfdg +101 -0
  97. data/lib/image_paradise/cfdg/blue_galaxy.cfdg +20 -0
  98. data/lib/image_paradise/cfdg/blue_moon.cfdg +36 -0
  99. data/lib/image_paradise/cfdg/boa_feathers.cfdg +53 -0
  100. data/lib/image_paradise/cfdg/bomb.cfdg +75 -0
  101. data/lib/image_paradise/cfdg/boxy_continent.cfdg +111 -0
  102. data/lib/image_paradise/cfdg/bright_coloured_neurons.cfdg +53 -0
  103. data/lib/image_paradise/cfdg/brightness_flower.cfdg +31 -0
  104. data/lib/image_paradise/cfdg/btp_71_beautiful_coloured_lines.cfdg +85 -0
  105. data/lib/image_paradise/cfdg/btp_73.cfdg +76 -0
  106. data/lib/image_paradise/cfdg/bubblesun.cfdg +46 -0
  107. data/lib/image_paradise/cfdg/burning_bush.cfdg +31 -0
  108. data/lib/image_paradise/cfdg/butterflies_in_the_moonlight.cfdg +55 -0
  109. data/lib/image_paradise/cfdg/cardiod_arc.cfdg +44 -0
  110. data/lib/image_paradise/cfdg/cardioid.cfdg +41 -0
  111. data/lib/image_paradise/cfdg/caros_wallpaper.cfdg +46 -0
  112. data/lib/image_paradise/cfdg/cartoony_face_arrays.cfdg +137 -0
  113. data/lib/image_paradise/cfdg/centerfold.cfdg +12 -0
  114. data/lib/image_paradise/cfdg/chain_link_fence.cfdg +31 -0
  115. data/lib/image_paradise/cfdg/chanukah.cfdg +109 -0
  116. data/lib/image_paradise/cfdg/chaos_red_sun.cfdg +42 -0
  117. data/lib/image_paradise/cfdg/chaotic_farn.cfdg +76 -0
  118. data/lib/image_paradise/cfdg/chaotic_fractal_shell.cfdg +41 -0
  119. data/lib/image_paradise/cfdg/charleston.cfdg +182 -0
  120. data/lib/image_paradise/cfdg/ciliasun.cfdg +109 -0
  121. data/lib/image_paradise/cfdg/cipal.cfdg +65 -0
  122. data/lib/image_paradise/cfdg/circuits.cfdg +176 -0
  123. data/lib/image_paradise/cfdg/city_map.cfdg +66 -0
  124. data/lib/image_paradise/cfdg/clifford_torus.cfdg +135 -0
  125. data/lib/image_paradise/cfdg/colonize_flat_colour_pattern.cfdg +14 -0
  126. data/lib/image_paradise/cfdg/colour_blind_squid.cfdg +30 -0
  127. data/lib/image_paradise/cfdg/colour_hole.cfdg +56 -0
  128. data/lib/image_paradise/cfdg/colour_wheel.cfdg +40 -0
  129. data/lib/image_paradise/cfdg/coloured_eyes.cfdg +40 -0
  130. data/lib/image_paradise/cfdg/coloured_forest.cfdg +133 -0
  131. data/lib/image_paradise/cfdg/coloured_tree.cfdg +50 -0
  132. data/lib/image_paradise/cfdg/colourful_lives.cfdg +123 -0
  133. data/lib/image_paradise/cfdg/colourful_neuronal_network.cfdg +32 -0
  134. data/lib/image_paradise/cfdg/complex_city_plans.cfdg +75 -0
  135. data/lib/image_paradise/cfdg/complex_kritworks.cfdg +75 -0
  136. data/lib/image_paradise/cfdg/complex_snowflake.cfdg +61 -0
  137. data/lib/image_paradise/cfdg/conspiracy_theory.cfdg +104 -0
  138. data/lib/image_paradise/cfdg/constellation_grid.cfdg +29 -0
  139. data/lib/image_paradise/cfdg/cool_caterpillar.cfdg +44 -0
  140. data/lib/image_paradise/cfdg/coolcubes.cfdg +70 -0
  141. data/lib/image_paradise/cfdg/crawler_battle.cfdg +93 -0
  142. data/lib/image_paradise/cfdg/crazy_octo.cfdg +48 -0
  143. data/lib/image_paradise/cfdg/cthulhu.cfdg +166 -0
  144. data/lib/image_paradise/cfdg/cubies.cfdg +43 -0
  145. data/lib/image_paradise/cfdg/cubist_sunset.cfdg +55 -0
  146. data/lib/image_paradise/cfdg/curled_tree.cfdg +37 -0
  147. data/lib/image_paradise/cfdg/curls.cfdg +45 -0
  148. data/lib/image_paradise/cfdg/curve_stiched.cfdg +59 -0
  149. data/lib/image_paradise/cfdg/curved_tubes.cfdg +20 -0
  150. data/lib/image_paradise/cfdg/cylinder_city.cfdg +27 -0
  151. data/lib/image_paradise/cfdg/cymbal.cfdg +38 -0
  152. data/lib/image_paradise/cfdg/d_mustard.cfdg +52 -0
  153. data/lib/image_paradise/cfdg/dance_party.cfdg +81 -0
  154. data/lib/image_paradise/cfdg/dance_party_and_background.cfdg +86 -0
  155. data/lib/image_paradise/cfdg/decreasing_aperture.cfdg +16 -0
  156. data/lib/image_paradise/cfdg/delicat_twist.cfdg +13 -0
  157. data/lib/image_paradise/cfdg/demo_text.cfdg +22 -0
  158. data/lib/image_paradise/cfdg/dennis_ritchie.cfdg +294 -0
  159. data/lib/image_paradise/cfdg/diablo.cfdg +47 -0
  160. data/lib/image_paradise/cfdg/different_flowers.cfdg +60 -0
  161. data/lib/image_paradise/cfdg/different_snowflakes_shapes.cfdg +149 -0
  162. data/lib/image_paradise/cfdg/dimensions.cfdg +33 -0
  163. data/lib/image_paradise/cfdg/domino_pieces.cfdg +166 -0
  164. data/lib/image_paradise/cfdg/dong.cfdg +41 -0
  165. data/lib/image_paradise/cfdg/drip_shape.cfdg +24 -0
  166. data/lib/image_paradise/cfdg/earthday2007b.cfdg +49 -0
  167. data/lib/image_paradise/cfdg/edera_circles.cfdg +55 -0
  168. data/lib/image_paradise/cfdg/eight_queens_problem.cfdg +85 -0
  169. data/lib/image_paradise/cfdg/electro_shock.cfdg +88 -0
  170. data/lib/image_paradise/cfdg/enter_the_force_field.cfdg +56 -0
  171. data/lib/image_paradise/cfdg/escargot_fleur.cfdg +98 -0
  172. data/lib/image_paradise/cfdg/european_city.cfdg +63 -0
  173. data/lib/image_paradise/cfdg/evil_eye.cfdg +74 -0
  174. data/lib/image_paradise/cfdg/evolving_coloured_spots.cfdg +47 -0
  175. data/lib/image_paradise/cfdg/excellines_nr2.cfdg +171 -0
  176. data/lib/image_paradise/cfdg/exoplanet_settlement.cfdg +117 -0
  177. data/lib/image_paradise/cfdg/explosion.cfdg +45 -0
  178. data/lib/image_paradise/cfdg/explosion_of_a_megabyte.cfdg +73 -0
  179. data/lib/image_paradise/cfdg/eye_of_katora.cfdg +20 -0
  180. data/lib/image_paradise/cfdg/family_tree.cfdg +169 -0
  181. data/lib/image_paradise/cfdg/feathers.cfdg +17 -0
  182. data/lib/image_paradise/cfdg/ferma_drawings.cfdg +23 -0
  183. data/lib/image_paradise/cfdg/fevrier.cfdg +66 -0
  184. data/lib/image_paradise/cfdg/fibmod.cfdg +25 -0
  185. data/lib/image_paradise/cfdg/field_of_boxes.cfdg +21 -0
  186. data/lib/image_paradise/cfdg/finetre.cfdg +34 -0
  187. data/lib/image_paradise/cfdg/fireblorks.cfdg +37 -0
  188. data/lib/image_paradise/cfdg/first_branch.cfdg +18 -0
  189. data/lib/image_paradise/cfdg/fish_with_coloured_bubbles.cfdg +77 -0
  190. data/lib/image_paradise/cfdg/fishing_lure.cfdg +30 -0
  191. data/lib/image_paradise/cfdg/flake.cfdg +20 -0
  192. data/lib/image_paradise/cfdg/flaming_spiro.cfdg +10 -0
  193. data/lib/image_paradise/cfdg/fleshflower.cfdg +25 -0
  194. data/lib/image_paradise/cfdg/flourescent_fish_btp.cfdg +48 -0
  195. data/lib/image_paradise/cfdg/flow_control_shape.cfdg +45 -0
  196. data/lib/image_paradise/cfdg/flower_galaxy.cfdg +57 -0
  197. data/lib/image_paradise/cfdg/flower_house.cfdg +115 -0
  198. data/lib/image_paradise/cfdg/flower_stories.cfdg +136 -0
  199. data/lib/image_paradise/cfdg/fluctuating_heart.cfdg +87 -0
  200. data/lib/image_paradise/cfdg/fly_agaric.cfdg +22 -0
  201. data/lib/image_paradise/cfdg/forest_and_ocean.cfdg +65 -0
  202. data/lib/image_paradise/cfdg/fractal_fern.cfdg +15 -0
  203. data/lib/image_paradise/cfdg/fractal_shell.cfdg +36 -0
  204. data/lib/image_paradise/cfdg/frost_bite.cfdg +23 -0
  205. data/lib/image_paradise/cfdg/fun_with_paper.cfdg +17 -0
  206. data/lib/image_paradise/cfdg/func_plot.cfdg +59 -0
  207. data/lib/image_paradise/cfdg/funky_squiggle.cfdg +40 -0
  208. data/lib/image_paradise/cfdg/fuzzy_sun.cfdg +47 -0
  209. data/lib/image_paradise/cfdg/galaxy.cfdg +59 -0
  210. data/lib/image_paradise/cfdg/gallery.cfdg +28 -0
  211. data/lib/image_paradise/cfdg/game1_turn6.cfdg +35 -0
  212. data/lib/image_paradise/cfdg/garland.cfdg +42 -0
  213. data/lib/image_paradise/cfdg/general_polygons.cfdg +20 -0
  214. data/lib/image_paradise/cfdg/generational_birds.cfdg +118 -0
  215. data/lib/image_paradise/cfdg/ghostly_spine.cfdg +24 -0
  216. data/lib/image_paradise/cfdg/gift_wrapping.cfdg +46 -0
  217. data/lib/image_paradise/cfdg/glass_cubes.cfdg +33 -0
  218. data/lib/image_paradise/cfdg/gleaming_bush.cfdg +33 -0
  219. data/lib/image_paradise/cfdg/glowing_bush.cfdg +33 -0
  220. data/lib/image_paradise/cfdg/go_grid.cfdg +32 -0
  221. data/lib/image_paradise/cfdg/gold_tiles.cfdg +21 -0
  222. data/lib/image_paradise/cfdg/golden_rectangle.cfdg +19 -0
  223. data/lib/image_paradise/cfdg/golden_sierpinski.cfdg +49 -0
  224. data/lib/image_paradise/cfdg/golgi_stain.cfdg +74 -0
  225. data/lib/image_paradise/cfdg/gothic_bath_tiles.cfdg +14 -0
  226. data/lib/image_paradise/cfdg/grass_land.cfdg +112 -0
  227. data/lib/image_paradise/cfdg/gray_matter.cfdg +110 -0
  228. data/lib/image_paradise/cfdg/great_forest.cfdg +91 -0
  229. data/lib/image_paradise/cfdg/growth.cfdg +46 -0
  230. data/lib/image_paradise/cfdg/gumtree.cfdg +28 -0
  231. data/lib/image_paradise/cfdg/haggards_bull.cfdg +92 -0
  232. data/lib/image_paradise/cfdg/haight_ashbury.cfdg +882 -0
  233. data/lib/image_paradise/cfdg/hair_pattern.cfdg +59 -0
  234. data/lib/image_paradise/cfdg/hairy.cfdg +43 -0
  235. data/lib/image_paradise/cfdg/hairy_branch.cfdg +48 -0
  236. data/lib/image_paradise/cfdg/hands_and_feet.cfdg +49 -0
  237. data/lib/image_paradise/cfdg/happy_new_year.cfdg +3435 -0
  238. data/lib/image_paradise/cfdg/hatagu_lila_spiral.cfdg +27 -0
  239. data/lib/image_paradise/cfdg/hexaeder_triangle.cfdg +43 -0
  240. data/lib/image_paradise/cfdg/hexclouds_textures.cfdg +75 -0
  241. data/lib/image_paradise/cfdg/hextiles.cfdg +73 -0
  242. data/lib/image_paradise/cfdg/hexy_continent.cfdg +83 -0
  243. data/lib/image_paradise/cfdg/human_ballet.cfdg +215 -0
  244. data/lib/image_paradise/cfdg/human_eyes.cfdg +102 -0
  245. data/lib/image_paradise/cfdg/hydra_tail.cfdg +57 -0
  246. data/lib/image_paradise/cfdg/i_like_it_dirty.cfdg +88 -0
  247. data/lib/image_paradise/cfdg/i_pix.cfdg +679 -0
  248. data/lib/image_paradise/cfdg/imaginary_star.cfdg +55 -0
  249. data/lib/image_paradise/cfdg/imaginery_forest.cfdg +61 -0
  250. data/lib/image_paradise/cfdg/impossible_stairs.cfdg +211 -0
  251. data/lib/image_paradise/cfdg/in_the_morning.cfdg +83 -0
  252. data/lib/image_paradise/cfdg/inertial_confinement.cfdg +150 -0
  253. data/lib/image_paradise/cfdg/infected_shell.cfdg +56 -0
  254. data/lib/image_paradise/cfdg/insect_fight.cfdg +316 -0
  255. data/lib/image_paradise/cfdg/insectivore.cfdg +80 -0
  256. data/lib/image_paradise/cfdg/interference.cfdg +43 -0
  257. data/lib/image_paradise/cfdg/interference_fields.cfdg +25 -0
  258. data/lib/image_paradise/cfdg/into_the_deep.cfdg +96 -0
  259. data/lib/image_paradise/cfdg/inverted_decorations.cfdg +85 -0
  260. data/lib/image_paradise/cfdg/irregular_galaxies.cfdg +29 -0
  261. data/lib/image_paradise/cfdg/iso_blocks.cfdg +35 -0
  262. data/lib/image_paradise/cfdg/jewelry_old_style.cfdg +31 -0
  263. data/lib/image_paradise/cfdg/just_some_flowers.cfdg +127 -0
  264. data/lib/image_paradise/cfdg/kaboom.cfdg +40 -0
  265. data/lib/image_paradise/cfdg/kaleidoskop.cfdg +27 -0
  266. data/lib/image_paradise/cfdg/kama_sutra.cfdg +182 -0
  267. data/lib/image_paradise/cfdg/kitakoa_akiyoshi_illusions_roller.cfdg +40 -0
  268. data/lib/image_paradise/cfdg/koch_snowflake.cfdg +11 -0
  269. data/lib/image_paradise/cfdg/kochlea.cfdg +43 -0
  270. data/lib/image_paradise/cfdg/kreepykrawler.cfdg +48 -0
  271. data/lib/image_paradise/cfdg/kw_expanded_explosion.cfdg +46 -0
  272. data/lib/image_paradise/cfdg/lapsang_abstrait.cfdg +51 -0
  273. data/lib/image_paradise/cfdg/laser.cfdg +51 -0
  274. data/lib/image_paradise/cfdg/last_pluto_dream.cfdg +95 -0
  275. data/lib/image_paradise/cfdg/lazy_dust.cfdg +42 -0
  276. data/lib/image_paradise/cfdg/lesson_one_two_three_four.cfdg +217 -0
  277. data/lib/image_paradise/cfdg/lila_lili.cfdg +60 -0
  278. data/lib/image_paradise/cfdg/lindenmayergrassef2_pretty_flowers.cfdg +94 -0
  279. data/lib/image_paradise/cfdg/lines_from_excel.cfdg +136 -0
  280. data/lib/image_paradise/cfdg/looking_out.cfdg +51 -0
  281. data/lib/image_paradise/cfdg/looking_up_in_the_sky.cfdg +43 -0
  282. data/lib/image_paradise/cfdg/lotus_logo.cfdg +49 -0
  283. data/lib/image_paradise/cfdg/lowercased_alphabet.cfdg +565 -0
  284. data/lib/image_paradise/cfdg/luma_smiley.cfdg +563 -0
  285. data/lib/image_paradise/cfdg/maggi_stars.cfdg +11 -0
  286. data/lib/image_paradise/cfdg/mandelbrot_3.cfdg +111 -0
  287. data/lib/image_paradise/cfdg/martini.cfdg +147 -0
  288. data/lib/image_paradise/cfdg/material_studies.cfdg +172 -0
  289. data/lib/image_paradise/cfdg/math_eye.cfdg +30 -0
  290. data/lib/image_paradise/cfdg/matrix_freestyle.cfdg +127 -0
  291. data/lib/image_paradise/cfdg/maze.cfdg +211 -0
  292. data/lib/image_paradise/cfdg/meaculpo.cfdg +46 -0
  293. data/lib/image_paradise/cfdg/medieval_madness.cfdg +140 -0
  294. data/lib/image_paradise/cfdg/menage_a_trois.cfdg +77 -0
  295. data/lib/image_paradise/cfdg/micky_mouse.cfdg +75 -0
  296. data/lib/image_paradise/cfdg/mistletoe_forest.cfdg +62 -0
  297. data/lib/image_paradise/cfdg/mixed_simple_bubbles.cfdg +20 -0
  298. data/lib/image_paradise/cfdg/mod4g_starhole.cfdg +27 -0
  299. data/lib/image_paradise/cfdg/moebius.cfdg +57 -0
  300. data/lib/image_paradise/cfdg/molecules.cfdg +30 -0
  301. data/lib/image_paradise/cfdg/momos_blossom.cfdg +70 -0
  302. data/lib/image_paradise/cfdg/mona_lisa.cfdg +7937 -0
  303. data/lib/image_paradise/cfdg/more_arrows_in_quadcity.cfdg +49 -0
  304. data/lib/image_paradise/cfdg/more_cats.cfdg +1002 -0
  305. data/lib/image_paradise/cfdg/mosaic_for_2D_games.cfdg +69 -0
  306. data/lib/image_paradise/cfdg/mr_bezier.cfdg +195 -0
  307. data/lib/image_paradise/cfdg/mtree.cfdg +33 -0
  308. data/lib/image_paradise/cfdg/multiple_triangles.cfdg +13 -0
  309. data/lib/image_paradise/cfdg/mycel.cfdg +88 -0
  310. data/lib/image_paradise/cfdg/mytohexagone.cfdg +56 -0
  311. data/lib/image_paradise/cfdg/nature_is_not_like_that.cfdg +48 -0
  312. data/lib/image_paradise/cfdg/negative_flowers.cfdg +85 -0
  313. data/lib/image_paradise/cfdg/neo_town.cfdg +41 -0
  314. data/lib/image_paradise/cfdg/nesting_pattern.cfdg +34 -0
  315. data/lib/image_paradise/cfdg/neuronal_network.cfdg +94 -0
  316. data/lib/image_paradise/cfdg/neuronal_root.cfdg +46 -0
  317. data/lib/image_paradise/cfdg/night.cfdg +82 -0
  318. data/lib/image_paradise/cfdg/nightwalker.cfdg +23 -0
  319. data/lib/image_paradise/cfdg/no_xcape.cfdg +41 -0
  320. data/lib/image_paradise/cfdg/noise.cfdg +12 -0
  321. data/lib/image_paradise/cfdg/octopodi.cfdg +51 -0
  322. data/lib/image_paradise/cfdg/octopussy.cfdg +49 -0
  323. data/lib/image_paradise/cfdg/oldschool_cartoon_figure.cfdg +181 -0
  324. data/lib/image_paradise/cfdg/open_shapes.cfdg +240 -0
  325. data/lib/image_paradise/cfdg/orange_blossom.cfdg +57 -0
  326. data/lib/image_paradise/cfdg/orange_guts.cfdg +43 -0
  327. data/lib/image_paradise/cfdg/orange_monster.cfdg +42 -0
  328. data/lib/image_paradise/cfdg/organic.cfdg +30 -0
  329. data/lib/image_paradise/cfdg/ouo_happy_smiley.cfdg +45 -0
  330. data/lib/image_paradise/cfdg/output.png +0 -0
  331. data/lib/image_paradise/cfdg/pacman.cfdg +18 -0
  332. data/lib/image_paradise/cfdg/palmen.cfdg +162 -0
  333. data/lib/image_paradise/cfdg/pandoras_box.cfdg +53 -0
  334. data/lib/image_paradise/cfdg/papillon_butterfly.cfdg +28 -0
  335. data/lib/image_paradise/cfdg/patchwork.cfdg +32 -0
  336. data/lib/image_paradise/cfdg/pattern_grass.cfdg +110 -0
  337. data/lib/image_paradise/cfdg/peau_de_grenouille.cfdg +16 -0
  338. data/lib/image_paradise/cfdg/penrose_tiling.cfdg +102 -0
  339. data/lib/image_paradise/cfdg/pentagon.cfdg +68 -0
  340. data/lib/image_paradise/cfdg/pentagons.cfdg +25 -0
  341. data/lib/image_paradise/cfdg/perspective_tsunami.cfdg +20 -0
  342. data/lib/image_paradise/cfdg/phi_cloud.cfdg +23 -0
  343. data/lib/image_paradise/cfdg/picnic_birds_eye_view.cfdg +132 -0
  344. data/lib/image_paradise/cfdg/ping_pong.cfdg +29 -0
  345. data/lib/image_paradise/cfdg/pink_blossom.cfdg +58 -0
  346. data/lib/image_paradise/cfdg/piupole.cfdg +77 -0
  347. data/lib/image_paradise/cfdg/plotting.cfdg +61 -0
  348. data/lib/image_paradise/cfdg/point_onto_root.cfdg +64 -0
  349. data/lib/image_paradise/cfdg/primitive_reptile_pattern.cfdg +96 -0
  350. data/lib/image_paradise/cfdg/psycho_knot.cfdg +20 -0
  351. data/lib/image_paradise/cfdg/pyramide.cfdg +67 -0
  352. data/lib/image_paradise/cfdg/pythagoras_puzzle.cfdg +17 -0
  353. data/lib/image_paradise/cfdg/pythagorean_tree.cfdg +70 -0
  354. data/lib/image_paradise/cfdg/qimica.cfdg +64 -0
  355. data/lib/image_paradise/cfdg/quad_green_satellite.cfdg +53 -0
  356. data/lib/image_paradise/cfdg/quadcity.cfdg +24 -0
  357. data/lib/image_paradise/cfdg/quiet_wood_town.cfdg +195 -0
  358. data/lib/image_paradise/cfdg/r180.cfdg +26 -0
  359. data/lib/image_paradise/cfdg/r45.cfdg +26 -0
  360. data/lib/image_paradise/cfdg/r_square.cfdg +36 -0
  361. data/lib/image_paradise/cfdg/rads.cfdg +33 -0
  362. data/lib/image_paradise/cfdg/rainbow_black_hole.cfdg +9 -0
  363. data/lib/image_paradise/cfdg/rainbow_sun.cfdg +9 -0
  364. data/lib/image_paradise/cfdg/random_handwriting.cfdg +50 -0
  365. data/lib/image_paradise/cfdg/random_tile_shapes_jens_revisited.cfdg +146 -0
  366. data/lib/image_paradise/cfdg/rays_attack.cfdg +29 -0
  367. data/lib/image_paradise/cfdg/razpad.cfdg +20 -0
  368. data/lib/image_paradise/cfdg/rectangular_distortion.cfdg +169 -0
  369. data/lib/image_paradise/cfdg/recurse_path.cfdg +38 -0
  370. data/lib/image_paradise/cfdg/red_flurry.cfdg +64 -0
  371. data/lib/image_paradise/cfdg/red_horse_tail.cfdg +36 -0
  372. data/lib/image_paradise/cfdg/red_yellow_mosaic.cfdg +26 -0
  373. data/lib/image_paradise/cfdg/rendering_tests.cfdg +183 -0
  374. data/lib/image_paradise/cfdg/repeat_floor_tile_pattern.cfdg +153 -0
  375. data/lib/image_paradise/cfdg/repeat_tile.cfdg +160 -0
  376. data/lib/image_paradise/cfdg/retro_disc.cfdg +736 -0
  377. data/lib/image_paradise/cfdg/ring_growth_variation.cfdg +41 -0
  378. data/lib/image_paradise/cfdg/robot_nightlife.cfdg +25 -0
  379. data/lib/image_paradise/cfdg/rolled_firespiral.cfdg +34 -0
  380. data/lib/image_paradise/cfdg/rose.cfdg +44 -0
  381. data/lib/image_paradise/cfdg/round_tree.cfdg +121 -0
  382. data/lib/image_paradise/cfdg/rubiks_cube.cfdg +120 -0
  383. data/lib/image_paradise/cfdg/ruins.cfdg +19 -0
  384. data/lib/image_paradise/cfdg/sails_and_the_sea.cfdg +27 -0
  385. data/lib/image_paradise/cfdg/salt_crystals.cfdg +26 -0
  386. data/lib/image_paradise/cfdg/saturn.cfdg +105 -0
  387. data/lib/image_paradise/cfdg/scary_pot.cfdg +49 -0
  388. data/lib/image_paradise/cfdg/schematic_worm.cfdg +35 -0
  389. data/lib/image_paradise/cfdg/school_script.cfdg +359 -0
  390. data/lib/image_paradise/cfdg/seahorse.cfdg +78 -0
  391. data/lib/image_paradise/cfdg/seasons.cfdg +115 -0
  392. data/lib/image_paradise/cfdg/segmental_veins.cfdg +66 -0
  393. data/lib/image_paradise/cfdg/select_mayhem.cfdg +28 -0
  394. data/lib/image_paradise/cfdg/seven_folded_symmetry.cfdg +7 -0
  395. data/lib/image_paradise/cfdg/several_cats.cfdg +996 -0
  396. data/lib/image_paradise/cfdg/shadow_box.cfdg +49 -0
  397. data/lib/image_paradise/cfdg/shadowrun_google_maps.cfdg +66 -0
  398. data/lib/image_paradise/cfdg/shadowrun_nightline.cfdg +18 -0
  399. data/lib/image_paradise/cfdg/shards.cfdg +70 -0
  400. data/lib/image_paradise/cfdg/sheet_music.cfdg +213 -0
  401. data/lib/image_paradise/cfdg/shy_guy.cfdg +886 -0
  402. data/lib/image_paradise/cfdg/sierpinski1.cfdg +41 -0
  403. data/lib/image_paradise/cfdg/sierpinski2.cfdg +34 -0
  404. data/lib/image_paradise/cfdg/sierpinski_like_red_swirl.cfdg +46 -0
  405. data/lib/image_paradise/cfdg/sierpinsktri.cfdg +9 -0
  406. data/lib/image_paradise/cfdg/silk_flowers.cfdg +68 -0
  407. data/lib/image_paradise/cfdg/silk_scarf.cfdg +18 -0
  408. data/lib/image_paradise/cfdg/simple_cilia.cfdg +88 -0
  409. data/lib/image_paradise/cfdg/simple_circle_and_square.cfdg +7 -0
  410. data/lib/image_paradise/cfdg/simple_coloured_square.cfdg +38 -0
  411. data/lib/image_paradise/cfdg/simple_ferns.cfdg +40 -0
  412. data/lib/image_paradise/cfdg/simple_fish.cfdg +77 -0
  413. data/lib/image_paradise/cfdg/simple_orchid.cfdg +23 -0
  414. data/lib/image_paradise/cfdg/simple_rounded_colour_wheel.cfdg +10 -0
  415. data/lib/image_paradise/cfdg/simple_sheet_music.cfdg +27 -0
  416. data/lib/image_paradise/cfdg/sincos_pattern_2.cfdg +42 -0
  417. data/lib/image_paradise/cfdg/singing_birdy.cfdg +112 -0
  418. data/lib/image_paradise/cfdg/skyscraper.cfdg +85 -0
  419. data/lib/image_paradise/cfdg/small_golden_rectangle.cfdg +12 -0
  420. data/lib/image_paradise/cfdg/smells_like_layered.cfdg +43 -0
  421. data/lib/image_paradise/cfdg/snowflake.cfdg +26 -0
  422. data/lib/image_paradise/cfdg/snowstorm.cfdg +26 -0
  423. data/lib/image_paradise/cfdg/soar_on_wings.cfdg +8 -0
  424. data/lib/image_paradise/cfdg/soft_core.cfdg +26 -0
  425. data/lib/image_paradise/cfdg/soft_touch.cfdg +20 -0
  426. data/lib/image_paradise/cfdg/some_sort_of_tree.cfdg +57 -0
  427. data/lib/image_paradise/cfdg/spade_ball.cfdg +39 -0
  428. data/lib/image_paradise/cfdg/sparks.cfdg +39 -0
  429. data/lib/image_paradise/cfdg/sperm.cfdg +63 -0
  430. data/lib/image_paradise/cfdg/sphinx.cfdg +17 -0
  431. data/lib/image_paradise/cfdg/spiral_clusters.cfdg +29 -0
  432. data/lib/image_paradise/cfdg/spiral_cross.cfdg +27 -0
  433. data/lib/image_paradise/cfdg/spiral_star.cfdg +19 -0
  434. data/lib/image_paradise/cfdg/spiral_sun.cfdg +39 -0
  435. data/lib/image_paradise/cfdg/spirit.cfdg +47 -0
  436. data/lib/image_paradise/cfdg/splatter_tree.cfdg +61 -0
  437. data/lib/image_paradise/cfdg/spliced.cfdg +27 -0
  438. data/lib/image_paradise/cfdg/spring_parade.cfdg +105 -0
  439. data/lib/image_paradise/cfdg/sprinkle_explosion.cfdg +23 -0
  440. data/lib/image_paradise/cfdg/square_limit_one.cfdg +15 -0
  441. data/lib/image_paradise/cfdg/square_rose.cfdg +75 -0
  442. data/lib/image_paradise/cfdg/square_spiral4.cfdg +41 -0
  443. data/lib/image_paradise/cfdg/square_star.cfdg +39 -0
  444. data/lib/image_paradise/cfdg/squiggle.cfdg +54 -0
  445. data/lib/image_paradise/cfdg/stacked_blob.cfdg +27 -0
  446. data/lib/image_paradise/cfdg/star_explosion.cfdg +38 -0
  447. data/lib/image_paradise/cfdg/star_flower.cfdg +72 -0
  448. data/lib/image_paradise/cfdg/star_mosaic_2007.cfdg +51 -0
  449. data/lib/image_paradise/cfdg/starry_pines.cfdg +79 -0
  450. data/lib/image_paradise/cfdg/stars_tentacles.cfdg +28 -0
  451. data/lib/image_paradise/cfdg/starshape.cfdg +57 -0
  452. data/lib/image_paradise/cfdg/strange_antlers.cfdg +49 -0
  453. data/lib/image_paradise/cfdg/strange_carpet.cfdg +13 -0
  454. data/lib/image_paradise/cfdg/sunset_city.cfdg +112 -0
  455. data/lib/image_paradise/cfdg/sweep.cfdg +946 -0
  456. data/lib/image_paradise/cfdg/swimmers_sperms.cfdg +54 -0
  457. data/lib/image_paradise/cfdg/sword.cfdg +24 -0
  458. data/lib/image_paradise/cfdg/tangle.cfdg +25 -0
  459. data/lib/image_paradise/cfdg/tapestry.cfdg +40 -0
  460. data/lib/image_paradise/cfdg/tasty_loops.cfdg +97 -0
  461. data/lib/image_paradise/cfdg/tendril.cfdg +6 -0
  462. data/lib/image_paradise/cfdg/tentacle_tree.cfdg +57 -0
  463. data/lib/image_paradise/cfdg/terraforming.cfdg +87 -0
  464. data/lib/image_paradise/cfdg/test.cfdg +7 -0
  465. data/lib/image_paradise/cfdg/tetris.cfdg +123 -0
  466. data/lib/image_paradise/cfdg/textured_giraffes.cfdg +122 -0
  467. data/lib/image_paradise/cfdg/the_eye.cfdg +16 -0
  468. data/lib/image_paradise/cfdg/the_go_game.cfdg +81 -0
  469. data/lib/image_paradise/cfdg/the_secret.cfdg +52 -0
  470. data/lib/image_paradise/cfdg/the_third_eye.cfdg +42 -0
  471. data/lib/image_paradise/cfdg/thingy.cfdg +13 -0
  472. data/lib/image_paradise/cfdg/thorns.cfdg +26 -0
  473. data/lib/image_paradise/cfdg/too_many_notes.cfdg +155 -0
  474. data/lib/image_paradise/cfdg/top_down_plant_root.cfdg +43 -0
  475. data/lib/image_paradise/cfdg/top_view_tree.cfdg +79 -0
  476. data/lib/image_paradise/cfdg/transparent_heart.cfdg +31 -0
  477. data/lib/image_paradise/cfdg/tree.cfdg +68 -0
  478. data/lib/image_paradise/cfdg/tree_number_5.cfdg +28 -0
  479. data/lib/image_paradise/cfdg/tree_retro.cfdg +46 -0
  480. data/lib/image_paradise/cfdg/tree_spiral.cfdg +52 -0
  481. data/lib/image_paradise/cfdg/treematic.cfdg +42 -0
  482. data/lib/image_paradise/cfdg/tri_arc.cfdg +16 -0
  483. data/lib/image_paradise/cfdg/tri_squares.cfdg +7 -0
  484. data/lib/image_paradise/cfdg/tube_map.cfdg +112 -0
  485. data/lib/image_paradise/cfdg/turing_morphogenesis.cfdg +788 -0
  486. data/lib/image_paradise/cfdg/twisted_hex_grid.cfdg +26 -0
  487. data/lib/image_paradise/cfdg/twisty_triangel.cfdg +79 -0
  488. data/lib/image_paradise/cfdg/twizeeded.cfdg +19 -0
  489. data/lib/image_paradise/cfdg/uncontrolled_fungus.cfdg +36 -0
  490. data/lib/image_paradise/cfdg/underground.cfdg +72 -0
  491. data/lib/image_paradise/cfdg/underwater.cfdg +75 -0
  492. data/lib/image_paradise/cfdg/unicorn_boi.cfdg +20 -0
  493. data/lib/image_paradise/cfdg/unification_sign.cfdg +52 -0
  494. data/lib/image_paradise/cfdg/urban_connections.cfdg +44 -0
  495. data/lib/image_paradise/cfdg/us_flag.cfdg +109 -0
  496. data/lib/image_paradise/cfdg/v_null.cfdg +89 -0
  497. data/lib/image_paradise/cfdg/very_simple_flower.cfdg +45 -0
  498. data/lib/image_paradise/cfdg/very_simple_hexagon.cfdg +16 -0
  499. data/lib/image_paradise/cfdg/very_simple_octagon.cfg +13 -0
  500. data/lib/image_paradise/cfdg/vigorous_vine.cfdg +45 -0
  501. data/lib/image_paradise/cfdg/ville_topview.cfdg +70 -0
  502. data/lib/image_paradise/cfdg/vine.cfdg +176 -0
  503. data/lib/image_paradise/cfdg/vinyl.cfdg +12 -0
  504. data/lib/image_paradise/cfdg/violet_ribbons.cfdg +45 -0
  505. data/lib/image_paradise/cfdg/voronoi_2.cfdg +61 -0
  506. data/lib/image_paradise/cfdg/wald.cfdg +46 -0
  507. data/lib/image_paradise/cfdg/water_ink.cfdg +71 -0
  508. data/lib/image_paradise/cfdg/water_monster.cfdg +33 -0
  509. data/lib/image_paradise/cfdg/web.cfdg +53 -0
  510. data/lib/image_paradise/cfdg/weighting_demo.cfdg +16 -0
  511. data/lib/image_paradise/cfdg/weird_spots.cfdg +15 -0
  512. data/lib/image_paradise/cfdg/welcome.cfdg +109 -0
  513. data/lib/image_paradise/cfdg/where_do_you_want_to_go_today.cfdg +632 -0
  514. data/lib/image_paradise/cfdg/where_is_the_head.cfdg +28 -0
  515. data/lib/image_paradise/cfdg/where_to_go.cfdg +62 -0
  516. data/lib/image_paradise/cfdg/willow.cfdg +39 -0
  517. data/lib/image_paradise/cfdg/witch_poison.cfdg +58 -0
  518. data/lib/image_paradise/cfdg/wooden_floor.cfdg +95 -0
  519. data/lib/image_paradise/cfdg/writhing.cfdg +15 -0
  520. data/lib/image_paradise/cfdg/wrooom_cars.cfdg +124 -0
  521. data/lib/image_paradise/cfdg/xmas_code.cfdg +101 -0
  522. data/lib/image_paradise/cfdg/xmas_tree.cfdg +70 -0
  523. data/lib/image_paradise/cfdg/yellow_cactus.cfdg +52 -0
  524. data/lib/image_paradise/cfdg/yet_another_explosion.cfdg +46 -0
  525. data/lib/image_paradise/cfdg/yin_yang_taijitu_pattern.cfdg +44 -0
  526. data/lib/image_paradise/cfdg/yog.cfdg +27 -0
  527. data/lib/image_paradise/cfdg/yurbanis_m.cfdg +27 -0
  528. data/lib/image_paradise/cfdg/zen_tree.cfdg +79 -0
  529. data/lib/image_paradise/cfdg/ziggy_flowers.cfdg +44 -0
  530. data/lib/image_paradise/cfdg/zodiac.cfdg +43 -0
  531. data/lib/image_paradise/chunky_png/chunky_png.rb +54 -0
  532. data/lib/image_paradise/colours/colours.rb +55 -0
  533. data/lib/image_paradise/confree_generator/confree_generator.rb +793 -0
  534. data/lib/image_paradise/confree_generator/constants.rb +93 -0
  535. data/lib/image_paradise/constants/constants.rb +50 -0
  536. data/lib/image_paradise/constants/image_file_types.rb +27 -0
  537. data/lib/image_paradise/crop/crop.rb +429 -0
  538. data/lib/image_paradise/gm_support.rb +34 -0
  539. data/lib/image_paradise/graphs/accumulator_bar.rb +29 -0
  540. data/lib/image_paradise/graphs/area.rb +64 -0
  541. data/lib/image_paradise/graphs/bar.rb +117 -0
  542. data/lib/image_paradise/graphs/bar_conversion.rb +53 -0
  543. data/lib/image_paradise/graphs/base.rb +1392 -0
  544. data/lib/image_paradise/graphs/bezier.rb +45 -0
  545. data/lib/image_paradise/graphs/bullet.rb +115 -0
  546. data/lib/image_paradise/graphs/deprecated.rb +42 -0
  547. data/lib/image_paradise/graphs/dot.rb +129 -0
  548. data/lib/image_paradise/graphs/line.rb +328 -0
  549. data/lib/image_paradise/graphs/mini/bar.rb +42 -0
  550. data/lib/image_paradise/graphs/mini/legend.rb +109 -0
  551. data/lib/image_paradise/graphs/mini/pie.rb +42 -0
  552. data/lib/image_paradise/graphs/mini/side_bar.rb +41 -0
  553. data/lib/image_paradise/graphs/net.rb +133 -0
  554. data/lib/image_paradise/graphs/photo_bar.rb +106 -0
  555. data/lib/image_paradise/graphs/pie.rb +139 -0
  556. data/lib/image_paradise/graphs/scatter.rb +264 -0
  557. data/lib/image_paradise/graphs/scene.rb +216 -0
  558. data/lib/image_paradise/graphs/side_bar.rb +144 -0
  559. data/lib/image_paradise/graphs/side_stacked_bar.rb +116 -0
  560. data/lib/image_paradise/graphs/spider.rb +163 -0
  561. data/lib/image_paradise/graphs/stacked_area.rb +73 -0
  562. data/lib/image_paradise/graphs/stacked_bar.rb +68 -0
  563. data/lib/image_paradise/graphs/stacked_mixin.rb +30 -0
  564. data/lib/image_paradise/graphs/themes.rb +117 -0
  565. data/lib/image_paradise/graphs.rb +36 -0
  566. data/lib/image_paradise/graphviz/README.md +2 -0
  567. data/lib/image_paradise/graphviz/generate_graphviz_image.rb +276 -0
  568. data/lib/image_paradise/gui/gtk3/cfdg_widget/cfdg_widget.rb +1452 -0
  569. data/lib/image_paradise/gui/gtk3/cfdg_widget/connect_skeleton.rb +46 -0
  570. data/lib/image_paradise/gui/gtk3/image_editor/connect_skeleton.rb +126 -0
  571. data/lib/image_paradise/gui/gtk3/image_editor/image_editor.rb +2003 -0
  572. data/lib/image_paradise/identify.rb +184 -0
  573. data/lib/image_paradise/image_paradise.rb +153 -0
  574. data/lib/image_paradise/image_to_ascii/image_to_ascii.rb +187 -0
  575. data/lib/image_paradise/image_to_pdf/image_to_pdf.rb +99 -0
  576. data/lib/image_paradise/label/README.md +2 -0
  577. data/lib/image_paradise/label/simple_label.rb +206 -0
  578. data/lib/image_paradise/logo/IMGUR_LOGO.png +0 -0
  579. data/lib/image_paradise/project/project.rb +30 -0
  580. data/lib/image_paradise/requires/common_base_requires.rb +17 -0
  581. data/lib/image_paradise/requires/require_colours.rb +9 -0
  582. data/lib/image_paradise/requires/require_gtk_components.rb +8 -0
  583. data/lib/image_paradise/requires/require_image_to_ascii.rb +7 -0
  584. data/lib/image_paradise/requires/require_the_image_paradise_project.rb +42 -0
  585. data/lib/image_paradise/requires/require_toplevel_methods.rb +21 -0
  586. data/lib/image_paradise/rotate/README.md +2 -0
  587. data/lib/image_paradise/rotate/rotate.rb +124 -0
  588. data/lib/image_paradise/shell/interactive.rb +156 -0
  589. data/lib/image_paradise/svg/README.md +5 -0
  590. data/lib/image_paradise/svg/circle.rb +106 -0
  591. data/lib/image_paradise/svg/feature.rb +48 -0
  592. data/lib/image_paradise/svg/rectangle.rb +154 -0
  593. data/lib/image_paradise/svg/svg.rb +102 -0
  594. data/lib/image_paradise/toplevel_methods/add_black_border_to_this_image.rb +94 -0
  595. data/lib/image_paradise/toplevel_methods/create_animated_gif.rb +49 -0
  596. data/lib/image_paradise/toplevel_methods/crop.rb +29 -0
  597. data/lib/image_paradise/toplevel_methods/e.rb +16 -0
  598. data/lib/image_paradise/toplevel_methods/esystem.rb +19 -0
  599. data/lib/image_paradise/toplevel_methods/extract_text_from_this_image.rb +56 -0
  600. data/lib/image_paradise/toplevel_methods/file_related_code.rb +110 -0
  601. data/lib/image_paradise/toplevel_methods/flip_image_left_right.rb +59 -0
  602. data/lib/image_paradise/toplevel_methods/font_related_methods.rb +62 -0
  603. data/lib/image_paradise/toplevel_methods/greyscale_this_image.rb +76 -0
  604. data/lib/image_paradise/toplevel_methods/gui.rb +19 -0
  605. data/lib/image_paradise/toplevel_methods/help.rb +30 -0
  606. data/lib/image_paradise/toplevel_methods/interlace.rb +33 -0
  607. data/lib/image_paradise/toplevel_methods/is_an_image_file.rb +18 -0
  608. data/lib/image_paradise/toplevel_methods/make_this_image_transparent.rb +40 -0
  609. data/lib/image_paradise/toplevel_methods/menu.rb +110 -0
  610. data/lib/image_paradise/toplevel_methods/merge_these_images.rb +49 -0
  611. data/lib/image_paradise/toplevel_methods/mirror_image.rb +28 -0
  612. data/lib/image_paradise/toplevel_methods/misc.rb +1603 -0
  613. data/lib/image_paradise/toplevel_methods/negate.rb +36 -0
  614. data/lib/image_paradise/toplevel_methods/png_to_svg.rb +38 -0
  615. data/lib/image_paradise/toplevel_methods/quality.rb +34 -0
  616. data/lib/image_paradise/toplevel_methods/resized.rb +43 -0
  617. data/lib/image_paradise/toplevel_methods/roebe.rb +440 -0
  618. data/lib/image_paradise/toplevel_methods/thumbnail.rb +54 -0
  619. data/lib/image_paradise/toplevel_methods/to_png.rb +106 -0
  620. data/lib/image_paradise/toplevel_methods/wallpaper.rb +51 -0
  621. data/lib/image_paradise/toplevel_methods/write_this_text.rb +89 -0
  622. data/lib/image_paradise/utility_scripts/black_white.rb +92 -0
  623. data/lib/image_paradise/utility_scripts/create_new_image.rb +110 -0
  624. data/lib/image_paradise/utility_scripts/image_border.rb +226 -0
  625. data/lib/image_paradise/utility_scripts/image_gallery/image_gallery.rb +305 -0
  626. data/lib/image_paradise/utility_scripts/image_manipulations.rb +316 -0
  627. data/lib/image_paradise/utility_scripts/magic_card_border.rb +215 -0
  628. data/lib/image_paradise/utility_scripts/optimizer.rb +444 -0
  629. data/lib/image_paradise/utility_scripts/random_text_to_image.rb +364 -0
  630. data/lib/image_paradise/utility_scripts/text_on_image.rb +311 -0
  631. data/lib/image_paradise/utility_scripts/to_gif.rb +93 -0
  632. data/lib/image_paradise/utility_scripts/to_jpg.rb +82 -0
  633. data/lib/image_paradise/version/version.rb +19 -0
  634. data/lib/image_paradise/www/cfdg.cgi +25 -0
  635. data/lib/image_paradise/www/imagemagick/imagemagick.cgi +266 -0
  636. data/lib/image_paradise/yaml/README.md +2 -0
  637. data/lib/image_paradise/yaml/arc.yml +0 -0
  638. data/lib/image_paradise/yaml/circle.yml +6 -0
  639. data/lib/image_paradise/yaml/rectangle.yml +6 -0
  640. data/lib/image_paradise.rb +5 -0
  641. data/test/16x16_red_square_image_for_testing.png +0 -0
  642. data/test/misc/README.md +3 -0
  643. data/test/misc/testing_filling_up_with_circles.rb +65 -0
  644. data/test/testing_confree_generator.rb +8 -0
  645. data/test/testing_crop.rb +19 -0
  646. data/test/testing_image_magick_commands.rb +39 -0
  647. data/test/testing_image_paradise.rb +49 -0
  648. data/test/testing_the_svg_component.html +261 -0
  649. data/test/testing_the_svg_component.rb +106 -0
  650. metadata +762 -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