ScreenTranslator/ImageProcessing.cpp
2015-10-11 19:51:37 +03:00

157 lines
3.7 KiB
C++

#include <QDebug>
#include <leptonica/allheaders.h>
#include <tesseract/host.h>
#include "ImageProcessing.h"
#include "StAssert.h"
#if defined(Q_OS_LINUX)
# include <fstream>
# include <limits>
qint64 getFreeMemory () {
std::string token;
std::ifstream file ("/proc/meminfo");
qint64 freeMem = 0;
while (file >> token) {
if (token == "MemFree:" || token == "Buffers:" || token == "Cached:") {
unsigned long mem = 0;
freeMem += (file >> mem) ? mem : 0;
}
}
return freeMem * 1024;
}
#elif defined(Q_OS_WIN)
# include <windows.h>
qint64 getFreeMemory () {
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
if (GlobalMemoryStatusEx (&statex)) {
return statex.ullAvailPhys;
}
return -1;
}
#endif
Pix * convertImage (const QImage &image) {
PIX *pix;
int width = image.width ();
int height = image.height ();
int depth = image.depth ();
int bytesPerLine = image.bytesPerLine ();
int wpl = bytesPerLine / 4;
pix = pixCreate (width, height, depth);
pixSetWpl (pix, wpl);
pixSetColormap (pix, NULL);
memmove (pix->data, image.bits (), bytesPerLine * height);
const qreal toDPM = 1.0 / 0.0254;
int resolutionX = image.dotsPerMeterX () / toDPM;
int resolutionY = image.dotsPerMeterY () / toDPM;
if (resolutionX < 300) {
resolutionX = 300;
}
if (resolutionY < 300) {
resolutionY = 300;
}
pixSetResolution (pix, resolutionX, resolutionY);
return pix;
}
QImage convertImage (Pix &image) {
int width = pixGetWidth (&image);
int height = pixGetHeight (&image);
int depth = pixGetDepth (&image);
int bytesPerLine = pixGetWpl (&image) * 4;
l_uint32 *datas = pixGetData (&image);
QImage::Format format;
if (depth == 1) {
format = QImage::Format_Mono;
}
else if (depth == 8) {
format = QImage::Format_Indexed8;
}
else {
format = QImage::Format_RGB32;
}
QImage result ((uchar *)datas, width, height, bytesPerLine, format);
// Set resolution
l_int32 xres, yres;
pixGetResolution (&image, &xres, &yres);
const qreal toDPM = 1.0 / 0.0254;
result.setDotsPerMeterX (xres * toDPM);
result.setDotsPerMeterY (yres * toDPM);
// Handle pallete
QVector<QRgb> _bwCT;
_bwCT.append (qRgb (255,255,255));
_bwCT.append (qRgb (0,0,0));
QVector<QRgb> _grayscaleCT (256);
for (int i = 0; i < 256; i++) {
_grayscaleCT.append (qRgb (i, i, i));
}
switch (depth) {
case 1:
result.setColorTable (_bwCT);
break;
case 8:
result.setColorTable (_grayscaleCT);
break;
default:
result.setColorTable (_grayscaleCT);
}
if (result.isNull ()) {
static QImage none (0,0,QImage::Format_Invalid);
qDebug ("Invalid format!!!\n");
return none;
}
return result;
}
Pix * prepareImage (const QImage &image, int preferredScale) {
Pix *pix = convertImage (image);
ST_ASSERT (pix != NULL);
Pix *gray = pixConvertRGBToGray (pix, 0.0, 0.0, 0.0);
ST_ASSERT (gray != NULL);
pixDestroy (&pix);
Pix *scaled = gray;
if (preferredScale > 0) {
float maxScaleX = MAX_INT16 / double (gray->w);
float scaleX = std::min (float (preferredScale), maxScaleX);
float maxScaleY = MAX_INT16 / double (gray->h);
float scaleY = std::min (float (preferredScale), maxScaleY);
float scale = std::min (scaleX, scaleY);
qint64 availableMemory = getFreeMemory () * 0.95;
if (availableMemory > 0) {
qint32 actualSize = gray->w * gray->h * gray->d / 8;
float maxScaleMemory = float (availableMemory) / actualSize;
scale = std::min (scale, maxScaleMemory);
}
scaled = pixScale (gray, scale, scale);
if (scaled == NULL) {
scaled = gray;
}
}
if (scaled != gray) {
pixDestroy (&gray);
}
return scaled;
}
void cleanupImage (Pix **image) {
pixDestroy (image);
}