⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qjpeghandler.cpp

📁 M8手机图片查看器
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			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;
    }

};
#endif

struct my_error_mgr : public jpeg_error_mgr {
    jmp_buf setjmp_buffer;
};

#if defined(Q_C_CALLBACKS)
extern "C" {
#endif

static 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)
}
#endif


static 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" {
#endif

static 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)
}
#endif

inline 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 50

static bool read_jpeg_image(QIODevice *device, QImage *outImage, const QByteArray &parameters, QSize scaledSize, int inQuality )
{
#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

        // -1 means default quality.
        int quality = inQuality;
        if (quality < 0)
            quality = 75;

        QString params = QString::fromLatin1(parameters);
        params.simplified();
        int sWidth = 0, sHeight = 0;
        char sModeStr[1024] = "";
        Qt::AspectRatioMode sMode;

#ifndef QT_NO_IMAGE_SMOOTHSCALE
        // If high quality not required, shrink image during decompression
        if (scaledSize.isValid() && quality < HIGH_QUALITY_THRESHOLD && !params.contains(QLatin1String("GetHeaderInformation")) ) {
            cinfo.scale_denom = qMin(cinfo.image_width / scaledSize.width(),
                                     cinfo.image_width / scaledSize.height());
            if (cinfo.scale_denom < 2) {
                cinfo.scale_denom = 1;
            } else if (cinfo.scale_denom < 4) {
                cinfo.scale_denom = 2;
            } else if (cinfo.scale_denom < 8) {
                cinfo.scale_denom = 4;
            } else {
                cinfo.scale_denom = 8;
            }
            cinfo.scale_num = 1;
        }
#endif


        // If high quality not required, use fast decompression
        if( quality < HIGH_QUALITY_THRESHOLD ) {
            cinfo.dct_method = JDCT_IFAST;
            cinfo.do_fancy_upsampling = FALSE;
        }


        (void) jpeg_start_decompress(&cinfo);

        if (params.contains(QLatin1String("GetHeaderInformation"))) {

            // Create QImage but don't read the pixels
            static uchar dummy[1];
            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(dummy, 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(dummy, 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 && !defined(Q_OS_WINCE)
            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()) {
                (void) jpeg_finish_decompress(&cinfo);
                jpeg_destroy_decompress(&cinfo);
                delete iod_src;
                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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -