From fe9330f50e9a3bae9e42080d3ef009009b087e85 Mon Sep 17 00:00:00 2001 From: John Bintz Date: Thu, 7 Jan 2010 20:30:48 -0500 Subject: [PATCH] working on more cleanup --- classes/ConfigLoader.rb | 76 +++++++ classes/FileProcessor.rb | 155 ++++++++++++++ classes/TempBitmapToPaginatedPrint.rb | 42 ++++ classes/TempBitmapToPrint.rb | 17 ++ minicomic-backend.rb | 291 -------------------------- tests/TestConfigLoader.rb | 184 ++++++++++++++++ 6 files changed, 474 insertions(+), 291 deletions(-) create mode 100644 classes/ConfigLoader.rb create mode 100644 classes/FileProcessor.rb create mode 100644 classes/TempBitmapToPaginatedPrint.rb create mode 100644 classes/TempBitmapToPrint.rb create mode 100644 tests/TestConfigLoader.rb diff --git a/classes/ConfigLoader.rb b/classes/ConfigLoader.rb new file mode 100644 index 0000000..a3db718 --- /dev/null +++ b/classes/ConfigLoader.rb @@ -0,0 +1,76 @@ +class ConfigLoader + def load(file) + config = load_yaml(file) + + if !config['Global'] + return false + end + + global = config['Global'] + + if !global['path'] + return false + end + + if !global['page_index_format'] + global['page_index_format'] = count_pattern(global['path']) + end + + files = [] + fileinfo_by_file = {} + + if global['pages'] + re = nil + + files = global['pages'].collect do |f| + result = nil + case f.class.to_s + when 'String' + result = global['path'] + f + if f == "blank" + fileinfo_by_file[result] = { 'file' => f } + end + when 'Hash' + if f['file'] + case f['file'].class.to_s + when 'String' + result = global['path'] + f['file'] + fileinfo_by_file[result] = f + when 'Array' + result = f['file'].collect { |sub_f| global['path'] + sub_f } + fileinfo_by_file[result.join(",")] = f + end + else + result = f + end + end + result + end + else + if global['match'] + re = Regexp.new(global['match']) + + files = Dir[global['path']].sort.collect do |filename| + if matches = re.match(filename) + filename + end + end + end + end + + global['files'] = files + global['fileinfo_by_file'] = fileinfo_by_file + + config['Global'] = global + + config + end + + def load_yaml(file) + YAML::load(File.open(file, "r")) + end + + def count_pattern(path) + "%0#{Math.log10(Dir[path].length).ceil}d" + end +end diff --git a/classes/FileProcessor.rb b/classes/FileProcessor.rb new file mode 100644 index 0000000..c73e83a --- /dev/null +++ b/classes/FileProcessor.rb @@ -0,0 +1,155 @@ +class FileProcessor + def process + + paginated_source_files = {} + rsync_files_by_target = {} + + files.each do |filename| + ok = true; matches = nil; fileinfo = {} + + if filename.instance_of? Hash + if filename['blank'] + ok = false + config.each do |type, info| + if info['is_paginated'] + if !paginated_source_files[type]; paginated_source_files[type] = []; end + paginated_source_files[type] << nil + end + end + page_index += 1 + else + fileinfo = filename + filename = fileinfo['file'] + end + else + if re; ok = matches = re.match(filename); end + end + + if ok + filename_display = (filename.instance_of? Array) ? filename.join(", ") : filename + + puts "Examining #{filename_display}..." + + filename_parts = { + 'page_index' => sprintf(page_index_format, page_index) + } + + if matches + all, index, title = matches.to_a + else + index = page_index - 1 + title = "" + end + + if global['title']; title = global['title'].gsub("{index}", index).gsub("{title}", title); end + filename_parts['index'] = index + filename_parts['title'] = title + + config.each do |type, info| + if type != "Global" + input = nil; output = nil + + fileinfo_key = (filename.instance_of? Array) ? filename.join(",") : filename + + file_fileinfo = (fileinfo_by_file[fileinfo_key]) ? fileinfo_by_file[fileinfo_key] : {} + + extension = File.extname((filename.instance_of? Array) ? filename[0] : filename).downcase + + case extension + when ".svg" + case File.extname(config[type]['target']).downcase + when ".jpg", ".jpeg", ".png", ".gif" + input = SVGToTempBitmap + output = TempBitmapToWeb + when ".pdf" + input = SVGToTempBitmap + output = (info['is_paginated']) ? TempBitmapToPaginatedPrint : TempBitmapToPrint + end + end + + if !input; raise "No input handler for #{extension} defined"; end + if !output; raise "No output handler for #{File.extname(config[type]['target']).downcase} defined"; end + + input_obj = input.instance + input_obj.config = info.dup.merge(fileinfo).merge(file_fileinfo) + + output_obj = output.instance + output_obj.config = info.dup.merge(fileinfo).merge(file_fileinfo) + + if info['is_paginated'] + output_obj.config['target'] += "-{page_index}.png" + end + + targets = output_obj.targets(filename_parts) + + rebuild = false + + [ targets ].flatten.each do |t| + if !File.exists?(t) + rebuild = true + else + [ filename ].flatten.each do |f| + if File.basename(f) != "blank" + if File.mtime(f) > File.mtime(t) + rebuild = true + end + end + end + end + end + + if rebuild + any_rebuilt = true + + puts "Rebuilding #{filename_display} (#{type})..." + puts " Using #{filename} as a source" + puts " and writing to #{targets.inspect}" + + tmp_files = input_obj.build(filename) + + output_files = [] + case tmp_files.class.to_s + when "String" + output_obj.build(tmp_files, targets) + output_files << targets + when "Array" + [0,1].each do |i| + output_obj.build(tmp_files[i], targets[i], (i == 0) ? "left" : "right") + output_files << targets[i] + end + end + + input_obj.cleanup + end + if info['is_paginated'] + if !paginated_source_files[type]; paginated_source_files[type] = []; end + paginated_source_files[type] << targets + end + if info['rsync'] + if !rsync_files_by_target[info['rsync']]; rsync_files_by_target[info['rsync']] = []; end + rsync_files_by_target[info['rsync']] << targets + end + end + end + + page_index += 1 + end + end + + config.each do |type, info| + if info['is_paginated'] + output = TempBitmapToPaginatedPrint + + output_obj = output.instance + output_obj.config = info.dup + + output_obj.paginate(paginated_source_files[type].flatten) + end + + if info['rsync'] + system("echo '#{rsync_files_by_target[info['rsync']].join("\n")}' | rsync -vru --files-from=- . #{info['rsync']}") + end + end + end + +end diff --git a/classes/TempBitmapToPaginatedPrint.rb b/classes/TempBitmapToPaginatedPrint.rb new file mode 100644 index 0000000..ade17d2 --- /dev/null +++ b/classes/TempBitmapToPaginatedPrint.rb @@ -0,0 +1,42 @@ + +# +# Convert bitmap files to a paginated print-ready file +# +class TempBitmapToPaginatedPrint < OutputFilter + include PrintHandling, Pagination + def build(input, output, side = "none") + build_for_print(input, output, side) + end + + def targets(info) + (@config['spread'] == true) ? [ filename(info) + "-left.png", filename(info) + "-right.png" ] : filename(info) + end + + def process_pagination(output, face, total_faces, left, right) + page_width, page_height = calculate_page_size + + commands = [ + "-size #{page_width * 2}x#{page_height}", + "xc:white" + ] + + left_creep = 0 + right_creep = 0 + if @config['page_thickness'] + max_creep = (total_faces / 2) + + left_creep = ((max_creep - (face - max_creep).abs) * @config['page_thickness'].to_f * @config['dpi'].to_i).floor + right_creep = ((max_creep - (total_faces - face - max_creep).abs) * @config['page_thickness'].to_f * @config['dpi'].to_i).floor + end + + if left + commands << "\"#{left}\" -geometry +#{left_creep.to_i}+0 -composite" + end + if right + commands << "\"#{right}\" -geometry +#{(page_width + right_creep).to_i}+0 -composite" + end + commands << "-colorspace RGB -depth 8 pnm:- | sam2p -c:lzw -m:dpi:#{(72.0 * (72.0 / @config['dpi'].to_f))} - PDF:\"#{output}\"" + + convert(commands) + end +end diff --git a/classes/TempBitmapToPrint.rb b/classes/TempBitmapToPrint.rb new file mode 100644 index 0000000..8d94747 --- /dev/null +++ b/classes/TempBitmapToPrint.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/OutputFilter.rb' +require File.dirname(__FILE__) + '/../modules/PrintHandling.rb' + +# +# Convert a bitmap to a single page print for proofing +# +class TempBitmapToPrint < OutputFilter + include PrintHandling + + def build(input, output) + build_for_print(input, "| pbm:- | sam2p -c:lzw -m:dpi:#{calculate_dpi} - PDF:\"#{output}\"") + end + + def calculate_dpi + (72.0 * (72.0 / @config['dpi'].to_f)) + end +end diff --git a/minicomic-backend.rb b/minicomic-backend.rb index 2079dff..f11fc3c 100755 --- a/minicomic-backend.rb +++ b/minicomic-backend.rb @@ -7,100 +7,6 @@ Dir[File.dirname(__FILE__) + "/classes/*.rb"].each do |file| require file end -# -# Code to help with pagination -# -module Pagination - def paginate(files) - if !files.instance_of? Array; raise "File list must be an array"; end - if files.length == 0; raise "File list cannot be empty"; end - if (files.length % 4) != 0; raise "File list must be divisible by 4"; end - - number_of_sheet_faces = (files.length / 4) * 2 - - sheet_faces = [] - - is_right = 1 - is_descending = 1 - sheet_face_index = 0 - - files.each do |file| - if !sheet_faces[sheet_face_index]; sheet_faces[sheet_face_index] = []; end - - sheet_faces[sheet_face_index][is_right] = file - is_right = 1 - is_right - - sheet_face_index += is_descending - - if sheet_face_index == number_of_sheet_faces - sheet_face_index -= 1 - is_descending = -1 - end - end - - tmp_pdf_files = [] - 0.upto(sheet_faces.length - 1) do |i| - f = @config['target'] + "-#{i}.pdf" - process_pagination(f, i, sheet_faces.length, *sheet_faces[i]) - tmp_pdf_files << f - end - - system("pdfjoin #{tmp_pdf_files.collect { |f| "\"#{f}\"" }.join(" ")} --outfile \"#{@config['target']}\"") - end -end - -# -# Convert a bitmap to a single page print for proofing -# -class TempBitmapToPrint < OutputFilter - include PrintHandling - def build(input, output) - build_for_print(input, "| pbm:- | sam2p -c:lzw -m:dpi:#{(72.0 * (72.0 / @config['dpi'].to_f))} - PDF:\"#{output}\"") - end -end - -# -# Convert bitmap files to a paginated print-ready file -# -class TempBitmapToPaginatedPrint < OutputFilter - include PrintHandling, Pagination - def build(input, output, side = "none") - build_for_print(input, output, side) - end - - def targets(info) - (@config['spread'] == true) ? [ filename(info) + "-left.png", filename(info) + "-right.png" ] : filename(info) - end - - def process_pagination(output, face, total_faces, left, right) - page_width, page_height = calculate_page_size - - commands = [ - "-size #{page_width * 2}x#{page_height}", - "xc:white" - ] - - left_creep = 0 - right_creep = 0 - if @config['page_thickness'] - max_creep = (total_faces / 2) - - left_creep = ((max_creep - (face - max_creep).abs) * @config['page_thickness'].to_f * @config['dpi'].to_i).floor - right_creep = ((max_creep - (total_faces - face - max_creep).abs) * @config['page_thickness'].to_f * @config['dpi'].to_i).floor - end - - if left - commands << "\"#{left}\" -geometry +#{left_creep.to_i}+0 -composite" - end - if right - commands << "\"#{right}\" -geometry +#{(page_width + right_creep).to_i}+0 -composite" - end - commands << "-colorspace RGB -depth 8 pnm:- | sam2p -c:lzw -m:dpi:#{(72.0 * (72.0 / @config['dpi'].to_f))} - PDF:\"#{output}\"" - - convert(commands) - end -end - any_rebuilt = false any_rsync = false @@ -114,203 +20,6 @@ if !File.exists?(ARGV[0]) exit 1 end -config = YAML::load(File.open(ARGV[0], "r")) -global = config['Global'] - -if !global['path']; exit 1; end - -page_index_format = global['page_index_format'] ? global['page_index_format'] : "%0#{Math.log10(Dir[global['path']].length).ceil}d" - -page_index = 1 -fileinfo_by_file = {} - -if global['pages'] - re = nil - - files = global['pages'].collect do |f| - result = nil - case f.class.to_s - when 'String' - result = global['path'] + f - if f == "blank" - fileinfo_by_file[result] = { 'file' => f } - end - when 'Hash' - if f['file'] - case f['file'].class.to_s - when 'String' - result = global['path'] + f['file'] - fileinfo_by_file[result] = f - when 'Array' - result = f['file'].collect { |sub_f| global['path'] + sub_f } - fileinfo_by_file[result.join(",")] = f - end - else - result = f - end - end - result - end -else - re = Regexp.new(global['match']) - - files = Dir[global['path']].sort.collect do |filename| - if matches = re.match(filename) - filename - end - end -end - -paginated_source_files = {} -rsync_files_by_target = {} - -files.each do |filename| - ok = true; matches = nil; fileinfo = {} - - if filename.instance_of? Hash - if filename['blank'] - ok = false - config.each do |type, info| - if info['is_paginated'] - if !paginated_source_files[type]; paginated_source_files[type] = []; end - paginated_source_files[type] << nil - end - end - page_index += 1 - else - fileinfo = filename - filename = fileinfo['file'] - end - else - if re; ok = matches = re.match(filename); end - end - - if ok - filename_display = (filename.instance_of? Array) ? filename.join(", ") : filename - - puts "Examining #{filename_display}..." - - filename_parts = { - 'page_index' => sprintf(page_index_format, page_index) - } - - if matches - all, index, title = matches.to_a - else - index = page_index - 1 - title = "" - end - - if global['title']; title = global['title'].gsub("{index}", index).gsub("{title}", title); end - filename_parts['index'] = index - filename_parts['title'] = title - - config.each do |type, info| - if type != "Global" - input = nil; output = nil - - fileinfo_key = (filename.instance_of? Array) ? filename.join(",") : filename - - file_fileinfo = (fileinfo_by_file[fileinfo_key]) ? fileinfo_by_file[fileinfo_key] : {} - - extension = File.extname((filename.instance_of? Array) ? filename[0] : filename).downcase - - case extension - when ".svg" - case File.extname(config[type]['target']).downcase - when ".jpg", ".jpeg", ".png", ".gif" - input = SVGToTempBitmap - output = TempBitmapToWeb - when ".pdf" - input = SVGToTempBitmap - output = (info['is_paginated']) ? TempBitmapToPaginatedPrint : TempBitmapToPrint - end - end - - if !input; raise "No input handler for #{extension} defined"; end - if !output; raise "No output handler for #{File.extname(config[type]['target']).downcase} defined"; end - - input_obj = input.instance - input_obj.config = info.dup.merge(fileinfo).merge(file_fileinfo) - - output_obj = output.instance - output_obj.config = info.dup.merge(fileinfo).merge(file_fileinfo) - - if info['is_paginated'] - output_obj.config['target'] += "-{page_index}.png" - end - - targets = output_obj.targets(filename_parts) - - rebuild = false - - [ targets ].flatten.each do |t| - if !File.exists?(t) - rebuild = true - else - [ filename ].flatten.each do |f| - if File.basename(f) != "blank" - if File.mtime(f) > File.mtime(t) - rebuild = true - end - end - end - end - end - - if rebuild - any_rebuilt = true - - puts "Rebuilding #{filename_display} (#{type})..." - puts " Using #{filename} as a source" - puts " and writing to #{targets.inspect}" - - tmp_files = input_obj.build(filename) - - output_files = [] - case tmp_files.class.to_s - when "String" - output_obj.build(tmp_files, targets) - output_files << targets - when "Array" - [0,1].each do |i| - output_obj.build(tmp_files[i], targets[i], (i == 0) ? "left" : "right") - output_files << targets[i] - end - end - - input_obj.cleanup - end - if info['is_paginated'] - if !paginated_source_files[type]; paginated_source_files[type] = []; end - paginated_source_files[type] << targets - end - if info['rsync'] - if !rsync_files_by_target[info['rsync']]; rsync_files_by_target[info['rsync']] = []; end - rsync_files_by_target[info['rsync']] << targets - end - end - end - - page_index += 1 - end -end - -config.each do |type, info| - if info['is_paginated'] - output = TempBitmapToPaginatedPrint - - output_obj = output.instance - output_obj.config = info.dup - - output_obj.paginate(paginated_source_files[type].flatten) - end - - if info['rsync'] - system("echo '#{rsync_files_by_target[info['rsync']].join("\n")}' | rsync -vru --files-from=- . #{info['rsync']}") - end -end - if global['use_git'] system("git add .") system("git commit -a") diff --git a/tests/TestConfigLoader.rb b/tests/TestConfigLoader.rb new file mode 100644 index 0000000..245f3ee --- /dev/null +++ b/tests/TestConfigLoader.rb @@ -0,0 +1,184 @@ +require 'rubygems' +require 'test/unit' +require File.dirname(__FILE__) + '/../classes/ConfigLoader.rb' + +class TestConfigLoader < Test::Unit::TestCase + def setup + @config_loader = ConfigLoader.new + end + + def test_load + [ + [ {}, false, nil, nil ], + [ {'Global' => {}}, false, nil, nil ], + [ + { + 'Global' => { + 'path' => 'test/*.svg' + } + }, + { + 'Global' => { + 'path' => 'test/*.svg', + 'page_index_format' => '%02d', + 'files' => [], + 'fileinfo_by_file' => {} + } + }, + [ + { :expects => :count_pattern, :with => 'test/*.svg', :returns => '%02d' } + ], + nil + ], + [ + { + 'Global' => { + 'path' => '*.svg', + 'match' => '.*\.svg', + 'page_index_format' => '%02d' + } + }, + { + 'Global' => { + 'path' => '*.svg', + 'match' => '.*\.svg', + 'page_index_format' => '%02d', + 'files' => [ Dir.pwd + '/test1.svg', Dir.pwd + '/test2.svg' ], + 'fileinfo_by_file' => {} + } + }, + [], + [ 'test1.svg', 'test2.svg', 'test3.png' ] + ], + [ + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ 'test.svg' ] + } + }, + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ 'test.svg' ], + 'files' => [ 'test/test.svg' ], + 'fileinfo_by_file' => {} + } + } + ], + [ + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ 'blank' ] + } + }, + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ 'blank' ], + 'files' => [ 'test/blank' ], + 'fileinfo_by_file' => { 'test/blank' => { 'file' => 'blank' } } + } + } + ], + [ + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ {} ] + } + }, + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ {} ], + 'files' => [ {} ], + 'fileinfo_by_file' => {} + } + } + ], + [ + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ { 'file' => 'test', 'param' => 'test2' } ] + } + }, + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ { 'file' => 'test', 'param' => 'test2' } ], + 'files' => [ 'test/test' ], + 'fileinfo_by_file' => { 'test/test' => { 'file' => 'test', 'param' => 'test2' } } + } + } + ], + [ + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ { 'file' => [ 'test', 'test2' ], 'param' => 'test2' } ] + } + }, + { + 'Global' => { + 'path' => 'test/', + 'page_index_format' => '%02d', + 'pages' => [ { 'file' => [ 'test', 'test2' ], 'param' => 'test2' } ], + 'files' => [ [ 'test/test', 'test/test2' ] ], + 'fileinfo_by_file' => { 'test/test,test/test2' => { 'file' => [ 'test', 'test2' ], 'param' => 'test2' } } + } + } + ], + ].each do |yaml, expected_result, expectations, files| + @config_loader.expects(:load_yaml).with('file').returns(yaml) + + if expectations + expectations.each do |expectation| + e = @config_loader.expects(expectation[:expects]) + if expectation[:with] + e.with(expectation[:with]) + end + if expectation[:returns] + e.returns(expectation[:returns]) + end + end + end + + FakeFS do + if files + FileUtils.touch files + end + + assert_equal expected_result, @config_loader.load('file') + end + end + end + + def test_load_yaml + FakeFS do + File.open('test', 'w') do |fh| + fh.puts("- one\n- two\n- three") + end + + assert_equal %w(one two three), @config_loader.load_yaml('test') + end + end + + def test_count_pattern + FakeFS do + FileUtils.touch [ 'test', 'test2', 'test3' ] + assert_equal '%01d', @config_loader.count_pattern('*') + end + end +end