mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-03 19:17:02 -05:00 
			
		
		
		
	Port the border removal algorithm from IM to Qt
This commit is contained in:
		
							parent
							
								
									955a83a320
								
							
						
					
					
						commit
						b57ea0ffd0
					
				@ -239,6 +239,13 @@ extensions = [
 | 
				
			|||||||
                sip_files=['calibre/gui2/progress_indicator/QProgressIndicator.sip']
 | 
					                sip_files=['calibre/gui2/progress_indicator/QProgressIndicator.sip']
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Extension('imageops',
 | 
				
			||||||
 | 
					                ['calibre/utils/imageops/imageops.cpp'],
 | 
				
			||||||
 | 
					                inc_dirs=['calibre/utils/imageops'],
 | 
				
			||||||
 | 
					                headers=['calibre/utils/imageops/imageops.h'],
 | 
				
			||||||
 | 
					                sip_files=['calibre/utils/imageops/imageops.sip']
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Extension('qt_hack',
 | 
					    Extension('qt_hack',
 | 
				
			||||||
                ['calibre/ebooks/pdf/render/qt_hack.cpp'],
 | 
					                ['calibre/ebooks/pdf/render/qt_hack.cpp'],
 | 
				
			||||||
                inc_dirs=['calibre/ebooks/pdf/render'],
 | 
					                inc_dirs=['calibre/ebooks/pdf/render'],
 | 
				
			||||||
 | 
				
			|||||||
@ -143,6 +143,7 @@ class Plugins(collections.Mapping):
 | 
				
			|||||||
                'html',
 | 
					                'html',
 | 
				
			||||||
                'freetype',
 | 
					                'freetype',
 | 
				
			||||||
                'unrar',
 | 
					                'unrar',
 | 
				
			||||||
 | 
					                'imageops',
 | 
				
			||||||
                'qt_hack',
 | 
					                'qt_hack',
 | 
				
			||||||
                '_regex',
 | 
					                '_regex',
 | 
				
			||||||
                'hunspell',
 | 
					                'hunspell',
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										76
									
								
								src/calibre/utils/imageops/imageops.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/calibre/utils/imageops/imageops.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * imageops.cpp
 | 
				
			||||||
 | 
					 * Copyright (C) 2016 Kovid Goyal <kovid at kovidgoyal.net>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Distributed under terms of the GPL3 license.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "imageops.h"
 | 
				
			||||||
 | 
					#define SQUARE(x) (x)*(x)
 | 
				
			||||||
 | 
					#define MAX(x, y) ((x) > (y)) ? (x) : (y)
 | 
				
			||||||
 | 
					#define DISTANCE(r, g, b) (SQUARE(r - red_average) + SQUARE(g - green_average) + SQUARE(b - blue_average))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int read_border_row(const QImage &img, const unsigned int width, const unsigned int height, int *reds, const double fuzz, const bool top) {
 | 
				
			||||||
 | 
						unsigned int r = 0, c = 0, start = 0, delta = top ? 1 : -1, ans = 0;
 | 
				
			||||||
 | 
						const QRgb *row = NULL, *pixel = NULL;
 | 
				
			||||||
 | 
					    int *greens = NULL, *blues = NULL;
 | 
				
			||||||
 | 
						double red_average = 0, green_average = 0, blue_average = 0, distance = 0, first_red = 0, first_green = 0, first_blue = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    greens = reds + width + 1; blues = greens + width + 1;
 | 
				
			||||||
 | 
						start = top ? 0 : height - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (r = start; top ? height - r : r > 0; r += delta) {
 | 
				
			||||||
 | 
							row = reinterpret_cast<const QRgb*>(img.constScanLine(r));
 | 
				
			||||||
 | 
					        red_average = 0; green_average = 0; blue_average = 0;
 | 
				
			||||||
 | 
							for (c = 0, pixel = row; c < width; c++, pixel++) {
 | 
				
			||||||
 | 
					            reds[c] = qRed(*pixel); greens[c] = qGreen(*pixel); blues[c] = qBlue(*pixel); 
 | 
				
			||||||
 | 
					            red_average += reds[c]; green_average += greens[c]; blue_average += blues[c];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					        red_average /= MAX(1, width); green_average /= MAX(1, width); blue_average /= MAX(1, width);
 | 
				
			||||||
 | 
					        distance = 0;
 | 
				
			||||||
 | 
					        for (c = 0; c < width && distance <= fuzz; c++) 
 | 
				
			||||||
 | 
					            distance = MAX(distance, DISTANCE(reds[c], greens[c], blues[c]));
 | 
				
			||||||
 | 
					        if (distance > fuzz) break;  // row is not homogeneous
 | 
				
			||||||
 | 
					        if (r == start) { first_red = red_average; first_green = green_average; first_blue = blue_average; }
 | 
				
			||||||
 | 
					        else if (DISTANCE(first_red, first_green, first_blue) > fuzz) break;  // this row's average color is far from the previous row's average color
 | 
				
			||||||
 | 
					        ans += 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ans;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QImage* remove_borders(const QImage &image, double fuzz) {
 | 
				
			||||||
 | 
						int *buf = NULL;
 | 
				
			||||||
 | 
						QImage* ans = NULL, img = image, timg;
 | 
				
			||||||
 | 
						QTransform transpose;
 | 
				
			||||||
 | 
						transpose.rotate(90);
 | 
				
			||||||
 | 
						unsigned int width = img.width(), height = img.height();
 | 
				
			||||||
 | 
						unsigned int top_border = 0, bottom_border = 0, left_border = 0, right_border = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (img.format() != QImage::Format_RGB32) {
 | 
				
			||||||
 | 
							img = img.convertToFormat(QImage::Format_RGB32);
 | 
				
			||||||
 | 
							if (img.isNull()) { PyErr_NoMemory(); return NULL; }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf = new int[3*(MAX(width, height)+1)];
 | 
				
			||||||
 | 
						fuzz /= 255;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						top_border = read_border_row(img, width, height, buf, fuzz, true);
 | 
				
			||||||
 | 
						if (top_border >= height - 1) goto end;
 | 
				
			||||||
 | 
						bottom_border = read_border_row(img, width, height, buf, fuzz, false);
 | 
				
			||||||
 | 
						if (bottom_border >= height - 1) goto end;
 | 
				
			||||||
 | 
						timg = img.transformed(transpose);
 | 
				
			||||||
 | 
						if (timg.isNull()) { PyErr_NoMemory(); goto end; }
 | 
				
			||||||
 | 
						left_border = read_border_row(timg, height, width, buf, fuzz, true);
 | 
				
			||||||
 | 
						if (left_border >= width - 1) goto end;
 | 
				
			||||||
 | 
						right_border = read_border_row(timg, height, width, buf, fuzz, false);
 | 
				
			||||||
 | 
						if (right_border >= width - 1) goto end;
 | 
				
			||||||
 | 
						if (left_border || right_border || top_border || bottom_border) {
 | 
				
			||||||
 | 
					        // printf("111111 l=%d t=%d r=%d b=%d\n", left_border, top_border, right_border, bottom_border);
 | 
				
			||||||
 | 
							img = img.copy(left_border, top_border, width - left_border - right_border, height - top_border - bottom_border);
 | 
				
			||||||
 | 
							if (img.isNull()) { PyErr_NoMemory(); goto end; }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end:
 | 
				
			||||||
 | 
						delete[] buf;
 | 
				
			||||||
 | 
						if (!PyErr_Occurred()) ans = new QImage(img);
 | 
				
			||||||
 | 
						return ans;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/calibre/utils/imageops/imageops.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/calibre/utils/imageops/imageops.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * imageops.h
 | 
				
			||||||
 | 
					 * Copyright (C) 2016 Kovid Goyal <kovid at kovidgoyal.net>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Distributed under terms of the GPL3 license.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QImage>
 | 
				
			||||||
 | 
					#include <Python.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QImage* remove_borders(const QImage &image, double fuzz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/calibre/utils/imageops/imageops.sip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/calibre/utils/imageops/imageops.sip
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					//Define the SIP wrapper to the imageops code
 | 
				
			||||||
 | 
					//Author - Kovid Goyal <kovid@kovidgoyal.net>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%Module(name=imageops, version=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%Import QtCore/QtCoremod.sip
 | 
				
			||||||
 | 
					%Import QtGui/QtGuimod.sip
 | 
				
			||||||
 | 
					%ModuleCode
 | 
				
			||||||
 | 
					#include <imageops.h>
 | 
				
			||||||
 | 
					%End
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QImage* remove_borders(const QImage &image, double fuzz);
 | 
				
			||||||
 | 
					%MethodCode
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								sipRes = remove_borders(*a0, a1);
 | 
				
			||||||
 | 
								if (sipRes == NULL) return NULL;
 | 
				
			||||||
 | 
							} catch (std::bad_alloc) { PyErr_NoMemory(); return NULL; }
 | 
				
			||||||
 | 
					%End
 | 
				
			||||||
@ -10,9 +10,10 @@ from threading import Thread
 | 
				
			|||||||
from PyQt5.Qt import QImage, QByteArray, QBuffer, Qt, QPainter, QImageReader, QColor
 | 
					from PyQt5.Qt import QImage, QByteArray, QBuffer, Qt, QPainter, QImageReader, QColor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from calibre import fit_image, force_unicode
 | 
					from calibre import fit_image, force_unicode
 | 
				
			||||||
from calibre.constants import iswindows
 | 
					from calibre.constants import iswindows, plugins
 | 
				
			||||||
from calibre.utils.config_base import tweaks
 | 
					from calibre.utils.config_base import tweaks
 | 
				
			||||||
from calibre.utils.filenames import atomic_rename
 | 
					from calibre.utils.filenames import atomic_rename
 | 
				
			||||||
 | 
					imageops, imageops_err = plugins['imageops']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_exe_path(name):
 | 
					def get_exe_path(name):
 | 
				
			||||||
    from calibre.ebooks.pdf.pdftohtml import PDFTOHTML
 | 
					    from calibre.ebooks.pdf.pdftohtml import PDFTOHTML
 | 
				
			||||||
@ -198,6 +199,12 @@ class Canvas(object):
 | 
				
			|||||||
def flip_image(img, horizontal=False, vertical=False):
 | 
					def flip_image(img, horizontal=False, vertical=False):
 | 
				
			||||||
    return image_from_data(img).mirrored(horizontal, vertical)
 | 
					    return image_from_data(img).mirrored(horizontal, vertical)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def remove_borders(img, fuzz=None):
 | 
				
			||||||
 | 
					    if imageops is None:
 | 
				
			||||||
 | 
					        raise RuntimeError(imageops_err)
 | 
				
			||||||
 | 
					    fuzz = tweaks['cover_trim_fuzz_value'] if fuzz is None else fuzz
 | 
				
			||||||
 | 
					    return imageops.remove_borders(image_from_data(img), max(0, fuzz))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def run_optimizer(file_path, cmd, as_filter=False, input_data=None):
 | 
					def run_optimizer(file_path, cmd, as_filter=False, input_data=None):
 | 
				
			||||||
    file_path = os.path.abspath(file_path)
 | 
					    file_path = os.path.abspath(file_path)
 | 
				
			||||||
    cwd = os.path.dirname(file_path)
 | 
					    cwd = os.path.dirname(file_path)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user