smart_ass 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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rspec', '~> 2.11.0'
6
+ gem 'rr', '~> 1.0.4'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Stefano Pigozzi
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,51 @@
1
+ # SmartAss
2
+
3
+ Utility for Y'CbCr ColorMatrix conversion of ASS Subtitles
4
+
5
+ If you are smart and know about ASS subtitles you are probably wondering
6
+ what Y'CbCr has to do with ASS. As a matter of fact ASS uses RGB hex for
7
+ color representation.
8
+
9
+ The problem is some subtitles renderers (VSFilter) on Windows decided it was
10
+ too stupid to render the RGB directly (don't even ask about it). So they
11
+ started doing a `R'G'B' ->(BT.601) Y'CbCr ->(BT.601) R'G'B'` chain of
12
+ conversions.
13
+
14
+ The problem is some fansubbers started to actually author content for
15
+ these broken renderers and the result is you get broken colors on
16
+ subtitles in the video players that are actually getting it right.
17
+
18
+ This tool is an attempt to fix this problem. Using mkvextract/mkvmerge
19
+ and some matrix multiplications it generates a new ass file where the
20
+ colors passed through the following conversions:
21
+
22
+ R'G'B' ->(BT.601) Y'CbCr ->(BT.709) R'G'B'
23
+
24
+ ## Installation
25
+
26
+ Make sure you have mkvtoolnix (mkvmerge and mkvextract) utilities
27
+ installed and in your path. For example, on OSX and homebrew it's as simple as:
28
+
29
+ brew install mkvtoolnix
30
+
31
+ Install the Ruby Gem:
32
+
33
+ [sudo] gem smart_ass
34
+
35
+ ## Usage
36
+
37
+ This is really minimal. No options for now.
38
+
39
+ smart_ass path/to/movie.mkv
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create new Pull Request
48
+
49
+ ## Contacts
50
+
51
+ Look for pigoz on irc.freenode.net.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new('spec')
6
+
7
+ task :default => :spec
data/bin/smart_ass ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # vim: syntax=ruby
3
+ $:.unshift File.join(File.dirname(File.dirname(__FILE__)), 'lib')
4
+
5
+ require 'smart_ass'
6
+
7
+ if arg = ARGV[0] then
8
+ app = SmartAss::App.new(arg)
9
+ app.run
10
+ else
11
+ puts "Please provide an input file"
12
+ exit()
13
+ end
@@ -0,0 +1,67 @@
1
+ class SmartAss::App
2
+ def initialize(file)
3
+ @ass = SmartAss::Ass.new(file)
4
+ @file = Pathname.new(file)
5
+ end
6
+
7
+ def run
8
+ # function composition baby!
9
+ write_ass_script replace_colors extract track
10
+ end
11
+
12
+ private
13
+ def write_ass_script(ass_script)
14
+ script_file_basename = "#{@file.basename(@file.extname)}.ass"
15
+ File.open(@file.expand_path.dirname + script_file_basename, "w") {|f|
16
+ f.puts(ass_script)
17
+ }
18
+ end
19
+
20
+ def replace_colors(ass_script)
21
+ ass_script.gsub(/&H[\da-zA-Z]{6,8}/) {|c| convert_color(c)}
22
+ end
23
+
24
+ def convert_color(c)
25
+ @_colors_cache ||= Hash.new
26
+
27
+ unless @_colors_cache[c]
28
+ color = SmartAss::RGBAColor.from_ass(c)
29
+
30
+ bt601 = SmartAss::YCbCrConverter.new(:bt601)
31
+ bt709 = SmartAss::YCbCrConverter.new(:bt709)
32
+
33
+ ycbcr = bt601.to_ycbcr(*color.rgb_components)
34
+ rgb = bt709.to_rgb(*ycbcr)
35
+
36
+ puts "[converted color] ass-hex: #{c}, rgb: #{color.rgb_components}, " \
37
+ "ycbcr: #{ycbcr}, mangled-rgb: #{rgb}"
38
+
39
+ @_colors_cache[c] = SmartAss::RGBAColor.from_rgba(*rgb).to_ass
40
+ end
41
+
42
+ @_colors_cache[c]
43
+ end
44
+
45
+ def track
46
+ if @ass.tracks.size > 1
47
+ track = ask_for_track
48
+ elsif @ass.tracks.size == 1
49
+ track = @ass.tracks[0]
50
+ else
51
+ puts "No ASS tracks found. Aborting."
52
+ exit
53
+ end
54
+ end
55
+
56
+ def ask_for_track
57
+ puts "Please enter a track name - #{@ass.tracks.inspect}:"
58
+ readline.to_i
59
+ rescue
60
+ puts "Invalid track provided. Try again."
61
+ retry
62
+ end
63
+
64
+ def extract(track_id)
65
+ @ass.extract(track_id)
66
+ end
67
+ end
@@ -0,0 +1,40 @@
1
+ require 'pathname'
2
+
3
+ class SmartAss::Ass
4
+ attr_reader :file
5
+
6
+ def initialize(file)
7
+ @file = Pathname.new(file)
8
+ end
9
+
10
+ def tracks
11
+ identify.each_line \
12
+ .map {|l| (l =~ identify_ass_regexp) ? $1 : nil } \
13
+ .compact \
14
+ .map &:to_i
15
+ end
16
+
17
+ # TODO: test this!
18
+ def extract(track_id)
19
+ puts `mkvextract tracks "#{expanded_file}" #{track_id}:#{export_temp_file}`
20
+ IO.read(export_temp_file, :encoding => 'UTF-8') \
21
+ .tap {|_| File.delete(export_temp_file) }
22
+ end
23
+
24
+ private
25
+ def identify
26
+ `mkvmerge -i "#{expanded_file}"`
27
+ end
28
+
29
+ def expanded_file
30
+ file.expand_path
31
+ end
32
+
33
+ def identify_ass_regexp
34
+ /Track ID (\d): subtitles \(S_TEXT\/ASS\)/
35
+ end
36
+
37
+ def export_temp_file
38
+ "/tmp/smart_ass_export-#{Process.pid}"
39
+ end
40
+ end
@@ -0,0 +1,5 @@
1
+ class SmartAss::BT601ColorMatrix < SmartAss::YCbCrColorMatrix
2
+ def initialize
3
+ super(0.299, 0.587, 0.114)
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ class SmartAss::BT709ColorMatrix < SmartAss::YCbCrColorMatrix
2
+ def initialize
3
+ super(0.2126, 0.7152, 0.0722)
4
+ end
5
+
6
+ def offset_vector
7
+ Matrix.column_vector([22.0, 125.0, 125.0])
8
+ end
9
+ end
@@ -0,0 +1,49 @@
1
+ class SmartAss::RGBAColor
2
+ attr_reader :r, :g, :b, :a
3
+
4
+ def self.from_ass(string)
5
+ argb_hex = string.gsub(/^&H/, '')
6
+ components = argb_hex.scan(/.{2}/).map {|h| h.to_i(16)}
7
+ if components.size == 4
8
+ from_argb(*components)
9
+ else
10
+ from_rgba(*components)
11
+ end
12
+ end
13
+
14
+ def self.from_argb(*components)
15
+ from_rgba(*components.push(components.shift))
16
+ end
17
+
18
+ def self.from_rgba(*components)
19
+ new(*components)
20
+ end
21
+
22
+ def to_ass
23
+ hex = argb_components
24
+ .map {|c| c.to_s(16)}
25
+ .map {|c| c.rjust(2, "0")}
26
+ .map(&:upcase)
27
+ .join
28
+ "&H#{hex}"
29
+ end
30
+
31
+ def initialize(r, g, b, a=0x00)
32
+ @r, @g, @b, @a = [r, g, b, a].map {|n| n < 0 ? 0 : n}
33
+ end
34
+
35
+ def components
36
+ [@r, @g, @b, @a]
37
+ end
38
+
39
+ def argb_components
40
+ c = components
41
+ c.unshift(c.pop)
42
+ end
43
+
44
+ def rgb_components
45
+ c = components
46
+ c.pop
47
+ c
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module SmartAss
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,96 @@
1
+ require 'matrix'
2
+
3
+ class SmartAss::YCbCrColorMatrix
4
+ attr_reader :wr, :wg, :wb
5
+ def initialize(wr, wg, wb)
6
+ @wr, @wg, @wb = wr, wg, wb
7
+ end
8
+
9
+ # basic luma relation: converts R'G'B' -> Y'(B'-Y')(R'-Y')
10
+ def to_ybmyrmy_matrix
11
+ Matrix[
12
+ [ wr, wg, wb ],
13
+ [-wr, -wg, wr+wg],
14
+ [wg+wb, -wg, -wb ],
15
+ ]
16
+ end
17
+
18
+ # RGB -> YPbPr []
19
+ def to_ypbpr_matrix_from_rgb
20
+ scale_rows to_ybmyrmy_matrix, 1.0, 0.5 / (wr+wg), 0.5 / (wg+wb)
21
+ end
22
+
23
+ # YPbPr -> RGB []
24
+ def to_rgb_matrix_from_ypbpr
25
+ zeros to_ypbpr_matrix_from_rgb.inverse
26
+ end
27
+
28
+ # RGB -> YCbCr []
29
+ def to_ycbcr_matrix_from_rgb
30
+ scale_rows to_ypbpr_matrix_from_rgb, 219.0, 224.0, 224.0
31
+ end
32
+
33
+ # YCbCr -> RGB []
34
+ def to_rgb_matrix_from_ycbcr
35
+ zeros to_ycbcr_matrix_from_rgb.inverse
36
+ end
37
+
38
+ # RGB(digital) -> YCbCr []
39
+ def to_ycbcr_matrix_from_rgbd
40
+ scale_rows to_ycbcr_matrix_from_rgb, *[256.0/255.0]*3
41
+ end
42
+
43
+ # YCbCr -> RGB(digital) []
44
+ def to_rgbd_matrix_from_ycbcr
45
+ scale_rows zeros(to_ycbcr_matrix_from_rgbd.inverse), *[256.0*256.0]*3
46
+ end
47
+
48
+ # RGB(digital) -> YCbCr Equation
49
+ def to_ycbcr_from_rgb(*rgb)
50
+ apply_equation(*rgb) do |*rgb|
51
+ offset_vector + (to_ycbcr_matrix_from_rgbd * 1.0 / 256.0) *
52
+ Matrix.column_vector(rgb)
53
+ end
54
+ end
55
+
56
+ # YCbCr -> RGB(digital) Equation
57
+ def to_rgb_from_ycbcr(*ycbcr)
58
+ r = apply_equation(*ycbcr) do |*ycbcr|
59
+ (to_rgbd_matrix_from_ycbcr * 1.0 / 256.0) *
60
+ (Matrix.column_vector(ycbcr) - offset_vector)
61
+ end.map(&:round)
62
+
63
+ clip_rgb(r)
64
+ end
65
+
66
+ private
67
+ def clip_rgb(input)
68
+ input.map {|n| n >= 0 ? n : 0}
69
+ .map {|n| n <= 255 ? n : 255}
70
+ end
71
+
72
+ def offset_vector
73
+ Matrix.column_vector([16.0, 128.0, 128.0])
74
+ end
75
+
76
+ def apply_equation(*inputs, &block)
77
+ block.call(*inputs).to_a.flatten
78
+ end
79
+
80
+ def scale_rows(matrix, *factors)
81
+ raise InvalidArgumentError unless matrix.row_size == factors.size
82
+ Matrix[*factors.each_with_index.map{|factor, index|
83
+ matrix.row(index) * factor
84
+ }]
85
+ end
86
+
87
+ def zeros(matrix)
88
+ matrix.map {|n|
89
+ if n < 1e-5 and n > -1e-5 then
90
+ 0.0
91
+ else
92
+ n
93
+ end
94
+ }
95
+ end
96
+ end
@@ -0,0 +1,15 @@
1
+ class SmartAss::YCbCrConverter
2
+ attr_reader :matrix
3
+
4
+ def initialize(matrix)
5
+ @matrix = SmartAss.const_get("#{matrix.upcase}ColorMatrix".to_sym).new
6
+ end
7
+
8
+ def to_ycbcr(*rgb)
9
+ matrix.to_ycbcr_from_rgb(*rgb)
10
+ end
11
+
12
+ def to_rgb(*ycbcr)
13
+ matrix.to_rgb_from_ycbcr(*ycbcr)
14
+ end
15
+ end
data/lib/smart_ass.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "smart_ass/version"
2
+
3
+ module SmartAss
4
+ autoload :App, 'smart_ass/app'
5
+ autoload :Ass, 'smart_ass/ass'
6
+ autoload :BT601ColorMatrix, 'smart_ass/bt601_colormatrix'
7
+ autoload :BT709ColorMatrix, 'smart_ass/bt709_colormatrix'
8
+ autoload :RGBAColor, 'smart_ass/rgba_color'
9
+ autoload :YCbCrColorMatrix, 'smart_ass/ycbcr_colormatrix'
10
+ autoload :YCbCrConverter, 'smart_ass/ycbcr_converter'
11
+ end
data/smart_ass.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/smart_ass/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Stefano Pigozzi"]
6
+ gem.email = ["stefano.pigozzi@gmail.com"]
7
+ gem.description = %q{Utility for YCbCr ColorMatrix conversion of ASS Subtitles.}
8
+ gem.summary = %q{Utility for YCbCr ColorMatrix conversion of ASS Subtitles.}
9
+ gem.homepage = "http://github.com/pigoz/smart_ass"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "smart_ass"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = SmartAss::VERSION
17
+ end
data/spec/ass_spec.rb ADDED
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ describe SmartAss::Ass do
4
+ subject {
5
+ @file = "path/to/file/movie.mkv"
6
+ SmartAss::Ass.new(@file)
7
+ }
8
+
9
+ it "holds onto a file" do
10
+ subject.file.should == Pathname.new(@file)
11
+ end
12
+
13
+ describe "#tracks" do
14
+ [
15
+ {:f => 'info_1_t_3', :e => [3], :t => 'with 1 element'},
16
+ {:f => 'info_3_t_3_5_6', :e => [3, 5, 6], :t => 'with many elements'},
17
+ {:f => 'info_0', :e => [], :t => 'with 0 elements'},
18
+ ].each do |test|
19
+ it "returns an array of ASS track IDs (#{test[:t]})" do
20
+ mock(subject).identify {
21
+ IO.read(
22
+ File.join(File.dirname(__FILE__), 'fixtures', test[:f]))
23
+ }
24
+ subject.tracks.should == test[:e]
25
+ end # it #tracks
26
+ end # do
27
+ end # describe
28
+
29
+ end
@@ -0,0 +1,15 @@
1
+ File '/Users/stefano/Movies/[UTWoots]_Sword_Art_Online_-_01v2_[720p][E22288BC].mkv': container: Matroska
2
+ Track ID 1: video (V_MPEG4/ISO/AVC)
3
+ Track ID 2: audio (A_AAC)
4
+ Attachment ID 1: type 'application/x-truetype-font', size 168852 bytes, file name 'ACaslonPro-Regular.otf'
5
+ Attachment ID 2: type 'application/x-truetype-font', size 129676 bytes, file name 'GOTHICB.TTF'
6
+ Attachment ID 3: type 'application/x-truetype-font', size 6455918 bytes, file name 'IwaOMinPro-Hv-En.ttf'
7
+ Attachment ID 4: type 'application/x-truetype-font', size 767840 bytes, file name 'LinLibertine_DR.ttf'
8
+ Attachment ID 5: type 'application/x-truetype-font', size 43052 bytes, file name 'Montara-Bold.otf'
9
+ Attachment ID 6: type 'application/x-truetype-font', size 42004 bytes, file name 'Montara-BoldItalic.otf'
10
+ Attachment ID 7: type 'application/x-truetype-font', size 45316 bytes, file name 'Montara-Gothic.otf'
11
+ Attachment ID 8: type 'application/x-truetype-font', size 42608 bytes, file name 'Montara-Italic.TTF'
12
+ Attachment ID 9: type 'application/x-truetype-font', size 53092 bytes, file name 'QuaySansMdITCTT.ttf'
13
+ Attachment ID 10: type 'application/x-truetype-font', size 94300 bytes, file name 'raavi.ttf'
14
+ Attachment ID 11: type 'application/x-truetype-font', size 30352 bytes, file name 'wscsnrg.TTF'
15
+ Chapters: 6 entries
@@ -0,0 +1,16 @@
1
+ File '/Users/stefano/Movies/[UTWoots]_Sword_Art_Online_-_01v2_[720p][E22288BC].mkv': container: Matroska
2
+ Track ID 1: video (V_MPEG4/ISO/AVC)
3
+ Track ID 2: audio (A_AAC)
4
+ Track ID 3: subtitles (S_TEXT/ASS)
5
+ Attachment ID 1: type 'application/x-truetype-font', size 168852 bytes, file name 'ACaslonPro-Regular.otf'
6
+ Attachment ID 2: type 'application/x-truetype-font', size 129676 bytes, file name 'GOTHICB.TTF'
7
+ Attachment ID 3: type 'application/x-truetype-font', size 6455918 bytes, file name 'IwaOMinPro-Hv-En.ttf'
8
+ Attachment ID 4: type 'application/x-truetype-font', size 767840 bytes, file name 'LinLibertine_DR.ttf'
9
+ Attachment ID 5: type 'application/x-truetype-font', size 43052 bytes, file name 'Montara-Bold.otf'
10
+ Attachment ID 6: type 'application/x-truetype-font', size 42004 bytes, file name 'Montara-BoldItalic.otf'
11
+ Attachment ID 7: type 'application/x-truetype-font', size 45316 bytes, file name 'Montara-Gothic.otf'
12
+ Attachment ID 8: type 'application/x-truetype-font', size 42608 bytes, file name 'Montara-Italic.TTF'
13
+ Attachment ID 9: type 'application/x-truetype-font', size 53092 bytes, file name 'QuaySansMdITCTT.ttf'
14
+ Attachment ID 10: type 'application/x-truetype-font', size 94300 bytes, file name 'raavi.ttf'
15
+ Attachment ID 11: type 'application/x-truetype-font', size 30352 bytes, file name 'wscsnrg.TTF'
16
+ Chapters: 6 entries
@@ -0,0 +1,19 @@
1
+ File '/Users/stefano/Movies/[UTWoots]_Sword_Art_Online_-_01v2_[720p][E22288BC].mkv': container: Matroska
2
+ Track ID 1: video (V_MPEG4/ISO/AVC)
3
+ Track ID 2: audio (A_AAC)
4
+ Track ID 3: subtitles (S_TEXT/ASS)
5
+ Track ID 4: audio (A_AAC)
6
+ Track ID 5: subtitles (S_TEXT/ASS)
7
+ Track ID 6: subtitles (S_TEXT/ASS)
8
+ Attachment ID 1: type 'application/x-truetype-font', size 168852 bytes, file name 'ACaslonPro-Regular.otf'
9
+ Attachment ID 2: type 'application/x-truetype-font', size 129676 bytes, file name 'GOTHICB.TTF'
10
+ Attachment ID 3: type 'application/x-truetype-font', size 6455918 bytes, file name 'IwaOMinPro-Hv-En.ttf'
11
+ Attachment ID 4: type 'application/x-truetype-font', size 767840 bytes, file name 'LinLibertine_DR.ttf'
12
+ Attachment ID 5: type 'application/x-truetype-font', size 43052 bytes, file name 'Montara-Bold.otf'
13
+ Attachment ID 6: type 'application/x-truetype-font', size 42004 bytes, file name 'Montara-BoldItalic.otf'
14
+ Attachment ID 7: type 'application/x-truetype-font', size 45316 bytes, file name 'Montara-Gothic.otf'
15
+ Attachment ID 8: type 'application/x-truetype-font', size 42608 bytes, file name 'Montara-Italic.TTF'
16
+ Attachment ID 9: type 'application/x-truetype-font', size 53092 bytes, file name 'QuaySansMdITCTT.ttf'
17
+ Attachment ID 10: type 'application/x-truetype-font', size 94300 bytes, file name 'raavi.ttf'
18
+ Attachment ID 11: type 'application/x-truetype-font', size 30352 bytes, file name 'wscsnrg.TTF'
19
+ Chapters: 6 entries
@@ -0,0 +1,43 @@
1
+ require "spec_helper.rb"
2
+
3
+ describe SmartAss::RGBAColor do
4
+
5
+ it "holds onto its components" do
6
+ c = SmartAss::RGBAColor.new(50, 150, 200, 255)
7
+ c.r.should == 50
8
+ c.g.should == 150
9
+ c.b.should == 200
10
+ c.a.should == 255
11
+ c.components.should == [50, 150, 200, 255]
12
+ end
13
+
14
+ it "can be created from a hex rgba" do
15
+ c = SmartAss::RGBAColor.from_rgba(0xff, 0xff, 0xff, 0x00)
16
+ c.components.should == [255, 255, 255, 0]
17
+ end
18
+
19
+ it "can be created from a hex argb" do
20
+ c = SmartAss::RGBAColor.from_argb(0x00, 0xff, 0xff, 0xff)
21
+ c.components.should == [255, 255, 255, 0]
22
+ end
23
+
24
+ it "can be created from an .ass hex (with alpha)" do
25
+ c = SmartAss::RGBAColor.from_ass("&H00FFFFFF")
26
+ c.components.should == [255, 255, 255, 0]
27
+ end
28
+
29
+ it "can be created from an .ass hex (without alpha)" do
30
+ c = SmartAss::RGBAColor.from_ass("&HFFFFFF")
31
+ c.components.should == [255, 255, 255, 0]
32
+ end
33
+
34
+ describe "#to_ass" do
35
+ it "returns ass repesentation" do
36
+ c = SmartAss::RGBAColor.from_argb(0x00, 0xff, 0xff, 0xff)
37
+ c.to_ass.should == "&H00FFFFFF"
38
+
39
+ c = SmartAss::RGBAColor.from_rgba(*[0xff, 0xff, 0xff] + [0x00])
40
+ c.to_ass.should == "&H00FFFFFF"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ Bundler.require(:default)
4
+
5
+ RSpec.configure do |config|
6
+ config.treat_symbols_as_metadata_keys_with_true_values = true
7
+ config.run_all_when_everything_filtered = true
8
+ config.filter_run :focus
9
+ config.order = 'random'
10
+ config.mock_with :rr
11
+ end
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+
3
+ describe SmartAss::YCbCrConverter do
4
+
5
+ it "can mangle RGB doing RGB ->(bt601) YCbCr ->(b709) RGB" do
6
+ bt601 = SmartAss::YCbCrConverter.new(:bt601)
7
+ bt709 = SmartAss::YCbCrConverter.new(:bt709)
8
+
9
+ yuv = bt601.to_ycbcr(16, 138, 187)
10
+ rgb = bt709.to_rgb(*yuv)
11
+
12
+ rgb.should =~ [5, 129, 191]
13
+ end
14
+
15
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smart_ass
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stefano Pigozzi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-17 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Utility for YCbCr ColorMatrix conversion of ASS Subtitles.
15
+ email:
16
+ - stefano.pigozzi@gmail.com
17
+ executables:
18
+ - smart_ass
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - .rspec
24
+ - Gemfile
25
+ - LICENSE
26
+ - README.md
27
+ - Rakefile
28
+ - bin/smart_ass
29
+ - lib/smart_ass.rb
30
+ - lib/smart_ass/app.rb
31
+ - lib/smart_ass/ass.rb
32
+ - lib/smart_ass/bt601_colormatrix.rb
33
+ - lib/smart_ass/bt709_colormatrix.rb
34
+ - lib/smart_ass/rgba_color.rb
35
+ - lib/smart_ass/version.rb
36
+ - lib/smart_ass/ycbcr_colormatrix.rb
37
+ - lib/smart_ass/ycbcr_converter.rb
38
+ - smart_ass.gemspec
39
+ - spec/ass_spec.rb
40
+ - spec/fixtures/info_0
41
+ - spec/fixtures/info_1_t_3
42
+ - spec/fixtures/info_3_t_3_5_6
43
+ - spec/rgba_color_spec.rb
44
+ - spec/spec_helper.rb
45
+ - spec/ycbcr_converter_spec.rb
46
+ homepage: http://github.com/pigoz/smart_ass
47
+ licenses: []
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 1.8.24
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Utility for YCbCr ColorMatrix conversion of ASS Subtitles.
70
+ test_files:
71
+ - spec/ass_spec.rb
72
+ - spec/fixtures/info_0
73
+ - spec/fixtures/info_1_t_3
74
+ - spec/fixtures/info_3_t_3_5_6
75
+ - spec/rgba_color_spec.rb
76
+ - spec/spec_helper.rb
77
+ - spec/ycbcr_converter_spec.rb