diff --git a/README b/README index e69de29..a5e113a 100644 --- a/README +++ b/README @@ -0,0 +1,8 @@ +REQUIREMENTS +============ + +Python Image Library (PIL) +PyQT4 +Reportlab + +Mangle 2.4 Unofficial version diff --git a/mangle.pyw b/mangle.pyw index 4625b75..ad5e380 100755 --- a/mangle.pyw +++ b/mangle.pyw @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # Copyright (C) 2010 Alex Yatskov # diff --git a/mangle/book.py b/mangle/book.py index f9544f2..5ad7638 100644 --- a/mangle/book.py +++ b/mangle/book.py @@ -16,8 +16,11 @@ import os import os.path +from os.path import basename import util +import tempfile from PyQt4 import QtGui, QtCore, QtXml, uic +from zipfile import ZipFile from image import ImageFlags from about import DialogAbout from options import DialogOptions @@ -27,7 +30,7 @@ from natsort import natsorted class Book(object): DefaultDevice = 'Kindle 4' - DefaultOutputFormat = 'Images & CBZ' + DefaultOutputFormat = 'PDF only' DefaultOverwrite = True DefaultImageFlags = ImageFlags.Orient | ImageFlags.Resize | ImageFlags.Quantize @@ -208,9 +211,12 @@ class MainWindowBook(QtGui.QMainWindow): filenames = QtGui.QFileDialog.getOpenFileNames( parent=self, caption='Select image file(s) to add', - filter='Image files (*.jpeg *.jpg *.gif *.png);;All files (*.*)' + filter='Image files (*.jpeg *.jpg *.gif *.png);;Comic files (*.cbz)' ) - self.addImageFiles(filenames) + if(self.containsCbzFile(filenames)): + self.addCBZFiles(filenames) + else: + self.addImageFiles(filenames) def onBookAddDirectory(self): @@ -364,7 +370,6 @@ class MainWindowBook(QtGui.QMainWindow): self.book.images.append(filename) self.book.modified = True - def addImageDirs(self, directories): filenames = [] @@ -377,6 +382,33 @@ class MainWindowBook(QtGui.QMainWindow): self.addImageFiles(filenames) + def addCBZFiles(self, filenames): + directories = [] + tempDir = tempfile.gettempdir() + filenames.sort() + + filenamesListed = [] + for i in xrange(0, self.listWidgetFiles.count()): + filenamesListed.append(self.listWidgetFiles.item(i).text()) + + for filename in filenames: + folderName = os.path.splitext(basename(str(filename)))[0] + path = tempDir + "/" + folderName + "/" + cbzFile = ZipFile(str(filename)) + for f in cbzFile.namelist(): + if f.endswith('/'): + try: + os.makedirs(path+f) + except: + pass #the dir exists so we are going to extract the images only. + else: + cbzFile.extract(f, path) + #Add the directories + if os.path.isdir(unicode(path)): + directories.append(path) + #Add the files + self.addImageDirs(directories) + def isImageFile(self, filename): imageExts = ['.jpeg', '.jpg', '.gif', '.png'] @@ -386,6 +418,17 @@ class MainWindowBook(QtGui.QMainWindow): os.path.splitext(filename)[1].lower() in imageExts ) + def containsCbzFile(self, filenames): + cbzExts = ['.cbz'] + for filename in filenames: + filename = unicode(filename) + result = ( + os.path.isfile(filename) and + os.path.splitext(filename)[1].lower() in cbzExts + ) + if result == True: + return result + return False def cleanupBookFile(self, filename): if len(os.path.splitext(unicode(filename))[1]) == 0: diff --git a/mangle/convert.py b/mangle/convert.py index 506d542..173a4ce 100644 --- a/mangle/convert.py +++ b/mangle/convert.py @@ -18,6 +18,7 @@ import os, shutil from PyQt4 import QtGui, QtCore import image import cbz +import pdfimage class DialogConvert(QtGui.QProgressDialog): @@ -35,6 +36,11 @@ class DialogConvert(QtGui.QProgressDialog): self.archive = None if 'CBZ' in self.book.outputFormat: self.archive = cbz.Archive(self.bookPath) + + self.pdf = None + if "PDF" in self.book.outputFormat: + self.pdf = pdfimage.PDFImage(self.bookPath, str(self.book.title), str(self.book.device)) + def showEvent(self, event): @@ -50,6 +56,9 @@ class DialogConvert(QtGui.QProgressDialog): # Close the archive if we created a CBZ file if self.archive is not None: self.archive.close() + #Close and generate the PDF File + if self.pdf is not None: + self.pdf.close() # Remove image directory if the user didn't wish for images if 'Image' not in self.book.outputFormat: @@ -98,6 +107,8 @@ class DialogConvert(QtGui.QProgressDialog): image.convertImage(source, target, str(self.book.device), self.book.imageFlags) if self.archive is not None: self.archive.addFile(target) + if self.pdf is not None: + self.pdf.addImage(target) except RuntimeError, error: result = QtGui.QMessageBox.critical( self, diff --git a/mangle/image.py b/mangle/image.py index 1bc15e6..9174d76 100644 --- a/mangle/image.py +++ b/mangle/image.py @@ -22,6 +22,7 @@ class ImageFlags: Resize = 1 << 1 Frame = 1 << 2 Quantize = 1 << 3 + Stretch = 1 << 4 class KindleData: @@ -90,6 +91,10 @@ def quantizeImage(image, palette): return image.quantize(palette=palImg) +def stretchImage(image, size): + widthDev, heightDev = size + return image.resize((widthDev, heightDev), Image.ANTIALIAS) + def resizeImage(image, size): widthDev, heightDev = size widthImg, heightImg = image.size @@ -167,16 +172,17 @@ def convertImage(source, target, device, flags): image = Image.open(source) except IOError: raise RuntimeError('Cannot read image file %s' % source) - image = formatImage(image) if flags & ImageFlags.Orient: - image = orientImage(image, size) + image = orientImage(image, size) if flags & ImageFlags.Resize: - image = resizeImage(image, size) + image = resizeImage(image, size) + if flags & ImageFlags.Stretch: + image = stretchImage(image, size) if flags & ImageFlags.Frame: - image = frameImage(image, tuple(palette[:3]), tuple(palette[-3:]), size) + image = frameImage(image, tuple(palette[:3]), tuple(palette[-3:]), size) if flags & ImageFlags.Quantize: - image = quantizeImage(image, palette) + image = quantizeImage(image, palette) try: image.save(target) diff --git a/mangle/options.py b/mangle/options.py index 92ccd00..364dece 100644 --- a/mangle/options.py +++ b/mangle/options.py @@ -42,6 +42,7 @@ class DialogOptions(QtGui.QDialog): self.checkboxOverwrite.setChecked(self.book.overwrite) self.checkboxOrient.setChecked(self.book.imageFlags & ImageFlags.Orient) self.checkboxResize.setChecked(self.book.imageFlags & ImageFlags.Resize) + self.checkboxStretch.setChecked(self.book.imageFlags & ImageFlags.Stretch) self.checkboxQuantize.setChecked(self.book.imageFlags & ImageFlags.Quantize) self.checkboxFrame.setChecked(self.book.imageFlags & ImageFlags.Frame) @@ -57,10 +58,12 @@ class DialogOptions(QtGui.QDialog): imageFlags |= ImageFlags.Orient if self.checkboxResize.isChecked(): imageFlags |= ImageFlags.Resize + if self.checkboxStretch.isChecked(): + imageFlags |= ImageFlags.Stretch if self.checkboxQuantize.isChecked(): imageFlags |= ImageFlags.Quantize if self.checkboxFrame.isChecked(): - imageFlags |= ImageFlags.Frame + imageFlags |= ImageFlags.Frame modified = ( self.book.title != title or diff --git a/mangle/pdfimage.py b/mangle/pdfimage.py new file mode 100644 index 0000000..c7be86d --- /dev/null +++ b/mangle/pdfimage.py @@ -0,0 +1,49 @@ +# Copyright (C) 2012 Cristian Lizana +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import os.path + +from reportlab.pdfgen import canvas +from reportlab.lib.pagesizes import letter +from image import KindleData + +class PDFImage(object): + def __init__(self, path, title, device): + outputDirectory = os.path.dirname(path) + outputFileName = '%s.pdf' % os.path.basename(path) + outputPath = os.path.join(outputDirectory, outputFileName) + self.currentDevice = device + self.bookTitle = title + self.pageSize = KindleData.Profiles[self.currentDevice][0] + #pagesize could be letter or A4 for standarization but we need to control some image sizes + self.canvas = canvas.Canvas(outputPath, pagesize=self.pageSize) + self.canvas.setAuthor("Mangle") + self.canvas.setTitle(self.bookTitle) + self.canvas.setSubject("Created for " + self.currentDevice) + + + def addImage(self, filename): + self.canvas.drawImage(filename, 0, 0, width=self.pageSize[0], height=self.pageSize[1], preserveAspectRatio=True, anchor='c') + self.canvas.showPage() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + + def close(self): + self.canvas.save() diff --git a/mangle/ui/options.ui b/mangle/ui/options.ui index 47f0099..e2b7d73 100644 --- a/mangle/ui/options.ui +++ b/mangle/ui/options.ui @@ -99,7 +99,7 @@ - Images & CBZ + Images & CBZ & PDF @@ -107,6 +107,11 @@ Images only + + + PDF only + + CBZ only @@ -130,13 +135,6 @@ - - - - Resize images to center on screen - - - @@ -150,6 +148,27 @@ Draw frame around images + + + + + Size + + + + + + + Resize images to center on screen + + + + + + + Stretch images to fill the screen + +