Optimalizations

This commit is contained in:
hunbernd 2017-06-10 01:43:02 +02:00
parent af4817378c
commit c17a8e7d51

View File

@ -50,6 +50,7 @@ void ImageUtil::extractImage(QWidget *window, QTextCursor cursor)
void ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &optimized, int maxPixels, int maxBytes) void ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &optimized, int maxPixels, int maxBytes)
{ {
//nothing to do if it fits into the limits
optimized = original; optimized = original;
if ((maxPixels <= 0) || (optimized.width()*optimized.height() <= maxPixels)) { if ((maxPixels <= 0) || (optimized.width()*optimized.height() <= maxPixels)) {
if(checkSize(html, optimized, maxBytes)) { if(checkSize(html, optimized, maxBytes)) {
@ -65,31 +66,42 @@ void ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &opti
if(scale > 1.0) scale = 1.0; if(scale > 1.0) scale = 1.0;
//Half the resolution until image fits into maxBytes, or width becomes 0 //Half the resolution until image fits into maxBytes, or width becomes 0
bool success = false;
do { do {
optimized = original.scaledToWidth((int)(original.width() * scale), Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct); optimized = original.scaledToWidth((int)(original.width() * scale), Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct);
checkSize(html, optimized, maxBytes); success = checkSize(html, optimized, maxBytes);
scale = scale / 2.0; scale = scale / 2.0;
} while((!optimized.isNull()) && (!checkSize(html, optimized, maxBytes))); } while((!optimized.isNull()) && !success);
} }
bool ImageUtil::checkSize(QString &embeddedImage, const QImage &img, int maxBytes) bool ImageUtil::checkSize(QString &embeddedImage, const QImage &img, int maxBytes)
{ {
RsScopeTimer st("Check size");
//0 means no limit
if(maxBytes > 500)
maxBytes -= 500; //make place for html stuff
else if(maxBytes > 0) {
std::cerr << QString("Limit is too small nothing will fit in, limit: %1 bytes\n").arg(maxBytes).toStdString();
return false;
}
QByteArray bytearray; QByteArray bytearray;
QBuffer buffer(&bytearray); QBuffer buffer(&bytearray);
bool success = false;
std::cout << QString("Trying image: format PNG, size %1x%2, colors %3\n").arg(img.width()).arg(img.height()).arg(img.colorCount()).toStdString(); std::cout << QString("Trying image: format PNG, size %1x%2, colors %3\n").arg(img.width()).arg(img.height()).arg(img.colorCount()).toStdString();
if (buffer.open(QIODevice::WriteOnly)) { if (buffer.open(QIODevice::WriteOnly)) {
if (img.save(&buffer, "PNG", 0)) { if (img.save(&buffer, "PNG", 0)) {
QByteArray encodedByteArray = bytearray.toBase64(); if((maxBytes > 0) && (bytearray.length() * 4/3 > maxBytes)) // *4/3 for base64
embeddedImage = "<img src=\"data:image/png;base64,";
embeddedImage.append(encodedByteArray);
embeddedImage.append("\">");
if((maxBytes > 0) && (embeddedImage.size() > maxBytes))
{ {
std::cout << QString("\tToo large, size: %1, limit: %2 bytes\n").arg(embeddedImage.size()).arg(maxBytes).toStdString(); std::cout << QString("\tToo large, size: %1, limit: %2 bytes\n").arg(bytearray.length() * 4/3).arg(maxBytes).toStdString();
}else{ }else{
std::cout << QString("\tOK, size: %1, limit: %2 bytes\n").arg(embeddedImage.size()).arg(maxBytes).toStdString(); std::cout << QString("\tOK, size: %1, limit: %2 bytes\n").arg(bytearray.length() * 4/3).arg(maxBytes).toStdString();
return true; success = true;
QByteArray encodedByteArray = bytearray.toBase64();
embeddedImage = "<img src=\"data:image/png;base64,";
embeddedImage.append(encodedByteArray);
embeddedImage.append("\">");
} }
} else { } else {
std::cerr << "ImageUtil: image can't be saved to buffer" << std::endl; std::cerr << "ImageUtil: image can't be saved to buffer" << std::endl;
@ -99,32 +111,7 @@ bool ImageUtil::checkSize(QString &embeddedImage, const QImage &img, int maxByte
} else { } else {
std::cerr << "ImageUtil: buffer can't be opened" << std::endl; std::cerr << "ImageUtil: buffer can't be opened" << std::endl;
} }
return success;
std::cout << QString("Trying image: format JPEG, size %1x%2, colors %3\n").arg(img.width()).arg(img.height()).arg(img.colorCount()).toStdString();
if (buffer.open(QIODevice::WriteOnly)) {
if (img.save(&buffer, "JPEG")) {
QByteArray encodedByteArray = bytearray.toBase64();
embeddedImage = "<img src=\"data:image/jpeg;base64,";
embeddedImage.append(encodedByteArray);
embeddedImage.append("\">");
if((maxBytes > 0) && (embeddedImage.size() > maxBytes))
{
std::cout << QString("\tToo large, size: %1, limit: %2 bytes\n").arg(embeddedImage.size()).arg(maxBytes).toStdString();
}else{
std::cout << QString("\tOK, size: %1, limit: %2 bytes\n").arg(embeddedImage.size()).arg(maxBytes).toStdString();
return true;
}
} else {
std::cerr << "ImageUtil: image can't be saved to buffer" << std::endl;
}
buffer.close();
bytearray.clear();
} else {
std::cerr << "ImageUtil: buffer can't be opened" << std::endl;
}
embeddedImage.clear();
return false;
} }
bool redLessThan(const QRgb &c1, const QRgb &c2) bool redLessThan(const QRgb &c1, const QRgb &c2)
@ -146,15 +133,19 @@ bool blueLessThan(const QRgb &c1, const QRgb &c2)
void ImageUtil::quantization(const QImage &img, QVector<QRgb> &palette) void ImageUtil::quantization(const QImage &img, QVector<QRgb> &palette)
{ {
int bits = 4; // bits/pixel int bits = 4; // bits/pixel
int samplesize = 100000; //only take this many color samples
RsScopeTimer st("Quantization"); RsScopeTimer st("Quantization");
QSet<QRgb> colors; QSet<QRgb> colors;
//collect color information //collect color information
for (int x = 0; x < img.width(); ++x) { int imgsize = img.width()*img.height();
for (int y = 0; y < img.height(); ++y) { int width = img.width();
QRgb rgb = img.pixel(x, y); samplesize = qMin(samplesize, imgsize);
colors.insert(rgb); double sampledist = (double)imgsize / (double)samplesize;
} for (double i = 0; i < imgsize; i += sampledist) {
QRgb pixel = img.pixel((int)i % width, (int)i / width);
colors.insert(pixel);
} }
QList<QRgb> colorlist = colors.toList(); QList<QRgb> colorlist = colors.toList();