ico 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c064583f3bb03c8b2c7a4694c398cf335900de69
4
+ data.tar.gz: 3650715d02a41fe6ffc78af9dca2d40fedff8160
5
+ SHA512:
6
+ metadata.gz: db45233ea75ef0015f5e6adc091ed1747bdb1cfeb13fc947246772dae4e38e67354221f3cd70a858dd4c5efe7881f9ca620459e515538a19601105f162c27f36
7
+ data.tar.gz: 0512d897448380af03c439e6ad59717478cf3a860acaf2ea478edd9ddb7aa9ba71a8ebceb4ba0b93c34842bc6ec170129bd2aaa03fd62f53aada4697c83678e1
@@ -0,0 +1,25 @@
1
+ # -*- ruby -*-
2
+
3
+ require "autotest/restart"
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.testlib = "minitest/unit"
7
+ #
8
+ # at.extra_files << "../some/external/dependency.rb"
9
+ #
10
+ # at.libs << ":../some/external"
11
+ #
12
+ # at.add_exception "vendor"
13
+ #
14
+ # at.add_mapping(/dependency.rb/) do |f, _|
15
+ # at.files_matching(/test_.*rb$/)
16
+ # end
17
+ #
18
+ # %w(TestA TestB).each do |klass|
19
+ # at.extra_class_map[klass] = "test/test_misc.rb"
20
+ # end
21
+ # end
22
+
23
+ # Autotest.add_hook :run_command do |at|
24
+ # system "rake build"
25
+ # end
@@ -0,0 +1,54 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
51
+
52
+ .DS_Store
53
+ *.swp
54
+ *.swo
@@ -0,0 +1,11 @@
1
+ test/*
2
+ bin/*
3
+ .git/*
4
+
5
+ *.swp
6
+ .*.swp
7
+ **/*.swp
8
+ **/.*.swp
9
+
10
+ .DS_Store
11
+ **/.DS_Store
data/Gemfile ADDED
@@ -0,0 +1,21 @@
1
+ # -*- ruby -*-
2
+
3
+ # DO NOT EDIT THIS FILE. Instead, edit Rakefile, and run `rake bundler:gemfile`.
4
+
5
+ source "https://rubygems.org/"
6
+
7
+ gem "chunky_png", "1.3.8"
8
+ gem "bit-struct", "0.15.0"
9
+ gem "bmp-ruby", "0.1.1"
10
+
11
+ gem "minitest", "~>5.10", :group => [:development, :test]
12
+ gem "hoe-yard", ">=0.1.3", :group => [:development, :test]
13
+ gem "hoe-ignore", "~>1.0", :group => [:development, :test]
14
+ gem "hoe-bundler", "~>1.2", :group => [:development, :test]
15
+ gem "hoe-gemspec", "~>1.0", :group => [:development, :test]
16
+ gem "hoe-git", "~>1.6", :group => [:development, :test]
17
+ gem "yard", "~>0.8", :group => [:development, :test]
18
+ gem "redcarpet", "~>3.3", :group => [:development, :test]
19
+ gem "hoe", "~>3.16", :group => [:development, :test]
20
+
21
+ # vim: syntax=ruby
@@ -0,0 +1,6 @@
1
+ === 0.0.1 / 2017-04-01
2
+
3
+ * It's alive!
4
+
5
+ * Bornday!
6
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Bordee Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ .autotest
2
+ .gitignore
3
+ .hoeignore
4
+ Gemfile
5
+ History.txt
6
+ LICENSE
7
+ Manifest.txt
8
+ README.md
9
+ Rakefile
10
+ lib/core_ext/array/extract_options.rb
11
+ lib/ico.rb
12
+ lib/ico/icon_dir.rb
13
+ lib/ico/icon_dir_entry.rb
14
+ lib/ico/icon_image.rb
15
+ lib/ico/utils.rb
16
+ lib/ico/version.rb
17
+ lib/tasks/ico.rake
@@ -0,0 +1,107 @@
1
+ # ico
2
+
3
+ ICO file format in Ruby
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ require 'ico'
9
+
10
+ # (soon)
11
+ ```
12
+
13
+ ## Installation
14
+
15
+ Command Line
16
+
17
+ ```
18
+ gem install ico
19
+ ```
20
+
21
+ Gemfile
22
+
23
+ ```
24
+ gem "ico", "~>0.1"
25
+ ```
26
+
27
+ ## Development
28
+
29
+ (soon)
30
+
31
+ For more info, see: https://en.wikipedia.org/wiki/ICO_(file_format)
32
+
33
+ ### Requirements
34
+
35
+ * [Bit-Struct](https://github.com/vjoel/bit-struct)
36
+ * [BMP](https://github.com/bordeeinc/bmp-ruby)
37
+
38
+ ### Dev Requirements
39
+
40
+ * [hoe](https://github.com/seattlerb/hoe) gem manager
41
+ * [hoe-bundler] may need `gem install hoe-bundler` installation before using `rake bundler:gemfile`
42
+ * [YARD](http://yardoc.org) docs
43
+ * [redcarpet](https://github.com/vmg/redcarpet) for yardoc
44
+
45
+ [hoe-bundler]: https://github.com/flavorjones/hoe-bundler
46
+
47
+ ### Testing
48
+
49
+ Tests written with [minitest]
50
+
51
+ ```
52
+ rake test
53
+ ```
54
+
55
+ [minitest]: https://github.com/seattlerb/minitest
56
+
57
+ ### Contributing
58
+
59
+ Send tested code.
60
+ Thank you, [contributors]!
61
+
62
+ [contributors]: https://github.com/bordeeinc/ico/graphs/contributors
63
+
64
+ ### To Do
65
+
66
+ * (soon)
67
+
68
+ ## License
69
+
70
+ MIT License
71
+
72
+ Copyright (c) 2017 Bordee Inc.
73
+
74
+ Permission is hereby granted, free of charge, to any person obtaining
75
+ a copy of this software and associated documentation files (the
76
+ 'Software'), to deal in the Software without restriction, including
77
+ without limitation the rights to use, copy, modify, merge, publish,
78
+ distribute, sublicense, and/or sell copies of the Software, and to
79
+ permit persons to whom the Software is furnished to do so, subject to
80
+ the following conditions:
81
+
82
+ The above copyright notice and this permission notice shall be
83
+ included in all copies or substantial portions of the Software.
84
+
85
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
88
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
89
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
90
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
91
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
92
+
93
+ ## About
94
+
95
+ ![bordee](http://bordee.com/src/img/surf-with-bordee-github.png)
96
+
97
+ ICO is maintained and funded by Bordee Inc.
98
+ The names and logos for Bordee are trademarks of [Bordee Inc.][bordeeinc]
99
+
100
+ [bordeeinc]: http://bordee.com
101
+
102
+ We love open source software!
103
+ See [our other projects][bordee-github]
104
+ and [check out Seattle.rb!][community]
105
+
106
+ [bordee-github]: https://github.com/bordeeinc
107
+ [community]: https://seattlerb.org
@@ -0,0 +1,67 @@
1
+ # -*- ruby -*-
2
+
3
+ require "rubygems"
4
+ require "hoe"
5
+ require './lib/ico/version.rb'
6
+
7
+ Hoe.plugin :gemspec
8
+ Hoe.plugin :minitest
9
+ Hoe.plugin :yard
10
+ Hoe.plugin :bundler
11
+ Hoe.plugin :git
12
+ Hoe.plugin :ignore
13
+
14
+ Hoe.spec "ico" do
15
+ developer("So Awesome Man", "callme@1800aweso.me")
16
+
17
+ license "MIT" # this matches the license in the README
18
+
19
+ self.email = 'support@bordee.com'
20
+
21
+ self.name = 'ico'
22
+ self.version = ICO::VERSION
23
+ self.summary = 'ICO file format in Ruby'
24
+ self.description = self.summary
25
+ self.urls = ['https://github.com/bordeeinc/ico']
26
+ self.testlib = :minitest
27
+ self.readme_file = 'README.md'
28
+ self.history_file = 'History.txt'
29
+
30
+ # third-party
31
+ self.yard_title = self.name
32
+ self.yard_markup = 'markdown'
33
+
34
+ self.extra_deps += [
35
+ ['chunky_png', '1.3.8'],
36
+ ['bit-struct', '0.15.0'],
37
+ ['bmp-ruby', '0.1.1']
38
+ ]
39
+
40
+ self.extra_dev_deps += [
41
+ ["hoe-yard", "~> 0.1"],
42
+ ["hoe-ignore", "~> 1.0"],
43
+ ["hoe-bundler", "~> 1.2"],
44
+ ["hoe-gemspec", "~> 1.0"],
45
+ ["hoe-git", "~> 1.6"],
46
+ ["minitest", "~> 5.9"],
47
+ ["yard", "~> 0.8"],
48
+ ["redcarpet", "~> 3.3"] # yard/markdown
49
+ ]
50
+
51
+ self.clean_globs += [
52
+ '.yardoc',
53
+ 'vendor',
54
+ 'Gemfile.lock',
55
+ '.bundle',
56
+ ]
57
+
58
+ self.spec_extras = {
59
+ :required_ruby_version => '>= 1.9.2'
60
+ }
61
+ end
62
+
63
+ # require rake tasks
64
+ current_dir = File.expand_path(File.dirname(__FILE__))
65
+ Dir.glob(File.join(current_dir, 'lib/tasks/*.rake')).each {|r| import r}
66
+
67
+ # vim: syntax=ruby
@@ -0,0 +1,31 @@
1
+ # @note copied from the main Rails repo instead of adding via active_support
2
+ # @see https://github.com/rails/rails/blob/794a70f94485fb64ed1c49ba8532895306e2001c/activesupport/lib/active_support/core_ext/array/extract_options.rb
3
+ class Hash
4
+ # By default, only instances of Hash itself are extractable.
5
+ # Subclasses of Hash may implement this method and return
6
+ # true to declare themselves as extractable. If a Hash
7
+ # is extractable, Array#extract_options! pops it from
8
+ # the Array when it is the last element of the Array.
9
+ def extractable_options?
10
+ instance_of?(Hash)
11
+ end
12
+ end
13
+
14
+ class Array
15
+ # Extracts options from a set of arguments. Removes and returns the last
16
+ # element in the array if it's a hash, otherwise returns a blank hash.
17
+ #
18
+ # def options(*args)
19
+ # args.extract_options!
20
+ # end
21
+ #
22
+ # options(1, 2) # => {}
23
+ # options(1, 2, a: :b) # => {:a=>:b}
24
+ def extract_options!
25
+ if last.is_a?(Hash) && last.extractable_options?
26
+ pop
27
+ else
28
+ {}
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,109 @@
1
+ require 'bmp'
2
+
3
+ require 'core_ext/array/extract_options.rb' unless Array.method_defined?(:extract_options!)
4
+ require 'bit-struct' unless Object.const_defined?(:BitStruct)
5
+ require 'chunky_png' unless Object.const_defined?(:ChunkyPNG)
6
+
7
+ require 'ico/version'
8
+ require 'ico/utils'
9
+ require 'ico/icon_dir'
10
+ require 'ico/icon_dir_entry'
11
+ require 'ico/icon_image'
12
+
13
+ #
14
+ # @see https://en.wikipedia.org/wiki/ICO_(file_format)
15
+ #
16
+ module ICO
17
+
18
+ # make all methods class-methods
19
+ extend self
20
+
21
+ # create ICO object
22
+ #
23
+ # @param filename_array [String, Array<String>] filename, or array of filenames
24
+ # @return [BitStruct]
25
+ #
26
+ def new(filename_array)
27
+ raise ArgumentError unless (filename_array.is_a?(Array) || filename_array.is_a?(String))
28
+
29
+ # ensure non-nested array
30
+ fn_array = [filename_array].flatten
31
+
32
+ # ensure .png extensions
33
+ raise "more than PNG format files in #{filename_array.inspect}" if ICO::Utils.contains_other_than_ext?(fn_array, :png)
34
+
35
+ icon_dir = ICO::IconDir.new
36
+ icon_dir.image_count = fn_array.length
37
+ offset = ICO::IconDir::LENGTH_IN_BYTES + (fn_array.length * ICO::IconDirEntry::LENGTH_IN_BYTES)
38
+ entries = fn_array.inject({}) {|h,fn| h[fn] = ICO::IconDirEntry.new; h}
39
+ images = fn_array.inject({}) {|h,fn| h[fn] = ICO::IconImage.new; h}
40
+ images_hash = ICO::Utils.sizes_hash(fn_array, true, true)
41
+
42
+ images_hash.each do |size,fn|
43
+ img = ChunkyPNG::Image.from_file(fn)
44
+ img_hash = BMP::Utils.parse_image(img)
45
+
46
+ entry = entries[fn]
47
+ image = images[fn]
48
+
49
+ entry.width = img_hash[:image_width]
50
+ entry.height = img_hash[:image_height]
51
+ entry.bytes_in_res = img_hash[:file_size]
52
+ entry.image_offset = offset
53
+
54
+ image.width = img_hash[:image_width]
55
+ image.height = (img_hash[:image_height] * 2)
56
+ image.size_image = img_hash[:image_size]
57
+ image.data = img_hash[:pixel_array]
58
+
59
+ offset += img_hash[:file_size]
60
+ end
61
+
62
+ # IconDirEntry section as binary data string
63
+ icon_dir.data = images_hash.inject('') {|str,(k,v)| str += entries.fetch(v); str}
64
+
65
+ # IconImage section as binary data string
66
+ icon_dir.data += images_hash.inject('') {|str,(k,v)| str += images.fetch(v); str}
67
+
68
+ icon_dir
69
+ end
70
+
71
+ # PNG to ICO
72
+ #
73
+ # @param input_filename [Array<String>,String] "/path/to/example.png" OR ["/path/to/example.png", ...]
74
+ # @param output_filename [String] "/path/to/example_generated.ico"
75
+ # @return [String] filename of generated ico
76
+ #
77
+ def png_to_ico(filename_array, output_filename, overwrite=false)
78
+ ico = ICO.new(filename_array)
79
+
80
+ unless overwrite
81
+ raise "File exists: #{output_filename}" if File.exist?(output_filename)
82
+ end
83
+
84
+ IO.write(output_filename, ico)
85
+ end
86
+
87
+ # PNG to ICO force overwrite output_filename
88
+ #
89
+ def png_to_ico!(filename_array, output_filename)
90
+ png_to_ico(filename_array, output_filename, true)
91
+ end
92
+
93
+ # PNG to resized PNGs to ICO
94
+ #
95
+ # @param input_filename [String] "/path/to/example.png"
96
+ # @param sizes_array [Array<Array<Integer,Integer]>>, Array<Integer>]
97
+ # rectangles use Array with XY: `[x,y]`
98
+ # squares use single Integer `N`
99
+ # mixed indices is valid
100
+ # example: `[24, [24,24], [480,270], 888] # a[0] => 24x24; a[1] => 24x24; a[2] => 480x270; a[3] => 888x888`
101
+ # @param output_filename [String] "/path/to/example.ico"
102
+ # @return [String] filename of generated ico
103
+ #
104
+ def png_resize_to_ico(input_filename, sizes_array, output_filename)
105
+ output_dir = ICO::Utils.png_to_sizes(input_filename, sizes_array)
106
+ filename_array = Dir.glob(File.join(output_dir, '**/*'))
107
+ png_to_ico(filename_array, output_filename)
108
+ end
109
+ end
@@ -0,0 +1,17 @@
1
+ module ICO
2
+ class IconDir < BitStruct
3
+ LENGTH_IN_BYTES = 6
4
+
5
+ default_options :endian => :little
6
+
7
+ unsigned :reserved, 16, 'Reserved. Must always be 0.', :default => 0
8
+
9
+ unsigned :type, 16, 'Specifies image type: 1 for icon (.ICO) ' +
10
+ 'image, 2 for cursor (.CUR) image. Other ' +
11
+ 'values are invalid.', :default => 1
12
+
13
+ unsigned :image_count, 16, 'Specifies number of images in the file.', :default => 0
14
+
15
+ rest :data, 'IconDirEntry + IconImage sections as binary data strings'
16
+ end
17
+ end
@@ -0,0 +1,40 @@
1
+ module ICO
2
+ class IconDirEntry < BitStruct
3
+ LENGTH_IN_BYTES = 16
4
+
5
+ default_options :endian => :little
6
+
7
+ unsigned :width, 8, 'Specifies image width in pixels. Can be ' +
8
+ 'any number between 0 and 255. Value 0 ' +
9
+ 'means image width is 256 pixels.'
10
+
11
+ unsigned :height, 8, 'Specifies image height in pixels. Can be ' +
12
+ 'any number between 0 and 255. Value 0 ' +
13
+ 'means image width is 256 pixels.'
14
+
15
+ unsigned :color_count, 8, 'Specifies number of colors in the color ' +
16
+ 'palette. Should be 0 if the image does ' +
17
+ 'not use a color palette.', :default => 0
18
+
19
+ unsigned :reserved, 8, 'Reserved. Should be 0. [NOTES 2]', :default => 0
20
+
21
+ unsigned :planes, 16, 'In ICO format: Specifies color planes. ' +
22
+ "Should be 0 or 1.\n" +
23
+ 'In CUR format: Specifies the horizontal ' +
24
+ 'coordinates of the hotspot in number of ' +
25
+ 'pixels from the left.', :default => 1
26
+
27
+ unsigned :bit_count, 16, 'In ICO format: Specifies bits per pixel. ' +
28
+ "[NOTES 4]\n" +
29
+ 'In CUR format: Specifies the vertical ' +
30
+ 'coordinates of the hotspot in number of ' +
31
+ 'pixels from the top.', :default => 32
32
+
33
+ unsigned :bytes_in_res, 32, 'Specifies the size of the image\'s data ' +
34
+ 'in bytes'
35
+
36
+ unsigned :image_offset, 32, 'Specifies the offset of BMP or PNG data ' +
37
+ 'from the beginning of the ICO/CUR file'
38
+
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ module ICO
2
+ class IconImage < BitStruct
3
+ HEADER_SIZE_IN_BYTES = 40
4
+
5
+ default_options :endian => :little
6
+
7
+ # BITMAPINFOHEADER
8
+ unsigned :header_size, 32, nil, :default => HEADER_SIZE_IN_BYTES
9
+ unsigned :width, 32
10
+ unsigned :height, 32
11
+ unsigned :planes, 16, nil, :default => 1
12
+ unsigned :bit_count, 16, nil, :default => 32
13
+ unsigned :compression, 32, nil, :default => 0
14
+ unsigned :size_image, 32
15
+ unsigned :x_pixels_per_meter, 32, nil, :default => 5669
16
+ unsigned :y_pixels_per_meter, 32, nil, :default => 5669
17
+ unsigned :colors_used, 32, nil, :default => 0
18
+ unsigned :colors_important, 32, nil, :default => 0
19
+
20
+ # IMAGEDATA
21
+ rest :data, '32bit RGBQUAD written: BGRA'
22
+ end
23
+ end
@@ -0,0 +1,145 @@
1
+ module ICO
2
+ module Utils
3
+ APPEND_FILE_FORMAT = '-%<x>dx%<y>d'
4
+
5
+ extend self
6
+
7
+
8
+ # @see https://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-select
9
+ # @see https://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-reject
10
+ # @param filename_array [Array<String>] array of filenames with expanded paths
11
+ # @param enum [String,Symbol] accepts: `:select` or `:reject`
12
+ # @return [Array]
13
+ def filter_dir(filename_array, enum)
14
+ raise ArgumentError unless filename_array.is_a? Array
15
+ raise ArgumentError unless enum.is_a?(String) || enum.is_a?(Symbol)
16
+ raise ArgumentError unless enum.to_s =~ /reject|select/
17
+
18
+ filename_array.send(enum).each {|fn| Dir.exist?(fn)}
19
+ end
20
+
21
+ def filter_ext(filename_array, enum, extname, include_dirs=false)
22
+ raise ArgumentError unless filename_array.is_a? Array
23
+ raise ArgumentError unless enum.is_a?(String) || enum.is_a?(Symbol)
24
+ raise ArgumentError unless enum.to_s =~ /reject|select/
25
+ raise ArgumentError unless extname.is_a?(String) || extname.is_a?(Symbol)
26
+
27
+ # reject dirs for accuracy
28
+ tmp_array = filter_dir(filename_array, :reject)
29
+
30
+ # operation on array
31
+ tmp_array = tmp_array.send(enum).each {|fn| format_ext(File.extname(fn)) == format_ext(extname)}
32
+
33
+ include_dirs ? tmp_array + filter_dir(filename_array, :select) : tmp_array
34
+ end
35
+
36
+ def format_ext(extname, overwrite=false)
37
+ raise ArgumentError unless extname.is_a?(String) || extname.is_a?(Symbol)
38
+
39
+ temp_str = extname.to_s.sub(/\A\.?/, '.').downcase
40
+
41
+ extname = tmp_str if overwrite
42
+
43
+ temp_str
44
+ end
45
+
46
+ def format_ext!(extname)
47
+ format_ext(extname, true)
48
+ end
49
+
50
+ def contains_dir?(filename_array)
51
+ filename_dir(filename_array, :select).any?
52
+ end
53
+
54
+ def contains_other_than_ext?(filename_array, extname)
55
+ filter_ext(filename_array, :reject, extname, true).any?
56
+ end
57
+
58
+ # http://stackoverflow.com/questions/2450906/is-there-a-simple-way-to-get-image-dimensions-in-ruby#2450931
59
+ def get_size(image_filename)
60
+ IO.read(image_filename)[0x10..0x18].unpack('NN')
61
+ end
62
+
63
+ def sizes_hash(filename_array, sort=false, reverse=false)
64
+ raise ArgumentError unless filename_array.is_a? Array
65
+
66
+ tmp_hash = filename_array.inject({}) {|h,fn| h[get_size(fn)] = fn; h}
67
+
68
+ case
69
+ when sort && !reverse
70
+ return tmp_hash.sort.to_h
71
+
72
+ when reverse && !sort
73
+ return tmp_hash.to_a.reverse.to_h
74
+
75
+ when sort && reverse
76
+ return tmp_hash.sort.reverse.to_h
77
+
78
+ else
79
+ return tmp_hash
80
+ end
81
+ end
82
+
83
+
84
+ # resize PNG file and write new sizes to directory
85
+ #
86
+ # @see https://ruby-doc.org/core-2.2.0/Kernel.html#method-i-sprintf
87
+ # @param input_filename [String] input filename; required: file is PNG file format
88
+ # @param sizes_array [Array<Array<Integer,Integer]>>, Array<Integer>]
89
+ # rectangles use Array with XY: `[x,y]`
90
+ # squares use single Integer `N`
91
+ # mixed indices is valid
92
+ # example: `[24, [24,24], [480,270], 888] # a[0] => 24x24; a[1] => 24x24; a[2] => 480x270; a[3] => 888x888`
93
+ # @param output_dirname [String] (optional)
94
+ # directory name including expanded path
95
+ # default: new dir named input_filename's basename + "_sizes" in same dir as input_filename
96
+ # @param append_filenames [String] (optional,required-with-supplied-default)
97
+ # append resized filenames with Kernel#sprintf format_string
98
+ # available args: `{:x => N, :y => N}`
99
+ # default: `"-%<x>dx%<y>d"`
100
+ # @param force_overwrite [Boolean] overwrite existing resized images
101
+ # @param clear [Boolean] default: `true`
102
+ # @param force_clear [Boolean] clear output_dirname of contents before write; default: false
103
+ # @return [String] output_dirname; default: false
104
+ def png_to_sizes(input_filename, sizes_array, output_dirname=nil, append_filenames=APPEND_FILE_FORMAT, force_overwrite=false, clear=true, force_clear=false)
105
+ basename = File.basename(input_filename, '.*')
106
+
107
+ output_dirname ||= File.join(File.expand_path(File.dirname(input_filename)), "#{basename}_sizes")
108
+
109
+ # ensure dir exists
110
+ FileUtils.mkdir_p(output_dirname)
111
+
112
+ # ensure dir empty
113
+ if clear
114
+ filename_array = Dir.glob(File.join(output_dirname, '**/*'))
115
+
116
+ unless force_clear
117
+ # protect from destructive action
118
+ raise "more than ICO format files in #{output_dirname}" if contains_other_than_ext?(filename_array, :ico)
119
+ end
120
+
121
+ FileUtils.rm_rf(filename_array)
122
+ end
123
+
124
+ # import base image
125
+ img = ChunkyPNG::Image.from_file(input_filename)
126
+
127
+ # resize
128
+ sizes_array.each do |x,y|
129
+ y ||= x
130
+ img_attrs = {:x => x, :y => y}
131
+ bn = basename + Kernel.sprintf(append_filenames, img_attrs)
132
+ fn = File.join(output_dirname, "#{bn}.png")
133
+ img_out = img.resample_nearest_neighbor(x, y)
134
+
135
+ unless force_overwrite
136
+ raise "File exists: #{fn}" if File.exist?(fn)
137
+ end
138
+
139
+ IO.write(fn, img_out)
140
+ end
141
+
142
+ return output_dirname
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,3 @@
1
+ module ICO
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,48 @@
1
+ #require 'FileUtils' unless Object.const_defined?('FileUtils')
2
+ #
3
+ ## in lib/tasks/ico.rake
4
+ #CURRENT_DIR = File.expand_path(File.dirname(__FILE__))
5
+ #LIB_DIR = File.join(CURRENT_DIR, '..')
6
+ #
7
+ #namespace :ico do
8
+ #
9
+ # desc 'Transpile to-ico/* and write to lib/to-ico.js (requires browserify npm)'
10
+ # task :transpile do
11
+ #
12
+ # # ensure remove
13
+ # output_filename = File.join(LIB_DIR, 'to-ico.js')
14
+ # ico_config = File.join(LIB_DIR, '?????browserify.config.ruby.js')
15
+ #
16
+ # # ensure remove
17
+ # FileUtils.rm_f output_filename
18
+ # raise "ERROR: could not delete previous file in output path: #{output_filename}" if File.exist?(output_filename)
19
+ #
20
+ # puts "cd to-ico && ?????"
21
+ # puts `????`
22
+ #
23
+ # # ensure exists
24
+ # raise "ERROR: could not find file in output path: #{output_filename}" unless File.exist?(output_filename)
25
+ #
26
+ # puts "ico:transpile => done; success!"
27
+ # end
28
+ #
29
+ #
30
+ # desc 'Copy `lib/to-ico/browserify.config.ruby.js` to `to-ico/browserify/`'
31
+ # task :copy_config do
32
+ #
33
+ # # ensure remove
34
+ # output_filename = File.join(LIB_DIR, '../to-ico/browserify.config.ruby.js')
35
+ # ico_config = File.join(LIB_DIR, 'browserify/browserify.config.ruby.js')
36
+ #
37
+ # FileUtils.rm_f output_filename
38
+ # raise "ERROR: could not delete previous file in output path: #{output_filename}" if File.exist?(output_filename)
39
+ #
40
+ # FileUtils.cp(ico_config, output_filename)
41
+ #
42
+ # # ensure exists
43
+ # raise "ERROR: could not find file in output path: #{output_filename}" unless File.exist?(output_filename)
44
+ #
45
+ # puts "ico:copy_config => done; success!"
46
+ # end
47
+ #
48
+ #end
metadata ADDED
@@ -0,0 +1,236 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ico
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - So Awesome Man
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chunky_png
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.3.8
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.3.8
27
+ - !ruby/object:Gem::Dependency
28
+ name: bit-struct
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.15.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.15.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bmp-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.10'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: hoe-yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.1.3
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.1.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: hoe-ignore
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: hoe-bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.2'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.2'
111
+ - !ruby/object:Gem::Dependency
112
+ name: hoe-gemspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: hoe-git
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.6'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.6'
139
+ - !ruby/object:Gem::Dependency
140
+ name: yard
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.8'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.8'
153
+ - !ruby/object:Gem::Dependency
154
+ name: redcarpet
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '3.3'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '3.3'
167
+ - !ruby/object:Gem::Dependency
168
+ name: hoe
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '3.16'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '3.16'
181
+ description: ICO file format in Ruby
182
+ email: support@bordee.com
183
+ executables: []
184
+ extensions: []
185
+ extra_rdoc_files:
186
+ - History.txt
187
+ - Manifest.txt
188
+ - README.md
189
+ files:
190
+ - ".autotest"
191
+ - ".gitignore"
192
+ - ".hoeignore"
193
+ - Gemfile
194
+ - History.txt
195
+ - LICENSE
196
+ - Manifest.txt
197
+ - README.md
198
+ - Rakefile
199
+ - lib/core_ext/array/extract_options.rb
200
+ - lib/ico.rb
201
+ - lib/ico/icon_dir.rb
202
+ - lib/ico/icon_dir_entry.rb
203
+ - lib/ico/icon_image.rb
204
+ - lib/ico/utils.rb
205
+ - lib/ico/version.rb
206
+ - lib/tasks/ico.rake
207
+ homepage: https://github.com/bordeeinc/ico
208
+ licenses:
209
+ - MIT
210
+ metadata: {}
211
+ post_install_message:
212
+ rdoc_options:
213
+ - "--title"
214
+ - ico
215
+ - "--markup"
216
+ - markdown
217
+ - "--quiet"
218
+ require_paths:
219
+ - lib
220
+ required_ruby_version: !ruby/object:Gem::Requirement
221
+ requirements:
222
+ - - ">="
223
+ - !ruby/object:Gem::Version
224
+ version: 1.9.2
225
+ required_rubygems_version: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ requirements: []
231
+ rubyforge_project:
232
+ rubygems_version: 2.2.5
233
+ signing_key:
234
+ specification_version: 4
235
+ summary: ICO file format in Ruby
236
+ test_files: []