ico 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []