Cristian's PDF generation patch

This commit is contained in:
Alex Yatskov 2012-07-28 11:08:50 -07:00
parent a71ff52e22
commit 8077ca5391
8 changed files with 158 additions and 19 deletions

8
README
View File

@ -0,0 +1,8 @@
REQUIREMENTS
============
Python Image Library (PIL)
PyQT4
Reportlab
Mangle 2.4 Unofficial version

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python
# Copyright (C) 2010 Alex Yatskov # Copyright (C) 2010 Alex Yatskov
# #

View File

@ -16,8 +16,11 @@
import os import os
import os.path import os.path
from os.path import basename
import util import util
import tempfile
from PyQt4 import QtGui, QtCore, QtXml, uic from PyQt4 import QtGui, QtCore, QtXml, uic
from zipfile import ZipFile
from image import ImageFlags from image import ImageFlags
from about import DialogAbout from about import DialogAbout
from options import DialogOptions from options import DialogOptions
@ -26,7 +29,7 @@ from convert import DialogConvert
class Book(object): class Book(object):
DefaultDevice = 'Kindle 4' DefaultDevice = 'Kindle 4'
DefaultOutputFormat = 'Images & CBZ' DefaultOutputFormat = 'PDF only'
DefaultOverwrite = True DefaultOverwrite = True
DefaultImageFlags = ImageFlags.Orient | ImageFlags.Resize | ImageFlags.Quantize DefaultImageFlags = ImageFlags.Orient | ImageFlags.Resize | ImageFlags.Quantize
@ -207,9 +210,12 @@ class MainWindowBook(QtGui.QMainWindow):
filenames = QtGui.QFileDialog.getOpenFileNames( filenames = QtGui.QFileDialog.getOpenFileNames(
parent=self, parent=self,
caption='Select image file(s) to add', 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): def onBookAddDirectory(self):
@ -364,7 +370,6 @@ class MainWindowBook(QtGui.QMainWindow):
self.book.images.append(filename) self.book.images.append(filename)
self.book.modified = True self.book.modified = True
def addImageDirs(self, directories): def addImageDirs(self, directories):
filenames = [] filenames = []
@ -377,6 +382,33 @@ class MainWindowBook(QtGui.QMainWindow):
self.addImageFiles(filenames) 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): def isImageFile(self, filename):
imageExts = ['.jpeg', '.jpg', '.gif', '.png'] imageExts = ['.jpeg', '.jpg', '.gif', '.png']
@ -386,6 +418,17 @@ class MainWindowBook(QtGui.QMainWindow):
os.path.splitext(filename)[1].lower() in imageExts 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): def cleanupBookFile(self, filename):
if len(os.path.splitext(unicode(filename))[1]) == 0: if len(os.path.splitext(unicode(filename))[1]) == 0:

View File

@ -18,6 +18,7 @@ import os, shutil
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
import image import image
import cbz import cbz
import pdfimage
class DialogConvert(QtGui.QProgressDialog): class DialogConvert(QtGui.QProgressDialog):
@ -36,6 +37,11 @@ class DialogConvert(QtGui.QProgressDialog):
if 'CBZ' in self.book.outputFormat: if 'CBZ' in self.book.outputFormat:
self.archive = cbz.Archive(self.bookPath) 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): def showEvent(self, event):
if self.timer is None: if self.timer is None:
@ -50,6 +56,9 @@ class DialogConvert(QtGui.QProgressDialog):
# Close the archive if we created a CBZ file # Close the archive if we created a CBZ file
if self.archive is not None: if self.archive is not None:
self.archive.close() 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 # Remove image directory if the user didn't wish for images
if 'Image' not in self.book.outputFormat: 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) image.convertImage(source, target, str(self.book.device), self.book.imageFlags)
if self.archive is not None: if self.archive is not None:
self.archive.addFile(target) self.archive.addFile(target)
if self.pdf is not None:
self.pdf.addImage(target)
except RuntimeError, error: except RuntimeError, error:
result = QtGui.QMessageBox.critical( result = QtGui.QMessageBox.critical(
self, self,

View File

@ -22,6 +22,7 @@ class ImageFlags:
Resize = 1 << 1 Resize = 1 << 1
Frame = 1 << 2 Frame = 1 << 2
Quantize = 1 << 3 Quantize = 1 << 3
Stretch = 1 << 4
class KindleData: class KindleData:
@ -89,6 +90,10 @@ def quantizeImage(image, palette):
return image.quantize(palette=palImg) return image.quantize(palette=palImg)
def stretchImage(image, size):
widthDev, heightDev = size
return image.resize((widthDev, heightDev), Image.ANTIALIAS)
def resizeImage(image, size): def resizeImage(image, size):
widthDev, heightDev = size widthDev, heightDev = size
widthImg, heightImg = image.size widthImg, heightImg = image.size
@ -166,16 +171,17 @@ def convertImage(source, target, device, flags):
image = Image.open(source) image = Image.open(source)
except IOError: except IOError:
raise RuntimeError('Cannot read image file %s' % source) raise RuntimeError('Cannot read image file %s' % source)
image = formatImage(image) image = formatImage(image)
if flags & ImageFlags.Orient: if flags & ImageFlags.Orient:
image = orientImage(image, size) image = orientImage(image, size)
if flags & ImageFlags.Resize: if flags & ImageFlags.Resize:
image = resizeImage(image, size) image = resizeImage(image, size)
if flags & ImageFlags.Stretch:
image = stretchImage(image, size)
if flags & ImageFlags.Frame: 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: if flags & ImageFlags.Quantize:
image = quantizeImage(image, palette) image = quantizeImage(image, palette)
try: try:
image.save(target) image.save(target)

View File

@ -42,6 +42,7 @@ class DialogOptions(QtGui.QDialog):
self.checkboxOverwrite.setChecked(self.book.overwrite) self.checkboxOverwrite.setChecked(self.book.overwrite)
self.checkboxOrient.setChecked(self.book.imageFlags & ImageFlags.Orient) self.checkboxOrient.setChecked(self.book.imageFlags & ImageFlags.Orient)
self.checkboxResize.setChecked(self.book.imageFlags & ImageFlags.Resize) 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.checkboxQuantize.setChecked(self.book.imageFlags & ImageFlags.Quantize)
self.checkboxFrame.setChecked(self.book.imageFlags & ImageFlags.Frame) self.checkboxFrame.setChecked(self.book.imageFlags & ImageFlags.Frame)
@ -57,10 +58,12 @@ class DialogOptions(QtGui.QDialog):
imageFlags |= ImageFlags.Orient imageFlags |= ImageFlags.Orient
if self.checkboxResize.isChecked(): if self.checkboxResize.isChecked():
imageFlags |= ImageFlags.Resize imageFlags |= ImageFlags.Resize
if self.checkboxStretch.isChecked():
imageFlags |= ImageFlags.Stretch
if self.checkboxQuantize.isChecked(): if self.checkboxQuantize.isChecked():
imageFlags |= ImageFlags.Quantize imageFlags |= ImageFlags.Quantize
if self.checkboxFrame.isChecked(): if self.checkboxFrame.isChecked():
imageFlags |= ImageFlags.Frame imageFlags |= ImageFlags.Frame
modified = ( modified = (
self.book.title != title or self.book.title != title or

49
mangle/pdfimage.py Normal file
View File

@ -0,0 +1,49 @@
# Copyright (C) 2012 Cristian Lizana <cristian@lizana.in>
#
# 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 <http://www.gnu.org/licenses/>.
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()

View File

@ -99,7 +99,7 @@
<widget class="QComboBox" name="comboBoxFormat"> <widget class="QComboBox" name="comboBoxFormat">
<item> <item>
<property name="text"> <property name="text">
<string>Images &amp; CBZ</string> <string>Images &amp; CBZ &amp; PDF</string>
</property> </property>
</item> </item>
<item> <item>
@ -107,6 +107,11 @@
<string>Images only</string> <string>Images only</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>PDF only</string>
</property>
</item>
<item> <item>
<property name="text"> <property name="text">
<string>CBZ only</string> <string>CBZ only</string>
@ -130,13 +135,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="checkboxResize">
<property name="text">
<string>Resize images to center on screen</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="checkboxQuantize"> <widget class="QCheckBox" name="checkboxQuantize">
<property name="text"> <property name="text">
@ -150,6 +148,27 @@
<string>Draw frame around images</string> <string>Draw frame around images</string>
</property> </property>
</widget> </widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Size</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="checkboxResize">
<property name="text">
<string>Resize images to center on screen</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="checkboxStretch">
<property name="text">
<string>Stretch images to fill the screen</string>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>