├── .editorconfig ├── .github ├── FUNDING.yml ├── dependabot.yml ├── renovate.json └── workflows │ └── ruby.yml ├── .gitignore ├── .rubocop.yml ├── .tool-versions ├── .yardopts ├── .yardopts-dev ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── README.md ├── bin └── pixelchart ├── docs ├── images │ ├── default.png │ ├── logo.png │ ├── primes.png │ ├── random.png │ └── virus.png ├── index.html └── yard │ ├── PixelChart.html │ ├── Version.html │ ├── _index.html │ ├── class_list.html │ ├── css │ ├── common.css │ ├── full_list.css │ └── style.css │ ├── file.CHANGELOG.html │ ├── file.CLI.html │ ├── file.Install.html │ ├── file.LICENSE.html │ ├── file.Landing.html │ ├── file.Publishing.html │ ├── file.README.html │ ├── file.Scenarios.html │ ├── file_list.html │ ├── frames.html │ ├── index.html │ ├── js │ ├── app.js │ ├── full_list.js │ └── jquery.js │ ├── method_list.html │ └── top-level-namespace.html ├── lib ├── pixelchart.rb └── pixelchart │ └── version.rb ├── pages ├── CHANGELOG.md ├── CLI.md ├── Install.md ├── Landing.md ├── Publishing.md └── Scenarios.md └── pixelchart.gemspec /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # ruby 12 | [*.rb] 13 | charset = utf-8 14 | indent_style = space 15 | indent_size = 2 16 | trim_trailing_whitespace = true 17 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: noraj 2 | issuehunt: noraj 3 | ko_fi: noraj 4 | liberapay: noraj 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "bundler" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | labels: 13 | - "dependency::update" 14 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.github/workflows/ruby.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake 6 | # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby 7 | 8 | name: Ruby 9 | 10 | on: 11 | push: 12 | branches: [ master ] 13 | pull_request: 14 | branches: [ master ] 15 | 16 | jobs: 17 | test: 18 | 19 | runs-on: ubuntu-latest 20 | strategy: 21 | matrix: 22 | ruby-version: ['3.4', '3.3', '3.2', '3.1'] 23 | env: 24 | BUNDLE_WITHOUT: docs development # https://bundler.io/v1.5/groups.html 25 | steps: 26 | - uses: actions/checkout@v4 # https://github.com/actions/checkout 27 | - name: Install system dependencies 28 | run: | 29 | sudo apt-get update 30 | sudo apt-get install -y libvips-dev imagemagick 31 | - name: Set up Ruby 32 | # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, 33 | # change this to (see https://github.com/ruby/setup-ruby#versioning): 34 | uses: ruby/setup-ruby@v1 35 | with: 36 | ruby-version: ${{ matrix.ruby-version }} 37 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 38 | - name: Run lint 39 | run: bundle exec rubocop 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .yardoc 2 | *.gem 3 | /pkg 4 | /vendor 5 | .bundle/ 6 | /node_modules 7 | /*.png 8 | /*.csv 9 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | TargetRubyVersion: 3.1 3 | NewCops: enable 4 | SuggestExtensions: false 5 | # ~~~ Layout ~~~ 6 | Layout/EmptyLinesAroundAttributeAccessor: 7 | Enabled: true 8 | Layout/HashAlignment: 9 | Include: 10 | - 'lib/**/*.rb' 11 | Layout/LineLength: 12 | Include: 13 | - 'lib/**/*.rb' 14 | Layout/SpaceAroundMethodCallOperator: 15 | Enabled: true 16 | # ~~~ Lint ~~~ 17 | Lint/DeprecatedOpenSSLConstant: 18 | Enabled: true 19 | Lint/DuplicateElsifCondition: 20 | Enabled: true 21 | Lint/MixedRegexpCaptureTypes: 22 | Enabled: true 23 | Lint/RaiseException: 24 | Enabled: true 25 | Lint/StructNewOverride : 26 | Enabled: true 27 | # ~~~ Metrics ~~~ 28 | Metrics/AbcSize: 29 | Enabled: false 30 | Metrics/ClassLength: 31 | Max: 200 32 | Metrics/CyclomaticComplexity: 33 | Enabled: false 34 | Metrics/MethodLength: 35 | Max: 30 36 | Metrics/PerceivedComplexity: 37 | Max: 10 38 | # ~~~ Style ~~~ 39 | Style/AccessorGrouping: 40 | Enabled: false # for yard 41 | Style/ArrayCoercion: 42 | Enabled: true 43 | Style/BisectedAttrAccessor: 44 | Enabled: false # for yard 45 | Style/CaseLikeIf: 46 | Enabled: true 47 | Style/ExponentialNotation: 48 | Enabled: true 49 | Style/FormatStringToken: 50 | Enabled: false # https://github.com/rubocop-hq/rubocop/issues/7944 51 | Style/HashAsLastArrayItem: 52 | Enabled: true 53 | Style/HashEachMethods: 54 | Enabled: true 55 | Style/HashLikeCase: 56 | Enabled: true 57 | Style/HashTransformKeys: 58 | Enabled: true 59 | Style/HashTransformValues: 60 | Enabled: true 61 | Style/RedundantAssignment: 62 | Enabled: true 63 | Style/RedundantFetchBlock: 64 | Enabled: true 65 | Style/RedundantFileExtensionInRequire: 66 | Enabled: true 67 | Style/RedundantRegexpCharacterClass: 68 | Enabled: true 69 | Style/RedundantRegexpEscape: 70 | Enabled: true 71 | Style/RedundantReturn: 72 | Enabled: false 73 | Style/SlicingWithRange: 74 | Enabled: true 75 | # it's style! 76 | Gemspec/AddRuntimeDependency: 77 | Enabled: false # https://github.com/rubocop/rubocop/pull/13030#discussion_r1674791776 78 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | ruby 3.4.1 2 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --output-dir docs/yard 2 | --markup markdown 3 | --markup-provider commonmarker 4 | - 5 | --main pages/Landing.md 6 | pages/CHANGELOG.md 7 | pages/CLI.md 8 | pages/Install.md 9 | pages/Publishing.md 10 | pages/Scenarios.md 11 | LICENSE.txt 12 | -------------------------------------------------------------------------------- /.yardopts-dev: -------------------------------------------------------------------------------- 1 | --output-dir docs/yard 2 | --protected 3 | --private 4 | --markup markdown 5 | --markup-provider commonmarker 6 | - 7 | --main pages/Landing.md 8 | pages/CHANGELOG.md 9 | pages/CLI.md 10 | pages/Install.md 11 | pages/Publishing.md 12 | pages/Scenarios.md 13 | LICENSE.txt 14 | 15 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gemspec 6 | 7 | group :runtime, :cli do 8 | gem 'docopt', '~> 0.6' # for argument parsing 9 | gem 'paint', '~> 2.3' # for colorized ouput 10 | gem 'rmagick', '~> 6.0' # image processing (backend 1) 11 | gem 'ruby-vips', '~> 2.2' # image processing (backend 2) 12 | end 13 | 14 | group :development, :install do 15 | gem 'bundler', '~> 2.6' 16 | end 17 | 18 | group :development, :test do 19 | gem 'irb' 20 | gem 'minitest', '~> 5.25' 21 | gem 'rake', '~> 13.2' 22 | end 23 | 24 | group :development, :lint do 25 | gem 'rubocop', '~> 1.75' 26 | end 27 | 28 | group :development, :docs do 29 | gem 'commonmarker', '~> 0.23' # for markdown support in YARD 30 | gem 'yard', ['>= 0.9.27', '< 0.10'] 31 | end 32 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | pixelchart (1.3.0) 5 | docopt (~> 0.6) 6 | paint (~> 2.3) 7 | rmagick (~> 6.0) 8 | ruby-vips (~> 2.2) 9 | 10 | GEM 11 | remote: https://rubygems.org/ 12 | specs: 13 | ast (2.4.3) 14 | commonmarker (0.23.11) 15 | date (3.4.1) 16 | docopt (0.6.1) 17 | ffi (1.17.1) 18 | ffi (1.17.1-aarch64-linux-gnu) 19 | ffi (1.17.1-aarch64-linux-musl) 20 | ffi (1.17.1-arm-linux-gnu) 21 | ffi (1.17.1-arm-linux-musl) 22 | ffi (1.17.1-arm64-darwin) 23 | ffi (1.17.1-x86-linux-gnu) 24 | ffi (1.17.1-x86-linux-musl) 25 | ffi (1.17.1-x86_64-darwin) 26 | ffi (1.17.1-x86_64-linux-gnu) 27 | ffi (1.17.1-x86_64-linux-musl) 28 | io-console (0.8.0) 29 | irb (1.15.1) 30 | pp (>= 0.6.0) 31 | rdoc (>= 4.0.0) 32 | reline (>= 0.4.2) 33 | json (2.10.2) 34 | language_server-protocol (3.17.0.4) 35 | lint_roller (1.1.0) 36 | logger (1.7.0) 37 | minitest (5.25.5) 38 | observer (0.1.2) 39 | paint (2.3.0) 40 | parallel (1.26.3) 41 | parser (3.3.7.3) 42 | ast (~> 2.4.1) 43 | racc 44 | pkg-config (1.6.0) 45 | pp (0.6.2) 46 | prettyprint 47 | prettyprint (0.2.0) 48 | prism (1.4.0) 49 | psych (5.2.3) 50 | date 51 | stringio 52 | racc (1.8.1) 53 | rainbow (3.1.1) 54 | rake (13.2.1) 55 | rdoc (6.13.1) 56 | psych (>= 4.0.0) 57 | regexp_parser (2.10.0) 58 | reline (0.6.0) 59 | io-console (~> 0.5) 60 | rmagick (6.1.1) 61 | observer (~> 0.1) 62 | pkg-config (~> 1.4) 63 | rubocop (1.75.1) 64 | json (~> 2.3) 65 | language_server-protocol (~> 3.17.0.2) 66 | lint_roller (~> 1.1.0) 67 | parallel (~> 1.10) 68 | parser (>= 3.3.0.2) 69 | rainbow (>= 2.2.2, < 4.0) 70 | regexp_parser (>= 2.9.3, < 3.0) 71 | rubocop-ast (>= 1.43.0, < 2.0) 72 | ruby-progressbar (~> 1.7) 73 | unicode-display_width (>= 2.4.0, < 4.0) 74 | rubocop-ast (1.43.0) 75 | parser (>= 3.3.7.2) 76 | prism (~> 1.4) 77 | ruby-progressbar (1.13.0) 78 | ruby-vips (2.2.3) 79 | ffi (~> 1.12) 80 | logger 81 | stringio (3.1.6) 82 | unicode-display_width (3.1.4) 83 | unicode-emoji (~> 4.0, >= 4.0.4) 84 | unicode-emoji (4.0.4) 85 | yard (0.9.37) 86 | 87 | PLATFORMS 88 | aarch64-linux-gnu 89 | aarch64-linux-musl 90 | arm-linux-gnu 91 | arm-linux-musl 92 | arm64-darwin 93 | ruby 94 | x86-linux-gnu 95 | x86-linux-musl 96 | x86_64-darwin 97 | x86_64-linux-gnu 98 | x86_64-linux-musl 99 | 100 | DEPENDENCIES 101 | bundler (~> 2.6) 102 | commonmarker (~> 0.23) 103 | docopt (~> 0.6) 104 | irb 105 | minitest (~> 5.25) 106 | paint (~> 2.3) 107 | pixelchart! 108 | rake (~> 13.2) 109 | rmagick (~> 6.0) 110 | rubocop (~> 1.75) 111 | ruby-vips (~> 2.2) 112 | yard (>= 0.9.27, < 0.10) 113 | 114 | BUNDLED WITH 115 | 2.6.3 116 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-2025 Alexandre ZANNI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](docs/images/logo.png) 2 | 3 | [![Gem Version](https://badge.fury.io/rb/pixelchart.svg)](https://badge.fury.io/rb/pixelchart) 4 | ![AUR version](https://img.shields.io/aur/version/pixelchart) 5 | ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/noraj/PixelChart) 6 | ![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/noraj/PixelChart) 7 | [![GitHub forks](https://img.shields.io/github/forks/noraj/PixelChart)](https://github.com/noraj/PixelChart/network) 8 | [![GitHub stars](https://img.shields.io/github/stars/noraj/PixelChart)](https://github.com/noraj/PixelChart/stargazers) 9 | [![GitHub license](https://img.shields.io/github/license/noraj/PixelChart)](https://github.com/noraj/PixelChart/blob/master/LICENSE.txt) 10 | 11 | # PixelChart 12 | 13 | > Map binary data into a beautiful chart 14 | 15 | PixelChart let's you create an image, a pixel chart / plot, based on binary data. 16 | The idea is that truthy and falsy values will be represented by a different color 17 | to be able to quickly visualize boolean values. 18 | 19 | For example: 20 | 21 | ![](docs/images/default.png) 22 | 23 | ## Requirements 24 | 25 | You have to install the _system_ requirements for **both** backends. 26 | 27 | - [imagemagick](https://imagemagick.org/) 28 | - [libvips](https://libvips.github.io/libvips/) 29 | 30 | Example for Linux distros: 31 | 32 | - ArchLinux: `pacman -S libvips imagemagick` 33 | - openSUSE: `zypper in libvips42 ImageMagick` 34 | - Ubuntu: `apt install libvips42 imagemagick` 35 | 36 | ## Installation 37 | 38 | ``` 39 | $ gem install pixelchart 40 | ``` 41 | 42 | See [the documentation](https://noraj.github.io/PixelChart/yard/file.Install.html) for more more advanced options. 43 | 44 | ## Usage 45 | 46 | **CLI** 47 | 48 | ``` 49 | $ pixelchart draw test.csv test.png -w 100 -h 100 -s 3 50 | [+] Image saved 51 | ``` 52 | 53 | See the [CLI documentation](https://noraj.github.io/PixelChart/yard/file.CLI.html). 54 | 55 | **library** 56 | 57 | See the [library documentation](https://noraj.github.io/PixelChart/yard/PixelChart.html). 58 | 59 | **scenarios** 60 | 61 | See some [scenarios](https://noraj.github.io/PixelChart/yard/file.Scenarios.html) with examples. 62 | 63 | ## Documentation 64 | 65 | - [Custom domain](https://noraj.github.io/PixelChart/yard/PixelChart.html) 66 | - [Backup GitHub domain](https://noraj.github.io/PixelChart/yard/PixelChart.html) 67 | - [RubyDoc hosted](https://www.rubydoc.info/gems/pixelchart/PixelChart) 68 | -------------------------------------------------------------------------------- /bin/pixelchart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # Ruby internal 5 | # Project internal 6 | require 'pixelchart' 7 | # External 8 | require 'docopt' 9 | require 'paint' 10 | 11 | doc = <<~DOCOPT 12 | PixelChart - Map binary data into a beautiful chart 13 | 14 | Usage: 15 | pixelchart draw (--width --height ) [--colors ] [--backend ] [--scale ] [--no-color] [--debug] 16 | pixelchart calc (--area |) [--no-color] [--debug] 17 | pixelchart -H | --help 18 | pixelchart -V | --version 19 | 20 | Options: 21 | Input file containing values 22 | Output image (filename) 23 | -w , --width Width of the output image (in number pixel) 24 | -h , --height Height of the output image (in number pixel) 25 | -c , --colors Colors of the image (in RGB or random) 26 | -b , --backend Image processing backend (rmagick or rubyvips) 27 | -s , --scale Scale ratio or dimensions 28 | --area Area, number of values, total number of pixel 29 | --no-color Disable colorized output 30 | --debug Display arguments 31 | -H, --help Show this screen 32 | -V, --version Show version 33 | 34 | Examples: 35 | pixelchart draw test.csv test.png -w 100 -h 100 36 | pixelchart draw test.csv test.png -w 100 -h 100 -c 'random|125,125,125' -b rubyvips 37 | pixelchart calc test.csv 38 | pixelchart calc --area 10000 --no-color 39 | DOCOPT 40 | 41 | begin 42 | args = Docopt.docopt(doc, version: PixelChart::VERSION) 43 | puts args if args['--debug'] 44 | Paint.mode = 0 if args['--no-color'] 45 | if args['draw'] 46 | data = PixelChart.load_file(args['']) 47 | width = args['--width'].to_i 48 | height = args['--height'].to_i 49 | filename = args[''] 50 | opts = {} 51 | if args['--colors'] 52 | colors = args['--colors'].split('|') 53 | colors.each_with_index do |col, i| 54 | colors[i] = if col == 'random' 55 | col.to_sym 56 | else 57 | colors[i] = col.split(',').map(&:to_i) 58 | end 59 | end 60 | opts[:colors] = colors 61 | end 62 | opts[:backend] = args['--backend'].to_sym if args['--backend'] 63 | if args['--scale'] 64 | opts[:scale] = if /,/.match?(args['--scale']) # dimensions 65 | args['--scale'].split(',').map(&:to_i) 66 | else # ratio 67 | args['--scale'].to_f 68 | end 69 | end 70 | pc = PixelChart.new(data, width, height, opts) 71 | pc.draw(filename, opts) 72 | puts "#{Paint['[+]', :green]} Image saved" 73 | elsif args['calc'] 74 | dimensions = nil 75 | if args['--area'] 76 | dimensions = PixelChart.dimensions(args['--area'].to_i) 77 | elsif args[''] 78 | data = PixelChart.load_file(args['']) 79 | dimensions = PixelChart.dimensions(data.size) 80 | end 81 | puts 'Possible dimensions: width x height or height x width' 82 | dimensions.each do |xy| 83 | puts "#{Paint[xy[0], :magenta]} x #{Paint[xy[1], :magenta]}" 84 | end 85 | end 86 | rescue Docopt::Exit => e 87 | puts e.message 88 | end 89 | -------------------------------------------------------------------------------- /docs/images/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noraj/PixelChart/09e028fe6cf5bcd8ab8b8217a875d7ce3293be40/docs/images/default.png -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noraj/PixelChart/09e028fe6cf5bcd8ab8b8217a875d7ce3293be40/docs/images/logo.png -------------------------------------------------------------------------------- /docs/images/primes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noraj/PixelChart/09e028fe6cf5bcd8ab8b8217a875d7ce3293be40/docs/images/primes.png -------------------------------------------------------------------------------- /docs/images/random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noraj/PixelChart/09e028fe6cf5bcd8ab8b8217a875d7ce3293be40/docs/images/random.png -------------------------------------------------------------------------------- /docs/images/virus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noraj/PixelChart/09e028fe6cf5bcd8ab8b8217a875d7ce3293be40/docs/images/virus.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PixelChart 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 49 |
50 | 51 | 52 |
53 |
54 |
55 |
56 |
57 | 58 |
59 |
60 |
61 |

62 | PixelChart 63 |

64 |

65 | Map binary data into a beautiful chart 66 |

67 |
68 |
69 | 70 | 71 |
72 | 85 |
86 |
87 | 88 | 89 | -------------------------------------------------------------------------------- /docs/yard/PixelChart.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: PixelChart 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: PixelChart 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Object 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 |
80 | show all 81 | 82 |
83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 |
91 |
Includes:
92 |
Version
93 |
94 | 95 | 96 | 97 | 98 | 99 | 100 |
101 |
Defined in:
102 |
lib/pixelchart.rb
103 |
104 | 105 |
106 | 107 |

Overview

108 |
109 |

PixelChart class

110 | 111 | 112 |
113 |
114 |
115 | 116 | 117 |
118 | 119 | 120 |

Constant Summary

121 | 122 |

Constants included 123 | from Version

124 |

Version::VERSION

125 | 126 | 127 | 128 | 129 | 130 | 131 |

132 | Class Method Summary 133 | collapse 134 |

135 | 136 |
    137 | 138 |
  • 139 | 140 | 141 | .dimensions(area) ⇒ Array<Array<Integer>> 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 |

    Calculate the possible dimensions (width, height) for a given area.

    156 |
    157 | 158 |
  • 159 | 160 | 161 |
  • 162 | 163 | 164 | .load_file(filename) ⇒ Array<Integer> 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 |

    Read the input file to extract the values.

    179 |
    180 | 181 |
  • 182 | 183 | 184 |
185 | 186 |

187 | Instance Method Summary 188 | collapse 189 |

190 | 191 |
    192 | 193 |
  • 194 | 195 | 196 | #dimensions ⇒ Array<Array<Integer>> 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 |

    Calculate the possible dimensions (width, height) for the data of the object.

    211 |
    212 | 213 |
  • 214 | 215 | 216 |
  • 217 | 218 | 219 | #draw(filename, opts = {}) ⇒ Object 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 |

    Generate and save the image.

    234 |
    235 | 236 |
  • 237 | 238 | 239 |
  • 240 | 241 | 242 | #initialize(data, width, height, opts = {}) ⇒ PixelChart 243 | 244 | 245 | 246 | 247 | 248 | 249 | constructor 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 |

    A new instance of PixelChart.

    259 |
    260 | 261 |
  • 262 | 263 | 264 |
265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 |
274 |

Constructor Details

275 | 276 |
277 |

278 | 279 | #initialize(data, width, height, opts = {}) ⇒ PixelChart 280 | 281 | 282 | 283 | 284 | 285 |

286 |
287 |

A new instance of PixelChart

288 | 289 | 290 |
291 |
292 |
293 |

Parameters:

294 |
    295 | 296 |
  • 297 | 298 | data 299 | 300 | 301 | (Array<Boolean>) 302 | 303 | 304 | 305 | — 306 |

    An array containing values 307 | (0, 1) used to generate the image.

    308 |
    309 | 310 |
  • 311 | 312 |
  • 313 | 314 | width 315 | 316 | 317 | (Integer) 318 | 319 | 320 | 321 | — 322 |

    Desired width of the image.

    323 |
    324 | 325 |
  • 326 | 327 |
  • 328 | 329 | height 330 | 331 | 332 | (Integer) 333 | 334 | 335 | 336 | — 337 |

    Desired height of the image.

    338 |
    339 | 340 |
  • 341 | 342 |
  • 343 | 344 | opts 345 | 346 | 347 | (Hash) 348 | 349 | 350 | (defaults to: {}) 351 | 352 | 353 | — 354 |

    a customizable set of options

    355 |
    356 | 357 |
  • 358 | 359 |
360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 |

Options Hash (opts):

371 |
    372 | 373 |
  • 374 | :colors 375 | (Array<Color>) 376 | 377 | 378 | 379 | 380 | —

    Must be an array containing 2 values. 381 | Each value is either the :random symbol to get a random color or a 382 | color given as RGB, so 3 integers in an array.

    383 |
    384 | 385 |
  • 386 | 387 |
  • 388 | :scale 389 | (Scale) 390 | 391 | 392 | 393 | 394 | —

    Scale the image to dimensions or with a ratio. 395 | Ratio must be a positive (non-nul) float or integer, and dimensions must 396 | be a set of width and height separated by a comma.

    397 |
    398 | 399 |
  • 400 | 401 |
402 | 403 | 404 | 405 |
406 | 407 | 425 | 442 | 443 |
408 |
409 | 
410 | 
411 | 27
412 | 28
413 | 29
414 | 30
415 | 31
416 | 32
417 | 33
418 | 34
419 | 35
420 | 36
421 | 37
422 | 38
423 | 39
424 |
426 |
# File 'lib/pixelchart.rb', line 27
427 | 
428 | def initialize(data, width, height, opts = {})
429 |   @width = check_int(width)
430 |   @height = check_int(height)
431 |   @data = check_data(data)
432 |   opts[:colors] ||= [[255, 255, 255], [0, 0, 0]] # white, black
433 |   check_colors(opts[:colors])
434 |   opts[:colors].each_with_index do |color, i|
435 |     opts[:colors][i] = (0..2).map { |_x| rand(256) } if color == :random
436 |   end
437 |   @colors = opts[:colors]
438 |   opts[:scale] ||= nil
439 |   @scale = opts[:scale]
440 | end
441 |
444 |
445 | 446 |
447 | 448 | 449 |
450 |

Class Method Details

451 | 452 | 453 |
454 |

455 | 456 | .dimensions(area) ⇒ Array<Array<Integer>> 457 | 458 | 459 | 460 | 461 | 462 |

463 |
464 |

Calculate the possible dimensions (width, height) for a given area

465 | 466 | 467 |
468 |
469 |
470 |

Parameters:

471 |
    472 | 473 |
  • 474 | 475 | area 476 | 477 | 478 | (Integer) 479 | 480 | 481 | 482 | — 483 |

    number of values, total of pixels

    484 |
    485 | 486 |
  • 487 | 488 |
489 | 490 |

Returns:

491 |
    492 | 493 |
  • 494 | 495 | 496 | (Array<Array<Integer>>) 497 | 498 | 499 | 500 | — 501 |

    Array of possible dimensions

    502 |
    503 | 504 |
  • 505 | 506 |
507 | 508 |
509 | 510 | 523 | 535 | 536 |
511 |
512 | 
513 | 
514 | 60
515 | 61
516 | 62
517 | 63
518 | 64
519 | 65
520 | 66
521 | 67
522 |
524 |
# File 'lib/pixelchart.rb', line 60
525 | 
526 | def self.dimensions(area)
527 |   dim = []
528 |   (1..Math.sqrt(area).to_i).each do |x|
529 |     y, rem = area.divmod(x)
530 |     dim.push([x, y]) if rem.zero?
531 |   end
532 |   dim
533 | end
534 |
537 |
538 | 539 |
540 |

541 | 542 | .load_file(filename) ⇒ Array<Integer> 543 | 544 | 545 | 546 | 547 | 548 |

549 |
550 |

Read the input file to extract the values

551 | 552 | 553 |
554 |
555 |
556 |

Parameters:

557 |
    558 | 559 |
  • 560 | 561 | filename 562 | 563 | 564 | (String) 565 | 566 | 567 | 568 | — 569 |

    Name of the input file containing data. Values must 570 | be 0, 1, true, false and separated by commas.

    571 |
    572 | 573 |
  • 574 | 575 |
576 | 577 |

Returns:

578 |
    579 | 580 |
  • 581 | 582 | 583 | (Array<Integer>) 584 | 585 | 586 | 587 | — 588 |

    Array of 0, 1. Can be directly passed to initialize

    589 |
    590 | 591 |
  • 592 | 593 |
594 | 595 |
596 | 597 | 611 | 624 | 625 |
598 |
599 | 
600 | 
601 | 79
602 | 80
603 | 81
604 | 82
605 | 83
606 | 84
607 | 85
608 | 86
609 | 87
610 |
612 |
# File 'lib/pixelchart.rb', line 79
613 | 
614 | def self.load_file(filename)
615 |   content = File.read(filename).gsub(/\s+/, '')
616 |   data = content.split(',')
617 |   data.each_with_index do |x, i|
618 |     data[i] = 0 if x == '0' || x.downcase == 'false'
619 |     data[i] = 1 if x == '1' || x.downcase == 'true'
620 |   end
621 |   data
622 | end
623 |
626 |
627 | 628 |
629 | 630 |
631 |

Instance Method Details

632 | 633 | 634 |
635 |

636 | 637 | #dimensionsArray<Array<Integer>> 638 | 639 | 640 | 641 | 642 | 643 |

644 |
645 |

Calculate the possible dimensions (width, height) for the data of the object

646 | 647 | 648 |
649 |
650 |
651 | 652 |

Returns:

653 |
    654 | 655 |
  • 656 | 657 | 658 | (Array<Array<Integer>>) 659 | 660 | 661 | 662 | — 663 |

    Array of possible dimensions

    664 |
    665 | 666 |
  • 667 | 668 |
669 | 670 |
671 | 672 | 680 | 687 | 688 |
673 |
674 | 
675 | 
676 | 71
677 | 72
678 | 73
679 |
681 |
# File 'lib/pixelchart.rb', line 71
682 | 
683 | def dimensions
684 |   dimensions(@data.size)
685 | end
686 |
689 |
690 | 691 |
692 |

693 | 694 | #draw(filename, opts = {}) ⇒ Object 695 | 696 | 697 | 698 | 699 | 700 |

701 |
702 |

Generate and save the image

703 | 704 | 705 |
706 |
707 |
708 |

Parameters:

709 |
    710 | 711 |
  • 712 | 713 | filename 714 | 715 | 716 | (String) 717 | 718 | 719 | 720 | — 721 |

    Name of the output image.

    722 |
    723 | 724 |
  • 725 | 726 |
  • 727 | 728 | opts 729 | 730 | 731 | (Hash) 732 | 733 | 734 | (defaults to: {}) 735 | 736 | 737 | — 738 |

    options for image processing

    739 |
    740 | 741 |
  • 742 | 743 |
744 | 745 | 746 | 747 | 748 | 749 | 750 |

Options Hash (opts):

751 |
    752 | 753 |
  • 754 | :backend 755 | (Symbol) 756 | 757 | 758 | 759 | 760 | —

    Image processing backend, :rmagick for 761 | Rmagick/Imagemagick or :rubyvips for ruby-vips/libvips.

    762 |
    763 | 764 |
  • 765 | 766 |
767 | 768 | 769 | 770 |
771 | 772 | 787 | 801 | 802 |
773 |
774 | 
775 | 
776 | 46
777 | 47
778 | 48
779 | 49
780 | 50
781 | 51
782 | 52
783 | 53
784 | 54
785 | 55
786 |
788 |
# File 'lib/pixelchart.rb', line 46
789 | 
790 | def draw(filename, opts = {})
791 |   opts[:backend] ||= :rmagick
792 |   backend = check_backend(opts[:backend])
793 |   case backend
794 |   when :rmagick
795 |     draw_rmagick(filename)
796 |   when :rubyvips
797 |     draw_rubyvips(filename)
798 |   end
799 | end
800 |
803 |
804 | 805 |
806 | 807 |
808 | 809 | 814 | 815 |
816 | 817 | -------------------------------------------------------------------------------- /docs/yard/Version.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Module: Version 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Module: Version 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
78 |
Included in:
79 |
PixelChart
80 |
81 | 82 | 83 | 84 |
85 |
Defined in:
86 |
lib/pixelchart/version.rb
87 |
88 | 89 |
90 | 91 | 92 | 93 |

94 | Constant Summary 95 | collapse 96 |

97 | 98 |
99 | 100 |
VERSION = 101 | 102 |
103 |
'1.3.0'
104 | 105 |
106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 |
117 | 118 | 123 | 124 |
125 | 126 | -------------------------------------------------------------------------------- /docs/yard/_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Documentation by YARD 0.9.37 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 |
34 | 54 | 55 |

Documentation by YARD 0.9.37

56 |
57 |

Alphabetic Index

58 | 59 |

File Listing

60 | 85 | 86 |
87 |

Namespace Listing A-Z

88 | 89 | 90 | 91 | 92 | 93 | 94 | 123 | 124 |
95 | 96 | 97 |
    98 |
  • P
  • 99 |
      100 | 101 |
    • 102 | PixelChart 103 | 104 |
    • 105 | 106 |
    107 |
108 | 109 | 110 |
    111 |
  • V
  • 112 |
      113 | 114 |
    • 115 | Version 116 | 117 |
    • 118 | 119 |
    120 |
121 | 122 |
125 | 126 |
127 | 128 |
129 | 130 | 135 | 136 |
137 | 138 | -------------------------------------------------------------------------------- /docs/yard/class_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Class List 19 | 20 | 21 | 22 |
23 |
24 |

Class List

25 |
26 | 27 | 28 | Classes 29 | 30 | 31 | 32 | Methods 33 | 34 | 35 | 36 | Files 37 | 38 | 39 |
40 | 41 | 45 |
46 | 47 | 52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/yard/css/common.css: -------------------------------------------------------------------------------- 1 | /* Override this file with custom rules */ -------------------------------------------------------------------------------- /docs/yard/css/full_list.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; 4 | font-size: 13px; 5 | height: 101%; 6 | overflow-x: hidden; 7 | background: #fafafa; 8 | } 9 | 10 | h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; } 11 | .clear { clear: both; } 12 | .fixed_header { position: fixed; background: #fff; width: 100%; padding-bottom: 10px; margin-top: 0; top: 0; z-index: 9999; height: 70px; } 13 | #search { position: absolute; right: 5px; top: 9px; padding-left: 24px; } 14 | #content.insearch #search, #content.insearch #noresults { background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat center left; } 15 | #full_list { padding: 0; list-style: none; margin-left: 0; margin-top: 80px; font-size: 1.1em; } 16 | #full_list ul { padding: 0; } 17 | #full_list li { padding: 0; margin: 0; list-style: none; } 18 | #full_list li .item { padding: 5px 5px 5px 12px; } 19 | #noresults { padding: 7px 12px; background: #fff; } 20 | #content.insearch #noresults { margin-left: 7px; } 21 | li.collapsed ul { display: none; } 22 | li a.toggle { cursor: default; position: relative; left: -5px; top: 4px; text-indent: -999px; width: 10px; height: 9px; margin-left: -10px; display: block; float: left; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; } 23 | li.collapsed a.toggle { cursor: default; background-position: top left; } 24 | li { color: #666; cursor: pointer; } 25 | li.deprecated { text-decoration: line-through; font-style: italic; } 26 | li.odd { background: #f0f0f0; } 27 | li.even { background: #fafafa; } 28 | .item:hover { background: #ddd; } 29 | li small:before { content: "("; } 30 | li small:after { content: ")"; } 31 | li small.search_info { display: none; } 32 | a, a:visited { text-decoration: none; color: #05a; } 33 | li.clicked > .item { background: #05a; color: #ccc; } 34 | li.clicked > .item a, li.clicked > .item a:visited { color: #eee; } 35 | li.clicked > .item a.toggle { opacity: 0.5; background-position: bottom right; } 36 | li.collapsed.clicked a.toggle { background-position: top right; } 37 | #search input { border: 1px solid #bbb; border-radius: 3px; } 38 | #full_list_nav { margin-left: 10px; font-size: 0.9em; display: block; color: #aaa; } 39 | #full_list_nav a, #nav a:visited { color: #358; } 40 | #full_list_nav a:hover { background: transparent; color: #5af; } 41 | #full_list_nav span:after { content: ' | '; } 42 | #full_list_nav span:last-child:after { content: ''; } 43 | 44 | #content h1 { margin-top: 0; } 45 | li { white-space: nowrap; cursor: normal; } 46 | li small { display: block; font-size: 0.8em; } 47 | li small:before { content: ""; } 48 | li small:after { content: ""; } 49 | li small.search_info { display: none; } 50 | #search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #666; padding-left: 0; padding-right: 24px; } 51 | #content.insearch #search { background-position: center right; } 52 | #search input { width: 110px; } 53 | 54 | #full_list.insearch ul { display: block; } 55 | #full_list.insearch .item { display: none; } 56 | #full_list.insearch .found { display: block; padding-left: 11px !important; } 57 | #full_list.insearch li a.toggle { display: none; } 58 | #full_list.insearch li small.search_info { display: block; } 59 | -------------------------------------------------------------------------------- /docs/yard/css/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; 7 | font-size: 13px; 8 | width: 100%; 9 | margin: 0; 10 | padding: 0; 11 | display: flex; 12 | display: -webkit-flex; 13 | display: -ms-flexbox; 14 | } 15 | 16 | #nav { 17 | position: relative; 18 | width: 100%; 19 | height: 100%; 20 | border: 0; 21 | border-right: 1px dotted #eee; 22 | overflow: auto; 23 | } 24 | .nav_wrap { 25 | margin: 0; 26 | padding: 0; 27 | width: 20%; 28 | height: 100%; 29 | position: relative; 30 | display: flex; 31 | display: -webkit-flex; 32 | display: -ms-flexbox; 33 | flex-shrink: 0; 34 | -webkit-flex-shrink: 0; 35 | -ms-flex: 1 0; 36 | } 37 | #resizer { 38 | position: absolute; 39 | right: -5px; 40 | top: 0; 41 | width: 10px; 42 | height: 100%; 43 | cursor: col-resize; 44 | z-index: 9999; 45 | } 46 | #main { 47 | flex: 5 1; 48 | -webkit-flex: 5 1; 49 | -ms-flex: 5 1; 50 | outline: none; 51 | position: relative; 52 | background: #fff; 53 | padding: 1.2em; 54 | padding-top: 0.2em; 55 | box-sizing: border-box; 56 | } 57 | 58 | @media (max-width: 920px) { 59 | .nav_wrap { width: 100%; top: 0; right: 0; overflow: visible; position: absolute; } 60 | #resizer { display: none; } 61 | #nav { 62 | z-index: 9999; 63 | background: #fff; 64 | display: none; 65 | position: absolute; 66 | top: 40px; 67 | right: 12px; 68 | width: 500px; 69 | max-width: 80%; 70 | height: 80%; 71 | overflow-y: scroll; 72 | border: 1px solid #999; 73 | border-collapse: collapse; 74 | box-shadow: -7px 5px 25px #aaa; 75 | border-radius: 2px; 76 | } 77 | } 78 | 79 | @media (min-width: 920px) { 80 | body { height: 100%; overflow: hidden; } 81 | #main { height: 100%; overflow: auto; } 82 | #search { display: none; } 83 | } 84 | 85 | @media (max-width: 320px) { 86 | body { height: 100%; overflow: hidden; overflow-wrap: break-word; } 87 | #main { height: 100%; overflow: auto; } 88 | } 89 | 90 | #main img { max-width: 100%; } 91 | h1 { font-size: 25px; margin: 1em 0 0.5em; padding-top: 4px; border-top: 1px dotted #d5d5d5; } 92 | h1.noborder { border-top: 0px; margin-top: 0; padding-top: 4px; } 93 | h1.title { margin-bottom: 10px; } 94 | h1.alphaindex { margin-top: 0; font-size: 22px; } 95 | h2 { 96 | padding: 0; 97 | padding-bottom: 3px; 98 | border-bottom: 1px #aaa solid; 99 | font-size: 1.4em; 100 | margin: 1.8em 0 0.5em; 101 | position: relative; 102 | } 103 | h2 small { font-weight: normal; font-size: 0.7em; display: inline; position: absolute; right: 0; } 104 | h2 small a { 105 | display: block; 106 | height: 20px; 107 | border: 1px solid #aaa; 108 | border-bottom: 0; 109 | border-top-left-radius: 5px; 110 | background: #f8f8f8; 111 | position: relative; 112 | padding: 2px 7px; 113 | } 114 | a { font-weight: 550; } 115 | .clear { clear: both; } 116 | .inline { display: inline; } 117 | .inline p:first-child { display: inline; } 118 | .docstring, .tags, #filecontents { font-size: 15px; line-height: 1.5145em; } 119 | .docstring p > code, .docstring p > tt, .tags p > code, .tags p > tt { 120 | color: #c7254e; background: #f9f2f4; padding: 2px 4px; font-size: 1em; 121 | border-radius: 4px; 122 | } 123 | .docstring h1, .docstring h2, .docstring h3, .docstring h4 { padding: 0; border: 0; border-bottom: 1px dotted #bbb; } 124 | .docstring h1 { font-size: 1.2em; } 125 | .docstring h2 { font-size: 1.1em; } 126 | .docstring h3, .docstring h4 { font-size: 1em; border-bottom: 0; padding-top: 10px; } 127 | .summary_desc .object_link a, .docstring .object_link a { 128 | font-family: monospace; font-size: 1.05em; 129 | color: #05a; background: #EDF4FA; padding: 2px 4px; font-size: 1em; 130 | border-radius: 4px; 131 | } 132 | .rdoc-term { padding-right: 25px; font-weight: bold; } 133 | .rdoc-list p { margin: 0; padding: 0; margin-bottom: 4px; } 134 | .summary_desc pre.code .object_link a, .docstring pre.code .object_link a { 135 | padding: 0px; background: inherit; color: inherit; border-radius: inherit; 136 | } 137 | 138 | /* style for */ 139 | #filecontents table, .docstring table { border-collapse: collapse; } 140 | #filecontents table th, #filecontents table td, 141 | .docstring table th, .docstring table td { border: 1px solid #ccc; padding: 8px; padding-right: 17px; } 142 | #filecontents table tr:nth-child(odd), 143 | .docstring table tr:nth-child(odd) { background: #eee; } 144 | #filecontents table tr:nth-child(even), 145 | .docstring table tr:nth-child(even) { background: #fff; } 146 | #filecontents table th, .docstring table th { background: #fff; } 147 | 148 | /* style for
    */ 149 | #filecontents li > p, .docstring li > p { margin: 0px; } 150 | #filecontents ul, .docstring ul { padding-left: 20px; } 151 | /* style for
    */ 152 | #filecontents dl, .docstring dl { border: 1px solid #ccc; } 153 | #filecontents dt, .docstring dt { background: #ddd; font-weight: bold; padding: 3px 5px; } 154 | #filecontents dd, .docstring dd { padding: 5px 0px; margin-left: 18px; } 155 | #filecontents dd > p, .docstring dd > p { margin: 0px; } 156 | 157 | .note { 158 | color: #222; 159 | margin: 20px 0; 160 | padding: 10px; 161 | border: 1px solid #eee; 162 | border-radius: 3px; 163 | display: block; 164 | } 165 | .docstring .note { 166 | border-left-color: #ccc; 167 | border-left-width: 5px; 168 | } 169 | .note.todo { background: #ffffc5; border-color: #ececaa; } 170 | .note.returns_void { background: #efefef; } 171 | .note.deprecated { background: #ffe5e5; border-color: #e9dada; } 172 | .note.title.deprecated { background: #ffe5e5; border-color: #e9dada; } 173 | .note.private { background: #ffffc5; border-color: #ececaa; } 174 | .note.title { padding: 3px 6px; font-size: 0.9em; font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; display: inline; } 175 | .summary_signature + .note.title { margin-left: 7px; } 176 | h1 .note.title { font-size: 0.5em; font-weight: normal; padding: 3px 5px; position: relative; top: -3px; text-transform: capitalize; } 177 | .note.title { background: #efefef; } 178 | .note.title.constructor { color: #fff; background: #6a98d6; border-color: #6689d6; } 179 | .note.title.writeonly { color: #fff; background: #45a638; border-color: #2da31d; } 180 | .note.title.readonly { color: #fff; background: #6a98d6; border-color: #6689d6; } 181 | .note.title.private { background: #d5d5d5; border-color: #c5c5c5; } 182 | .note.title.not_defined_here { background: transparent; border: none; font-style: italic; } 183 | .discussion .note { margin-top: 6px; } 184 | .discussion .note:first-child { margin-top: 0; } 185 | 186 | h3.inherited { 187 | font-style: italic; 188 | font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; 189 | font-weight: normal; 190 | padding: 0; 191 | margin: 0; 192 | margin-top: 12px; 193 | margin-bottom: 3px; 194 | font-size: 13px; 195 | } 196 | p.inherited { 197 | padding: 0; 198 | margin: 0; 199 | margin-left: 25px; 200 | } 201 | 202 | .box_info dl { 203 | margin: 0; 204 | border: 0; 205 | width: 100%; 206 | font-size: 1em; 207 | display: flex; 208 | display: -webkit-flex; 209 | display: -ms-flexbox; 210 | } 211 | .box_info dl dt { 212 | flex-shrink: 0; 213 | -webkit-flex-shrink: 1; 214 | -ms-flex-shrink: 1; 215 | width: 100px; 216 | text-align: right; 217 | font-weight: bold; 218 | border: 1px solid #aaa; 219 | border-width: 1px 0px 0px 1px; 220 | padding: 6px 0; 221 | padding-right: 10px; 222 | } 223 | .box_info dl dd { 224 | flex-grow: 1; 225 | -webkit-flex-grow: 1; 226 | -ms-flex: 1; 227 | max-width: 420px; 228 | padding: 6px 0; 229 | padding-right: 20px; 230 | border: 1px solid #aaa; 231 | border-width: 1px 1px 0 0; 232 | overflow: hidden; 233 | position: relative; 234 | } 235 | .box_info dl:last-child > * { 236 | border-bottom: 1px solid #aaa; 237 | } 238 | .box_info dl:nth-child(odd) > * { background: #eee; } 239 | .box_info dl:nth-child(even) > * { background: #fff; } 240 | .box_info dl > * { margin: 0; } 241 | 242 | ul.toplevel { list-style: none; padding-left: 0; font-size: 1.1em; } 243 | .index_inline_list { padding-left: 0; font-size: 1.1em; } 244 | 245 | .index_inline_list li { 246 | list-style: none; 247 | display: inline-block; 248 | padding: 0 12px; 249 | line-height: 30px; 250 | margin-bottom: 5px; 251 | } 252 | 253 | dl.constants { margin-left: 10px; } 254 | dl.constants dt { font-weight: bold; font-size: 1.1em; margin-bottom: 5px; } 255 | dl.constants.compact dt { display: inline-block; font-weight: normal } 256 | dl.constants dd { width: 75%; white-space: pre; font-family: monospace; margin-bottom: 18px; } 257 | dl.constants .docstring .note:first-child { margin-top: 5px; } 258 | 259 | .summary_desc { 260 | margin-left: 32px; 261 | display: block; 262 | font-family: sans-serif; 263 | font-size: 1.1em; 264 | margin-top: 8px; 265 | line-height: 1.5145em; 266 | margin-bottom: 0.8em; 267 | } 268 | .summary_desc tt { font-size: 0.9em; } 269 | dl.constants .note { padding: 2px 6px; padding-right: 12px; margin-top: 6px; } 270 | dl.constants .docstring { margin-left: 32px; font-size: 0.9em; font-weight: normal; } 271 | dl.constants .tags { padding-left: 32px; font-size: 0.9em; line-height: 0.8em; } 272 | dl.constants .discussion *:first-child { margin-top: 0; } 273 | dl.constants .discussion *:last-child { margin-bottom: 0; } 274 | 275 | .method_details { border-top: 1px dotted #ccc; margin-top: 25px; padding-top: 0; } 276 | .method_details.first { border: 0; margin-top: 5px; } 277 | .method_details.first h3.signature { margin-top: 1em; } 278 | p.signature, h3.signature { 279 | font-size: 1.1em; font-weight: normal; font-family: Monaco, Consolas, Courier, monospace; 280 | padding: 6px 10px; margin-top: 1em; 281 | background: #E8F4FF; border: 1px solid #d8d8e5; border-radius: 5px; 282 | } 283 | p.signature tt, 284 | h3.signature tt { font-family: Monaco, Consolas, Courier, monospace; } 285 | p.signature .overload, 286 | h3.signature .overload { display: block; } 287 | p.signature .extras, 288 | h3.signature .extras { font-weight: normal; font-family: sans-serif; color: #444; font-size: 1em; } 289 | p.signature .not_defined_here, 290 | h3.signature .not_defined_here, 291 | p.signature .aliases, 292 | h3.signature .aliases { display: block; font-weight: normal; font-size: 0.9em; font-family: sans-serif; margin-top: 0px; color: #555; } 293 | p.signature .aliases .names, 294 | h3.signature .aliases .names { font-family: Monaco, Consolas, Courier, monospace; font-weight: bold; color: #000; font-size: 1.2em; } 295 | 296 | .tags .tag_title { font-size: 1.05em; margin-bottom: 0; font-weight: bold; } 297 | .tags .tag_title tt { color: initial; padding: initial; background: initial; } 298 | .tags ul { margin-top: 5px; padding-left: 30px; list-style: square; } 299 | .tags ul li { margin-bottom: 3px; } 300 | .tags ul .name { font-family: monospace; font-weight: bold; } 301 | .tags ul .note { padding: 3px 6px; } 302 | .tags { margin-bottom: 12px; } 303 | 304 | .tags .examples .tag_title { margin-bottom: 10px; font-weight: bold; } 305 | .tags .examples .inline p { padding: 0; margin: 0; font-weight: bold; font-size: 1em; } 306 | .tags .examples .inline p:before { content: "▸"; font-size: 1em; margin-right: 5px; } 307 | 308 | .tags .overload .overload_item { list-style: none; margin-bottom: 25px; } 309 | .tags .overload .overload_item .signature { 310 | padding: 2px 8px; 311 | background: #F1F8FF; border: 1px solid #d8d8e5; border-radius: 3px; 312 | } 313 | .tags .overload .signature { margin-left: -15px; font-family: monospace; display: block; font-size: 1.1em; } 314 | .tags .overload .docstring { margin-top: 15px; } 315 | 316 | .defines { display: none; } 317 | 318 | #method_missing_details .notice.this { position: relative; top: -8px; color: #888; padding: 0; margin: 0; } 319 | 320 | .showSource { font-size: 0.9em; } 321 | .showSource a, .showSource a:visited { text-decoration: none; color: #666; } 322 | 323 | #content a, #content a:visited { text-decoration: none; color: #05a; } 324 | #content a:hover { background: #ffffa5; } 325 | 326 | ul.summary { 327 | list-style: none; 328 | font-family: monospace; 329 | font-size: 1em; 330 | line-height: 1.5em; 331 | padding-left: 0px; 332 | } 333 | ul.summary a, ul.summary a:visited { 334 | text-decoration: none; font-size: 1.1em; 335 | } 336 | ul.summary li { margin-bottom: 5px; } 337 | .summary_signature { padding: 4px 8px; background: #f8f8f8; border: 1px solid #f0f0f0; border-radius: 5px; } 338 | .summary_signature:hover { background: #CFEBFF; border-color: #A4CCDA; cursor: pointer; } 339 | .summary_signature.deprecated { background: #ffe5e5; border-color: #e9dada; } 340 | ul.summary.compact li { display: inline-block; margin: 0px 5px 0px 0px; line-height: 2.6em;} 341 | ul.summary.compact .summary_signature { padding: 5px 7px; padding-right: 4px; } 342 | #content .summary_signature:hover a, 343 | #content .summary_signature:hover a:visited { 344 | background: transparent; 345 | color: #049; 346 | } 347 | 348 | p.inherited a { font-family: monospace; font-size: 0.9em; } 349 | p.inherited { word-spacing: 5px; font-size: 1.2em; } 350 | 351 | p.children { font-size: 1.2em; } 352 | p.children a { font-size: 0.9em; } 353 | p.children strong { font-size: 0.8em; } 354 | p.children strong.modules { padding-left: 5px; } 355 | 356 | ul.fullTree { display: none; padding-left: 0; list-style: none; margin-left: 0; margin-bottom: 10px; } 357 | ul.fullTree ul { margin-left: 0; padding-left: 0; list-style: none; } 358 | ul.fullTree li { text-align: center; padding-top: 18px; padding-bottom: 12px; background: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAHtJREFUeNqMzrEJAkEURdGzuhgZbSoYWcAWoBVsB4JgZAGmphsZCZYzTQgWNCYrDN9RvMmHx+X916SUBFbo8CzD1idXrLErw1mQttgXtyrOcQ/Ny5p4Qh+2XqLYYazsPWNTiuMkRxa4vcV+evuNAUOLIx5+c2hyzv7hNQC67Q+/HHmlEwAAAABJRU5ErkJggg==) no-repeat top center; } 359 | ul.fullTree li:first-child { padding-top: 0; background: transparent; } 360 | ul.fullTree li:last-child { padding-bottom: 0; } 361 | .showAll ul.fullTree { display: block; } 362 | .showAll .inheritName { display: none; } 363 | 364 | #search { position: absolute; right: 12px; top: 0px; z-index: 9000; } 365 | #search a { 366 | display: block; float: left; 367 | padding: 4px 8px; text-decoration: none; color: #05a; fill: #05a; 368 | border: 1px solid #d8d8e5; 369 | border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; 370 | background: #F1F8FF; 371 | box-shadow: -1px 1px 3px #ddd; 372 | } 373 | #search a:hover { background: #f5faff; color: #06b; fill: #06b; } 374 | #search a.active { 375 | background: #568; padding-bottom: 20px; color: #fff; fill: #fff; 376 | border: 1px solid #457; 377 | border-top-left-radius: 5px; border-top-right-radius: 5px; 378 | } 379 | #search a.inactive { color: #999; fill: #999; } 380 | .inheritanceTree, .toggleDefines { 381 | float: right; 382 | border-left: 1px solid #aaa; 383 | position: absolute; top: 0; right: 0; 384 | height: 100%; 385 | background: #f6f6f6; 386 | padding: 5px; 387 | min-width: 55px; 388 | text-align: center; 389 | } 390 | 391 | #menu { font-size: 1.3em; color: #bbb; } 392 | #menu .title, #menu a { font-size: 0.7em; } 393 | #menu .title a { font-size: 1em; } 394 | #menu .title { color: #555; } 395 | #menu a, #menu a:visited { color: #333; text-decoration: none; border-bottom: 1px dotted #bbd; } 396 | #menu a:hover { color: #05a; } 397 | 398 | #footer { margin-top: 15px; border-top: 1px solid #ccc; text-align: center; padding: 7px 0; color: #999; } 399 | #footer a, #footer a:visited { color: #444; text-decoration: none; border-bottom: 1px dotted #bbd; } 400 | #footer a:hover { color: #05a; } 401 | 402 | #listing ul.alpha { font-size: 1.1em; } 403 | #listing ul.alpha { margin: 0; padding: 0; padding-bottom: 10px; list-style: none; } 404 | #listing ul.alpha li.letter { font-size: 1.4em; padding-bottom: 10px; } 405 | #listing ul.alpha ul { margin: 0; padding-left: 15px; } 406 | #listing ul small { color: #666; font-size: 0.7em; } 407 | 408 | li.r1 { background: #f0f0f0; } 409 | li.r2 { background: #fafafa; } 410 | 411 | #content ul.summary li.deprecated .summary_signature a, 412 | #content ul.summary li.deprecated .summary_signature a:visited { text-decoration: line-through; font-style: italic; } 413 | 414 | #toc { 415 | position: relative; 416 | float: right; 417 | overflow-x: auto; 418 | right: -3px; 419 | margin-left: 20px; 420 | margin-bottom: 20px; 421 | padding: 20px; padding-right: 30px; 422 | max-width: 300px; 423 | z-index: 5000; 424 | background: #fefefe; 425 | border: 1px solid #ddd; 426 | box-shadow: -2px 2px 6px #bbb; 427 | } 428 | #toc .title { margin: 0; } 429 | #toc ol { padding-left: 1.8em; } 430 | #toc li { font-size: 1.1em; line-height: 1.7em; } 431 | #toc > ol > li { font-size: 1.1em; font-weight: bold; } 432 | #toc ol > li > ol { font-size: 0.9em; } 433 | #toc ol ol > li > ol { padding-left: 2.3em; } 434 | #toc ol + li { margin-top: 0.3em; } 435 | #toc.hidden { padding: 10px; background: #fefefe; box-shadow: none; } 436 | #toc.hidden:hover { background: #fafafa; } 437 | #filecontents h1 + #toc.nofloat { margin-top: 0; } 438 | @media (max-width: 560px) { 439 | #toc { 440 | margin-left: 0; 441 | margin-top: 16px; 442 | float: none; 443 | max-width: none; 444 | } 445 | } 446 | 447 | /* syntax highlighting */ 448 | .source_code { display: none; padding: 3px 8px; border-left: 8px solid #ddd; margin-top: 5px; } 449 | #filecontents pre.code, .docstring pre.code, .source_code pre { font-family: monospace; } 450 | #filecontents pre.code, .docstring pre.code { display: block; } 451 | .source_code .lines { padding-right: 12px; color: #555; text-align: right; } 452 | #filecontents pre.code, .docstring pre.code, 453 | .tags pre.example { 454 | padding: 9px 14px; 455 | margin-top: 4px; 456 | border: 1px solid #e1e1e8; 457 | background: #f7f7f9; 458 | border-radius: 4px; 459 | font-size: 1em; 460 | overflow-x: auto; 461 | line-height: 1.2em; 462 | } 463 | pre.code { color: #000; tab-size: 2; } 464 | pre.code .info.file { color: #555; } 465 | pre.code .val { color: #036A07; } 466 | pre.code .tstring_content, 467 | pre.code .heredoc_beg, pre.code .heredoc_end, 468 | pre.code .qwords_beg, pre.code .qwords_end, pre.code .qwords_sep, 469 | pre.code .words_beg, pre.code .words_end, pre.code .words_sep, 470 | pre.code .qsymbols_beg, pre.code .qsymbols_end, pre.code .qsymbols_sep, 471 | pre.code .symbols_beg, pre.code .symbols_end, pre.code .symbols_sep, 472 | pre.code .tstring, pre.code .dstring { color: #036A07; } 473 | pre.code .fid, pre.code .rubyid_new, pre.code .rubyid_to_s, 474 | pre.code .rubyid_to_sym, pre.code .rubyid_to_f, 475 | pre.code .dot + pre.code .id, 476 | pre.code .rubyid_to_i pre.code .rubyid_each { color: #0085FF; } 477 | pre.code .comment { color: #0066FF; } 478 | pre.code .const, pre.code .constant { color: #585CF6; } 479 | pre.code .label, 480 | pre.code .symbol { color: #C5060B; } 481 | pre.code .kw, 482 | pre.code .rubyid_require, 483 | pre.code .rubyid_extend, 484 | pre.code .rubyid_include { color: #0000FF; } 485 | pre.code .ivar { color: #318495; } 486 | pre.code .gvar, 487 | pre.code .rubyid_backref, 488 | pre.code .rubyid_nth_ref { color: #6D79DE; } 489 | pre.code .regexp, .dregexp { color: #036A07; } 490 | pre.code a { border-bottom: 1px dotted #bbf; } 491 | /* inline code */ 492 | *:not(pre) > code { 493 | padding: 1px 3px 1px 3px; 494 | border: 1px solid #E1E1E8; 495 | background: #F7F7F9; 496 | border-radius: 4px; 497 | } 498 | 499 | /* Color fix for links */ 500 | #content .summary_desc pre.code .id > .object_link a, /* identifier */ 501 | #content .docstring pre.code .id > .object_link a { color: #0085FF; } 502 | #content .summary_desc pre.code .const > .object_link a, /* constant */ 503 | #content .docstring pre.code .const > .object_link a { color: #585CF6; } 504 | -------------------------------------------------------------------------------- /docs/yard/file.CHANGELOG.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: CHANGELOG 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
    36 | 59 | 60 |

    [1.3.0]

    61 |
      62 |
    • Breaking change: drop Ruby 3.0 support (EOL)
    • 63 |
    • Chore: 64 |
        65 |
      • Add support for Ruby 3.4
      • 66 |
      • Update dependencies
      • 67 |
      68 |
    • 69 |
    70 |

    [1.2.0]

    71 |
      72 |
    • Deprecation: now requires ruby 3.0+ instead of 2.7+
    • 73 |
    • Chore: 74 |
        75 |
      • Add support for Ruby 3.2
      • 76 |
      77 |
    • 78 |
    • Lib: define a bit depth of 1 (fix #1), even if it seems to be automatic with newer version of (ruby-)vips, to save some storage
    • 79 |
    80 |

    [1.1.0]

    81 |
      82 |
    • Dependencies: 83 |
        84 |
      • Update to yard v0.9.27 85 |
          86 |
        • Move from Redcarpet to CommonMarker markdown provider
        • 87 |
        • Move doc syntax from Rdoc to markdown
        • 88 |
        89 |
      • 90 |
      • Move dev dependencies from gemspec to gemfile
      • 91 |
      92 |
    • 93 |
    • Chore: 94 |
        95 |
      • Add support for Ruby 3.1
      • 96 |
      97 |
    • 98 |
    99 |

    [1.0.2]

    100 |
      101 |
    • lib: code lint
    • 102 |
    • dependencies: update
    • 103 |
    • rubocop: new rules for new cops
    • 104 |
    • deprecation: now requires ruby 2.7+ instead of 2.4+
    • 105 |
    • doc: fix a CLI value name
    • 106 |
    107 |

    [1.0.1]

    108 |
      109 |
    • doc: final documentation
    • 110 |
    • gem: add metadata to gemspec
    • 111 |
    112 |

    [1.0.0]

    113 |
      114 |
    • Initial version
    • 115 |
    116 |
    117 | 118 | 123 | 124 |
    125 | 126 | -------------------------------------------------------------------------------- /docs/yard/file.CLI.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: CLI 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
    36 | 59 | 60 |

    Usage

    61 |
    PixelChart
     62 | 
     63 | Usage:
     64 |   pixelchart draw <input> <output> (--width <pixel> --height <pixel>) [--colors <colors>] [--backend <name>] [--scale <ratio>] [--no-color] [--debug]
     65 |   pixelchart calc (--area <size>|<input>) [--no-color] [--debug]
     66 |   pixelchart -H | --help
     67 |   pixelchart -V | --version
     68 | 
     69 | Options:
     70 |   <input>                         Input file containing values
     71 |   <output>                        Output image (filename)
     72 |   -w <pixel>, --width <pixel>     Width of the output image (in number pixel)
     73 |   -h <pixel>, --height <pixel>    Height of the output image (in number pixel)
     74 |   -c <colors>, --colors <colors>  Colors of the image (in RGB or random)
     75 |   -b <name>, --backend <name>     Image processing backend (rmagick or ruby-vips)
     76 |   -s <ratio>, --scale <ratio>     Scale ratio or dimensions
     77 |   --area <size>                   Area, number of values, total number of pixel
     78 |   --no-color      Disable colorized output
     79 |   --debug         Display arguments
     80 |   -H, --help      Show this screen
     81 |   -V, --version   Show version
     82 | 
     83 | Examples:
     84 |   pixelchart draw test.csv test.png -w 100 -h 100
     85 |   pixelchart draw test.csv test.png -w 100 -h 100 -c 'random|125,125,125' -b rubyvips
     86 |   pixelchart calc test.csv
     87 |   pixelchart calc --area 10000 --no-color
     88 | 
    89 |

    draw

    90 |

    The input is a file file containing data that will be used to generate the image. 91 | Values must be 0, 1, true, false and separated by commas.

    92 |

    Then we choose the destination image and the desired dimensions.

    93 |
    $ pixelchart draw test.csv test.png -w 100 -h 100
     94 | [+] Image saved
     95 | 
    96 |

    We can also choose the color of the pixels, the first value will be the falsy 97 | color (0 or false) and the second value will be the truthy color (1 or true). 98 | The magic random keyword can be used to pick a random color. Else the color 99 | value must be specified as RGB.

    100 |
    $ pixelchart draw test.csv test.png -w 100 -h 100 -c 'random|125,125,125'
    101 | [+] Image saved
    102 | 
    103 |

    By default the Rmagick (Imagemagick) backend is used for image processing but 104 | it is also possible to use ruby-vips (libvips).

    105 |

    Rmagick will generally output a smaller image (in bytes) but ruby-vips will 106 | operate a bit faster and requires less memory (RAM).

    107 |
    $ pixelchart draw test.csv test.png -w 100 -h 100 -b rubyvips
    108 | [+] Image saved
    109 | 
    110 |

    If you have a dataset of 10,000 values and choose a 100x100 dimensions but feel 111 | that a 100x100 image is too small, you can use the scale option to scale the 112 | image differently (smaller, bigger, different aspect ratio). 113 | So if want a final image of 500x500 size, you can apply a x5 ratio.

    114 |

    Note: the scale factor must be a ratio or dimensions. Ratio must be a positive 115 | (non-nul) float or integer, and dimensions must be a set of width and height 116 | separated by a comma. Eg. 10, 4.2, 100,500. The aspect ratio may be 117 | different than the initial dimensions chosen, eg. -w 100 -h 100 -s 600,70. 118 | rubyvips backend only supports a ratio, not dimensions.

    119 |
    $ pixelchart draw test.csv test.png -w 100 -h 100 -s 5
    120 | [+] Image saved
    121 | 
    122 |

    calc

    123 |

    As pixelchart draw requires a width and a height that match the total number 124 | of pixels/values, I you don't know which resolutions are possible use 125 | pixelchart calc to display the possible dimensions.

    126 |
    $ pixelchart calc test.csv
    127 | Possible dimensions: width x height or height x width
    128 | 1 x 10000
    129 | 2 x 5000
    130 | 4 x 2500
    131 | 5 x 2000
    132 | 8 x 1250
    133 | 10 x 1000
    134 | 16 x 625
    135 | 20 x 500
    136 | 25 x 400
    137 | 40 x 250
    138 | 50 x 200
    139 | 80 x 125
    140 | 100 x 100
    141 | 
    142 | $ pixelchart calc --area 775
    143 | Possible dimensions: width x height or height x width
    144 | 1 x 775
    145 | 5 x 155
    146 | 25 x 31
    147 | 
    148 |

    misc

    149 |

    The --no-color flag can be used to disable the color in output but the 150 | NO_COLOR environment variable is also checked.

    151 |

    Use export NO_COLOR to disable color and unset NO_COLOR to remove this 152 | behavior.

    153 |
    154 | 155 | 160 | 161 |
    162 | 163 | -------------------------------------------------------------------------------- /docs/yard/file.Install.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: Install 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
    36 | 59 | 60 |

    Production

    61 |

    Install from rubygems.org

    62 |
    $ gem install pixelchart
     63 | 
    64 |

    Gem: pixelchart

    65 |

    Install from ArchLinux

    66 |

    Manually:

    67 |
    $ git clone https://aur.archlinux.org/pixelchart.git
     68 | $ cd pixelchart
     69 | $ makepkg -sic
     70 | 
    71 |

    With an AUR helper (Pacman wrappers), eg. pikaur:

    72 |
    $ pikaur -S pixelchart
     73 | 
    74 |

    AUR: pixelchart

    75 |

    Development

    76 |

    It's better to use rbenv to have latests version of ruby and to avoid trashing your system ruby.

    77 |

    Install from rubygems.org

    78 |
    $ gem install --development pixelchart
     79 | 
    80 |

    Build from git

    81 |

    Just replace x.x.x with the gem version you see after gem build.

    82 |
    $ git clone https://github.com/noraj/PixelChart.git pixelchart
     83 | $ cd pixelchart
     84 | $ gem install bundler
     85 | $ bundler install
     86 | $ gem build pixelchart.gemspec
     87 | $ gem install pixelchart-x.x.x.gem
     88 | 
    89 |

    Note: if an automatic install is needed you can get the version with gem build pixelchart.gemspec | grep Version | cut -d' ' -f4.

    90 |

    Run the library/CLI in irb without installing the gem

    91 |

    Library:

    92 |
    $ irb -Ilib -rpixelchart
     93 | 
    94 |

    CLI tool:

    95 |
    $ ruby -Ilib -rpixelchart bin/pixelchart 
     96 | 
    97 |

    Build the gem doc

    98 |

    Building locally: for library users

    99 |

    For developers who only want to use the library.

    100 |
    $ bundle exec yard doc
    101 | 
    102 |

    Building locally: for developer

    103 |

    For developers who want to participate to the development.

    104 |
    $ bundle exec yard doc --yardopts .yardopts-dev
    105 | 
    106 |
    107 | 108 | 113 | 114 |
    115 | 116 | -------------------------------------------------------------------------------- /docs/yard/file.LICENSE.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: LICENSE 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
    36 | 59 | 60 |
    The MIT License (MIT)

    Copyright (c) 2019-2025 Alexandre ZANNI

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
    61 | 62 | 67 | 68 |
    69 | 70 | -------------------------------------------------------------------------------- /docs/yard/file.Landing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: Landing 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
    36 | 59 | 60 |

    61 |

    Gem Version 62 | AUR version 63 | GitHub release (latest SemVer) 64 | GitHub tag (latest SemVer) 65 | GitHub forks 66 | GitHub stars 67 | GitHub license

    68 |

    PixelChart

    69 |
    70 |

    Map binary data into a beautiful chart

    71 |
    72 |

    PixelChart let's you create an image, a pixel chart / plot, based on binary data. 73 | The idea is that truthy and falsy values will be represented by a different color 74 | to be able to quickly visualize boolean values.

    75 |

    For example:

    76 |

    77 |

    Requirements

    78 |

    You have to install the system requirements for both backends.

    79 | 83 |

    Example for Linux distros:

    84 |
      85 |
    • ArchLinux: pacman -S libvips imagemagick
    • 86 |
    • openSUSE: zypper in libvips42 ImageMagick
    • 87 |
    • Ubuntu: apt install libvips42 imagemagick
    • 88 |
    89 |

    Installation

    90 |
    $ gem install pixelchart
     91 | 
    92 |

    See the the documentation for more advanced options.

    93 |

    Usage

    94 |

    CLI

    95 |
    $ pixelchart draw test.csv test.png -w 100 -h 100 -s 3
     96 | [+] Image saved
     97 | 
    98 |

    See the CLI documentation.

    99 |

    library

    100 |

    See the PixelChart.

    101 |

    scenarios

    102 |

    See some scenarios with examples.

    103 |

    Documentation

    104 | 108 |
    109 | 110 | 115 | 116 |
    117 | 118 | -------------------------------------------------------------------------------- /docs/yard/file.Publishing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: Publishing 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
    36 | 59 | 60 |

    On Rubygems.org

    61 |
    $ git tag -a vx.x.x
    62 | $ git push --follow-tags
    63 | $ gem push pixelchart-x.x.x.gem
    64 | 
    65 |

    See https://guides.rubygems.org/publishing/.

    66 |

    On new release don't forget to rebuild the library documentation:

    67 |
    $ bundle exec yard doc
    68 | 
    69 |

    On AUR

    70 |
    $ updpkgsums
    71 | $ makepkg --printsrcinfo > .SRCINFO
    72 | 
    73 |
    74 | 75 | 80 | 81 |
    82 | 83 | -------------------------------------------------------------------------------- /docs/yard/file.README.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: README 8 | 9 | — Documentation by YARD 0.9.24 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
    36 | 59 | 60 |

    PixelChart

    61 | 62 |

    Requirements

    63 | 64 |

    You have to install the system requirements for both backends.

    65 | 66 | 70 | 71 |

    Example for Linux distros:

    72 | 73 |
      74 |
    • ArchLinux: pacman -S libvips imagemagick
    • 75 |
    • openSUSE: zypper in libvips42 ImageMagick
    • 76 |
    • Ubuntu: apt install libvips42 imagemagick
    • 77 |
    78 | 79 |

    Installation

    80 | 81 |
    $ gem install pixelchart
     82 | 
    83 | 84 |

    More doc

    85 | 86 |

    Usage

    87 | 88 |
    $ pixelchart draw test.csv test.png -w 100 -h 100
     89 | [+] Image saved
     90 | 
    91 | 92 |

    93 | 94 |

    CLI

    95 | 96 |

    LIB

    97 | 98 |

    scenarios

    99 | 100 |

    Roadmap

    101 | 102 |
      103 |
    • options: 104 | 105 |
        106 |
      • [ ] ascii art
      • 107 |
      • [ ] random data (0 ... (@width * @height)).map {|_i| rand(2) }
      • 108 |
    • 109 |
    • lib: 110 | 111 |
        112 |
      • input format:
      • 113 |
      • [ ] read binary
      • 114 |
    • 115 |
    • bonus: 116 | 117 |
        118 |
      • [ ] choose color of pixel: rgb, other format?
      • 119 |
    • 120 |
    • docs 121 | 122 |
    • 129 |
    130 |
    131 | 132 | 137 | 138 |
    139 | 140 | -------------------------------------------------------------------------------- /docs/yard/file.Scenarios.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: Scenarios 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
    36 | 59 | 60 |

    Default

    61 |

    Just display a representation of binary data.

    62 |
    pixelchart draw test.csv test.png -w 100 -h 100 -s 3
     63 | 
    64 |

    65 |

    Prime numbers

    66 |

    A representation of prime numbers under 10,000.

    67 |
    require 'pixelchart'
     68 | require 'prime'
     69 | 
     70 | primes = (1..10000).map{ |i| Prime.prime?(i) }
     71 | options = {
     72 |   colors: [[255,255,255],[255,20,147]],
     73 |   scale: 5
     74 | }
     75 | im = PixelChart.new(primes, 100, 100, options)
     76 | im.draw('primes.png')
     77 | 
    78 |

    79 |

    Malware hash

    80 |

    Create a unique fingerprint image for a malware (eg. 81 | VirusTotal).

    82 |
    require 'pixelchart'
     83 | require 'ctf_party'
     84 | 
     85 | sha256 = '142b638c6a60b60c7f9928da4fb85a5a8e1422a9ffdc9ee49e17e56ccca9cf6e'.hex2bin.split('')
     86 | sha256.map! { |x| x.to_i }
     87 | options = {
     88 |   colors: [:random,:random],
     89 |   scale: 50
     90 | }
     91 | im = PixelChart.new(sha256, 23, 11, options)
     92 | im.draw('virus.png')
     93 | 
    94 |

    95 |

    Random data

    96 |

    Create an image with random data, for example for a default profile image on a 97 | forum.

    98 |
    require 'pixelchart'
     99 | 
    100 | data = (0 ... 10000).map {|_i| rand(2) }
    101 | options = {
    102 |   colors: [[0,255,127],[0,0,0]],
    103 |   scale: 5
    104 | }
    105 | im = PixelChart.new(data, 100, 100, options)
    106 | im.draw('random.png')
    107 | 
    108 |

    109 |

    The logo

    110 |

    The PixelChart logo was designed pixel by pixel on a 7*7 square.

    111 |
    ░▓▓▓▓▓░
    112 | ░░▓░▓▓░
    113 | ░░▓░░▓░
    114 | ░░▓▓▓▓░
    115 | ░░▓░░░░
    116 | ░░▓░░░░
    117 | ░░▓░░░░
    118 | 
    119 |

    Then convert black and white pixel to 1 and 0.

    120 |
    0,1,1,1,1,1,0
    121 | 0,0,1,0,1,1,0
    122 | 0,0,1,0,0,1,0
    123 | 0,0,1,1,1,1,0
    124 | 0,0,1,0,0,0,0
    125 | 0,0,1,0,0,0,0
    126 | 0,0,1,0,0,0,0
    127 | 
    128 |

    Inline.

    129 |
    0,1,1,1,1,1,0,0,0,1,0,1,1,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0
    130 | 
    131 |

    Then map the data and choose some colors.

    132 |
    require 'pixelchart'
    133 | 
    134 | data = [0,1,1,1,1,1,0,0,0,1,0,1,1,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0]
    135 | options = {
    136 |   colors: [[0,0,0],[0,255,127]],
    137 |   scale: 30
    138 | }
    139 | im = PixelChart.new(data, 7, 7, options)
    140 | im.draw('logo.png')
    141 | 
    142 |

    Tada! The logo is done!

    143 |

    144 |
    145 | 146 | 151 | 152 |
    153 | 154 | -------------------------------------------------------------------------------- /docs/yard/file_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | File List 19 | 20 | 21 | 22 |
    23 |
    24 |

    File List

    25 |
    26 | 27 | 28 | Classes 29 | 30 | 31 | 32 | Methods 33 | 34 | 35 | 36 | Files 37 | 38 | 39 |
    40 | 41 | 45 |
    46 | 47 | 87 |
    88 | 89 | 90 | -------------------------------------------------------------------------------- /docs/yard/frames.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Documentation by YARD 0.9.37 6 | 7 | 18 | 22 | 23 | -------------------------------------------------------------------------------- /docs/yard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | File: Landing 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
    36 | 59 | 60 |

    61 |

    Gem Version 62 | AUR version 63 | GitHub release (latest SemVer) 64 | GitHub tag (latest SemVer) 65 | GitHub forks 66 | GitHub stars 67 | GitHub license

    68 |

    PixelChart

    69 |
    70 |

    Map binary data into a beautiful chart

    71 |
    72 |

    PixelChart let's you create an image, a pixel chart / plot, based on binary data. 73 | The idea is that truthy and falsy values will be represented by a different color 74 | to be able to quickly visualize boolean values.

    75 |

    For example:

    76 |

    77 |

    Requirements

    78 |

    You have to install the system requirements for both backends.

    79 | 83 |

    Example for Linux distros:

    84 |
      85 |
    • ArchLinux: pacman -S libvips imagemagick
    • 86 |
    • openSUSE: zypper in libvips42 ImageMagick
    • 87 |
    • Ubuntu: apt install libvips42 imagemagick
    • 88 |
    89 |

    Installation

    90 |
    $ gem install pixelchart
     91 | 
    92 |

    See the the documentation for more advanced options.

    93 |

    Usage

    94 |

    CLI

    95 |
    $ pixelchart draw test.csv test.png -w 100 -h 100 -s 3
     96 | [+] Image saved
     97 | 
    98 |

    See the CLI documentation.

    99 |

    library

    100 |

    See the PixelChart.

    101 |

    scenarios

    102 |

    See some scenarios with examples.

    103 |

    Documentation

    104 | 108 |
    109 | 110 | 115 | 116 |
    117 | 118 | -------------------------------------------------------------------------------- /docs/yard/js/app.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var localStorage = {}, 3 | sessionStorage = {}; 4 | try { 5 | localStorage = window.localStorage; 6 | } catch (e) {} 7 | try { 8 | sessionStorage = window.sessionStorage; 9 | } catch (e) {} 10 | 11 | function createSourceLinks() { 12 | $(".method_details_list .source_code").before( 13 | "[View source]" 14 | ); 15 | $(".toggleSource").toggle( 16 | function () { 17 | $(this).parent().nextAll(".source_code").slideDown(100); 18 | $(this).text("Hide source"); 19 | }, 20 | function () { 21 | $(this).parent().nextAll(".source_code").slideUp(100); 22 | $(this).text("View source"); 23 | } 24 | ); 25 | } 26 | 27 | function createDefineLinks() { 28 | var tHeight = 0; 29 | $(".defines").after(" more..."); 30 | $(".toggleDefines").toggle( 31 | function () { 32 | tHeight = $(this).parent().prev().height(); 33 | $(this).prev().css("display", "inline"); 34 | $(this).parent().prev().height($(this).parent().height()); 35 | $(this).text("(less)"); 36 | }, 37 | function () { 38 | $(this).prev().hide(); 39 | $(this).parent().prev().height(tHeight); 40 | $(this).text("more..."); 41 | } 42 | ); 43 | } 44 | 45 | function createFullTreeLinks() { 46 | var tHeight = 0; 47 | $(".inheritanceTree").toggle( 48 | function () { 49 | tHeight = $(this).parent().prev().height(); 50 | $(this).parent().toggleClass("showAll"); 51 | $(this).text("(hide)"); 52 | $(this).parent().prev().height($(this).parent().height()); 53 | }, 54 | function () { 55 | $(this).parent().toggleClass("showAll"); 56 | $(this).parent().prev().height(tHeight); 57 | $(this).text("show all"); 58 | } 59 | ); 60 | } 61 | 62 | function searchFrameButtons() { 63 | $(".full_list_link").click(function () { 64 | toggleSearchFrame(this, $(this).attr("href")); 65 | return false; 66 | }); 67 | window.addEventListener("message", function (e) { 68 | if (e.data === "navEscape") { 69 | $("#nav").slideUp(100); 70 | $("#search a").removeClass("active inactive"); 71 | $(window).focus(); 72 | } 73 | }); 74 | 75 | $(window).resize(function () { 76 | if ($("#search:visible").length === 0) { 77 | $("#nav").removeAttr("style"); 78 | $("#search a").removeClass("active inactive"); 79 | $(window).focus(); 80 | } 81 | }); 82 | } 83 | 84 | function toggleSearchFrame(id, link) { 85 | var frame = $("#nav"); 86 | $("#search a").removeClass("active").addClass("inactive"); 87 | if (frame.attr("src") === link && frame.css("display") !== "none") { 88 | frame.slideUp(100); 89 | $("#search a").removeClass("active inactive"); 90 | } else { 91 | $(id).addClass("active").removeClass("inactive"); 92 | if (frame.attr("src") !== link) frame.attr("src", link); 93 | frame.slideDown(100); 94 | } 95 | } 96 | 97 | function linkSummaries() { 98 | $(".summary_signature").click(function () { 99 | document.location = $(this).find("a").attr("href"); 100 | }); 101 | } 102 | 103 | function summaryToggle() { 104 | $(".summary_toggle").click(function (e) { 105 | e.preventDefault(); 106 | localStorage.summaryCollapsed = $(this).text(); 107 | $(".summary_toggle").each(function () { 108 | $(this).text($(this).text() == "collapse" ? "expand" : "collapse"); 109 | var next = $(this).parent().parent().nextAll("ul.summary").first(); 110 | if (next.hasClass("compact")) { 111 | next.toggle(); 112 | next.nextAll("ul.summary").first().toggle(); 113 | } else if (next.hasClass("summary")) { 114 | var list = $('
      '); 115 | list.html(next.html()); 116 | list.find(".summary_desc, .note").remove(); 117 | list.find("a").each(function () { 118 | $(this).html($(this).find("strong").html()); 119 | $(this).parent().html($(this)[0].outerHTML); 120 | }); 121 | next.before(list); 122 | next.toggle(); 123 | } 124 | }); 125 | return false; 126 | }); 127 | if (localStorage.summaryCollapsed == "collapse") { 128 | $(".summary_toggle").first().click(); 129 | } else { 130 | localStorage.summaryCollapsed = "expand"; 131 | } 132 | } 133 | 134 | function constantSummaryToggle() { 135 | $(".constants_summary_toggle").click(function (e) { 136 | e.preventDefault(); 137 | localStorage.summaryCollapsed = $(this).text(); 138 | $(".constants_summary_toggle").each(function () { 139 | $(this).text($(this).text() == "collapse" ? "expand" : "collapse"); 140 | var next = $(this).parent().parent().nextAll("dl.constants").first(); 141 | if (next.hasClass("compact")) { 142 | next.toggle(); 143 | next.nextAll("dl.constants").first().toggle(); 144 | } else if (next.hasClass("constants")) { 145 | var list = $('
      '); 146 | list.html(next.html()); 147 | list.find("dt").each(function () { 148 | $(this).addClass("summary_signature"); 149 | $(this).text($(this).text().split("=")[0]); 150 | if ($(this).has(".deprecated").length) { 151 | $(this).addClass("deprecated"); 152 | } 153 | }); 154 | // Add the value of the constant as "Tooltip" to the summary object 155 | list.find("pre.code").each(function () { 156 | console.log($(this).parent()); 157 | var dt_element = $(this).parent().prev(); 158 | var tooltip = $(this).text(); 159 | if (dt_element.hasClass("deprecated")) { 160 | tooltip = "Deprecated. " + tooltip; 161 | } 162 | dt_element.attr("title", tooltip); 163 | }); 164 | list.find(".docstring, .tags, dd").remove(); 165 | next.before(list); 166 | next.toggle(); 167 | } 168 | }); 169 | return false; 170 | }); 171 | if (localStorage.summaryCollapsed == "collapse") { 172 | $(".constants_summary_toggle").first().click(); 173 | } else { 174 | localStorage.summaryCollapsed = "expand"; 175 | } 176 | } 177 | 178 | function generateTOC() { 179 | if ($("#filecontents").length === 0) return; 180 | var _toc = $('
        '); 181 | var show = false; 182 | var toc = _toc; 183 | var counter = 0; 184 | var tags = ["h2", "h3", "h4", "h5", "h6"]; 185 | var i; 186 | var curli; 187 | if ($("#filecontents h1").length > 1) tags.unshift("h1"); 188 | for (i = 0; i < tags.length; i++) { 189 | tags[i] = "#filecontents " + tags[i]; 190 | } 191 | var lastTag = parseInt(tags[0][1], 10); 192 | $(tags.join(", ")).each(function () { 193 | if ($(this).parents(".method_details .docstring").length != 0) return; 194 | if (this.id == "filecontents") return; 195 | show = true; 196 | var thisTag = parseInt(this.tagName[1], 10); 197 | if (this.id.length === 0) { 198 | var proposedId = $(this).attr("toc-id"); 199 | if (typeof proposedId != "undefined") this.id = proposedId; 200 | else { 201 | var proposedId = $(this) 202 | .text() 203 | .replace(/[^a-z0-9-]/gi, "_"); 204 | if ($("#" + proposedId).length > 0) { 205 | proposedId += counter; 206 | counter++; 207 | } 208 | this.id = proposedId; 209 | } 210 | } 211 | if (thisTag > lastTag) { 212 | for (i = 0; i < thisTag - lastTag; i++) { 213 | if (typeof curli == "undefined") { 214 | curli = $("
      1. "); 215 | toc.append(curli); 216 | } 217 | toc = $("
          "); 218 | curli.append(toc); 219 | curli = undefined; 220 | } 221 | } 222 | if (thisTag < lastTag) { 223 | for (i = 0; i < lastTag - thisTag; i++) { 224 | toc = toc.parent(); 225 | toc = toc.parent(); 226 | } 227 | } 228 | var title = $(this).attr("toc-title"); 229 | if (typeof title == "undefined") title = $(this).text(); 230 | curli = $('
        1. ' + title + "
        2. "); 231 | toc.append(curli); 232 | lastTag = thisTag; 233 | }); 234 | if (!show) return; 235 | html = 236 | ''; 237 | $("#content").prepend(html); 238 | $("#toc").append(_toc); 239 | $("#toc .hide_toc").toggle( 240 | function () { 241 | $("#toc .top").slideUp("fast"); 242 | $("#toc").toggleClass("hidden"); 243 | $("#toc .title small").toggle(); 244 | }, 245 | function () { 246 | $("#toc .top").slideDown("fast"); 247 | $("#toc").toggleClass("hidden"); 248 | $("#toc .title small").toggle(); 249 | } 250 | ); 251 | } 252 | 253 | function navResizeFn(e) { 254 | if (e.which !== 1) { 255 | navResizeFnStop(); 256 | return; 257 | } 258 | 259 | sessionStorage.navWidth = e.pageX.toString(); 260 | $(".nav_wrap").css("width", e.pageX); 261 | $(".nav_wrap").css("-ms-flex", "inherit"); 262 | } 263 | 264 | function navResizeFnStop() { 265 | $(window).unbind("mousemove", navResizeFn); 266 | window.removeEventListener("message", navMessageFn, false); 267 | } 268 | 269 | function navMessageFn(e) { 270 | if (e.data.action === "mousemove") navResizeFn(e.data.event); 271 | if (e.data.action === "mouseup") navResizeFnStop(); 272 | } 273 | 274 | function navResizer() { 275 | $("#resizer").mousedown(function (e) { 276 | e.preventDefault(); 277 | $(window).mousemove(navResizeFn); 278 | window.addEventListener("message", navMessageFn, false); 279 | }); 280 | $(window).mouseup(navResizeFnStop); 281 | 282 | if (sessionStorage.navWidth) { 283 | navResizeFn({ which: 1, pageX: parseInt(sessionStorage.navWidth, 10) }); 284 | } 285 | } 286 | 287 | function navExpander() { 288 | if (typeof pathId === "undefined") return; 289 | var done = false, 290 | timer = setTimeout(postMessage, 500); 291 | function postMessage() { 292 | if (done) return; 293 | clearTimeout(timer); 294 | var opts = { action: "expand", path: pathId }; 295 | document.getElementById("nav").contentWindow.postMessage(opts, "*"); 296 | done = true; 297 | } 298 | 299 | window.addEventListener( 300 | "message", 301 | function (event) { 302 | if (event.data === "navReady") postMessage(); 303 | return false; 304 | }, 305 | false 306 | ); 307 | } 308 | 309 | function mainFocus() { 310 | var hash = window.location.hash; 311 | if (hash !== "" && $(hash)[0]) { 312 | $(hash)[0].scrollIntoView(); 313 | } 314 | 315 | setTimeout(function () { 316 | $("#main").focus(); 317 | }, 10); 318 | } 319 | 320 | function navigationChange() { 321 | // This works around the broken anchor navigation with the YARD template. 322 | window.onpopstate = function () { 323 | var hash = window.location.hash; 324 | if (hash !== "" && $(hash)[0]) { 325 | $(hash)[0].scrollIntoView(); 326 | } 327 | }; 328 | } 329 | 330 | $(document).ready(function () { 331 | navResizer(); 332 | navExpander(); 333 | createSourceLinks(); 334 | createDefineLinks(); 335 | createFullTreeLinks(); 336 | searchFrameButtons(); 337 | linkSummaries(); 338 | summaryToggle(); 339 | constantSummaryToggle(); 340 | generateTOC(); 341 | mainFocus(); 342 | navigationChange(); 343 | }); 344 | })(); 345 | -------------------------------------------------------------------------------- /docs/yard/js/full_list.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | var $clicked = $(null); 4 | var searchTimeout = null; 5 | var searchCache = []; 6 | var caseSensitiveMatch = false; 7 | var ignoreKeyCodeMin = 8; 8 | var ignoreKeyCodeMax = 46; 9 | var commandKey = 91; 10 | 11 | RegExp.escape = function(text) { 12 | return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 13 | } 14 | 15 | function escapeShortcut() { 16 | $(document).keydown(function(evt) { 17 | if (evt.which == 27) { 18 | window.parent.postMessage('navEscape', '*'); 19 | } 20 | }); 21 | } 22 | 23 | function navResizer() { 24 | $(window).mousemove(function(e) { 25 | window.parent.postMessage({ 26 | action: 'mousemove', event: {pageX: e.pageX, which: e.which} 27 | }, '*'); 28 | }).mouseup(function(e) { 29 | window.parent.postMessage({action: 'mouseup'}, '*'); 30 | }); 31 | window.parent.postMessage("navReady", "*"); 32 | } 33 | 34 | function clearSearchTimeout() { 35 | clearTimeout(searchTimeout); 36 | searchTimeout = null; 37 | } 38 | 39 | function enableLinks() { 40 | // load the target page in the parent window 41 | $('#full_list li').on('click', function(evt) { 42 | $('#full_list li').removeClass('clicked'); 43 | $clicked = $(this); 44 | $clicked.addClass('clicked'); 45 | evt.stopPropagation(); 46 | 47 | if (evt.target.tagName === 'A') return true; 48 | 49 | var elem = $clicked.find('> .item .object_link a')[0]; 50 | var e = evt.originalEvent; 51 | var newEvent = new MouseEvent(evt.originalEvent.type); 52 | newEvent.initMouseEvent(e.type, e.canBubble, e.cancelable, e.view, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); 53 | elem.dispatchEvent(newEvent); 54 | evt.preventDefault(); 55 | return false; 56 | }); 57 | } 58 | 59 | function enableToggles() { 60 | // show/hide nested classes on toggle click 61 | $('#full_list a.toggle').on('click', function(evt) { 62 | evt.stopPropagation(); 63 | evt.preventDefault(); 64 | $(this).parent().parent().toggleClass('collapsed'); 65 | $(this).attr('aria-expanded', function (i, attr) { 66 | return attr == 'true' ? 'false' : 'true' 67 | }); 68 | highlight(); 69 | }); 70 | 71 | // navigation of nested classes using keyboard 72 | $('#full_list a.toggle').on('keypress',function(evt) { 73 | // enter key is pressed 74 | if (evt.which == 13) { 75 | evt.stopPropagation(); 76 | evt.preventDefault(); 77 | $(this).parent().parent().toggleClass('collapsed'); 78 | $(this).attr('aria-expanded', function (i, attr) { 79 | return attr == 'true' ? 'false' : 'true' 80 | }); 81 | highlight(); 82 | } 83 | }); 84 | } 85 | 86 | function populateSearchCache() { 87 | $('#full_list li .item').each(function() { 88 | var $node = $(this); 89 | var $link = $node.find('.object_link a'); 90 | if ($link.length > 0) { 91 | searchCache.push({ 92 | node: $node, 93 | link: $link, 94 | name: $link.text(), 95 | fullName: $link.attr('title').split(' ')[0] 96 | }); 97 | } 98 | }); 99 | } 100 | 101 | function enableSearch() { 102 | $('#search input').keyup(function(event) { 103 | if (ignoredKeyPress(event)) return; 104 | if (this.value === "") { 105 | clearSearch(); 106 | } else { 107 | performSearch(this.value); 108 | } 109 | }); 110 | 111 | $('#full_list').after(""); 112 | } 113 | 114 | function ignoredKeyPress(event) { 115 | if ( 116 | (event.keyCode > ignoreKeyCodeMin && event.keyCode < ignoreKeyCodeMax) || 117 | (event.keyCode == commandKey) 118 | ) { 119 | return true; 120 | } else { 121 | return false; 122 | } 123 | } 124 | 125 | function clearSearch() { 126 | clearSearchTimeout(); 127 | $('#full_list .found').removeClass('found').each(function() { 128 | var $link = $(this).find('.object_link a'); 129 | $link.text($link.text()); 130 | }); 131 | $('#full_list, #content').removeClass('insearch'); 132 | $clicked.parents().removeClass('collapsed'); 133 | highlight(); 134 | } 135 | 136 | function performSearch(searchString) { 137 | clearSearchTimeout(); 138 | $('#full_list, #content').addClass('insearch'); 139 | $('#noresults').text('').hide(); 140 | partialSearch(searchString, 0); 141 | } 142 | 143 | function partialSearch(searchString, offset) { 144 | var lastRowClass = ''; 145 | var i = null; 146 | for (i = offset; i < Math.min(offset + 50, searchCache.length); i++) { 147 | var item = searchCache[i]; 148 | var searchName = (searchString.indexOf('::') != -1 ? item.fullName : item.name); 149 | var matchString = buildMatchString(searchString); 150 | var matchRegexp = new RegExp(matchString, caseSensitiveMatch ? "" : "i"); 151 | if (searchName.match(matchRegexp) == null) { 152 | item.node.removeClass('found'); 153 | item.link.text(item.link.text()); 154 | } 155 | else { 156 | item.node.addClass('found'); 157 | item.node.removeClass(lastRowClass).addClass(lastRowClass == 'r1' ? 'r2' : 'r1'); 158 | lastRowClass = item.node.hasClass('r1') ? 'r1' : 'r2'; 159 | item.link.html(item.name.replace(matchRegexp, "$&")); 160 | } 161 | } 162 | if(i == searchCache.length) { 163 | searchDone(); 164 | } else { 165 | searchTimeout = setTimeout(function() { 166 | partialSearch(searchString, i); 167 | }, 0); 168 | } 169 | } 170 | 171 | function searchDone() { 172 | searchTimeout = null; 173 | highlight(); 174 | var found = $('#full_list li:visible').size(); 175 | if (found === 0) { 176 | $('#noresults').text('No results were found.'); 177 | } else { 178 | // This is read out to screen readers 179 | $('#noresults').text('There are ' + found + ' results.'); 180 | } 181 | $('#noresults').show(); 182 | $('#content').removeClass('insearch'); 183 | } 184 | 185 | function buildMatchString(searchString, event) { 186 | caseSensitiveMatch = searchString.match(/[A-Z]/) != null; 187 | var regexSearchString = RegExp.escape(searchString); 188 | if (caseSensitiveMatch) { 189 | regexSearchString += "|" + 190 | $.map(searchString.split(''), function(e) { return RegExp.escape(e); }). 191 | join('.+?'); 192 | } 193 | return regexSearchString; 194 | } 195 | 196 | function highlight() { 197 | $('#full_list li:visible').each(function(n) { 198 | $(this).removeClass('even odd').addClass(n % 2 == 0 ? 'odd' : 'even'); 199 | }); 200 | } 201 | 202 | /** 203 | * Expands the tree to the target element and its immediate 204 | * children. 205 | */ 206 | function expandTo(path) { 207 | var $target = $(document.getElementById('object_' + path)); 208 | $target.addClass('clicked'); 209 | $target.removeClass('collapsed'); 210 | $target.parentsUntil('#full_list', 'li').removeClass('collapsed'); 211 | 212 | $target.find('a.toggle').attr('aria-expanded', 'true') 213 | $target.parentsUntil('#full_list', 'li').each(function(i, el) { 214 | $(el).find('> div > a.toggle').attr('aria-expanded', 'true'); 215 | }); 216 | 217 | if($target[0]) { 218 | window.scrollTo(window.scrollX, $target.offset().top - 250); 219 | highlight(); 220 | } 221 | } 222 | 223 | function windowEvents(event) { 224 | var msg = event.data; 225 | if (msg.action === "expand") { 226 | expandTo(msg.path); 227 | } 228 | return false; 229 | } 230 | 231 | window.addEventListener("message", windowEvents, false); 232 | 233 | $(document).ready(function() { 234 | escapeShortcut(); 235 | navResizer(); 236 | enableLinks(); 237 | enableToggles(); 238 | populateSearchCache(); 239 | enableSearch(); 240 | }); 241 | 242 | })(); 243 | -------------------------------------------------------------------------------- /docs/yard/method_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Method List 19 | 20 | 21 | 22 |
          23 |
          24 |

          Method List

          25 |
          26 | 27 | 28 | Classes 29 | 30 | 31 | 32 | Methods 33 | 34 | 35 | 36 | Files 37 | 38 | 39 |
          40 | 41 | 45 |
          46 | 47 |
            48 | 49 | 50 |
          • 51 |
            52 | dimensions 53 | PixelChart 54 |
            55 |
          • 56 | 57 | 58 |
          • 59 |
            60 | #dimensions 61 | PixelChart 62 |
            63 |
          • 64 | 65 | 66 |
          • 67 |
            68 | #draw 69 | PixelChart 70 |
            71 |
          • 72 | 73 | 74 |
          • 75 |
            76 | #initialize 77 | PixelChart 78 |
            79 |
          • 80 | 81 | 82 |
          • 83 |
            84 | load_file 85 | PixelChart 86 |
            87 |
          • 88 | 89 | 90 | 91 |
          92 |
          93 | 94 | 95 | -------------------------------------------------------------------------------- /docs/yard/top-level-namespace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Top Level Namespace 8 | 9 | — Documentation by YARD 0.9.37 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
          36 | 61 | 62 |

          Top Level Namespace 63 | 64 | 65 | 66 |

          67 |
          68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
          80 | 81 |

          Defined Under Namespace

          82 |

          83 | 84 | 85 | Modules: Version 86 | 87 | 88 | 89 | Classes: PixelChart 90 | 91 | 92 |

          93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 |
          103 | 104 | 109 | 110 |
          111 | 112 | -------------------------------------------------------------------------------- /lib/pixelchart.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby internal 4 | require 'set' 5 | # Project internal 6 | require 'pixelchart/version' 7 | # External 8 | require 'rmagick' 9 | require 'vips' 10 | 11 | # PixelChart class 12 | class PixelChart 13 | # Constants 14 | include Version 15 | 16 | # A new instance of PixelChart 17 | # @param data [Array] An array containing values 18 | # (0, 1) used to generate the image. 19 | # @param width [Integer] Desired width of the image. 20 | # @param height [Integer] Desired height of the image. 21 | # @option opts [Array] :colors Must be an array containing 2 values. 22 | # Each value is either the `:random` symbol to get a random color or a 23 | # color given as RGB, so 3 integers in an array. 24 | # @option opts [Scale] :scale Scale the image to dimensions or with a ratio. 25 | # Ratio must be a positive (non-nul) float or integer, and dimensions must 26 | # be a set of width and height separated by a comma. 27 | def initialize(data, width, height, opts = {}) 28 | @width = check_int(width) 29 | @height = check_int(height) 30 | @data = check_data(data) 31 | opts[:colors] ||= [[255, 255, 255], [0, 0, 0]] # white, black 32 | check_colors(opts[:colors]) 33 | opts[:colors].each_with_index do |color, i| 34 | opts[:colors][i] = (0..2).map { |_x| rand(256) } if color == :random 35 | end 36 | @colors = opts[:colors] 37 | opts[:scale] ||= nil 38 | @scale = opts[:scale] 39 | end 40 | 41 | # Generate and save the image 42 | # @param filename [String] Name of the output image. 43 | # @param opts [Hash] options for image processing 44 | # @option opts [Symbol] :backend Image processing backend, `:rmagick` for 45 | # Rmagick/Imagemagick or `:rubyvips` for ruby-vips/libvips. 46 | def draw(filename, opts = {}) 47 | opts[:backend] ||= :rmagick 48 | backend = check_backend(opts[:backend]) 49 | case backend 50 | when :rmagick 51 | draw_rmagick(filename) 52 | when :rubyvips 53 | draw_rubyvips(filename) 54 | end 55 | end 56 | 57 | # Calculate the possible dimensions (width, height) for a given area 58 | # @param area [Integer] number of values, total of pixels 59 | # @return [Array>] Array of possible dimensions 60 | def self.dimensions(area) 61 | dim = [] 62 | (1..Math.sqrt(area).to_i).each do |x| 63 | y, rem = area.divmod(x) 64 | dim.push([x, y]) if rem.zero? 65 | end 66 | dim 67 | end 68 | 69 | # Calculate the possible dimensions (width, height) for the data of the object 70 | # @return [Array>] Array of possible dimensions 71 | def dimensions 72 | dimensions(@data.size) 73 | end 74 | 75 | # Read the input file to extract the values 76 | # @param filename [String] Name of the input file containing data. Values must 77 | # be 0, 1, true, false and separated by commas. 78 | # @return [Array] Array of 0, 1. Can be directly passed to initialize 79 | def self.load_file(filename) 80 | content = File.read(filename).gsub(/\s+/, '') 81 | data = content.split(',') 82 | data.each_with_index do |x, i| 83 | data[i] = 0 if x == '0' || x.downcase == 'false' 84 | data[i] = 1 if x == '1' || x.downcase == 'true' 85 | end 86 | data 87 | end 88 | 89 | private 90 | 91 | # Generate and save the image with Rmagick 92 | # @param filename [String] Name of the output image. 93 | def draw_rmagick(filename) 94 | img = Magick::Image.new(@width, @height) 95 | i = 0 96 | (0...@height).each do |y| 97 | (0...@width).each do |x| 98 | if [1, true].include?(@data[i]) # true color 99 | img.pixel_color(x, y, "rgb(#{@colors[1].join(',')}") 100 | else # false color 101 | img.pixel_color(x, y, "rgb(#{@colors[0].join(',')})") 102 | end 103 | i += 1 104 | end 105 | end 106 | unless @scale.nil? 107 | case @scale 108 | when Numeric 109 | raise(ArgumentError, 'Scale must be a ratio or a set of width and height') if @scale.zero? 110 | 111 | img.scale!(@scale) 112 | when Array 113 | img.scale!(@scale[0], @scale[1]) 114 | else 115 | raise(ArgumentError, 'Scale must be a ratio or a set of width and height') 116 | end 117 | end 118 | img.write(filename) 119 | end 120 | 121 | # Generate and save the image ruby-vips 122 | # @param filename [String] Name of the output image. 123 | def draw_rubyvips(filename) 124 | # true -> 1, false -> 0 125 | @data.map! { |x| x == true ? 1 : x } 126 | @data.map! { |x| x == false ? 0 : x } 127 | # make a 2D image from the data array 128 | im = Vips::Image.new_from_array(@data.each_slice(@width).to_a) 129 | im = (im == 1).ifthenelse(@colors[1], @colors[0], blend: true) 130 | if @scale.is_a?(Numeric) 131 | opts = { kernel: :nearest } 132 | im = im.resize(@scale, **opts) 133 | end 134 | im.write_to_file(filename, compression: 9, palette: true, colours: 2, Q: 0, bitdepth: 1) 135 | end 136 | 137 | # Check if the argument is an integer else raise an error 138 | # @param data [Object] The object to check 139 | # @return [Object] Untouched input object 140 | def check_int(data) 141 | raise(ArgumentError, 'Argument is not an integer') unless data.is_a?(Integer) 142 | 143 | data 144 | end 145 | 146 | # Check if the data is in the format expected by #initialize else raise an 147 | # error 148 | # @param data [Object] The object to check 149 | # @return [Object] Untouched input object 150 | def check_data(data) 151 | raise(ArgumentError, 'Argument is not an array') unless data.is_a?(Array) 152 | 153 | possible_values = PixelChart.dimensions(data.size) 154 | possible_sets = possible_values.map(&:to_set) 155 | 156 | unless possible_sets.include?(Set[@width, @height]) 157 | raise(ArgumentError, 'The number of values does not match with the possible dimensions') 158 | end 159 | 160 | data 161 | end 162 | 163 | # Check if the colors are in the format expected by #initialize else raise an 164 | # error 165 | # @param data [Object] The object to check 166 | # @return [Object] Untouched input object 167 | def check_colors(data) 168 | raise(ArgumentError, 'Argument is not an array') unless data.is_a?(Array) 169 | 170 | data.each do |item| 171 | case item 172 | when :random 173 | # nothing 174 | when Array 175 | raise(ArgumentError, 'RGB must contains 3 values') unless item.size == 3 176 | 177 | item.each do |i| 178 | raise(ArgumentError, 'RGB values are not integers') unless i.is_a?(Integer) 179 | raise(ArgumentError, 'RGB values must be between 0 and 255') unless (0..255).include?(i) 180 | end 181 | else 182 | raise(ArgumentError, 'Colors are not a RGB array or :random') 183 | end 184 | end 185 | data 186 | end 187 | 188 | # Check if the backend option is in the format expected by #draw else raise 189 | # an error 190 | # @param data [Object] The object to check 191 | # @return [Object] Untouched input object 192 | def check_backend(data) 193 | accepted_values = %i[rmagick rubyvips] 194 | raise(ArgumentError, "Backend must be #{accepted_values.join(' or ')}") unless accepted_values.include?(data) 195 | 196 | data 197 | end 198 | end 199 | -------------------------------------------------------------------------------- /lib/pixelchart/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Version 4 | VERSION = '1.3.0' 5 | end 6 | -------------------------------------------------------------------------------- /pages/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.3.0] 2 | 3 | - **Breaking change**: drop Ruby 3.0 support (EOL) 4 | - Chore: 5 | - Add support for Ruby 3.4 6 | - Update dependencies 7 | 8 | ## [1.2.0] 9 | 10 | - Deprecation: now requires ruby 3.0+ instead of 2.7+ 11 | - Chore: 12 | - Add support for Ruby 3.2 13 | - Lib: define a bit depth of 1 (fix [#1](https://github.com/noraj/PixelChart/issues/1)), even if it seems to be automatic with newer version of (ruby-)vips, to save some storage 14 | 15 | ## [1.1.0] 16 | 17 | - Dependencies: 18 | - Update to yard [v0.9.27](https://github.com/lsegal/yard/releases/tag/v0.9.27) 19 | - Move from Redcarpet to CommonMarker markdown provider 20 | - Move doc syntax from Rdoc to markdown 21 | - Move dev dependencies from gemspec to gemfile 22 | - Chore: 23 | - Add support for Ruby 3.1 24 | 25 | ## [1.0.2] 26 | 27 | - lib: code lint 28 | - dependencies: update 29 | - rubocop: new rules for new cops 30 | - deprecation: now requires ruby 2.7+ instead of 2.4+ 31 | - doc: fix a CLI value name 32 | 33 | ## [1.0.1] 34 | 35 | - doc: final documentation 36 | - gem: add metadata to gemspec 37 | 38 | ## [1.0.0] 39 | 40 | - Initial version 41 | -------------------------------------------------------------------------------- /pages/CLI.md: -------------------------------------------------------------------------------- 1 | ## Usage 2 | 3 | ``` 4 | PixelChart 5 | 6 | Usage: 7 | pixelchart draw (--width --height ) [--colors ] [--backend ] [--scale ] [--no-color] [--debug] 8 | pixelchart calc (--area |) [--no-color] [--debug] 9 | pixelchart -H | --help 10 | pixelchart -V | --version 11 | 12 | Options: 13 | Input file containing values 14 | Output image (filename) 15 | -w , --width Width of the output image (in number pixel) 16 | -h , --height Height of the output image (in number pixel) 17 | -c , --colors Colors of the image (in RGB or random) 18 | -b , --backend Image processing backend (rmagick or ruby-vips) 19 | -s , --scale Scale ratio or dimensions 20 | --area Area, number of values, total number of pixel 21 | --no-color Disable colorized output 22 | --debug Display arguments 23 | -H, --help Show this screen 24 | -V, --version Show version 25 | 26 | Examples: 27 | pixelchart draw test.csv test.png -w 100 -h 100 28 | pixelchart draw test.csv test.png -w 100 -h 100 -c 'random|125,125,125' -b rubyvips 29 | pixelchart calc test.csv 30 | pixelchart calc --area 10000 --no-color 31 | ``` 32 | 33 | ## draw 34 | 35 | The input is a file file containing data that will be used to generate the image. 36 | Values must be 0, 1, true, false and separated by commas. 37 | 38 | Then we choose the destination image and the desired dimensions. 39 | 40 | ``` 41 | $ pixelchart draw test.csv test.png -w 100 -h 100 42 | [+] Image saved 43 | ``` 44 | 45 | We can also choose the color of the pixels, the first value will be the falsy 46 | color (0 or false) and the second value will be the truthy color (1 or true). 47 | The magic `random` keyword can be used to pick a random color. Else the color 48 | value must be specified as RGB. 49 | 50 | ``` 51 | $ pixelchart draw test.csv test.png -w 100 -h 100 -c 'random|125,125,125' 52 | [+] Image saved 53 | ``` 54 | 55 | By default the Rmagick (Imagemagick) backend is used for image processing but 56 | it is also possible to use ruby-vips (libvips). 57 | 58 | Rmagick will generally output a smaller image (in bytes) but ruby-vips will 59 | operate a bit faster and requires less memory (RAM). 60 | 61 | ``` 62 | $ pixelchart draw test.csv test.png -w 100 -h 100 -b rubyvips 63 | [+] Image saved 64 | ``` 65 | 66 | If you have a dataset of 10,000 values and choose a 100x100 dimensions but feel 67 | that a 100x100 image is too small, you can use the scale option to scale the 68 | image differently (smaller, bigger, different aspect ratio). 69 | So if want a final image of 500x500 size, you can apply a x5 ratio. 70 | 71 | Note: the scale factor must be a ratio or dimensions. Ratio must be a positive 72 | (non-nul) float or integer, and dimensions must be a set of width and height 73 | separated by a comma. Eg. `10`, `4.2`, `100,500`. The aspect ratio may be 74 | different than the initial dimensions chosen, eg. `-w 100 -h 100 -s 600,70`. 75 | rubyvips backend only supports a ratio, not dimensions. 76 | 77 | ``` 78 | $ pixelchart draw test.csv test.png -w 100 -h 100 -s 5 79 | [+] Image saved 80 | ``` 81 | 82 | ## calc 83 | 84 | As `pixelchart draw` requires a width and a height that match the total number 85 | of pixels/values, I you don't know which resolutions are possible use 86 | `pixelchart calc` to display the possible dimensions. 87 | 88 | ``` 89 | $ pixelchart calc test.csv 90 | Possible dimensions: width x height or height x width 91 | 1 x 10000 92 | 2 x 5000 93 | 4 x 2500 94 | 5 x 2000 95 | 8 x 1250 96 | 10 x 1000 97 | 16 x 625 98 | 20 x 500 99 | 25 x 400 100 | 40 x 250 101 | 50 x 200 102 | 80 x 125 103 | 100 x 100 104 | 105 | $ pixelchart calc --area 775 106 | Possible dimensions: width x height or height x width 107 | 1 x 775 108 | 5 x 155 109 | 25 x 31 110 | ``` 111 | 112 | ## misc 113 | 114 | The `--no-color` flag can be used to disable the color in output but the 115 | [NO_COLOR](https://no-color.org/) environment variable is also checked. 116 | 117 | Use `export NO_COLOR` to disable color and `unset NO_COLOR` to remove this 118 | behavior. 119 | -------------------------------------------------------------------------------- /pages/Install.md: -------------------------------------------------------------------------------- 1 | ## Production 2 | 3 | ### Install from rubygems.org 4 | 5 | ``` 6 | $ gem install pixelchart 7 | ``` 8 | 9 | Gem: [pixelchart](https://rubygems.org/gems/pixelchart) 10 | 11 | ### Install from ArchLinux 12 | 13 | Manually: 14 | 15 | ``` 16 | $ git clone https://aur.archlinux.org/pixelchart.git 17 | $ cd pixelchart 18 | $ makepkg -sic 19 | ``` 20 | 21 | With an AUR helper ([Pacman wrappers](https://wiki.archlinux.org/index.php/AUR_helpers#Pacman_wrappers)), eg. pikaur: 22 | 23 | ``` 24 | $ pikaur -S pixelchart 25 | ``` 26 | 27 | AUR: [pixelchart](https://aur.archlinux.org/packages/pixelchart/) 28 | 29 | ## Development 30 | 31 | It's better to use [rbenv][rbenv] to have latests version of ruby and to avoid trashing your system ruby. 32 | 33 | [rbenv]:https://github.com/rbenv/rbenv 34 | 35 | ### Install from rubygems.org 36 | 37 | ``` 38 | $ gem install --development pixelchart 39 | ``` 40 | 41 | ### Build from git 42 | 43 | Just replace `x.x.x` with the gem version you see after `gem build`. 44 | 45 | ``` 46 | $ git clone https://github.com/noraj/PixelChart.git pixelchart 47 | $ cd pixelchart 48 | $ gem install bundler 49 | $ bundler install 50 | $ gem build pixelchart.gemspec 51 | $ gem install pixelchart-x.x.x.gem 52 | ``` 53 | 54 | Note: if an automatic install is needed you can get the version with `gem build pixelchart.gemspec | grep Version | cut -d' ' -f4`. 55 | 56 | ### Run the library/CLI in irb without installing the gem 57 | 58 | Library: 59 | 60 | ``` 61 | $ irb -Ilib -rpixelchart 62 | ``` 63 | 64 | CLI tool: 65 | 66 | ``` 67 | $ ruby -Ilib -rpixelchart bin/pixelchart 68 | ``` 69 | 70 | 71 | ### Build the gem doc 72 | 73 | **Building locally: for library users** 74 | 75 | For developers who only want to use the library. 76 | 77 | ``` 78 | $ bundle exec yard doc 79 | ``` 80 | 81 | **Building locally: for developer** 82 | 83 | For developers who want to participate to the development. 84 | 85 | ``` 86 | $ bundle exec yard doc --yardopts .yardopts-dev 87 | ``` 88 | -------------------------------------------------------------------------------- /pages/Landing.md: -------------------------------------------------------------------------------- 1 | ![](../images/logo.png) 2 | 3 | [![Gem Version](https://badge.fury.io/rb/pixelchart.svg)](https://badge.fury.io/rb/pixelchart) 4 | ![AUR version](https://img.shields.io/aur/version/pixelchart) 5 | ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/noraj/PixelChart) 6 | ![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/noraj/PixelChart) 7 | [![GitHub forks](https://img.shields.io/github/forks/noraj/PixelChart)](https://github.com/noraj/PixelChart/network) 8 | [![GitHub stars](https://img.shields.io/github/stars/noraj/PixelChart)](https://github.com/noraj/PixelChart/stargazers) 9 | [![GitHub license](https://img.shields.io/github/license/noraj/PixelChart)](https://github.com/noraj/PixelChart/blob/master/LICENSE.txt) 10 | 11 | # PixelChart 12 | 13 | > Map binary data into a beautiful chart 14 | 15 | PixelChart let's you create an image, a pixel chart / plot, based on binary data. 16 | The idea is that truthy and falsy values will be represented by a different color 17 | to be able to quickly visualize boolean values. 18 | 19 | For example: 20 | 21 | ![](../images/default.png) 22 | 23 | ## Requirements 24 | 25 | You have to install the _system_ requirements for **both** backends. 26 | 27 | - [imagemagick](https://imagemagick.org/) 28 | - [libvips](https://libvips.github.io/libvips/) 29 | 30 | Example for Linux distros: 31 | 32 | - ArchLinux: `pacman -S libvips imagemagick` 33 | - openSUSE: `zypper in libvips42 ImageMagick` 34 | - Ubuntu: `apt install libvips42 imagemagick` 35 | 36 | ## Installation 37 | 38 | ``` 39 | $ gem install pixelchart 40 | ``` 41 | 42 | See the {file:pages/Install.md the documentation} for more advanced options. 43 | 44 | ## Usage 45 | 46 | **CLI** 47 | 48 | ``` 49 | $ pixelchart draw test.csv test.png -w 100 -h 100 -s 3 50 | [+] Image saved 51 | ``` 52 | 53 | See the {file:pages/CLI.md CLI documentation}. 54 | 55 | **library** 56 | 57 | See the {PixelChart}. 58 | 59 | **scenarios** 60 | 61 | See some {file:pages/Scenarios.md scenarios} with examples. 62 | 63 | ## Documentation 64 | 65 | - [GitHub domain](https://noraj.github.io/PixelChart/yard/PixelChart.html) 66 | - [RubyDoc hosted](https://www.rubydoc.info/gems/pixelchart/PixelChart) 67 | 68 | -------------------------------------------------------------------------------- /pages/Publishing.md: -------------------------------------------------------------------------------- 1 | ## On Rubygems.org 2 | 3 | ``` 4 | $ git tag -a vx.x.x 5 | $ git push --follow-tags 6 | $ gem push pixelchart-x.x.x.gem 7 | ``` 8 | 9 | See https://guides.rubygems.org/publishing/. 10 | 11 | On new release don't forget to rebuild the library documentation: 12 | 13 | ``` 14 | $ bundle exec yard doc 15 | ``` 16 | 17 | ## On AUR 18 | 19 | ``` 20 | $ updpkgsums 21 | $ makepkg --printsrcinfo > .SRCINFO 22 | ``` 23 | -------------------------------------------------------------------------------- /pages/Scenarios.md: -------------------------------------------------------------------------------- 1 | ## Default 2 | 3 | Just display a representation of binary data. 4 | 5 | ``` 6 | pixelchart draw test.csv test.png -w 100 -h 100 -s 3 7 | ``` 8 | 9 | ![](../images/default.png) 10 | 11 | ## Prime numbers 12 | 13 | A representation of prime numbers under 10,000. 14 | 15 | ```ruby 16 | require 'pixelchart' 17 | require 'prime' 18 | 19 | primes = (1..10000).map{ |i| Prime.prime?(i) } 20 | options = { 21 | colors: [[255,255,255],[255,20,147]], 22 | scale: 5 23 | } 24 | im = PixelChart.new(primes, 100, 100, options) 25 | im.draw('primes.png') 26 | ``` 27 | 28 | ![](../images/primes.png) 29 | 30 | ## Malware hash 31 | 32 | Create a unique fingerprint image for a malware (eg. 33 | [VirusTotal](https://www.virustotal.com/gui/file/142b638c6a60b60c7f9928da4fb85a5a8e1422a9ffdc9ee49e17e56ccca9cf6e/details)). 34 | 35 | ```ruby 36 | require 'pixelchart' 37 | require 'ctf_party' 38 | 39 | sha256 = '142b638c6a60b60c7f9928da4fb85a5a8e1422a9ffdc9ee49e17e56ccca9cf6e'.hex2bin.split('') 40 | sha256.map! { |x| x.to_i } 41 | options = { 42 | colors: [:random,:random], 43 | scale: 50 44 | } 45 | im = PixelChart.new(sha256, 23, 11, options) 46 | im.draw('virus.png') 47 | ``` 48 | 49 | ![](../images/virus.png) 50 | 51 | ## Random data 52 | 53 | Create an image with random data, for example for a default profile image on a 54 | forum. 55 | 56 | ```ruby 57 | require 'pixelchart' 58 | 59 | data = (0 ... 10000).map {|_i| rand(2) } 60 | options = { 61 | colors: [[0,255,127],[0,0,0]], 62 | scale: 5 63 | } 64 | im = PixelChart.new(data, 100, 100, options) 65 | im.draw('random.png') 66 | ``` 67 | 68 | ![](../images/random.png) 69 | 70 | ## The logo 71 | 72 | The PixelChart logo was designed pixel by pixel on a 7*7 square. 73 | 74 | ``` 75 | ░▓▓▓▓▓░ 76 | ░░▓░▓▓░ 77 | ░░▓░░▓░ 78 | ░░▓▓▓▓░ 79 | ░░▓░░░░ 80 | ░░▓░░░░ 81 | ░░▓░░░░ 82 | ``` 83 | 84 | Then convert black and white pixel to 1 and 0. 85 | 86 | ``` 87 | 0,1,1,1,1,1,0 88 | 0,0,1,0,1,1,0 89 | 0,0,1,0,0,1,0 90 | 0,0,1,1,1,1,0 91 | 0,0,1,0,0,0,0 92 | 0,0,1,0,0,0,0 93 | 0,0,1,0,0,0,0 94 | ``` 95 | 96 | Inline. 97 | 98 | ``` 99 | 0,1,1,1,1,1,0,0,0,1,0,1,1,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0 100 | ``` 101 | 102 | Then map the data and choose some colors. 103 | 104 | ```ruby 105 | require 'pixelchart' 106 | 107 | data = [0,1,1,1,1,1,0,0,0,1,0,1,1,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0] 108 | options = { 109 | colors: [[0,0,0],[0,255,127]], 110 | scale: 30 111 | } 112 | im = PixelChart.new(data, 7, 7, options) 113 | im.draw('logo.png') 114 | ``` 115 | 116 | Tada! The logo is done! 117 | 118 | ![](../images/logo.png) 119 | -------------------------------------------------------------------------------- /pixelchart.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'lib/pixelchart/version' 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'pixelchart' 7 | s.version = Version::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.summary = 'Create a binary pixel map' 10 | s.description = s.summary 11 | s.authors = ['Alexandre ZANNI'] 12 | s.email = 'alexandre.zanni@engineer.com' 13 | s.homepage = 'https://noraj.github.io/PixelChart/' 14 | s.license = 'MIT' 15 | 16 | s.files = Dir['bin/*'] + Dir['lib/**/*.rb'] + ['LICENSE.txt'] 17 | s.bindir = 'bin' 18 | s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) } 19 | s.require_paths = ['lib'] 20 | 21 | s.metadata = { 22 | 'yard.run' => 'yard', 23 | 'bug_tracker_uri' => 'https://github.com/noraj/PixelChart/issues', 24 | 'changelog_uri' => 'https://github.com/noraj/PixelChart/blob/master/pages/CHANGELOG.md', 25 | 'documentation_uri' => 'https://noraj.github.io/PixelChart/yard/', 26 | 'homepage_uri' => 'https://noraj.github.io/PixelChart/', 27 | 'source_code_uri' => 'https://github.com/noraj/PixelChart', 28 | 'funding_uri' => 'https://github.com/sponsors/noraj', 29 | 'rubygems_mfa_required' => 'true' 30 | } 31 | 32 | s.required_ruby_version = ['>= 3.1.0', '< 4.0'] 33 | 34 | s.add_runtime_dependency('docopt', '~> 0.6') # for argument parsing 35 | s.add_runtime_dependency('paint', '~> 2.3') # for colorized output 36 | s.add_runtime_dependency('rmagick', '~> 6.0') # image processing (backend 1) 37 | s.add_runtime_dependency('ruby-vips', '~> 2.2') # image processing (backend 2) 38 | end 39 | --------------------------------------------------------------------------------