about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaweł Jastrzębski <[email protected]>2016-11-22 08:53:56 +0100
committerGitHub <[email protected]>2016-11-22 08:53:56 +0100
commitdd5c907bad7b2d2623b970d7f2c7559af154f937 (patch)
tree3f8c5205afc008887841dcd4dead321d29fc49ce
parentMerge pull request #207 from ciromattia/dev (diff)
parentUpdated README + version bump (diff)
downloadkcc-dd5c907bad7b2d2623b970d7f2c7559af154f937.tar.gz
kcc-dd5c907bad7b2d2623b970d7f2c7559af154f937.tar.bz2
kcc-dd5c907bad7b2d2623b970d7f2c7559af154f937.zip
Merge pull request #215 from ciromattia/dev
5.2
-rw-r--r--README.md35
-rw-r--r--gui/KCC.ui4
-rw-r--r--kcc.iss2
-rw-r--r--kcc/KCC_gui.py66
-rw-r--r--kcc/KCC_ui.py4
-rw-r--r--kcc/__init__.py2
-rw-r--r--kcc/cbxarchive.py6
-rwxr-xr-xkcc/comic2ebook.py105
-rw-r--r--kcc/comic2panel.py8
-rwxr-xr-xkcc/image.py229
-rw-r--r--kcc/shared.py3
-rw-r--r--other/osx/Info.plist6
12 files changed, 185 insertions, 285 deletions
diff --git a/README.md b/README.md
index f700680..cfaf214 100644
--- a/README.md
+++ b/README.md
@@ -75,9 +75,11 @@ Usage: kcc-c2e [options] comic_file|comic_folder
 Options:
   MAIN:
     -p PROFILE, --profile=PROFILE
-                        Device profile (Available options: K1, K2, K3, K45, KDX,
-                        KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO) [Default=KV]
+                        Device profile (Available options: K1, K2, K3, K45,
+                        KDX, KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O,
+                        KoAO) [Default=KV]
     -m, --manga-style   Manga style (right-to-left reading and splitting)
+    -2, --two-panel     Display two not four panels in Panel View mode
     -w, --webtoon       Webtoon processing mode
 
   OUTPUT SETTINGS:
@@ -86,29 +88,28 @@ Options:
     -t TITLE, --title=TITLE
                         Comic title [Default=filename or directory name]
     -f FORMAT, --format=FORMAT
-                        Output format (Available options: Auto, MOBI, EPUB, CBZ)
-                        [Default=Auto]
+                        Output format (Available options: Auto, MOBI, EPUB,
+                        CBZ) [Default=Auto]
     -b, --batchsplit    Split output into multiple files
 
   PROCESSING:
     -u, --upscale       Resize images smaller than device's resolution
     -s, --stretch       Stretch images to device's resolution
     -r SPLITTER, --splitter=SPLITTER
-                        Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]
+                        Double page parsing mode. 0: Split 1: Rotate 2: Both
+                        [Default=0]
     -g GAMMA, --gamma=GAMMA
-                        Apply gamma correction to linearize the image [Default=Auto]
-    --hq                Enable high quality Panel View
+                        Apply gamma correction to linearize the image
+                        [Default=Auto]
+    -c CROPPING, --cropping=CROPPING
+                        Set cropping mode. 0: Disabled 1: Margins 2: Margins +
+                        page numbers [Default=2]
+    --cp=CROPPINGP, --croppingpower=CROPPINGP
+                        Set cropping power [Default=1.0]
     --blackborders      Disable autodetection and force black borders
     --whiteborders      Disable autodetection and force white borders
     --forcecolor        Don't convert images to grayscale
     --forcepng          Create PNG files instead JPEG
-    --cropping=CROPPING
-                        Set cropping mode. 0: Disabled 1: Margins 2: Margins +
-                        page numbers [Default=2]
-    --croppingpower=CROPPINGP
-                        Set margin cropping threshold [Default=0.1]
-    --croppingpowerpage=CROPPINGPN
-                        Set page number cropping threshold [Default=5.0]
 
   CUSTOM PROFILE:
     --customwidth=CUSTOMWIDTH
@@ -159,6 +160,12 @@ The app relies and includes the following scripts:
 * [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
 
 ## CHANGELOG
+####5.2:
+* Added new Panel View options
+* Implemented new margin detection algorithm
+* Removed HQ Panel View mode
+* Fixed multiple smaller issues
+
 ####5.1.3:
 * Added Kobo Aura ONE profile
 * Fixed few small bugs
diff --git a/gui/KCC.ui b/gui/KCC.ui
index eb8b84e..3bdd917 100644
--- a/gui/KCC.ui
+++ b/gui/KCC.ui
@@ -174,10 +174,10 @@
        <item row="0" column="2">
         <widget class="QCheckBox" name="qualityBox">
          <property name="toolTip">
-          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;High quality Panel View.&lt;br/&gt;Require source files with bigger resolution than target device.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Highly impact size of output file!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style=\'white-space:pre\'&gt;&lt;span style=\&quot; font-weight:600; text-decoration: underline;\&quot;&gt;Unchecked - 4 panels&lt;br/&gt;&lt;/span&gt;Zoom each corner separately.&lt;/p&gt;&lt;p style=\'white-space:pre\'&gt;&lt;span style=\&quot; font-weight:600; text-decoration: underline;\&quot;&gt;Checked - 2 panels&lt;br/&gt;&lt;/span&gt;Zoom only the top and bottom of the page.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
          </property>
          <property name="text">
-          <string>HQ zoom</string>
+          <string>Panel View 4/2</string>
          </property>
         </widget>
        </item>
diff --git a/kcc.iss b/kcc.iss
index d536ab2..28a7317 100644
--- a/kcc.iss
+++ b/kcc.iss
@@ -1,5 +1,5 @@
 #define MyAppName "Kindle Comic Converter"
-#define MyAppVersion "5.1.3"
+#define MyAppVersion "5.2"
 #define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
 #define MyAppURL "http://kcc.iosphe.re/"
 #define MyAppExeName "KCC.exe"
diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py
index c773529..dcc9e1b 100644
--- a/kcc/KCC_gui.py
+++ b/kcc/KCC_gui.py
@@ -33,7 +33,7 @@ from distutils.version import StrictVersion
 from xml.sax.saxutils import escape
 from platform import platform
 from raven import Client
-from .shared import md5Checksum, HTMLStripper, sanitizeTrace
+from .shared import md5Checksum, HTMLStripper, sanitizeTrace, saferRemove
 from . import __version__
 from . import comic2ebook
 from . import metadata
@@ -257,7 +257,7 @@ class WorkerThread(QtCore.QThread):
         elif GUI.rotateBox.checkState() == 2:
             options.splitter = 1
         if GUI.qualityBox.isChecked():
-            options.hqmode = True
+            options.autoscale = True
         if GUI.webtoonBox.isChecked():
             options.webtoon = True
         if GUI.upscaleBox.checkState() == 1:
@@ -331,7 +331,7 @@ class WorkerThread(QtCore.QThread):
                 if 'outputPath' in locals():
                     for item in outputPath:
                         if os.path.exists(item):
-                            os.remove(item)
+                            saferRemove(item)
                 self.clean()
                 return
             if not self.errors:
@@ -358,9 +358,9 @@ class WorkerThread(QtCore.QThread):
                     if not self.conversionAlive:
                         for item in outputPath:
                             if os.path.exists(item):
-                                os.remove(item)
+                                saferRemove(item)
                             if os.path.exists(item.replace('.epub', '.mobi')):
-                                os.remove(item.replace('.epub', '.mobi'))
+                                saferRemove(item.replace('.epub', '.mobi'))
                         self.clean()
                         return
                     if self.kindlegenErrorCode[0] == 0:
@@ -381,7 +381,7 @@ class WorkerThread(QtCore.QThread):
                             for item in outputPath:
                                 GUI.progress.content = ''
                                 mobiPath = item.replace('.epub', '.mobi')
-                                os.remove(mobiPath + '_toclean')
+                                saferRemove(mobiPath + '_toclean')
                                 if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(mobiPath):
                                     try:
                                         move(mobiPath, GUI.targetDirectory)
@@ -393,15 +393,15 @@ class WorkerThread(QtCore.QThread):
                                 for item in outputPath:
                                     comic2ebook.options.covers[outputPath.index(item)][0].saveToKindle(
                                         k, comic2ebook.options.covers[outputPath.index(item)][1])
-                                MW.addMessage.emit('Kindle detected. Uploading covers...', 'info', False)
+                                MW.addMessage.emit('Kindle detected. Uploading covers... <b>Done!</b>', 'info', False)
                         else:
                             GUI.progress.content = ''
                             for item in outputPath:
                                 mobiPath = item.replace('.epub', '.mobi')
                                 if os.path.exists(mobiPath):
-                                    os.remove(mobiPath)
+                                    saferRemove(mobiPath)
                                 if os.path.exists(mobiPath + '_toclean'):
-                                    os.remove(mobiPath + '_toclean')
+                                    saferRemove(mobiPath + '_toclean')
                             MW.addMessage.emit('Failed to process MOBI file!', 'error', False)
                             MW.addTrayMessage.emit('Failed to process MOBI file!', 'Critical')
                     else:
@@ -409,9 +409,9 @@ class WorkerThread(QtCore.QThread):
                         epubSize = (os.path.getsize(self.kindlegenErrorCode[2])) // 1024 // 1024
                         for item in outputPath:
                             if os.path.exists(item):
-                                os.remove(item)
+                                saferRemove(item)
                             if os.path.exists(item.replace('.epub', '.mobi')):
-                                os.remove(item.replace('.epub', '.mobi'))
+                                saferRemove(item.replace('.epub', '.mobi'))
                         MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False)
                         MW.addTrayMessage.emit('KindleGen failed to create MOBI!', 'Critical')
                         if self.kindlegenErrorCode[0] == 1 and self.kindlegenErrorCode[1] != '':
@@ -603,7 +603,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
             GUI.upscaleBox.setEnabled(False)
             GUI.upscaleBox.setChecked(True)
         else:
-            GUI.qualityBox.setEnabled(True)
+            profile = GUI.profiles[str(GUI.deviceBox.currentText())]
+            if profile['PVOptions']:
+                GUI.qualityBox.setEnabled(True)
             GUI.mangaBox.setEnabled(True)
             GUI.rotateBox.setEnabled(True)
             GUI.upscaleBox.setEnabled(True)
@@ -629,9 +631,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
         self.changeFormat()
         GUI.gammaSlider.setValue(0)
         self.changeGamma(0)
-        GUI.qualityBox.setEnabled(profile['Quality'])
+        GUI.qualityBox.setEnabled(profile['PVOptions'])
         GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
-        if not profile['Quality']:
+        if not profile['PVOptions']:
             GUI.qualityBox.setChecked(False)
         if str(GUI.deviceBox.currentText()) == 'Other':
             self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/NonKindle-devices">'
@@ -643,7 +645,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
             GUI.formatBox.setCurrentIndex(outputFormat)
         else:
             GUI.formatBox.setCurrentIndex(profile['DefaultFormat'])
-        GUI.qualityBox.setEnabled(profile['Quality'])
+        GUI.qualityBox.setEnabled(profile['PVOptions'])
 
     def stripTags(self, html):
         s = HTMLStripper()
@@ -894,39 +896,39 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
                 MW.resize(500, 500)
 
         self.profiles = {
-            "Kindle Oasis": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
+            "Kindle Oasis": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
                              'DefaultUpscale': True, 'Label': 'KV'},
-            "Kindle Voyage": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
+            "Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
                               'DefaultUpscale': True, 'Label': 'KV'},
-            "Kindle PW 3": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
+            "Kindle PW 3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
                             'DefaultUpscale': True, 'Label': 'KV'},
-            "Kindle PW 1/2": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
+            "Kindle PW 1/2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
                               'DefaultUpscale': False, 'Label': 'KPW'},
-            "Kindle": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
+            "Kindle": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
                        'DefaultUpscale': False, 'Label': 'K45'},
-            "Kindle DX/DXG": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 2,
+            "Kindle DX/DXG": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
                               'DefaultUpscale': False, 'Label': 'KDX'},
-            "Kobo Mini/Touch": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
+            "Kobo Mini/Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
                                 'DefaultUpscale': False, 'Label': 'KoMT'},
-            "Kobo Glo": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
+            "Kobo Glo": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
                          'DefaultUpscale': False, 'Label': 'KoG'},
-            "Kobo Glo HD": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
+            "Kobo Glo HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
                             'DefaultUpscale': False, 'Label': 'KoGHD'},
-            "Kobo Aura": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
+            "Kobo Aura": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
                           'DefaultUpscale': False, 'Label': 'KoA'},
-            "Kobo Aura HD": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
+            "Kobo Aura HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
                              'DefaultUpscale': True, 'Label': 'KoAHD'},
-            "Kobo Aura H2O": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
+            "Kobo Aura H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
                               'DefaultUpscale': True, 'Label': 'KoAH2O'},
-            "Kobo Aura ONE": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
+            "Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
                               'DefaultUpscale': True, 'Label': 'KoAO'},
-            "Other": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 1,
+            "Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1,
                       'DefaultUpscale': False, 'Label': 'OTHER'},
-            "Kindle 1": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
+            "Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
                          'DefaultUpscale': False, 'Label': 'K1'},
-            "Kindle 2": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
+            "Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
                          'DefaultUpscale': False, 'Label': 'K2'},
-            "Kindle 3": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
+            "Kindle 3": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
                          'DefaultUpscale': False, 'Label': 'K3'},
         }
         profilesGUI = [
diff --git a/kcc/KCC_ui.py b/kcc/KCC_ui.py
index 5418e3e..5e718ef 100644
--- a/kcc/KCC_ui.py
+++ b/kcc/KCC_ui.py
@@ -241,8 +241,8 @@ class Ui_mainWindow(object):
         self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
         self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>"))
         self.rotateBox.setText(_translate("mainWindow", "Spread splitter"))
-        self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>High quality Panel View.<br/>Require source files with bigger resolution than target device.<br/><span style=\" font-weight:600;\">Highly impact size of output file!</span></p></body></html>"))
-        self.qualityBox.setText(_translate("mainWindow", "HQ zoom"))
+        self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2 panels<br/></span>Zoom only the top and bottom of the page.</p></body></html>"))
+        self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2"))
         self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>"))
         self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode"))
         self.upscaleBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>"))
diff --git a/kcc/__init__.py b/kcc/__init__.py
index 5382553..d4f4bd0 100644
--- a/kcc/__init__.py
+++ b/kcc/__init__.py
@@ -1,4 +1,4 @@
-__version__ = '5.1.3'
+__version__ = '5.2'
 __license__ = 'ISC'
 __copyright__ = '2012-2016, Ciro Mattia Gonano <[email protected]>, Pawel Jastrzebski <[email protected]>'
 __docformat__ = 'restructuredtext en'
diff --git a/kcc/cbxarchive.py b/kcc/cbxarchive.py
index 569dad5..3c857e7 100644
--- a/kcc/cbxarchive.py
+++ b/kcc/cbxarchive.py
@@ -27,7 +27,7 @@ try:
 except ImportError:
     walk = os.walk
 from . import rarfile
-from .shared import check7ZFile as is_7zfile, saferReplace
+from .shared import check7ZFile as is_7zfile, saferReplace, saferRemove
 
 
 class CBxArchive:
@@ -66,7 +66,7 @@ class CBxArchive:
         for root, dirnames, filenames in walk(targetdir):
             for filename in filenames:
                 if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
-                    os.remove(os.path.join(root, filename))
+                    saferRemove(os.path.join(root, filename))
 
     def extractCB7(self, targetdir):
         # Workaround for some wide UTF-8 + Popen abnormalities
@@ -80,7 +80,7 @@ class CBxArchive:
             if b"Everything is Ok" in line:
                 extracted = True
         if sys.platform.startswith('darwin'):
-            os.remove(self.origFileName)
+            saferRemove(self.origFileName)
         if not extracted:
             raise OSError
 
diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py
index a303739..da9c906 100755
--- a/kcc/comic2ebook.py
+++ b/kcc/comic2ebook.py
@@ -95,8 +95,6 @@ def buildHTML(path, imgfile, imgfilepath):
         additionalStyle = 'background-color:#FFFFFF;'
     htmlpath = ''
     postfix = ''
-    size = ''
-    imgfilepv = ''
     backref = 1
     head = path
     while True:
@@ -122,21 +120,16 @@ def buildHTML(path, imgfile, imgfilepath):
                   "<body style=\"background-image: ",
                   "url('", "../" * backref, "Images/", postfix, imgfile, "'); " + additionalStyle + "\">\n"])
     if options.iskindle and options.panelview:
-        if options.hqmode:
-            imgfilepv = list(os.path.splitext(imgfile))
-            imgfilepv[0] += "-hq"
-            imgfilepv = "".join(imgfilepv)
-            if os.path.isfile(os.path.join(head, "Images", postfix, imgfilepv)):
-                size = Image.open(os.path.join(head, "Images", postfix, imgfilepv)).size
-        if not options.hqmode or not size:
-            imgfilepv = imgfile
-            sizeTmp = Image.open(os.path.join(head, "Images", postfix, imgfilepv)).size
+        sizeTmp = Image.open(os.path.join(head, "Images", postfix, imgfile)).size
+        if options.autoscale:
+            size = (getPanelViewResolution(sizeTmp, deviceres))
+        else:
             size = (int(sizeTmp[0] * 1.5), int(sizeTmp[1] * 1.5))
-        if size[0] <= deviceres[0]:
+        if size[0] - deviceres[0] < deviceres[0] * 0.01:
             noHorizontalPV = True
         else:
             noHorizontalPV = False
-        if size[1] <= deviceres[1]:
+        if size[1] - deviceres[1] < deviceres[1] * 0.01:
             noVerticalPV = True
         else:
             noVerticalPV = False
@@ -193,7 +186,7 @@ def buildHTML(path, imgfile, imgfilepath):
         for box in boxes:
             f.writelines(["<div class=\"PV-P\" id=\"" + box + "-P\" style=\"" + additionalStyle + "\">\n",
                           "<img style=\"" + boxStyles[box] + "\" src=\"", "../" * backref, "Images/", postfix,
-                          imgfilepv, "\" width=\"" + str(size[0]) + "\" height=\"" + str(size[1]) + "\"/>\n",
+                          imgfile, "\" width=\"" + str(size[0]) + "\" height=\"" + str(size[1]) + "\"/>\n",
                           "</div>\n"])
     f.writelines(["</body>\n",
                   "</html>\n"])
@@ -336,29 +329,6 @@ def buildOPF(dstdir, title, filelist, cover=None):
         f.write("</manifest>\n<spine page-progression-direction=\"rtl\" toc=\"ncx\">\n")
     else:
         f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
-    # if options.iskindle and options.profile != 'Custom':
-    #     if options.righttoleft:
-    #         nextflow = 'right'
-    #     else:
-    #         nextflow = 'left'
-    #     for entry in reflist:
-    #         if '-kcc-b' in entry:
-    #             if options.righttoleft:
-    #                 f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-right\"/>\n")
-    #             else:
-    #                 f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-left\"/>\n")
-    #         elif '-kcc-c' in entry:
-    #             if options.righttoleft:
-    #                 f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-left\"/>\n")
-    #             else:
-    #                 f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-right\"/>\n")
-    #         else:
-    #             f.write("<itemref idref=\"page_" + entry + "\" properties=\"facing-page-" + nextflow + "\"/>\n")
-    #             if nextflow == 'right':
-    #                 nextflow = 'left'
-    #             else:
-    #                 nextflow = 'right'
-    # else:
     for entry in reflist:
         f.write("<itemref idref=\"page_" + entry + "\"/>\n")
     f.write("</spine>\n</package>\n")
@@ -460,17 +430,15 @@ def buildEPUB(path, chapterNames, tomeNumber):
         chapter = False
         dirnames, filenames = walkSort(dirnames, filenames)
         for afile in filenames:
-            filename = getImageFileName(afile)
-            if not filename[0].endswith('-hq'):
-                filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile)))
-                if not chapter:
-                    chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1]))
-                    chapter = True
-                if cover is None:
-                    cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
-                                         'cover' + getImageFileName(filelist[-1][1])[1])
-                    options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options,
-                                                       tomeNumber), options.uuid))
+            filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile)))
+            if not chapter:
+                chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1]))
+                chapter = True
+            if cover is None:
+                cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
+                                     'cover' + getImageFileName(filelist[-1][1])[1])
+                options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options,
+                                                   tomeNumber), options.uuid))
     # Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
     if not chapterNames and options.chapters:
         chapterlist = []
@@ -548,10 +516,10 @@ def imgFileProcessing(work):
         workImg = image.ComicPageParser((dirpath, afile), opt)
         for i in workImg.payload:
             img = image.ComicPage(i[0], i[1], i[2], i[3], i[4], opt)
-            if opt.cropping > 0 and not opt.webtoon:
-                img.cropWhiteSpace(opt.croppingp)
             if opt.cropping == 2 and not opt.webtoon:
-                img.cutPageNumber(opt.croppingpn)
+                img.cropPageNumber(opt.croppingp)
+            if opt.cropping > 0 and not opt.webtoon:
+                img.cropMargin(opt.croppingp)
             img.autocontrastImage()
             img.resizeImage()
             if opt.forcepng and not opt.forcecolor:
@@ -653,7 +621,7 @@ def getComicInfo(path, originalPath):
         try:
             xml = metadata.MetadataParser(xmlPath)
         except Exception:
-            os.remove(xmlPath)
+            saferRemove(xmlPath)
             return
         options.authors = []
         if defaultTitle:
@@ -678,7 +646,7 @@ def getComicInfo(path, originalPath):
             options.chapters = xml.data['Bookmarks']
         if xml.data['Summary']:
             options.summary = escape(xml.data['Summary'])
-        os.remove(xmlPath)
+        saferRemove(xmlPath)
 
 
 def getCoversFromMCB(mangaID):
@@ -704,6 +672,11 @@ def getDirectorySize(start_path='.'):
     return total_size
 
 
+def getPanelViewResolution(imageSize, deviceRes):
+    scale = float(deviceRes[0]) / float(imageSize[0])
+    return int(deviceRes[0]), int(scale * imageSize[1])
+
+
 def getPanelViewSize(deviceres, size):
     x = int(deviceres[0] / 2 - size[0] / 2) / deviceres[0] * 100
     y = int(deviceres[1] / 2 - size[1] / 2) / deviceres[1] * 100
@@ -963,6 +936,8 @@ def makeParser():
                                 " KoA, KoAHD, KoAH2O, KoAO) [Default=KV]")
     mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
                            help="Manga style (right-to-left reading and splitting)")
+    mainOptions.add_option("-2", "--two-panel", action="store_true", dest="autoscale", default=False,
+                           help="Display two not four panels in Panel View mode")
     mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
                            help="Webtoon processing mode"),
 
@@ -983,8 +958,10 @@ def makeParser():
                                  help="Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]")
     processingOptions.add_option("-g", "--gamma", type="float", dest="gamma", default="0.0",
                                  help="Apply gamma correction to linearize the image [Default=Auto]")
-    processingOptions.add_option("--hq", action="store_true", dest="hqmode", default=False,
-                                 help="Enable high quality Panel View")
+    processingOptions.add_option("-c", "--cropping", type="int", dest="cropping", default="2",
+                                 help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]")
+    processingOptions.add_option("--cp", "--croppingpower", type="float", dest="croppingp", default="1.0",
+                                 help="Set cropping power [Default=1.0]")
     processingOptions.add_option("--blackborders", action="store_true", dest="black_borders", default=False,
                                  help="Disable autodetection and force black borders")
     processingOptions.add_option("--whiteborders", action="store_true", dest="white_borders", default=False,
@@ -993,12 +970,6 @@ def makeParser():
                                  help="Don't convert images to grayscale")
     processingOptions.add_option("--forcepng", action="store_true", dest="forcepng", default=False,
                                  help="Create PNG files instead JPEG")
-    processingOptions.add_option("--cropping", type="int", dest="cropping", default="2",
-                                 help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]")
-    processingOptions.add_option("--croppingpower", type="float", dest="croppingp", default="0.1",
-                                 help="Set margin cropping threshold [Default=0.1]")
-    processingOptions.add_option("--croppingpowerpage", type="float", dest="croppingpn", default="5.0",
-                                 help="Set page number cropping threshold [Default=5.0]")
 
     customProfileOptions.add_option("--customwidth", type="int", dest="customwidth", default=0,
                                     help="Replace screen width provided by device profile")
@@ -1040,20 +1011,16 @@ def checkOptions():
     # Older Kindle don't need higher resolution files due lack of Panel View.
     if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'K3' or options.profile == 'KDX':
         options.panelview = False
-        options.hqmode = False
     # Webtoon mode mandatory options
     if options.webtoon:
         options.panelview = False
-        options.hqmode = False
         options.righttoleft = False
         options.upscale = True
     # Disable all Kindle features for other e-readers
     if options.profile == 'OTHER':
         options.panelview = False
-        options.hqmode = False
     if 'Ko' in options.profile:
         options.panelview = False
-        options.hqmode = False
     # CBZ files on Kindle DX/DXG support higher resolution
     if options.profile == 'KDX' and options.format == 'CBZ':
         options.customheight = 1200
@@ -1066,7 +1033,7 @@ def checkOptions():
         if options.customheight != 0:
             Y = options.customheight
         newProfile = ("Custom", (int(X), int(Y)), image.ProfileData.Palette16,
-                      image.ProfileData.Profiles[options.profile][3], (int(int(X) * 1.5), int(int(Y) * 1.5)))
+                      image.ProfileData.Profiles[options.profile][3])
         image.ProfileData.Profiles["Custom"] = newProfile
         options.profile = "Custom"
     options.profileData = image.ProfileData.Profiles[options.profile]
@@ -1184,7 +1151,6 @@ def makeBook(source, qtGUI=None):
     if not GUI and options.format == 'MOBI':
         print("Creating MOBI files...")
         work = []
-        k = kindle.Kindle()
         for i in filepath:
             work.append([i])
         output = makeMOBI(work, GUI)
@@ -1193,6 +1159,7 @@ def makeBook(source, qtGUI=None):
                 print('Error: KindleGen failed to create MOBI!')
                 print(errors)
                 return filepath
+        k = kindle.Kindle()
         if k.path and k.coverSupport:
             print("Kindle detected. Uploading covers...")
         for i in filepath:
@@ -1201,14 +1168,14 @@ def makeBook(source, qtGUI=None):
                 print('Error: Failed to tweak KindleGen output!')
                 return filepath
             else:
