📄 qjpeghandler.cpp
字号:
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; } } jpegSmoothScaler scaler(&cinfo, QString().sprintf("Scale( %d, %d, ScaleFree )", scaledSize.width(), scaledSize.height()).toLatin1().data()); *outImage = scaler.scale();#endif } else { 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); } 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()) { uchar* data = outImage->bits(); int bpl = outImage->bytesPerLine(); while (cinfo.output_scanline < cinfo.output_height) { uchar *d = data + cinfo.output_scanline * bpl; (void) jpeg_read_scanlines(&cinfo, &d, 1); } (void) jpeg_finish_decompress(&cinfo); if (cinfo.output_components == 3) { // Expand 24->32 bpp. for (uint j=0; j<cinfo.output_height; j++) { uchar *in = outImage->scanLine(j) + cinfo.output_width * 3; QRgb *out = (QRgb*)outImage->scanLine(j); for (uint i=cinfo.output_width; i--;) { in-=3; out[i] = qRgb(in[0], in[1], in[2]); } } } else if (cinfo.out_color_space == JCS_CMYK) { for (uint j = 0; j < cinfo.output_height; ++j) { uchar *in = outImage->scanLine(j) + cinfo.output_width * 4; QRgb *out = (QRgb*)outImage->scanLine(j); for (uint i = cinfo.output_width; i--; ) { in-=4; int k = in[3]; out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255); } } } if (cinfo.density_unit == 1) { outImage->setDotsPerMeterX(int(100. * cinfo.X_density / 2.54)); outImage->setDotsPerMeterY(int(100. * cinfo.Y_density / 2.54)); } else if (cinfo.density_unit == 2) { outImage->setDotsPerMeterX(int(100. * cinfo.X_density)); outImage->setDotsPerMeterY(int(100. * cinfo.Y_density)); } } } } jpeg_destroy_decompress(&cinfo); delete iod_src; return !outImage->isNull();}struct my_jpeg_destination_mgr : public jpeg_destination_mgr { // Nothing dynamic - cannot rely on destruction over longjump QIODevice *device; JOCTET buffer[max_buf];public: my_jpeg_destination_mgr(QIODevice *);};#if defined(Q_C_CALLBACKS)extern "C" {#endifstatic void qt_init_destination(j_compress_ptr){}static boolean qt_empty_output_buffer(j_compress_ptr cinfo){ my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest; int written = dest->device->write((char*)dest->buffer, max_buf); if (written == -1) (*cinfo->err->error_exit)((j_common_ptr)cinfo); dest->next_output_byte = dest->buffer; dest->free_in_buffer = max_buf;#if defined(Q_OS_UNIXWARE) return B_TRUE;#else return true;#endif}static void qt_term_destination(j_compress_ptr cinfo){ my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest; qint64 n = max_buf - dest->free_in_buffer; qint64 written = dest->device->write((char*)dest->buffer, n); if (written == -1) (*cinfo->err->error_exit)((j_common_ptr)cinfo);}#if defined(Q_C_CALLBACKS)}#endifinline my_jpeg_destination_mgr::my_jpeg_destination_mgr(QIODevice *device){ jpeg_destination_mgr::init_destination = qt_init_destination; jpeg_destination_mgr::empty_output_buffer = qt_empty_output_buffer; jpeg_destination_mgr::term_destination = qt_term_destination; this->device = device; next_output_byte = buffer; free_in_buffer = max_buf;}static bool write_jpeg_image(const QImage &sourceImage, QIODevice *device, int sourceQuality){ bool success = false; const QImage image = sourceImage; const QVector<QRgb> cmap = image.colorTable(); struct jpeg_compress_struct cinfo; JSAMPROW row_pointer[1]; row_pointer[0] = 0; struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device); struct my_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = my_error_exit; if (!setjmp(jerr.setjmp_buffer)) { // WARNING: // this if loop is inside a setjmp/longjmp branch // do not create C++ temporaries here because the destructor may never be called // if you allocate memory, make sure that you can free it (row_pointer[0]) jpeg_create_compress(&cinfo); cinfo.dest = iod_dest; cinfo.image_width = image.width(); cinfo.image_height = image.height(); bool gray=false; switch (image.depth()) { case 1: case 8: gray = true; for (int i = image.numColors(); gray && i--;) { gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && qRed(cmap[i]) == qBlue(cmap[i])); } cinfo.input_components = gray ? 1 : 3; cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB; break; case 32: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; } jpeg_set_defaults(&cinfo); qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.)) + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.)); qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.)) + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54; if (diffInch < diffCm) { cinfo.density_unit = 1; // dots/inch cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.); cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.); } else { cinfo.density_unit = 2; // dots/cm cinfo.X_density = (image.dotsPerMeterX()+50) / 100; cinfo.Y_density = (image.dotsPerMeterY()+50) / 100; } int quality = sourceQuality >= 0 ? qMin(sourceQuality,100) : 75;#if defined(Q_OS_UNIXWARE) jpeg_set_quality(&cinfo, quality, B_TRUE /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, B_TRUE);#else jpeg_set_quality(&cinfo, quality, true /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, true);#endif row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components]; int w = cinfo.image_width; while (cinfo.next_scanline < cinfo.image_height) { uchar *row = row_pointer[0]; switch (image.depth()) { case 1: if (gray) { const uchar* data = image.scanLine(cinfo.next_scanline); if (image.format() == QImage::Format_MonoLSB) { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); row[i] = qRed(cmap[bit]); } } else { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); row[i] = qRed(cmap[bit]); } } } else { const uchar* data = image.scanLine(cinfo.next_scanline); if (image.format() == QImage::Format_MonoLSB) { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); *row++ = qRed(cmap[bit]); *row++ = qGreen(cmap[bit]); *row++ = qBlue(cmap[bit]); } } else { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); *row++ = qRed(cmap[bit]); *row++ = qGreen(cmap[bit]); *row++ = qBlue(cmap[bit]); } } } break; case 8: if (gray) { const uchar* pix = image.scanLine(cinfo.next_scanline); for (int i=0; i<w; i++) { *row = qRed(cmap[*pix]); ++row; ++pix; } } else { const uchar* pix = image.scanLine(cinfo.next_scanline); for (int i=0; i<w; i++) { *row++ = qRed(cmap[*pix]); *row++ = qGreen(cmap[*pix]); *row++ = qBlue(cmap[*pix]); ++pix; } } break; case 32: { QRgb* rgb = (QRgb*)image.scanLine(cinfo.next_scanline); for (int i=0; i<w; i++) { *row++ = qRed(*rgb); *row++ = qGreen(*rgb); *row++ = qBlue(*rgb); ++rgb; } } } jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); success = true; } else { jpeg_destroy_compress(&cinfo); success = false; } delete iod_dest; delete [] row_pointer[0]; return success;}QJpegHandler::QJpegHandler(){ quality = 75;}bool QJpegHandler::canRead() const{ if (canRead(device())) { setFormat("jpeg"); return true; } return false;}bool QJpegHandler::canRead(QIODevice *device){ if (!device) { qWarning("QJpegHandler::canRead() called with no device"); return false; } return device->peek(2) == "\xFF\xD8";}bool QJpegHandler::read(QImage *image){ if (!canRead()) return false; return read_jpeg_image(device(), image, parameters, scaledSize, quality);}bool QJpegHandler::write(const QImage &image){ return write_jpeg_image(image, device(), quality);}bool QJpegHandler::supportsOption(ImageOption option) const{ return option == Quality#ifndef QT_NO_IMAGE_SMOOTHSCALE || option == ScaledSize#endif || option == Size;}QVariant QJpegHandler::option(ImageOption option) const{ if (option == Quality) { return quality;#ifndef QT_NO_IMAGE_SMOOTHSCALE } else if (option == ScaledSize) { return scaledSize;#endif } else if (option == Size) { if (canRead() && !device()->isSequential()) { qint64 pos = device()->pos(); QImage image; read_jpeg_image(device(), &image, "GetHeaderInformation", scaledSize, quality); device()->seek(pos); return image.size(); } } return QVariant();}void QJpegHandler::setOption(ImageOption option, const QVariant &value){ if (option == Quality) quality = value.toInt();#ifndef QT_NO_IMAGE_SMOOTHSCALE else if ( option == ScaledSize ) scaledSize = value.toSize();#endif}QByteArray QJpegHandler::name() const{ return "jpeg";}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -