mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04: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']
|
||||
),
|
||||
|
||||
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',
|
||||
['calibre/ebooks/pdf/render/qt_hack.cpp'],
|
||||
inc_dirs=['calibre/ebooks/pdf/render'],
|
||||
|
@ -143,6 +143,7 @@ class Plugins(collections.Mapping):
|
||||
'html',
|
||||
'freetype',
|
||||
'unrar',
|
||||
'imageops',
|
||||
'qt_hack',
|
||||
'_regex',
|
||||
'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 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.filenames import atomic_rename
|
||||
imageops, imageops_err = plugins['imageops']
|
||||
|
||||
def get_exe_path(name):
|
||||
from calibre.ebooks.pdf.pdftohtml import PDFTOHTML
|
||||
@ -198,6 +199,12 @@ class Canvas(object):
|
||||
def flip_image(img, horizontal=False, vertical=False):
|
||||
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):
|
||||
file_path = os.path.abspath(file_path)
|
||||
cwd = os.path.dirname(file_path)
|
||||
|
Loading…
x
Reference in New Issue
Block a user