-                os.remove(i.replace('.epub', '.mobi') + '_toclean')
+                saferRemove(i.replace('.epub', '.mobi') + '_toclean')
             if k.path and k.coverSupport:
                 options.covers[filepath.index(i)][0].saveToKindle(k, options.covers[filepath.index(i)][1])
     return filepath
 
 
 def makeMOBIFix(item, uuid):
-    os.remove(item)
+    saferRemove(item)
     mobiPath = item.replace('.epub', '.mobi')
     move(mobiPath, mobiPath + '_toclean')
     try:
diff --git a/kcc/comic2panel.py b/kcc/comic2panel.py
index 6602a91..def8250 100644
--- a/kcc/comic2panel.py
+++ b/kcc/comic2panel.py
@@ -24,7 +24,7 @@ from shutil import rmtree, copytree, move
 from optparse import OptionParser, OptionGroup
 from multiprocessing import Pool
 from PIL import Image, ImageStat, ImageOps
-from .shared import getImageFileName, walkLevel, walkSort
+from .shared import getImageFileName, walkLevel, walkSort, saferRemove
 try:
     from PyQt5 import QtCore
 except ImportError:
@@ -77,7 +77,7 @@ def mergeDirectory(work):
                     img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
                 result.paste(img, (0, y))
                 y += img.size[1]
-                os.remove(i)
+                saferRemove(i)
             savePath = os.path.split(imagesValid[0])
             result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
     except Exception:
@@ -203,7 +203,7 @@ def splitImage(work):
                         targetHeight += panels[panel][2]
                     newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG')
                     pageNumber += 1
-            os.remove(filePath)
+            saferRemove(filePath)
     except Exception:
         return str(sys.exc_info()[1])
 
@@ -275,7 +275,7 @@ def main(argv=None, qtGUI=None):
                         pagenumber += 1
                         work.append([root, name, options])
                     else:
-                        os.remove(os.path.join(root, name))
+                        saferRemove(os.path.join(root, name))
             if GUI:
                 GUI.progressBarTick.emit('Splitting images')
                 GUI.progressBarTick.emit(str(pagenumber))
diff --git a/kcc/image.py b/kcc/image.py
index aef77e5..009b2bb 100755
--- a/kcc/image.py
+++ b/kcc/image.py
@@ -1,5 +1,6 @@
 # Copyright (C) 2010  Alex Yatskov
 # Copyright (C) 2011  Stanislav (proDOOMman) Kosolapov <[email protected]>
+# Copyright (c) 2016  Alberto Planas <[email protected]>
 # Copyright (c) 2012-2014 Ciro Mattia Gonano <[email protected]>
 # Copyright (c) 2013-2016 Pawel Jastrzebski <[email protected]>
 #
@@ -20,7 +21,7 @@ import os
 from io import BytesIO
 from urllib.request import Request, urlopen
 from urllib.parse import quote
-from PIL import Image, ImageOps, ImageStat, ImageChops
+from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
 from .shared import md5Checksum
 from . import __version__
 
@@ -77,21 +78,21 @@ class ProfileData:
     ]
 
     Profiles = {
-        'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)),
-        'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
-        'K3': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
-        'K45': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
-        'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8, (1236, 1500)),
-        'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8, (1137, 1536)),
-        'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8, (1608, 2172)),
-        'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8, (900, 1200)),
-        'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8, (1152, 1536)),
-        'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8, (1608, 2172)),
-        'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8, (1137, 1536)),
-        'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8, (1620, 2160)),
-        'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8, (1620, 2145)),
-        'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8, (2106, 2808)),
-        'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)),
+        'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
+        'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
+        'K3': ("Kindle", (600, 800), Palette16, 1.8),
+        'K45': ("Kindle", (600, 800), Palette16, 1.8),
+        'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
+        'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
+        'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
+        'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
+        'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
+        'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
+        'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8),
+        'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8),
+        'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8),
+        'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
+        'OTHER': ("Other", (0, 0), Palette16, 1.8),
     }
 
 
@@ -105,8 +106,6 @@ class ComicPageParser:
         self.color = self.colorCheck()
         self.fill = self.fillCheck()
         self.splitCheck()
-        if self.opt.hqmode:
-            self.sizeCheck()
 
     def getImageHistogram(self, image):
         histogram = image.histogram()
@@ -205,29 +204,16 @@ class ComicPageParser:
                 else:
                     return 'white'
 
-    def sizeCheck(self):
-        additionalPayload = []
-        width, height = self.image.size
-        dstwidth, dstheight = self.size
-        for work in self.payload:
-            if width > dstwidth and height > dstheight:
-                additionalPayload.append([work[0] + '+', work[1], work[2].copy(), work[3], work[4]])
-        self.payload = self.payload + additionalPayload
-
 
 class ComicPage:
     def __init__(self, mode, path, image, color, fill, options):
         self.opt = options
-        _, self.size, self.palette, self.gamma, self.panelviewsize = self.opt.profileData
+        _, self.size, self.palette, self.gamma = self.opt.profileData
         self.image = image
         self.color = color
         self.fill = fill
         self.rotated = False
         self.orgPath = os.path.join(path[0], path[1])
-        if '+' in mode:
-            self.hqMode = True
-        else:
-            self.hqMode = False
         if 'N' in mode:
             self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC'
         elif 'R' in mode:
@@ -247,8 +233,6 @@ class ComicPage:
                 flags.append('Rotated')
             if self.fill != 'white':
                 flags.append('BlackFill')
-            if self.hqMode:
-                self.targetPath += '-HQ'
             if self.opt.forcepng:
                 self.targetPath += '.png'
                 self.image.save(self.targetPath, 'PNG', optimize=1)
@@ -282,128 +266,69 @@ class ComicPage:
         self.image = self.image.quantize(palette=palImg)
 
     def resizeImage(self):
-        if self.hqMode:
-            size = (self.panelviewsize[0], self.panelviewsize[1])
-            if self.image.size[0] > size[0] or self.image.size[1] > size[1]:
-                self.image.thumbnail(size, Image.LANCZOS)
+        if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
+            method = Image.BICUBIC
         else:
-            size = (self.size[0], self.size[1])
-            if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
-                method = Image.BICUBIC
-            else:
-                method = Image.LANCZOS
-            if self.opt.stretch:
-                self.image = self.image.resize(size, method)
-            elif self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not self.opt.upscale:
-                if self.opt.format == 'CBZ':
-                    borderw = int((size[0] - self.image.size[0]) / 2)
-                    borderh = int((size[1] - self.image.size[1]) / 2)
-                    self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill)
-                    if self.image.size[0] != size[0] or self.image.size[1] != size[1]:
-                        self.image = ImageOps.fit(self.image, size, method=Image.BICUBIC, centering=(0.5, 0.5))
+            method = Image.LANCZOS
+        if self.opt.stretch:
+            self.image = self.image.resize(self.size, method)
+        elif self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1] and not self.opt.upscale:
+            if self.opt.format == 'CBZ':
+                borderw = int((self.size[0] - self.image.size[0]) / 2)
+                borderh = int((self.size[1] - self.image.size[1]) / 2)
+                self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill)
+                if self.image.size[0] != self.size[0] or self.image.size[1] != self.size[1]:
+                    self.image = ImageOps.fit(self.image, self.size, method=Image.BICUBIC, centering=(0.5, 0.5))
+        else:
+            if self.opt.format == 'CBZ':
+                ratioDev = float(self.size[0]) / float(self.size[1])
+                if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
+                    diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
+                    self.image = ImageOps.expand(self.image, border=(int(diff / 2), 0), fill=self.fill)
+                elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
+                    diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
+                    self.image = ImageOps.expand(self.image, border=(0, int(diff / 2)), fill=self.fill)
+                self.image = ImageOps.fit(self.image, self.size, method=method, centering=(0.5, 0.5))
             else:
-                if self.opt.format == 'CBZ':
-                    ratioDev = float(size[0]) / float(size[1])
-                    if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
-                        diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
-                        self.image = ImageOps.expand(self.image, border=(int(diff / 2), 0), fill=self.fill)
-                    elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
-                        diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
-                        self.image = ImageOps.expand(self.image, border=(0, int(diff / 2)), fill=self.fill)
-                    self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5))
-                else:
-                    hpercent = size[1] / float(self.image.size[1])
-                    wsize = int((float(self.image.size[0]) * float(hpercent)))
-                    self.image = self.image.resize((wsize, size[1]), method)
-                    if self.image.size[0] > size[0] or self.image.size[1] > size[1]:
-                        self.image.thumbnail(size, Image.LANCZOS)
+                hpercent = self.size[1] / float(self.image.size[1])
+                wsize = int((float(self.image.size[0]) * float(hpercent)))
+                self.image = self.image.resize((wsize, self.size[1]), method)
+                if self.image.size[0] > self.size[0] or self.image.size[1] > self.size[1]:
+                    self.image.thumbnail(self.size, Image.LANCZOS)
 
-    def cutPageNumber(self, fixedThreshold):
-        if ImageChops.invert(self.image).getbbox() is not None:
-            widthImg, heightImg = self.image.size
-            delta = 2
-            diff = delta
-            if ImageStat.Stat(self.image).var[0] < 2 * fixedThreshold:
-                return self.image
-            while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] < fixedThreshold\
-                    and diff < heightImg:
-                diff += delta
-            diff -= delta
-            pageNumberCut1 = diff
-            if diff < delta:
-                diff = delta
-            oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0]
-            diff += delta
-            while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] - oldStat > 0\
-                    and diff < heightImg // 4:
-                oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0]
-                diff += delta
-            diff -= delta
-            pageNumberCut2 = diff
-            diff += delta
-            oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg,
-                                                      heightImg - pageNumberCut2))).var[0]
-            while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg - pageNumberCut2))).var[0]\
-                    < fixedThreshold + oldStat and diff < heightImg // 4:
-                diff += delta
-            diff -= delta
-            pageNumberCut3 = diff
-            delta = 5
-            diff = delta
-            while ImageStat.Stat(self.image.crop((0, heightImg - pageNumberCut2, diff, heightImg))).var[0]\
-                    < fixedThreshold and diff < widthImg:
-                diff += delta
-            diff -= delta
-            pageNumberX1 = diff
-            diff = delta
-            while ImageStat.Stat(self.image.crop((widthImg - diff, heightImg - pageNumberCut2,
-                                                  widthImg, heightImg))).var[0] < fixedThreshold and diff < widthImg:
-                diff += delta
-            diff -= delta
-            pageNumberX2 = widthImg - diff
-            if pageNumberCut3 - pageNumberCut1 > 2 * delta\
-                    and float(pageNumberX2 - pageNumberX1) / float(pageNumberCut2 - pageNumberCut1) <= 9.0\
-                    and ImageStat.Stat(self.image.crop((0, heightImg - pageNumberCut3, widthImg, heightImg))).var[0]\
-                    / ImageStat.Stat(self.image).var[0] < 0.1\
-                    and pageNumberCut3 < heightImg / 4 - delta:
-                diff = pageNumberCut3
-            else:
-                diff = pageNumberCut1
-            self.image = self.image.crop((0, 0, widthImg, heightImg - diff))
+    def getBoundingBox(self, tmpImg):
+        min_margin = [int(0.005 * i + 0.5) for i in tmpImg.size]
+        max_margin = [int(0.1 * i + 0.5) for i in tmpImg.size]
+        bbox = tmpImg.getbbox()
+        bbox = (
+            max(0, min(max_margin[0], bbox[0] - min_margin[0])),
+            max(0, min(max_margin[1], bbox[1] - min_margin[1])),
+            min(tmpImg.size[0],
+                max(tmpImg.size[0] - max_margin[0], bbox[2] + min_margin[0])),
+            min(tmpImg.size[1],
+                max(tmpImg.size[1] - max_margin[1], bbox[3] + min_margin[1])),
+        )
+        return bbox
 
-    def cropWhiteSpace(self, fixedThreshold):
-        if ImageChops.invert(self.image).getbbox() is not None:
-            widthImg, heightImg = self.image.size
-            delta = 10
-            diff = delta
-            # top
-            while ImageStat.Stat(self.image.crop((0, 0, widthImg, diff))).var[0] < fixedThreshold and diff < heightImg:
-                diff += delta
-            diff -= delta
-            self.image = self.image.crop((0, diff, widthImg, heightImg))
-            widthImg, heightImg = self.image.size
-            diff = delta
-            # left
-            while ImageStat.Stat(self.image.crop((0, 0, diff, heightImg))).var[0] < fixedThreshold and diff < widthImg:
-                diff += delta
-            diff -= delta
-            self.image = self.image.crop((diff, 0, widthImg, heightImg))
-            widthImg, heightImg = self.image.size
-            diff = delta
-            # down
-            while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] < fixedThreshold\
-                    and diff < heightImg:
-                diff += delta
-            diff -= delta
-            self.image = self.image.crop((0, 0, widthImg, heightImg - diff))
-            widthImg, heightImg = self.image.size
-            diff = delta
-            # right
-            while ImageStat.Stat(self.image.crop((widthImg - diff, 0, widthImg, heightImg))).var[0] < fixedThreshold\
-                    and diff < widthImg:
-                diff += delta
-            diff -= delta
-            self.image = self.image.crop((0, 0, widthImg - diff, heightImg))
+    def cropPageNumber(self, power):
+        if self.fill != 'white':
+            tmpImg = self.image.convert(mode='L')
+        else:
+            tmpImg = ImageOps.invert(self.image.convert(mode='L'))
+        tmpImg = tmpImg.point(lambda x: x and 255)
+        tmpImg = tmpImg.filter(ImageFilter.MinFilter(size=3))
+        tmpImg = tmpImg.filter(ImageFilter.GaussianBlur(radius=5))
+        tmpImg = tmpImg.point(lambda x: (x >= 48 * power) and x)
+        self.image = self.image.crop(tmpImg.getbbox()) if tmpImg.getbbox() else self.image
+
+    def cropMargin(self, power):
+        if self.fill != 'white':
+            tmpImg = self.image.convert(mode='L')
+        else:
+            tmpImg = ImageOps.invert(self.image.convert(mode='L'))
+        tmpImg = tmpImg.filter(ImageFilter.GaussianBlur(radius=3))
+        tmpImg = tmpImg.point(lambda x: (x >= 16 * power) and x)
+        self.image = self.image.crop(self.getBoundingBox(tmpImg)) if tmpImg.getbbox() else self.image
 
 
 class Cover:
diff --git a/kcc/shared.py b/kcc/shared.py
index c149502..88d1782 100644
--- a/kcc/shared.py
+++ b/kcc/shared.py
@@ -144,8 +144,7 @@ def removeFromZIP(zipfname, *filenames):
 
 def sanitizeTrace(traceback):
     return ''.join(format_tb(traceback))\
-        .replace('C:\\Users\\pawel\\Documents\\Projekty\\KCC\\', '') \
-        .replace('C:\\Users\\Paweł\\Documents\\Projekty\\KCC\\', '') \
+        .replace('C:\\Users\\Pawel\\Documents\\Projekty\\KCC\\', '') \
         .replace('C:\\Python35\\', '')\
         .replace('c:\\python35\\', '')
 
diff --git a/other/osx/Info.plist b/other/osx/Info.plist
index 0194378..d883b4d 100644
--- a/other/osx/Info.plist
+++ b/other/osx/Info.plist
@@ -9,7 +9,7 @@
 	<key>CFBundleExecutable</key>
 	<string>MacOS/Kindle Comic Converter</string>
 	<key>CFBundleGetInfoString</key>
-	<string>KindleComicConverter 5.1.3, written 2012-2016 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
+	<string>KindleComicConverter 5.2, written 2012-2016 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
 	<key>CFBundleIconFile</key>
 	<string>comic2ebook.icns</string>
 	<key>CFBundleIdentifier</key>
@@ -21,11 +21,11 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>5.1.3</string>
+	<string>5.2.0</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>5.1.3</string>
+	<string>5.2.0</string>
 	<key>LSEnvironment</key>
 	<dict>
 		<key>PATH</key>