Merge branch 'master' of https://github.com/FooSoft/mangle
This commit is contained in:
commit
87701a38ec
28
.gitignore
vendored
28
.gitignore
vendored
@ -5,3 +5,31 @@ dist
|
|||||||
*.mngl
|
*.mngl
|
||||||
*.cbz
|
*.cbz
|
||||||
*.bat
|
*.bat
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
*.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
@ -45,7 +45,7 @@ def natural_key(string_):
|
|||||||
|
|
||||||
|
|
||||||
class Book(object):
|
class Book(object):
|
||||||
DefaultDevice = 'Kindle Paperwhite'
|
DefaultDevice = 'Kindle Paperwhite 3/Voyage/Oasis'
|
||||||
DefaultOutputFormat = 'CBZ only'
|
DefaultOutputFormat = 'CBZ only'
|
||||||
DefaultOverwrite = True
|
DefaultOverwrite = True
|
||||||
DefaultImageFlags = ImageFlags.Orient | ImageFlags.Resize | ImageFlags.Quantize
|
DefaultImageFlags = ImageFlags.Orient | ImageFlags.Resize | ImageFlags.Quantize
|
||||||
|
@ -36,6 +36,7 @@ class DialogConvert(QtGui.QProgressDialog):
|
|||||||
self.setWindowTitle('Exporting book...')
|
self.setWindowTitle('Exporting book...')
|
||||||
self.setMaximum(len(self.book.images))
|
self.setMaximum(len(self.book.images))
|
||||||
self.setValue(0)
|
self.setValue(0)
|
||||||
|
self.increment = 0
|
||||||
|
|
||||||
self.archive = None
|
self.archive = None
|
||||||
if 'CBZ' in self.book.outputFormat:
|
if 'CBZ' in self.book.outputFormat:
|
||||||
@ -79,7 +80,8 @@ class DialogConvert(QtGui.QProgressDialog):
|
|||||||
|
|
||||||
def onTimer(self):
|
def onTimer(self):
|
||||||
index = self.value()
|
index = self.value()
|
||||||
target = os.path.join(self.bookPath, '%05d.png' % index)
|
pages_split = self.increment
|
||||||
|
target = os.path.join(self.bookPath, '%05d.png' % (index + pages_split))
|
||||||
source = unicode(self.book.images[index])
|
source = unicode(self.book.images[index])
|
||||||
|
|
||||||
if index == 0:
|
if index == 0:
|
||||||
@ -121,30 +123,34 @@ class DialogConvert(QtGui.QProgressDialog):
|
|||||||
archive = self.archive
|
archive = self.archive
|
||||||
pdf = self.pdf
|
pdf = self.pdf
|
||||||
|
|
||||||
# Maybe the user ask for a split, but the picture is not a large one, so skip
|
# Check if page wide enough to split
|
||||||
# it but only for this picture
|
if (flags & ImageFlags.SplitRightLeft) or (flags & ImageFlags.SplitLeftRight):
|
||||||
if (flags & ImageFlags.Split) or (flags & ImageFlags.SplitInverse):
|
|
||||||
if not image.isSplitable(source):
|
if not image.isSplitable(source):
|
||||||
# remove split flags
|
# remove split flags
|
||||||
splitFlags= [ImageFlags.Split, ImageFlags.SplitInverse, ImageFlags.SplitRight, ImageFlags.SplitLeft]
|
splitFlags = [ImageFlags.SplitRightLeft, ImageFlags.SplitLeftRight, ImageFlags.SplitRight,
|
||||||
|
ImageFlags.SplitLeft]
|
||||||
for f in splitFlags:
|
for f in splitFlags:
|
||||||
flags &= ~f
|
flags &= ~f
|
||||||
|
|
||||||
# For right page (if requested in options and need for this image)
|
# For right page (if requested in options and need for this image)
|
||||||
if (flags & ImageFlags.Split):
|
if flags & ImageFlags.SplitRightLeft:
|
||||||
# New path based on modified index
|
self.convertAndSave(source, target, device,
|
||||||
target = os.path.join(self.bookPath, '%05d.png' % (index * 2 + 0))
|
flags ^ ImageFlags.SplitRightLeft | ImageFlags.SplitRight,
|
||||||
self.convertAndSave(source, target, device, flags ^ ImageFlags.Split | ImageFlags.SplitRight, archive, pdf)
|
archive, pdf)
|
||||||
# Change target once again for left page
|
|
||||||
target = os.path.join(self.bookPath, '%05d.png' % (index * 2 + 1))
|
# Change target for left page
|
||||||
|
target = os.path.join(self.bookPath, '%05d.png' % (index + pages_split + 1))
|
||||||
|
self.increment += 1
|
||||||
|
|
||||||
# For right page (if requested), but in inverted mode
|
# For right page (if requested), but in inverted mode
|
||||||
if (flags & ImageFlags.SplitInverse):
|
if flags & ImageFlags.SplitLeftRight:
|
||||||
# New path based on modified index
|
self.convertAndSave(source, target, device,
|
||||||
target = os.path.join(self.bookPath, '%05d.png' % (index * 2 + 0))
|
flags ^ ImageFlags.SplitLeftRight | ImageFlags.SplitLeft,
|
||||||
self.convertAndSave(source, target, device, flags ^ ImageFlags.SplitInverse | ImageFlags.SplitLeft, archive, pdf)
|
archive, pdf)
|
||||||
# Change target once again for left page
|
|
||||||
target = os.path.join(self.bookPath, '%05d.png' % (index * 2 + 1))
|
# Change target for left page
|
||||||
|
target = os.path.join(self.bookPath, '%05d.png' % (index + pages_split + 1))
|
||||||
|
self.increment += 1
|
||||||
|
|
||||||
# Convert page
|
# Convert page
|
||||||
self.convertAndSave(source, target, device, flags, archive, pdf)
|
self.convertAndSave(source, target, device, flags, archive, pdf)
|
||||||
|
@ -20,16 +20,16 @@ from PIL import Image, ImageDraw, ImageStat, ImageChops
|
|||||||
|
|
||||||
|
|
||||||
class ImageFlags:
|
class ImageFlags:
|
||||||
Orient = 1 << 0
|
Orient = 1 << 0
|
||||||
Resize = 1 << 1
|
Resize = 1 << 1
|
||||||
Frame = 1 << 2
|
Frame = 1 << 2
|
||||||
Quantize = 1 << 3
|
Quantize = 1 << 3
|
||||||
Stretch = 1 << 4
|
Stretch = 1 << 4
|
||||||
Split = 1 << 5 # split right then left
|
SplitRightLeft = 1 << 5 # split right then left
|
||||||
SplitRight = 1 << 6 # split only the right page
|
SplitRight = 1 << 6 # split only the right page
|
||||||
SplitLeft = 1 << 7 # split only the left page
|
SplitLeft = 1 << 7 # split only the left page
|
||||||
SplitInverse = 1 << 8 # split left then right page
|
SplitLeftRight = 1 << 8 # split left then right page
|
||||||
AutoCrop = 1 << 9 # split left then right page
|
AutoCrop = 1 << 9
|
||||||
|
|
||||||
|
|
||||||
class KindleData:
|
class KindleData:
|
||||||
@ -78,16 +78,17 @@ class KindleData:
|
|||||||
|
|
||||||
Profiles = {
|
Profiles = {
|
||||||
'Kindle 1': ((600, 800), Palette4),
|
'Kindle 1': ((600, 800), Palette4),
|
||||||
'Kindle 2': ((600, 800), Palette15a),
|
'Kindle 2/3/Touch': ((600, 800), Palette15a),
|
||||||
'Kindle 3': ((600, 800), Palette15a),
|
'Kindle 4 & 5': ((600, 800), Palette15b),
|
||||||
'Kindle 4': ((600, 800), Palette15b),
|
'Kindle DX/DXG': ((824, 1200), Palette15a),
|
||||||
'Kindle 5': ((600, 800), Palette15b),
|
'Kindle Paperwhite 1 & 2': ((758, 1024), Palette15b),
|
||||||
'Kindle DX': ((824, 1200), Palette15a),
|
'Kindle Paperwhite 3/Voyage/Oasis': ((1072, 1448), Palette15b),
|
||||||
'Kindle DXG': ((824, 1200), Palette15a),
|
'Kobo Mini/Touch': ((600, 800), Palette15b),
|
||||||
'Kindle Touch': ((600, 800), Palette15a),
|
'Kobo Glo': ((768, 1024), Palette15b),
|
||||||
'Kindle Paperwhite': ((758, 1024), Palette15b), # resolution given in manual, see http://kindle.s3.amazonaws.com/Kindle_Paperwhite_Users_Guide.pdf
|
'Kobo Glo HD': ((1072, 1448), Palette15b),
|
||||||
'Kindle Paperwhite 3': ((1072, 1448), Palette15b),
|
'Kobo Aura': ((758, 1024), Palette15b),
|
||||||
'KoBo Aura H2o': ((1080, 1430), Palette15a), # resolution from http://www.fnac.com/Liseuse-Numerique-Kobo-by-Fnac-Kobo-Aura-H2O-Noir/a7745120/w-4
|
'Kobo Aura HD': ((1080, 1440), Palette15b),
|
||||||
|
'Kobo Aura H2O': ((1080, 1430), Palette15a),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -102,12 +103,14 @@ def protect_bad_image(func):
|
|||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
except IOError: # Exception from PIL about bad image
|
except IOError: # Exception from PIL about bad image
|
||||||
return args[0]
|
return args[0]
|
||||||
|
|
||||||
return func_wrapper
|
return func_wrapper
|
||||||
|
|
||||||
|
|
||||||
@protect_bad_image
|
@protect_bad_image
|
||||||
def splitLeft(image):
|
def splitLeft(image):
|
||||||
widthImg, heightImg = image.size
|
widthImg, heightImg = image.size
|
||||||
|
|
||||||
return image.crop((0, 0, widthImg / 2, heightImg))
|
return image.crop((0, 0, widthImg / 2, heightImg))
|
||||||
|
|
||||||
|
|
||||||
@ -188,6 +191,7 @@ def autoCropImage(image):
|
|||||||
except TypeError: # bad image, specific to chops
|
except TypeError: # bad image, specific to chops
|
||||||
return image
|
return image
|
||||||
image = image.crop((x0, y0, xend, yend))
|
image = image.crop((x0, y0, xend, yend))
|
||||||
|
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
@ -253,29 +257,22 @@ def convertImage(source, target, device, flags):
|
|||||||
# Load image from source path
|
# Load image from source path
|
||||||
image = loadImage(source)
|
image = loadImage(source)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Format according to palette
|
# Format according to palette
|
||||||
image = formatImage(image)
|
image = formatImage(image)
|
||||||
# Apply flag transforms
|
|
||||||
|
|
||||||
# Second pass of first split
|
# Apply flag transforms
|
||||||
if flags & ImageFlags.SplitRight:
|
if flags & ImageFlags.SplitRight:
|
||||||
image = splitRight(image)
|
image = splitRight(image)
|
||||||
# First pass of first split option
|
if flags & ImageFlags.SplitRightLeft:
|
||||||
if (flags & ImageFlags.Split):
|
|
||||||
image = splitLeft(image)
|
image = splitLeft(image)
|
||||||
# First pass of second splitting option
|
|
||||||
if flags & ImageFlags.SplitLeft:
|
if flags & ImageFlags.SplitLeft:
|
||||||
image = splitLeft(image)
|
image = splitLeft(image)
|
||||||
# second pass of second splitting option
|
if flags & ImageFlags.SplitLeftRight:
|
||||||
if (flags & ImageFlags.SplitInverse):
|
|
||||||
image = splitRight(image)
|
image = splitRight(image)
|
||||||
|
|
||||||
# Auto crop the image, but before manage size and co, clean the source so
|
# Auto crop the image, but before manage size and co, clean the source so
|
||||||
if flags & ImageFlags.AutoCrop:
|
if flags & ImageFlags.AutoCrop:
|
||||||
image = autoCropImage(image)
|
image = autoCropImage(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:
|
||||||
@ -284,9 +281,6 @@ def convertImage(source, target, device, flags):
|
|||||||
image = stretchImage(image, size)
|
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)
|
||||||
|
|
||||||
|
@ -69,9 +69,9 @@ class DialogOptions(QtGui.QDialog):
|
|||||||
if self.checkboxFrame.isChecked():
|
if self.checkboxFrame.isChecked():
|
||||||
imageFlags |= ImageFlags.Frame
|
imageFlags |= ImageFlags.Frame
|
||||||
if self.checkboxSplit.isChecked():
|
if self.checkboxSplit.isChecked():
|
||||||
imageFlags |= ImageFlags.Split
|
imageFlags |= ImageFlags.SplitRightLeft
|
||||||
if self.checkboxSplitInverse.isChecked():
|
if self.checkboxSplitInverse.isChecked():
|
||||||
imageFlags |= ImageFlags.SplitInverse
|
imageFlags |= ImageFlags.SplitLeftRight
|
||||||
if self.checkboxAutoCrop.isChecked():
|
if self.checkboxAutoCrop.isChecked():
|
||||||
imageFlags |= ImageFlags.AutoCrop
|
imageFlags |= ImageFlags.AutoCrop
|
||||||
|
|
||||||
|
@ -63,52 +63,57 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Kindle 2</string>
|
<string>Kindle 2/3/Touch</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Kindle 3</string>
|
<string>Kindle 4 & 5</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Kindle 4</string>
|
<string>Kindle DX/DXG</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Kindle 5</string>
|
<string>Kindle Paperwhite 1 & 2</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Kindle DX</string>
|
<string>Kindle Paperwhite 3/Voyage/Oasis</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Kindle DXG</string>
|
<string>Kobo Mini/Touch</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Kindle Touch</string>
|
<string>Kobo Glo</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Kindle Paperwhite</string>
|
<string>Kobo Glo HD</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Kindle Paperwhite 3</string>
|
<string>Kobo Aura</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>KoBo Aura H2o</string>
|
<string>Kobo Aura HD</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Kobo Aura H2O</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
|
Loading…
Reference in New Issue
Block a user