mirror of
https://github.com/ciromattia/kcc
synced 2025-12-22 06:01:49 +00:00
Added --black-borders option to set added borders black when page's ratio is not the device's one (fixes #11).
Fixes epub containing zipped itself (fixes #10).
This commit is contained in:
@@ -12,7 +12,7 @@ It also optimizes comic images by:
|
|||||||
|
|
||||||
## BINARY RELEASES
|
## BINARY RELEASES
|
||||||
You can find the latest released binary at the following links:
|
You can find the latest released binary at the following links:
|
||||||
- OS X: [https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.4.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.4.zip)
|
- OS X: [https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.5.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.5.zip)
|
||||||
- Win64: [https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.4.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.4.zip)
|
- Win64: [https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.4.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.4.zip)
|
||||||
- Linux: just download sourcecode and launch `python kcc.py` *(provided you have Python and Pillow installed)*
|
- Linux: just download sourcecode and launch `python kcc.py` *(provided you have Python and Pillow installed)*
|
||||||
|
|
||||||
@@ -64,6 +64,9 @@ comic2ebook.py [options] comic_file|comic_folder
|
|||||||
--upscale-images Resize images smaller than device's resolution
|
--upscale-images Resize images smaller than device's resolution
|
||||||
[default=False]
|
[default=False]
|
||||||
--stretch-images Stretch images to device's resolution [default=False]
|
--stretch-images Stretch images to device's resolution [default=False]
|
||||||
|
--black-borders Use black borders (instead of white ones) when not
|
||||||
|
stretching and ratio is not like the device's one
|
||||||
|
[default=False]
|
||||||
--no-cut-page-numbers
|
--no-cut-page-numbers
|
||||||
Do not try to cut page numbering on images
|
Do not try to cut page numbering on images
|
||||||
[default=True]
|
[default=True]
|
||||||
@@ -109,6 +112,8 @@ and installed in a directory reachable by your PATH (e.g. `/usr/local/bin/` or `
|
|||||||
- 2.3: Fixed win32 ePub generation, folder handling, filenames with spaces and subfolders
|
- 2.3: Fixed win32 ePub generation, folder handling, filenames with spaces and subfolders
|
||||||
- 2.4: Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
|
- 2.4: Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
|
||||||
Fixed "add folders" from GUI.
|
Fixed "add folders" from GUI.
|
||||||
|
- 2.5: Added --black-borders option to set added borders black when page's ratio is not the device's one (#11).
|
||||||
|
Fixes epub containing zipped itself (#10).
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- Add gracefully exit for CBR if no rarfile.py and no unrar executable are found
|
- Add gracefully exit for CBR if no rarfile.py and no unrar executable are found
|
||||||
|
|||||||
2
kcc.py
2
kcc.py
@@ -16,7 +16,7 @@
|
|||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
__version__ = '2.4'
|
__version__ = '2.5'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>'
|
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
__version__ = '2.4'
|
__version__ = '2.5'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>'
|
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -164,7 +164,7 @@ def applyImgOptimization(img):
|
|||||||
img.cropWhiteSpace(10.0)
|
img.cropWhiteSpace(10.0)
|
||||||
if options.cutpagenumbers:
|
if options.cutpagenumbers:
|
||||||
img.cutPageNumber()
|
img.cutPageNumber()
|
||||||
img.resizeImage(options.upscale,options.stretch)
|
img.resizeImage(options.upscale,options.stretch,options.black_borders)
|
||||||
img.quantizeImage()
|
img.quantizeImage()
|
||||||
|
|
||||||
|
|
||||||
@@ -275,6 +275,8 @@ def main(argv=None):
|
|||||||
help="Resize images smaller than device's resolution [default=False]")
|
help="Resize images smaller than device's resolution [default=False]")
|
||||||
parser.add_option("--stretch-images", action="store_true", dest="stretch", default=False,
|
parser.add_option("--stretch-images", action="store_true", dest="stretch", default=False,
|
||||||
help="Stretch images to device's resolution [default=False]")
|
help="Stretch images to device's resolution [default=False]")
|
||||||
|
parser.add_option("--black-borders", action="store_true", dest="black_borders", default=False,
|
||||||
|
help="Use black borders (instead of white ones) when not stretching and ratio is not like the device's one [default=False]")
|
||||||
parser.add_option("--no-cut-page-numbers", action="store_false", dest="cutpagenumbers", default=True,
|
parser.add_option("--no-cut-page-numbers", action="store_false", dest="cutpagenumbers", default=True,
|
||||||
help="Do not try to cut page numbering on images [default=True]")
|
help="Do not try to cut page numbering on images [default=True]")
|
||||||
options, args = parser.parse_args(argv)
|
options, args = parser.parse_args(argv)
|
||||||
@@ -294,8 +296,8 @@ def main(argv=None):
|
|||||||
epubpath = args[0] + '.epub'
|
epubpath = args[0] + '.epub'
|
||||||
else:
|
else:
|
||||||
epubpath = os.path.splitext(args[0])[0] + '.epub'
|
epubpath = os.path.splitext(args[0])[0] + '.epub'
|
||||||
make_archive(os.path.join(path,'comic'),'zip',path)
|
make_archive(path + '_comic','zip',path)
|
||||||
move(os.path.join(path,'comic') + '.zip', epubpath)
|
move(path + '_comic.zip', epubpath)
|
||||||
rmtree(path)
|
rmtree(path)
|
||||||
return epubpath
|
return epubpath
|
||||||
|
|
||||||
|
|||||||
82
kcc/gui.py
82
kcc/gui.py
@@ -75,48 +75,37 @@ class MainWindow:
|
|||||||
self.open_folder.grid(row=4,column=2,rowspan=3)
|
self.open_folder.grid(row=4,column=2,rowspan=3)
|
||||||
|
|
||||||
self.profile = StringVar()
|
self.profile = StringVar()
|
||||||
options = sorted(ProfileData.ProfileLabels.iterkeys())
|
profiles = sorted(ProfileData.ProfileLabels.iterkeys())
|
||||||
self.profile.set(options[-1])
|
self.profile.set(profiles[-1])
|
||||||
w = apply(OptionMenu, (self.master, self.profile) + tuple(options))
|
w = apply(OptionMenu, (self.master, self.profile) + tuple(profiles))
|
||||||
w.grid(row=1,column=3)
|
w.grid(row=1,column=3)
|
||||||
|
|
||||||
self.epub_only = IntVar()
|
self.options = {
|
||||||
self.epub_only = 0
|
'epub_only':IntVar(None,0),
|
||||||
self.image_preprocess = IntVar()
|
'image_preprocess':IntVar(None,1),
|
||||||
self.image_preprocess = 1
|
'cut_page_numbers':IntVar(None,1),
|
||||||
self.cut_page_numbers = IntVar()
|
'mangastyle':IntVar(None,0),
|
||||||
self.cut_page_numbers = 1
|
'image_upscale':IntVar(None,0),
|
||||||
self.mangastyle = IntVar()
|
'image_stretch':IntVar(None,0),
|
||||||
self.mangastyle = 0
|
'black_borders':IntVar(None,0)
|
||||||
self.image_upscale = IntVar()
|
}
|
||||||
self.image_upscale = 0
|
self.optionlabels = {
|
||||||
self.image_stretch = IntVar()
|
'epub_only':"Generate ePub only (does not call 'kindlegen')",
|
||||||
self.image_stretch = 0
|
'image_preprocess':"Apply image optimizations",
|
||||||
self.c = Checkbutton(self.master, text="Generate ePub only (does not call 'kindlegen')",
|
'cut_page_numbers':"Cut page numbers",
|
||||||
variable=self.epub_only)
|
'mangastyle':"Split manga-style (right-to-left reading)",
|
||||||
self.c.grid(row=3,column=3,sticky=W)
|
'image_upscale':"Allow image upscaling",
|
||||||
self.c = Checkbutton(self.master, text="Apply image optimizations",
|
'image_stretch':"Stretch images",
|
||||||
variable=self.image_preprocess)
|
'black_borders':"Use black borders"
|
||||||
self.c.select()
|
}
|
||||||
self.c.grid(row=4,column=3,sticky=W)
|
for key in self.options:
|
||||||
self.c = Checkbutton(self.master, text="Cut page numbers",
|
aCheckButton = Checkbutton(self.master, text=self.optionlabels[key],variable=self.options[key])
|
||||||
variable=self.cut_page_numbers)
|
aCheckButton.grid(column=3,sticky='w')
|
||||||
self.c.grid(row=5,column=3,sticky=W)
|
|
||||||
self.c = Checkbutton(self.master, text="Split manga-style (right-to-left reading)",
|
|
||||||
variable=self.mangastyle)
|
|
||||||
self.c.grid(row=6,column=3,sticky=W)
|
|
||||||
self.c = Checkbutton(self.master, text="Allow image upscaling",
|
|
||||||
variable=self.image_upscale)
|
|
||||||
self.c.grid(row=7,column=3,sticky=W)
|
|
||||||
self.c = Checkbutton(self.master, text="Stretch images",
|
|
||||||
variable=self.image_stretch)
|
|
||||||
self.c.grid(row=8,column=3,sticky=W)
|
|
||||||
|
|
||||||
self.progressbar = ttk.Progressbar(orient=HORIZONTAL, length=200, mode='determinate')
|
self.progressbar = ttk.Progressbar(orient=HORIZONTAL, length=200, mode='determinate')
|
||||||
|
|
||||||
self.submit = Button(self.master, text="Execute!", command=self.start_conversion, fg="red")
|
self.submit = Button(self.master, text="Execute!", command=self.start_conversion, fg="red")
|
||||||
self.submit.grid(row=9,column=3)
|
self.submit.grid(column=3)
|
||||||
self.progressbar.grid(row=10,column=0,columnspan=4,sticky=W+E+N+S)
|
self.progressbar.grid(column=0,columnspan=4,sticky=W+E+N+S)
|
||||||
|
|
||||||
# self.debug = Listbox(self.master)
|
# self.debug = Listbox(self.master)
|
||||||
# self.debug.grid(row=9,columnspan=4,sticky=W+E+N+S)
|
# self.debug.grid(row=9,columnspan=4,sticky=W+E+N+S)
|
||||||
@@ -128,19 +117,24 @@ class MainWindow:
|
|||||||
self.progressbar.stop()
|
self.progressbar.stop()
|
||||||
|
|
||||||
def convert(self):
|
def convert(self):
|
||||||
tkMessageBox.showerror('Starting conversion', "KCC will now start converting files. GUI can seem frozen, kindly wait until some message appears!")
|
if len(self.filelist) < 1:
|
||||||
|
tkMessageBox.showwarning('No file selected', "You should really select some files to convert...")
|
||||||
|
return
|
||||||
|
tkMessageBox.showinfo('Starting conversion', "KCC will now start converting files. GUI can seem frozen, kindly wait until some message appears!")
|
||||||
profilekey = ProfileData.ProfileLabels[self.profile.get()]
|
profilekey = ProfileData.ProfileLabels[self.profile.get()]
|
||||||
argv = ["-p",profilekey]
|
argv = ["-p",profilekey]
|
||||||
if self.image_preprocess == 0:
|
if self.options['image_preprocess'].get() == 0:
|
||||||
argv.append("--no-image-processing")
|
argv.append("--no-image-processing")
|
||||||
if self.cut_page_numbers == 0:
|
if self.options['cut_page_numbers'].get() == 0:
|
||||||
argv.append("--no-cut-page-numbers")
|
argv.append("--no-cut-page-numbers")
|
||||||
if self.mangastyle == 1:
|
if self.options['mangastyle'].get() == 1:
|
||||||
argv.append("-m")
|
argv.append("-m")
|
||||||
if self.image_upscale == 1:
|
if self.options['image_upscale'].get() == 1:
|
||||||
argv.append("--upscale-images")
|
argv.append("--upscale-images")
|
||||||
if self.image_stretch == 1:
|
if self.options['image_stretch'].get() == 1:
|
||||||
argv.append("--stretch-images")
|
argv.append("--stretch-images")
|
||||||
|
if self.options['black_borders'].get() == 1:
|
||||||
|
argv.append("--black-borders")
|
||||||
errors = False
|
errors = False
|
||||||
for entry in self.filelist:
|
for entry in self.filelist:
|
||||||
self.master.update()
|
self.master.update()
|
||||||
@@ -152,7 +146,7 @@ class MainWindow:
|
|||||||
tkMessageBox.showerror('Error comic2ebook', "Error on file %s:\n%s" % (subargv[-1], str(err)))
|
tkMessageBox.showerror('Error comic2ebook', "Error on file %s:\n%s" % (subargv[-1], str(err)))
|
||||||
errors = True
|
errors = True
|
||||||
continue
|
continue
|
||||||
if self.epub_only == 1:
|
if self.options['epub_only'] == 1:
|
||||||
continue;
|
continue;
|
||||||
try:
|
try:
|
||||||
retcode = call("kindlegen \"" + epub_path + "\"", shell=True)
|
retcode = call("kindlegen \"" + epub_path + "\"", shell=True)
|
||||||
|
|||||||
12
kcc/image.py
12
kcc/image.py
@@ -127,14 +127,18 @@ class ComicPage:
|
|||||||
palImg.putpalette(self.palette)
|
palImg.putpalette(self.palette)
|
||||||
self.image = self.image.quantize(palette=palImg)
|
self.image = self.image.quantize(palette=palImg)
|
||||||
|
|
||||||
def resizeImage(self,upscale=False, stretch=False):
|
def resizeImage(self,upscale=False, stretch=False, black_borders=False):
|
||||||
method = Image.ANTIALIAS
|
method = Image.ANTIALIAS
|
||||||
|
if black_borders:
|
||||||
|
fill = 'black'
|
||||||
|
else:
|
||||||
|
fill = 'white'
|
||||||
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
||||||
if not upscale:
|
if not upscale:
|
||||||
# do not upscale but center image in a device-sized image
|
# do not upscale but center image in a device-sized image
|
||||||
borderw = (self.size[0] - self.image.size[0]) / 2
|
borderw = (self.size[0] - self.image.size[0]) / 2
|
||||||
borderh = (self.size[1] - self.image.size[1]) / 2
|
borderh = (self.size[1] - self.image.size[1]) / 2
|
||||||
self.image = ImageOps.expand(self.image, border=(borderw,borderh), fill='white')
|
self.image = ImageOps.expand(self.image, border=(borderw,borderh), fill=fill)
|
||||||
return self.image
|
return self.image
|
||||||
else:
|
else:
|
||||||
method = Image.NEAREST
|
method = Image.NEAREST
|
||||||
@@ -146,10 +150,10 @@ class ComicPage:
|
|||||||
ratioDev = float(self.size[0]) / float(self.size[1])
|
ratioDev = float(self.size[0]) / float(self.size[1])
|
||||||
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
||||||
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
|
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
|
||||||
self.image = ImageOps.expand(self.image, border=(diff/2,0), fill='white')
|
self.image = ImageOps.expand(self.image, border=(diff/2,0), fill=fill)
|
||||||
elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
|
elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
|
||||||
diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
|
diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
|
||||||
self.image = ImageOps.expand(self.image, border=(0,diff/2), fill='white')
|
self.image = ImageOps.expand(self.image, border=(0,diff/2), fill=fill)
|
||||||
self.image = ImageOps.fit(self.image, self.size, method = method, centering = (0.5,0.5))
|
self.image = ImageOps.fit(self.image, self.size, method = method, centering = (0.5,0.5))
|
||||||
return self.image
|
return self.image
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user