#include #include #include #include "ImageProcessing.h" #include "StAssert.h" #if defined(Q_OS_LINUX) # include # include 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 qint64 getFreeMemory () { MEMORYSTATUSEX statex; statex.dwLength = sizeof (statex); if (GlobalMemoryStatusEx (&statex)) { return statex.ullAvailPhys; } return -1; } #endif Pix * convertImage (const QImage &image) { PIX *pix; QImage swapped = image.rgbSwapped (); int width = swapped.width (); int height = swapped.height (); int depth = swapped.depth (); int wpl = swapped.bytesPerLine () / 4; pix = pixCreate (width, height, depth); pixSetWpl (pix, wpl); pixSetColormap (pix, NULL); l_uint32 *outData = pix->data; for (int y = 0; y < height; y++) { l_uint32 *lines = outData + y * wpl; QByteArray a ((const char *)swapped.scanLine (y), swapped.bytesPerLine ()); for (int j = 0; j < a.size (); j++) { *((l_uint8 *)lines + j) = a[j]; } } const qreal toDPM = 1.0 / 0.0254; int resolutionX = swapped.dotsPerMeterX () / toDPM; int resolutionY = swapped.dotsPerMeterY () / toDPM; if (resolutionX < 300) { resolutionX = 300; } if (resolutionY < 300) { resolutionY = 300; } pixSetResolution (pix, resolutionX, resolutionY); pixEndianByteSwap (pix); 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 (pixEndianByteSwapNew (&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 _bwCT; _bwCT.append (qRgb (255,255,255)); _bwCT.append (qRgb (0,0,0)); QVector _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.rgbSwapped (); } 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); }