📄 qjpeghandler.cpp
字号:
} if (as) { a += fraccolleft * qAlpha( *xP ); r += fraccolleft * qRed( *xP ) * qAlpha( *xP ) / 255; g += fraccolleft * qGreen( *xP ) * qAlpha( *xP ) / 255; b += fraccolleft * qBlue( *xP ) * qAlpha( *xP ) / 255; } else { r += fraccolleft * qRed( *xP ); g += fraccolleft * qGreen( *xP ); b += fraccolleft * qBlue( *xP ); } fraccoltofill -= fraccolleft; } } if ( fraccoltofill > 0 ) { --xP; if (as) { a += fraccolleft * qAlpha( *xP ); r += fraccoltofill * qRed( *xP ) * qAlpha( *xP ) / 255; g += fraccoltofill * qGreen( *xP ) * qAlpha( *xP ) / 255; b += fraccoltofill * qBlue( *xP ) * qAlpha( *xP ) / 255; if ( a ) { r = r * 255 / a * SCALE; g = g * 255 / a * SCALE; b = b * 255 / a * SCALE; } } else { r += fraccoltofill * qRed( *xP ); g += fraccoltofill * qGreen( *xP ); b += fraccoltofill * qBlue( *xP ); } } if ( ! needcol ) { r /= SCALE; if ( r > maxval ) r = maxval; g /= SCALE; if ( g > maxval ) g = maxval; b /= SCALE; if ( b > maxval ) b = maxval; if (as) { a /= SCALE; if ( a > maxval ) a = maxval; *nxP = qRgba( (int)r, (int)g, (int)b, (int)a ); } else { *nxP = qRgb( (int)r, (int)g, (int)b ); } } } } if ( d->newrows != d->rows && tempxelrow )// Robust, tempxelrow might be 0 1 day delete [] tempxelrow; if ( as ) // Avoid purify complaint delete [] as; if ( rs ) // Robust, rs might be 0 one day delete [] rs; if ( gs ) // Robust, gs might be 0 one day delete [] gs; if ( bs ) // Robust, bs might be 0 one day delete [] bs; return dst;}class jpegSmoothScaler : public QImageSmoothScaler{public: jpegSmoothScaler(struct jpeg_decompress_struct *info, const char *params): QImageSmoothScaler(info->output_width, info->output_height, params) { cinfo = info; cols24Bit = scaledWidth() * 3; cacheHeight = 1; imageCache = QImage( info->output_width, cacheHeight, QImage::Format_RGB32 ); }private: int cols24Bit; QImage imageCache; int cacheHeight; struct jpeg_decompress_struct *cinfo; QRgb *scanLine(const int line = 0, const QImage *src = 0) { QRgb *out; uchar *in; Q_UNUSED(line); Q_UNUSED(src); uchar* data = imageCache.bits(); jpeg_read_scanlines(cinfo, &data, 1); out = (QRgb*)imageCache.scanLine(0); // // The smooth scale algorithm only works on 32-bit images; // convert from (8|24) bits to 32. // if (cinfo->output_components == 1) { in = (uchar*)out + scaledWidth(); for (uint i = scaledWidth(); i--; ) { in--; out[i] = qRgb(*in, *in, *in); } } else { in = (uchar*)out + cols24Bit; for (uint i = scaledWidth(); i--; ) { in -= 3; out[i] = qRgb(in[0], in[1], in[2]); } } return out; }};#endifstruct my_error_mgr : public jpeg_error_mgr { jmp_buf setjmp_buffer;};#if defined(Q_C_CALLBACKS)extern "C" {#endifstatic void my_error_exit (j_common_ptr cinfo){ my_error_mgr* myerr = (my_error_mgr*) cinfo->err; char buffer[JMSG_LENGTH_MAX]; (*cinfo->err->format_message)(cinfo, buffer); qWarning("%s", buffer); longjmp(myerr->setjmp_buffer, 1);}#if defined(Q_C_CALLBACKS)}#endifstatic const int max_buf = 4096;struct my_jpeg_source_mgr : public jpeg_source_mgr { // Nothing dynamic - cannot rely on destruction over longjump QIODevice *device; JOCTET buffer[max_buf];public: my_jpeg_source_mgr(QIODevice *device);};#if defined(Q_C_CALLBACKS)extern "C" {#endifstatic void qt_init_source(j_decompress_ptr){}static boolean qt_fill_input_buffer(j_decompress_ptr cinfo){ int num_read; my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src; src->next_input_byte = src->buffer; num_read = src->device->read((char*)src->buffer, max_buf); if (num_read <= 0) { // Insert a fake EOI marker - as per jpeglib recommendation src->buffer[0] = (JOCTET) 0xFF; src->buffer[1] = (JOCTET) JPEG_EOI; src->bytes_in_buffer = 2; } else { src->bytes_in_buffer = num_read; }#if defined(Q_OS_UNIXWARE) return B_TRUE;#else return true;#endif}static void qt_skip_input_data(j_decompress_ptr cinfo, long num_bytes){ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src; // `dumb' implementation from jpeglib /* Just a dumb implementation for now. Could use fseek() except * it doesn't work on pipes. Not clear that being smart is worth * any trouble anyway --- large skips are infrequent. */ if (num_bytes > 0) { while (num_bytes > (long) src->bytes_in_buffer) { num_bytes -= (long) src->bytes_in_buffer; (void) qt_fill_input_buffer(cinfo); /* note we assume that qt_fill_input_buffer will never return false, * so suspension need not be handled. */ } src->next_input_byte += (size_t) num_bytes; src->bytes_in_buffer -= (size_t) num_bytes; }}static void qt_term_source(j_decompress_ptr cinfo){ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src; if (!src->device->isSequential()) src->device->seek(src->device->pos() - src->bytes_in_buffer);}#if defined(Q_C_CALLBACKS)}#endifinline my_jpeg_source_mgr::my_jpeg_source_mgr(QIODevice *device){ jpeg_source_mgr::init_source = qt_init_source; jpeg_source_mgr::fill_input_buffer = qt_fill_input_buffer; jpeg_source_mgr::skip_input_data = qt_skip_input_data; jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart; jpeg_source_mgr::term_source = qt_term_source; this->device = device; bytes_in_buffer = 0; next_input_byte = buffer;}static void scaleSize(int &reqW, int &reqH, int imgW, int imgH, Qt::AspectRatioMode mode){ if (mode == Qt::IgnoreAspectRatio) return; int t1 = imgW * reqH; int t2 = reqW * imgH; if ((mode == Qt::KeepAspectRatio && (t1 > t2)) || (mode == Qt::KeepAspectRatioByExpanding && (t1 < t2))) reqH = t2 / imgW; else reqW = t1 / imgH;}#define HIGH_QUALITY_THRESHOLD 50static bool read_jpeg_image(QIODevice *device, QImage *outImage, const QByteArray ¶meters, QSize scaledSize, int quality ){#ifdef QT_NO_IMAGE_SMOOTHSCALE Q_UNUSED( scaledSize );#endif struct jpeg_decompress_struct cinfo; struct my_jpeg_source_mgr *iod_src = new my_jpeg_source_mgr(device); struct my_error_mgr jerr; jpeg_create_decompress(&cinfo); cinfo.src = iod_src; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = my_error_exit; if (!setjmp(jerr.setjmp_buffer)) {#if defined(Q_OS_UNIXWARE) (void) jpeg_read_header(&cinfo, B_TRUE);#else (void) jpeg_read_header(&cinfo, true);#endif (void) jpeg_start_decompress(&cinfo); QString params = QString::fromLatin1(parameters); params.simplified(); int sWidth = 0, sHeight = 0; char sModeStr[1024] = ""; Qt::AspectRatioMode sMode; // If high quality not required, use fast decompression if( quality < HIGH_QUALITY_THRESHOLD ) { cinfo.dct_method = JDCT_IFAST; cinfo.do_fancy_upsampling = FALSE; } if (params.contains(QLatin1String("GetHeaderInformation"))) { // Create QImage but don't read the pixels if (cinfo.output_components == 3 || cinfo.output_components == 4) { if (outImage->size() != QSize(cinfo.output_width, cinfo.output_height) || outImage->format() != QImage::Format_RGB32) { *outImage = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_RGB32); } } else if (cinfo.output_components == 1) { if (outImage->size() != QSize(cinfo.output_width, cinfo.output_height) || outImage->format() != QImage::Format_Indexed8) { *outImage = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_Indexed8); } } else { // Unsupported format return false; } } else if (params.contains(QLatin1String("Scale"))) {#if defined(_MSC_VER) && _MSC_VER >= 1400 sscanf_s(params.toLatin1().data(), "Scale(%i, %i, %1023s)", &sWidth, &sHeight, sModeStr, sizeof(sModeStr));#else sscanf(params.toLatin1().data(), "Scale(%i, %i, %1023s)", &sWidth, &sHeight, sModeStr);#endif QString sModeQStr(QString::fromLatin1(sModeStr)); if (sModeQStr == QLatin1String("IgnoreAspectRatio")) { sMode = Qt::IgnoreAspectRatio; } else if (sModeQStr == QLatin1String("KeepAspectRatio")) { sMode = Qt::KeepAspectRatio; } else if (sModeQStr == QLatin1String("KeepAspectRatioByExpanding")) { sMode = Qt::KeepAspectRatioByExpanding; } else { qDebug("read_jpeg_image: invalid aspect ratio mode \"%s\", see QImage::AspectRatioMode documentation", sModeStr); sMode = Qt::KeepAspectRatio; }// qDebug("Parameters ask to scale the image to %i x %i AspectRatioMode: %s", sWidth, sHeight, sModeStr); scaleSize(sWidth, sHeight, cinfo.output_width, cinfo.output_height, sMode);// qDebug("Scaling the jpeg to %i x %i", sWidth, sHeight, sModeStr); if (cinfo.output_components == 3 || cinfo.output_components == 4) { if (outImage->size() != QSize(sWidth, sHeight) || outImage->format() != QImage::Format_RGB32) *outImage = QImage(sWidth, sHeight, QImage::Format_RGB32); } else if (cinfo.output_components == 1) { if (outImage->size() != QSize(sWidth, sHeight) || outImage->format() != QImage::Format_Indexed8) *outImage = QImage(sWidth, sHeight, QImage::Format_Indexed8); outImage->setNumColors(256); for (int i=0; i<256; i++) outImage->setColor(i, qRgb(i,i,i)); } else { // Unsupported format } if (outImage->isNull()) return false; if (!outImage->isNull()) { QImage tmpImage(cinfo.output_width, 1, QImage::Format_RGB32); uchar* inData = tmpImage.bits(); uchar* outData = outImage->bits(); int out_bpl = outImage->bytesPerLine(); while (cinfo.output_scanline < cinfo.output_height) { int outputLine = sHeight * cinfo.output_scanline / cinfo.output_height; (void) jpeg_read_scanlines(&cinfo, &inData, 1); if (cinfo.output_components == 3) { uchar *in = inData; QRgb *out = (QRgb*)outData + outputLine * out_bpl; for (uint i=0; i<cinfo.output_width; i++) {// ### Only scaling down an image works, I don't think scaling up will work at the moment// ### An idea I have to make this a smooth scale is to progressively add the pixel values up// When scaling down, multiple values are being over drawn in to the output buffer.// Instead, a weighting based on the distance the line or pixel is from the output pixel determines// the weight of it when added to the output buffer. At present it is a non-smooth scale which is// inefficently implemented, it still uncompresses all the jpeg, an optimization for progressive// jpegs could be made if scaling by say 50% or some other special cases out[sWidth * i / cinfo.output_width] = qRgb(in[0], in[1], in[2]); in += 3; } } else {// ### Need to test the case where the jpeg is grayscale, need some black and white jpegs to test// this code. (also only scales down and probably won't scale to a larger size) uchar *in = inData; uchar *out = outData + outputLine*out_bpl; for (uint i=0; i<cinfo.output_width; i++) { out[sWidth * i / cinfo.output_width] = in[i]; } } } (void) jpeg_finish_decompress(&cinfo); }#ifndef QT_NO_IMAGE_SMOOTHSCALE } else if (scaledSize.isValid()) { // If high quality not required, shrink image during decompression if(quality < HIGH_QUALITY_THRESHOLD) { cinfo.scale_denom = qMin(cinfo.output_width / scaledSize.width(), cinfo.output_height / scaledSize.height()); if (cinfo.scale_denom < 2) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -