cgbi_to_png 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f4ad6bde43d1022a868cb745aadaf43a1e3ecbeb
4
+ data.tar.gz: a5bccff0fd3ed467a7fb7ecdbb7fd4def2fb961c
5
+ SHA512:
6
+ metadata.gz: c1791c19c73e9a83a995704bf1d63bc1e97bad31470f68c13e7547abdc248a90e3a61063d48d2b6512f1b26fbfd648463d41de4e528f0eb327ea9e0381e0fa66
7
+ data.tar.gz: 7bfc27e6f153637b96021ad00396cf708eb4d52a1fd78123037ee276e6046545661ae1e9fa92940dcd56e9c3a97c81d8a8623a6e7a0430fdfb9af90b10acbdb8
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Jon Appelberg
2
+
3
+ MIT License
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
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # cgbi_to_png
2
+
3
+ This Gem allows converting CgBI (Apple's optimized PNG) images into standard PNG images. See http://iphonedevwiki.net/index.php/CgBI_file_format
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'cgbi_to_png'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install cgbi_to_png
18
+
19
+ ## Usage
20
+
21
+ opng = CgBItoPNG::from_file('apple-optimized-image.png')
22
+ opng.unoptimize
23
+ opng.to_file('standard-image.png')
24
+
25
+ ## Limitations
26
+
27
+ - Currently this Gem only supports 8bit color depth and Color Type '6' (RGB + alpha)
28
+ - Interlacing is not supported
29
+ - Alpha channel correction is not performed
30
+
31
+ Taking into account the expected usage of this Gem (viewing iOS optimized icons) these limitations are probably not a problem.
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it ( http://github.com/jappelbe/cgbi_to_png/fork )
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cgbi_to_png/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cgbi_to_png"
8
+ spec.version = OptimizedPngs::VERSION
9
+ spec.authors = ["Jon Appelberg"]
10
+ spec.summary = %q{Convert Apple optimized PNG images to standard PNG images}
11
+ spec.description = %q{This Gem allows converting CgBI (Apple's optimized PNG) images into 'standard' PNG images. See http://iphonedevwiki.net/index.php/CgBI_file_format}
12
+ spec.homepage = "http://github.com/jappelbe/cgbi_to_png"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.5"
21
+ spec.add_development_dependency "rake"
22
+ end
@@ -0,0 +1,104 @@
1
+ require 'zlib'
2
+
3
+ module CgBItoPNG
4
+ class Chunk
5
+ attr_reader :type, :data
6
+
7
+ def initialize(length, type, crc, data)
8
+ raise ArgumentError.new("Length-field does not match length of data, specified '#{length}', got '#{data.length}'") unless data.length == length
9
+ @type = type
10
+ @data = data
11
+ @crc = crc
12
+ end
13
+
14
+ def get_dimensions
15
+ raise "No dimensions in this chunk (Expected 'IHDR', got '#{@type}')" unless @type == 'IHDR'
16
+ ihdr = {}
17
+ ihdr[:width] = @data[0...4].unpack(BIG_ENDIAN_LONG).first
18
+ ihdr[:height] = @data[4...8].unpack(BIG_ENDIAN_LONG).first
19
+ ihdr[:bit_depth] = @data[8].unpack(UINT_8).first
20
+ ihdr[:color_type] = @data[9].unpack(UINT_8).first
21
+ ihdr[:compression_method] = @data[10].unpack(UINT_8).first
22
+ ihdr[:filter_method] = @data[11].unpack(UINT_8).first
23
+ ihdr[:interlace_method] = @data[12].unpack(UINT_8).first
24
+
25
+ raise "Not supported bit depth: '#{ihdr[:bit_depth]}'" unless ihdr[:bit_depth] == 8
26
+ raise "Not supported bit depth: '#{ihdr[:color_type]}'" unless ihdr[:color_type] == 6
27
+ raise "Not supported bit depth: '#{ihdr[:interlace_method]}'" unless ihdr[:interlace_method] == 0
28
+ ihdr
29
+ end
30
+
31
+ # Need to change RGBA -> BGRA
32
+ def self.replace_colors(blob, width, color_depth)
33
+ fixed_blob = ""
34
+ while blob.size > 0
35
+ scanline_bytes = width * color_depth + 1
36
+ scanline = blob.slice!(0, scanline_bytes)
37
+ filterbyte = scanline.slice!(0, 1).b # filter byte at start of scanline
38
+ fixed_blob << filterbyte
39
+ while scanline.size > 0
40
+ slice = scanline.slice!(0, 4).b
41
+
42
+ # Red Gren Blue Alpha
43
+ [2, 1, 0, 3].each do |color_idx|
44
+ fixed_blob << slice[color_idx]
45
+ end
46
+ end
47
+ end
48
+ fixed_blob
49
+ end
50
+
51
+ def replace_data_with_blob(blob)
52
+ @data = Zlib::Deflate.deflate(blob, Zlib::FINISH)
53
+ end
54
+
55
+ def make_crc
56
+ crc = Zlib::crc32(@type)
57
+ Zlib::crc32(@data, crc)
58
+ end
59
+
60
+ def to_blob
61
+ blob = [@data.length].pack(BIG_ENDIAN_LONG)
62
+ blob << @type
63
+ blob << @data
64
+ blob << [self.make_crc].pack(BIG_ENDIAN_LONG)
65
+ end
66
+
67
+ def to_s
68
+ "Chunk type=#{@type}, #{@data.length}bytes"
69
+ end
70
+
71
+ def self.join_and_unoptimize_idat(chunks, image_width, color_depth)
72
+ combined_data = ''
73
+ chunks.each do |chunk|
74
+ combined_data << chunk.data
75
+ end
76
+ inflator = Zlib::Inflate.new(-Zlib::MAX_WBITS)
77
+ blob = inflator.inflate(combined_data)
78
+
79
+ inflator.close
80
+
81
+ fixed_data = self.replace_colors(blob, image_width, color_depth)
82
+
83
+ chunks.first.replace_data_with_blob(fixed_data)
84
+ chunks.first
85
+ end
86
+
87
+ def self.get_chunks(data_blob)
88
+ pngheader = PNG_HEADER
89
+ blob_header = data_blob[0..7]
90
+ raise ArgumentError.new("Data is not a valid PNG file. Header missmatch (#{pngheader} != #{blob_header})") unless pngheader == blob_header
91
+ chunks = {}
92
+ index = LEN_HEADER
93
+ while index < data_blob.length
94
+ chunk_length = data_blob[index...(index += LEN_LENGTH)].unpack(BIG_ENDIAN_LONG).first
95
+ chunk_type = data_blob[index...(index += LEN_CHUNK_TYPE)]
96
+ chunk_data = data_blob[index...(index += chunk_length)]
97
+ chunk_crc = data_blob[index...(index += LEN_CRC)].unpack(BIG_ENDIAN_LONG).first
98
+ chunks[chunk_type] ||= []
99
+ chunks[chunk_type] << Chunk.new(chunk_length, chunk_type, chunk_crc, chunk_data)
100
+ end
101
+ chunks
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,52 @@
1
+ require 'cgbi_to_png/chunk'
2
+
3
+ module CgBItoPNG
4
+ class PNGfile
5
+ def initialize(data_blob)
6
+ @blob = data_blob
7
+ @chunks = Chunk.get_chunks(data_blob)
8
+ @ihdr = @chunks['IHDR'].first.get_dimensions
9
+ @width = @ihdr[:width]
10
+ @height = @ihdr[:height]
11
+ end
12
+
13
+ def to_s
14
+ str = "Pngfile #{@chunks.length} chunks."
15
+ str << " (Contains optimized chunk)" if self.optimized?
16
+ @chunks.each do |_k, v|
17
+ v.each do |c|
18
+ str << "\n" << c.to_s
19
+ end
20
+ end
21
+ str
22
+ end
23
+
24
+ def to_blob
25
+ blob = PNG_HEADER
26
+ @chunks.each do |_k, v|
27
+ v.each do |chunk|
28
+ next if chunk.type == 'CgBI'
29
+ blob << chunk.to_blob
30
+ end
31
+ end
32
+ blob
33
+ end
34
+
35
+ def to_file(filename)
36
+ File.open(filename, 'wb+') do |f|
37
+ f.write(self.to_blob)
38
+ end
39
+ end
40
+
41
+ def optimized?
42
+ @chunks['CgBI']
43
+ end
44
+
45
+ def unoptimize
46
+ bytes_per_pixel = 4
47
+ @chunks['IDAT'] =
48
+ [ Chunk::join_and_unoptimize_idat(@chunks['IDAT'], @width, bytes_per_pixel) ]
49
+ @chunks.delete('CgBI')
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ module OptimizedPngs
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,20 @@
1
+ require 'cgbi_to_png/version'
2
+ require 'cgbi_to_png/png_file.rb'
3
+
4
+ module CgBItoPNG
5
+ PNG_HEADER = "\x89PNG\r\n\x1a\n".force_encoding('ASCII-8BIT')
6
+ LEN_HEADER = 8
7
+ LEN_LENGTH = 4
8
+ LEN_CHUNK_TYPE = 4
9
+ LEN_CRC = 4
10
+ BIG_ENDIAN_LONG = 'L>'
11
+ UINT_8 = 'C'
12
+ COMPRESS_WINDOW_BITS = 8
13
+
14
+ def self.from_file(file_path)
15
+ raise ArgumentError.new("File #{file_path} does not exist") unless File.exists?(file_path)
16
+ raise ArgumentError.new("File #{file_path} is not readable for current user") unless File.readable?(file_path)
17
+ png_contents = File.open(file_path, 'rb') { |file| file.read }
18
+ PNGfile.new(png_contents)
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cgbi_to_png
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jon Appelberg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: This Gem allows converting CgBI (Apple's optimized PNG) images into 'standard'
42
+ PNG images. See http://iphonedevwiki.net/index.php/CgBI_file_format
43
+ email:
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - Gemfile
49
+ - LICENSE.txt
50
+ - README.md
51
+ - Rakefile
52
+ - cgbi_to_png.gemspec
53
+ - lib/cgbi_to_png.rb
54
+ - lib/cgbi_to_png/chunk.rb
55
+ - lib/cgbi_to_png/png_file.rb
56
+ - lib/cgbi_to_png/version.rb
57
+ homepage: http://github.com/jappelbe/cgbi_to_png
58
+ licenses:
59
+ - MIT
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.4.2
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Convert Apple optimized PNG images to standard PNG images
81
+ test_files: []
82
+ has_rdoc: