diff --git a/KindleComicConverter.app/Contents/Info.plist b/KindleComicConverter.app/Contents/Info.plist index 807ec5d..2115763 100644 --- a/KindleComicConverter.app/Contents/Info.plist +++ b/KindleComicConverter.app/Contents/Info.plist @@ -57,9 +57,9 @@ positionOfDivider 568 savedFrame - 666 338 889 690 0 0 1680 1028 + 144 338 889 690 0 0 1680 1028 selectedTabView - event log + result diff --git a/KindleComicConverter.app/Contents/Resources/Scripts/main.scpt b/KindleComicConverter.app/Contents/Resources/Scripts/main.scpt index 0dddff3..edd25dd 100644 Binary files a/KindleComicConverter.app/Contents/Resources/Scripts/main.scpt and b/KindleComicConverter.app/Contents/Resources/Scripts/main.scpt differ diff --git a/KindleComicConverter.app/Contents/Resources/comic2ebook.py b/KindleComicConverter.app/Contents/Resources/comic2ebook.py index 432812c..0b410f7 100755 --- a/KindleComicConverter.app/Contents/Resources/comic2ebook.py +++ b/KindleComicConverter.app/Contents/Resources/comic2ebook.py @@ -24,6 +24,8 @@ # with portrait target or portrait with landscape target), add palette # and other image optimizations from Mangle. # WARNING: PIL is required for all image mangling! +# 1.30 - Fixed an issue in OPF generation for device resolution +# Reworked options system (call with -h option to get the inline help) # # Todo: # - Add gracefully exit for CBR if no rarfile.py and no unrar @@ -31,10 +33,11 @@ # - Improve error reporting # - recurse into dirtree for multiple comics -__version__ = '1.20' +__version__ = '1.30' import os import sys +from optparse import OptionParser import image, cbxarchive class HTMLbuilder: @@ -77,17 +80,11 @@ class NCXbuilder: return class OPFBuilder: - def __init__(self, dstdir, title, filelist): + def __init__(self, profile, dstdir, title, filelist): opffile = dstdir + '/content.opf' # read the first file resolution - try: - from PIL import Image - im = Image.open(dstdir + "/" + filelist[0][0] + filelist[0][1]) - width, height = im.size - imgres = str(width) + "x" + str(height) - except ImportError: - print "Could not load PIL, falling back on default HD" - imgres = "758x1024" + deviceres, palette = image.ProfileData.Profiles[profile] + imgres = str(deviceres[0]) + "x" + str(deviceres[1]) f = open(opffile, "w"); f.writelines(["\n", "\n", @@ -137,34 +134,41 @@ def Copyright(): def Usage(): print "Generates HTML, NCX and OPF for a Comic ebook from a bunch of images" print "Optimized for creating Mobipockets to be read into Kindle Paperwhite" - print "Usage:" - print " %s " % sys.argv[0] - print " <title> is optional" + #print "Usage:" + #print " %s <profile> <dir> <title>" % sys.argv[0] + #print " <title> is optional" + parser.print_help() def main(argv=None): - if argv is None: - argv = sys.argv - profile = argv[1] - dir = argv[2] + global parser + usage = "Usage: %prog [options] comic_file|comic_folder" + parser = OptionParser(usage=usage, version=__version__) + parser.add_option("-p", "--profile", action="store", dest="profile", default="KHD", + help="Device profile (choose one among K1, K2, K3, K4, KHD [default])") + parser.add_option("-t", "--title", action="store", dest="title", default="comic", + help="Comic title") + parser.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False, + help="Split pages 'manga style' (right-to-left reading)") + options, args = parser.parse_args() + if len(args) != 1: + parser.print_help() + sys.exit(1) + dir = args[0] cbx = cbxarchive.CBxArchive(dir) if cbx.isCbxFile(): cbx.extract() dir = cbx.getPath() - if len(argv)==4: - title = argv[3] - else: - title = "comic" filelist = [] try: print "Splitting double pages..." for file in os.listdir(dir): if (getImageFileName(file) != None): - img = image.ComicPage(dir+'/'+file, profile) - img.splitPage(dir) + img = image.ComicPage(dir+'/'+file, options.profile) + img.splitPage(dir, options.righttoleft) for file in os.listdir(dir): if (getImageFileName(file) != None): - print "Optimizing " + file + " for " + profile - img = image.ComicPage(dir+'/'+file, profile) + print "Optimizing " + file + " for " + options.profile + img = image.ComicPage(dir+'/'+file, options.profile) img.resizeImage() #img.frameImage() img.quantizeImage() @@ -181,16 +185,12 @@ def main(argv=None): filename = HTMLbuilder(dir,file).getResult() if (filename != None): filelist.append(filename) - NCXbuilder(dir,title) + NCXbuilder(dir,options.title) # ensure we're sorting files alphabetically filelist = sorted(filelist, key=lambda name: name[0]) - OPFBuilder(dir,title,filelist) + OPFBuilder(options.profile,dir,options.title,filelist) if __name__ == "__main__": Copyright() - if len(sys.argv)<3 or len(sys.argv)>4: - Usage() - sys.exit(1) - else: - main() + main() sys.exit(0) diff --git a/KindleComicConverter.app/Contents/Resources/image.py b/KindleComicConverter.app/Contents/Resources/image.py index 31128fa..d072a78 100755 --- a/KindleComicConverter.app/Contents/Resources/image.py +++ b/KindleComicConverter.app/Contents/Resources/image.py @@ -24,7 +24,7 @@ class ImageFlags: Stretch = 1 << 4 -class KindleData: +class ProfileData: Palette4 = [ 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, @@ -80,7 +80,7 @@ class KindleData: class ComicPage: def __init__(self,source,device): try: - self.size, self.palette = KindleData.Profiles[device] + self.size, self.palette = ProfileData.Profiles[device] except KeyError: raise RuntimeError('Unexpected output device %s' % device) try: diff --git a/KindleComicConverter.app/Contents/Resources/rarfile.py b/KindleComicConverter.app/Contents/Resources/rarfile.py index 7c846e5..d78aafe 100644 --- a/KindleComicConverter.app/Contents/Resources/rarfile.py +++ b/KindleComicConverter.app/Contents/Resources/rarfile.py @@ -1699,10 +1699,6 @@ def custom_popen(cmd): if sys.platform == 'win32': creationflags = 0x08000000 # CREATE_NO_WINDOW - out_file = open("/tmp/test.txt","w") - out_file.write('[%s]' % ', '.join(map(str, cmd))) - out_file.close() - # run command p = Popen(cmd, bufsize = 0, stdout = PIPE, stdin = PIPE, stderr = STDOUT, creationflags = creationflags) diff --git a/README.md b/README.md index 09528e1..949f2fc 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,23 @@ The script takes care of calling `comic2ebook.py`, `kindlegen` and `kindlestrip. > If you want to specify other profiles, please use the script from command line. ### standalone `comic2ebook.py` usage: -1. Launch - ```python comic2ebook.py <profile> <directory|file> <title>``` +```comic2ebook.py [options] comic_file|comic_folder - The script takes care of unzipping/unrarring the file if it's an archive, creating a directory of images which should be then filled with a `.opf`, `.ncx`, and many `.html` files. -4. Run `Kindlegen` on `content.opf`. Depending on how many images you have, this may take awhile. Once completed, the `.mobi` file should be in the directory. -5. Remove the SRCS record to reduce the `.mobi` filesize in half. You can use [Kindlestrip](http://www.mobileread.com/forums/showthread.php?t=96903). -6. Copy the `.mobi` file to your Kindle! + Options: + --version show program's version number and exit + -h, --help show this help message and exit + -p PROFILE, --profile=PROFILE + Device profile (choose one among K1, K2, K3, K4, KHD + [default]) + -t TITLE, --title=TITLE + Comic title + -m, --manga-style Split pages 'manga style' (right-to-left reading)``` + +The script takes care of unzipping/unrarring the file if it's an archive, creating a directory of images which should be then filled with a `.opf`, `.ncx`, and many `.html` files. +Run `Kindlegen` on `content.opf`. Depending on how many images you have, this may take awhile. Once completed, the `.mobi` file should be in the directory. +Remove the SRCS record to reduce the `.mobi` filesize in half. You can use [Kindlestrip](http://www.mobileread.com/forums/showthread.php?t=96903). +Copy the `.mobi` file to your Kindle! ## CREDITS This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published in [this mobileread forum thread](http://www.mobileread.com/forums/showthread.php?t=192783)) @@ -51,6 +60,8 @@ and installed in `/usr/local/bin/` - 1.20 - Comic optimizations! Split pages not target-oriented (landscape with portrait target or portrait with landscape target), add palette and other image optimizations from Mangle. WARNING: PIL is required for all image mangling! + - 1.30 - Fixed an issue in OPF generation for device resolution + Reworked options system (call with -h option to get the inline help) - 2.00 - GUI! AppleScript is gone and Tk is used to provide cross-platform GUI support. ## TODO @@ -61,4 +72,4 @@ and installed in `/usr/local/bin/` ## COPYRIGHT -Copyright (c) 2012 Ciro Mattia Gonano. See LICENSE.txt for further details. \ No newline at end of file +Copyright (c) 2012-2013 Ciro Mattia Gonano. See LICENSE.txt for further details. \ No newline at end of file diff --git a/kcc.py b/kcc.py index 5837651..2d468c5 100644 --- a/kcc.py +++ b/kcc.py @@ -33,12 +33,12 @@ __version__ = '1.30' -import sys -from kcc import comic2ebook +from Tkinter import * +from kcc import gui -if __name__ == "__main__": - print ('kcc v%(__version__)s. ' - 'Written 2012 by Ciro Mattia Gonano.' % globals()) - for arg in sys.argv[1:]: - comic2ebook.main(['','KHD',arg]) - sys.exit(0) +root = Tk() +app = gui.MainWindow(master=root) +app.master.title("Kindle Comic Converter v" + __version__) +app.master.maxsize(1000, 400) +app.mainloop() +root.destroy() diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index 432812c..0b410f7 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -24,6 +24,8 @@ # with portrait target or portrait with landscape target), add palette # and other image optimizations from Mangle. # WARNING: PIL is required for all image mangling! +# 1.30 - Fixed an issue in OPF generation for device resolution +# Reworked options system (call with -h option to get the inline help) # # Todo: # - Add gracefully exit for CBR if no rarfile.py and no unrar @@ -31,10 +33,11 @@ # - Improve error reporting # - recurse into dirtree for multiple comics -__version__ = '1.20' +__version__ = '1.30' import os import sys +from optparse import OptionParser import image, cbxarchive class HTMLbuilder: @@ -77,17 +80,11 @@ class NCXbuilder: return class OPFBuilder: - def __init__(self, dstdir, title, filelist): + def __init__(self, profile, dstdir, title, filelist): opffile = dstdir + '/content.opf' # read the first file resolution - try: - from PIL import Image - im = Image.open(dstdir + "/" + filelist[0][0] + filelist[0][1]) - width, height = im.size - imgres = str(width) + "x" + str(height) - except ImportError: - print "Could not load PIL, falling back on default HD" - imgres = "758x1024" + deviceres, palette = image.ProfileData.Profiles[profile] + imgres = str(deviceres[0]) + "x" + str(deviceres[1]) f = open(opffile, "w"); f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", "<package version=\"2.0\" unique-identifier=\"PrimaryID\" xmlns=\"http://www.idpf.org/2007/opf\">\n", @@ -137,34 +134,41 @@ def Copyright(): def Usage(): print "Generates HTML, NCX and OPF for a Comic ebook from a bunch of images" print "Optimized for creating Mobipockets to be read into Kindle Paperwhite" - print "Usage:" - print " %s <profile> <dir> <title>" % sys.argv[0] - print " <title> is optional" + #print "Usage:" + #print " %s <profile> <dir> <title>" % sys.argv[0] + #print " <title> is optional" + parser.print_help() def main(argv=None): - if argv is None: - argv = sys.argv - profile = argv[1] - dir = argv[2] + global parser + usage = "Usage: %prog [options] comic_file|comic_folder" + parser = OptionParser(usage=usage, version=__version__) + parser.add_option("-p", "--profile", action="store", dest="profile", default="KHD", + help="Device profile (choose one among K1, K2, K3, K4, KHD [default])") + parser.add_option("-t", "--title", action="store", dest="title", default="comic", + help="Comic title") + parser.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False, + help="Split pages 'manga style' (right-to-left reading)") + options, args = parser.parse_args() + if len(args) != 1: + parser.print_help() + sys.exit(1) + dir = args[0] cbx = cbxarchive.CBxArchive(dir) if cbx.isCbxFile(): cbx.extract() dir = cbx.getPath() - if len(argv)==4: - title = argv[3] - else: - title = "comic" filelist = [] try: print "Splitting double pages..." for file in os.listdir(dir): if (getImageFileName(file) != None): - img = image.ComicPage(dir+'/'+file, profile) - img.splitPage(dir) + img = image.ComicPage(dir+'/'+file, options.profile) + img.splitPage(dir, options.righttoleft) for file in os.listdir(dir): if (getImageFileName(file) != None): - print "Optimizing " + file + " for " + profile - img = image.ComicPage(dir+'/'+file, profile) + print "Optimizing " + file + " for " + options.profile + img = image.ComicPage(dir+'/'+file, options.profile) img.resizeImage() #img.frameImage() img.quantizeImage() @@ -181,16 +185,12 @@ def main(argv=None): filename = HTMLbuilder(dir,file).getResult() if (filename != None): filelist.append(filename) - NCXbuilder(dir,title) + NCXbuilder(dir,options.title) # ensure we're sorting files alphabetically filelist = sorted(filelist, key=lambda name: name[0]) - OPFBuilder(dir,title,filelist) + OPFBuilder(options.profile,dir,options.title,filelist) if __name__ == "__main__": Copyright() - if len(sys.argv)<3 or len(sys.argv)>4: - Usage() - sys.exit(1) - else: - main() + main() sys.exit(0) diff --git a/kcc/gui.py b/kcc/gui.py new file mode 100644 index 0000000..ab685e9 --- /dev/null +++ b/kcc/gui.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# +# Copyright (c) 2013 Ciro Mattia Gonano <ciromattia@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software for +# any purpose with or without fee is hereby granted, provided that the +# above copyright notice and this permission notice appear in all +# copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA +# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +from Tkinter import * +import tkFileDialog + +class MainWindow(Frame): + def open_files(self): + self.files = tkFileDialog.askopenfilename() + + def createWidgets(self): + self.QUIT = Button(self) + self.QUIT["text"] = "Quit" + self.QUIT["fg"] = "red" + self.QUIT["command"] = self.quit + self.QUIT.pack({"side": "right"}) + + self.OPENFILES = Button(self) + self.OPENFILES["text"] = "Open files", + self.OPENFILES["command"] = self.open_files + self.OPENFILES.pack({"side": "left"}) + + def __init__(self, master=None): + Frame.__init__(self, master) + self.pack() + self.createWidgets() + + diff --git a/kcc/image.py b/kcc/image.py index 31128fa..d072a78 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -24,7 +24,7 @@ class ImageFlags: Stretch = 1 << 4 -class KindleData: +class ProfileData: Palette4 = [ 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, @@ -80,7 +80,7 @@ class KindleData: class ComicPage: def __init__(self,source,device): try: - self.size, self.palette = KindleData.Profiles[device] + self.size, self.palette = ProfileData.Profiles[device] except KeyError: raise RuntimeError('Unexpected output device %s' % device) try: diff --git a/resources/Scripts/main.scpt b/resources/Scripts/main.scpt index 0dddff3..edd25dd 100644 Binary files a/resources/Scripts/main.scpt and b/resources/Scripts/main.scpt differ