bool loadJPEGScaled(QImage& image, const QString& path, int maximumSize) { FileReadLocker lock(path); if (!isJpegImage(path)) { return false; } FILE* const inputFile = fopen(QFile::encodeName(path).constData(), "rb"); if (!inputFile) { return false; } struct jpeg_decompress_struct cinfo; struct jpegutils_jpeg_error_mgr jerr; // JPEG error handling - thanks to Marcus Meissner cinfo.err = jpeg_std_error(&jerr); cinfo.err->error_exit = jpegutils_jpeg_error_exit; cinfo.err->emit_message = jpegutils_jpeg_emit_message; cinfo.err->output_message = jpegutils_jpeg_output_message; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); fclose(inputFile); return false; } jpeg_create_decompress(&cinfo); #ifdef Q_OS_WIN QFile inFile(path); QByteArray buffer; if (inFile.open(QIODevice::ReadOnly)) { buffer = inFile.readAll(); inFile.close(); } jpeg_memory_src(&cinfo, (JOCTET*)buffer.data(), buffer.size()); #else // Q_OS_WIN jpeg_stdio_src(&cinfo, inputFile); #endif // Q_OS_WIN jpeg_read_header(&cinfo, true); int imgSize = qMax(cinfo.image_width, cinfo.image_height); // libjpeg supports 1/1, 1/2, 1/4, 1/8 int scale=1; while(maximumSize*scale*2 <= imgSize) { scale *= 2; } if (scale > 8) { scale = 8; } //cinfo.scale_num = 1; //cinfo.scale_denom = scale; cinfo.scale_denom *= scale; switch (cinfo.jpeg_color_space) { case JCS_UNKNOWN: break; case JCS_GRAYSCALE: case JCS_RGB: case JCS_YCbCr: cinfo.out_color_space = JCS_RGB; break; case JCS_CMYK: case JCS_YCCK: cinfo.out_color_space = JCS_CMYK; break; default: break; } jpeg_start_decompress(&cinfo); QImage img; // We only take RGB with 1 or 3 components, or CMYK with 4 components if (!( (cinfo.out_color_space == JCS_RGB && (cinfo.output_components == 3 || cinfo.output_components == 1)) || (cinfo.out_color_space == JCS_CMYK && cinfo.output_components == 4) )) { jpeg_destroy_decompress(&cinfo); fclose(inputFile); return false; } switch (cinfo.output_components) { case 3: case 4: img = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_RGB32); break; case 1: // B&W image img = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_Indexed8); img.setColorCount(256); for (int i = 0 ; i < 256 ; ++i) { img.setColor(i, qRgb(i, i, i)); } break; } uchar* const data = img.bits(); int bpl = img.bytesPerLine(); while (cinfo.output_scanline < cinfo.output_height) { uchar* d = data + cinfo.output_scanline * bpl; jpeg_read_scanlines(&cinfo, &d, 1); } jpeg_finish_decompress(&cinfo); if (cinfo.output_components == 3) { // Expand 24->32 bpp. for (uint j=0; j<cinfo.output_height; ++j) { uchar* in = img.scanLine(j) + cinfo.output_width * 3; QRgb* const out = reinterpret_cast<QRgb*>(img.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 = img.scanLine(j) + cinfo.output_width * 4; QRgb* const out = reinterpret_cast<QRgb*>(img.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) { img.setDotsPerMeterX(int(100. * cinfo.X_density / 2.54)); img.setDotsPerMeterY(int(100. * cinfo.Y_density / 2.54)); } else if (cinfo.density_unit == 2) { img.setDotsPerMeterX(int(100. * cinfo.X_density)); img.setDotsPerMeterY(int(100. * cinfo.Y_density)); } //int newMax = qMax(cinfo.output_width, cinfo.output_height); //int newx = maximumSize*cinfo.output_width / newMax; //int newy = maximumSize*cinfo.output_height / newMax; jpeg_destroy_decompress(&cinfo); fclose(inputFile); image = img; return true; }
bool QVideoEncoder::convertImage(const QImage &img) { // Check if the image matches the size if(img.width()!=getWidth() || img.height()!=getHeight()) { printf("Wrong image size!\n"); return false; } if(img.format()!=QImage::Format_RGB32 && img.format() != QImage::Format_ARGB32) { printf("Wrong image format\n"); return false; } // RGB32 to YUV420 int size = getWidth()*getHeight(); // Y for(unsigned y=0;y<getHeight();y++) { unsigned char *s = (unsigned char*)img.scanLine(y); unsigned char *d = (unsigned char*)&picture_buf[y*getWidth()]; //printf("Line %d. d: %p. picture_buf: %p\n",y,d,picture_buf); for(unsigned x=0;x<getWidth();x++) { unsigned int r=s[2]; unsigned int g=s[1]; unsigned int b=s[0]; unsigned Y = (r*2104 + g*4130 + b*802 + 4096 + 131072) >> 13; if(Y>235) Y=235; *d = Y; d+=1; s+=4; } } // U,V for(unsigned y=0;y<getHeight();y+=2) { unsigned char *s = (unsigned char*)img.scanLine(y); unsigned int ss = img.bytesPerLine(); unsigned char *d = (unsigned char*)&picture_buf[size+y/2*getWidth()/2]; //printf("Line %d. d: %p. picture_buf: %p\n",y,d,picture_buf); for(unsigned x=0;x<getWidth();x+=2) { // Cr = 128 + 1/256 * ( 112.439 * R'd - 94.154 * G'd - 18.285 * B'd) // Cb = 128 + 1/256 * (- 37.945 * R'd - 74.494 * G'd + 112.439 * B'd) // Get the average RGB in a 2x2 block int r=(s[2] + s[6] + s[ss+2] + s[ss+6] + 2) >> 2; int g=(s[1] + s[5] + s[ss+1] + s[ss+5] + 2) >> 2; int b=(s[0] + s[4] + s[ss+0] + s[ss+4] + 2) >> 2; int Cb = (-1214*r - 2384*g + 3598*b + 4096 + 1048576)>>13; if(Cb<16) Cb=16; if(Cb>240) Cb=240; int Cr = (3598*r - 3013*g - 585*b + 4096 + 1048576)>>13; if(Cr<16) Cr=16; if(Cr>240) Cr=240; *d = Cb; *(d+size/4) = Cr; d+=1; s+=8; } } return true; }
/** * Return icon for a window by name * * @param n - resource name of window */ Icon *IconMap::getIconByName( std::string n ) { // try to resolve alias { AliasToFile::iterator i; if( (i = nameToFile.find( n )) != nameToFile.end() ) n = (*i).second; } // cache look up { FileToIcon::iterator i; if( (i = cache.find( n )) != cache.end() ) return (*i).second; } // load PNG file from disk { std::string file = n+".png"; std::transform( file.begin(), file.end(), file.begin(), ::tolower ); for( Paths::const_iterator i = paths.begin(); i != paths.end(); ++i ) { std::string path = *i+file; struct stat buf; if( stat( path.c_str(), &buf ) > -1 ) { ArgbSurface *s = Png::load( path ); Icon *icon = createIcon( s, n, Icon::File ); delete s; return icon; } } } #ifdef HAVE_GTK // ask GNOME for icon { GtkIconTheme *theme = gtk_icon_theme_get_for_screen( gdk_screen_get_default() ); GdkPixbuf *pixbuf = 0; // theme look up { GtkIconInfo *iconInfo = gtk_icon_theme_lookup_icon( theme, n.c_str(), 128, GTK_ICON_LOOKUP_USE_BUILTIN ); if( iconInfo ) { pixbuf = gdk_pixbuf_new_from_file_at_size( gtk_icon_info_get_filename( iconInfo ), 128, -1, 0 ); gtk_icon_info_free( iconInfo ); } } // otherwise try to load the icon blindly if( !pixbuf ) pixbuf = gtk_icon_theme_load_icon( theme, n.c_str(), 128, GTK_ICON_LOOKUP_FORCE_SVG, 0 ); if( pixbuf && gdk_pixbuf_get_colorspace( pixbuf ) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample( pixbuf ) == 8 && gdk_pixbuf_get_n_channels( pixbuf ) == 4 && gdk_pixbuf_get_has_alpha( pixbuf ) ) { unsigned char *src = reinterpret_cast<unsigned char *>( gdk_pixbuf_get_pixels( pixbuf ) ); int w = gdk_pixbuf_get_width( pixbuf ); int h = gdk_pixbuf_get_height( pixbuf ); int p = gdk_pixbuf_get_rowstride( pixbuf )-(w<<2); ArgbSurface s( w, h ); unsigned char *dest = reinterpret_cast<unsigned char *>( s.getData() ); int dp = s.getPadding(); // only 4-byte alignments are sane for 32 bits per pixel if( p%4 || dp%4 ) return 0; for( int y = s.getHeight(); y--; src += p, dest += dp ) for( int x = s.getWidth(); x--; src += 4, dest += 4 ) { // swap Red with Blue; GdkPixbuf has BGR order dest[0] = src[2]; dest[1] = src[1]; dest[2] = src[0]; dest[3] = src[3]; } return createIcon( &s, n, Icon::File ); } } #endif #ifdef HAVE_KDE // ask KDE for icon { KIconLoader *loader; if( loader = KIconLoader::global() ) { QPixmap pixmap = loader->loadIcon( n.c_str(), KIconLoader::Desktop, 128, KIconLoader::DefaultState, QStringList(), 0L, true ); if( !pixmap.isNull() ) { QImage image = pixmap.toImage(); if( image.format() == QImage::Format_ARGB32_Premultiplied ) { ArgbSurface s( image.width(), image.height() ); unsigned char *dest = reinterpret_cast<unsigned char *>( s.getData() ); unsigned char *src = reinterpret_cast<unsigned char *>( image.bits() ); int p = image.bytesPerLine()-(image.width()<<2); int dp = s.getPadding(); if( s.getBytesPerLine() == image.bytesPerLine() ) memcpy( dest, src, s.getSize() ); else { // only 4-byte alignments are sane for 32 bits per pixel if( p%4 || dp%4 ) return 0; for( int y = s.getHeight(); y--; src += p, dest += dp ) for( int x = s.getWidth(); x--; src += 4, dest += 4 ) *reinterpret_cast<uint32_t *>( dest ) = *reinterpret_cast<uint32_t *>( src ); } return createIcon( &s, n, Icon::File ); } } } } #endif return 0; }
QImage HistogramGenerator::calculateHistogram(const QSize ¶deSize, const QImage &image, const int &components, HistogramGenerator::Rec rec, const bool &unscaled, const uint &accelFactor) const { if (paradeSize.height() <= 0 || paradeSize.width() <= 0 || image.width() <= 0 || image.height() <= 0) { return QImage(); } bool drawY = (components & HistogramGenerator::ComponentY) != 0; bool drawR = (components & HistogramGenerator::ComponentR) != 0; bool drawG = (components & HistogramGenerator::ComponentG) != 0; bool drawB = (components & HistogramGenerator::ComponentB) != 0; bool drawSum = (components & HistogramGenerator::ComponentSum) != 0; int r[256], g[256], b[256], y[256], s[766]; // Initialize the values to zero std::fill(r, r+256, 0); std::fill(g, g+256, 0); std::fill(b, b+256, 0); std::fill(y, y+256, 0); std::fill(s, s+766, 0); const uint iw = image.bytesPerLine(); const uint ih = image.height(); const uint ww = paradeSize.width(); const uint wh = paradeSize.height(); const uint byteCount = iw*ih; const uint stepsize = 4*accelFactor; const uchar *bits = image.bits(); QRgb *col; // Read the stats from the input image for (uint i = 0; i < byteCount; i += stepsize) { col = (QRgb *)bits; r[qRed(*col)]++; g[qGreen(*col)]++; b[qBlue(*col)]++; if (drawY) { // Use if branch to avoid expensive multiplication if Y disabled if (rec == HistogramGenerator::Rec_601) { y[(int)floor(.299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col))]++; } else { y[(int)floor(.2125*qRed(*col) + .7154*qGreen(*col) + .0721*qBlue(*col))]++; } } if (drawSum) { // Use an if branch here because the sum takes more operations than rgb s[qRed(*col)]++; s[qGreen(*col)]++; s[qBlue(*col)]++; } bits += stepsize; } const int nParts = (drawY ? 1 : 0) + (drawR ? 1 : 0) + (drawG ? 1 : 0) + (drawB ? 1 : 0) + (drawSum ? 1 : 0); if (nParts == 0) { // Nothing to draw return QImage(); } const int d = 20; // Distance for text const int partH = (wh-nParts*d)/nParts; const float scaling = (float)partH/(byteCount >> 7); const int dist = 40; int wy = 0; // Drawing position QImage histogram(paradeSize, QImage::Format_ARGB32); QPainter davinci(&histogram); davinci.setPen(QColor(220, 220, 220, 255)); histogram.fill(qRgba(0, 0, 0, 0)); if (drawY) { drawComponentFull(&davinci, y, scaling, QRect(0, wy, ww, partH + dist), QColor(220, 220, 210, 255), dist, unscaled, 256); wy += partH + d; } if (drawSum) { drawComponentFull(&davinci, s, scaling/3, QRect(0, wy, ww, partH + dist), QColor(220, 220, 210, 255), dist, unscaled, 256); wy += partH + d; } if (drawR) { drawComponentFull(&davinci, r, scaling, QRect(0, wy, ww, partH + dist), QColor(255, 128, 0, 255), dist, unscaled, 256); wy += partH + d; } if (drawG) { drawComponentFull(&davinci, g, scaling, QRect(0, wy, ww, partH + dist), QColor(128, 255, 0, 255), dist, unscaled, 256); wy += partH + d; } if (drawB) { drawComponentFull(&davinci, b, scaling, QRect(0, wy, ww, partH + dist), QColor(0, 128, 255, 255), dist, unscaled, 256); wy += partH + d; } return histogram; }
static cairo_status_t _cairo_qt_surface_acquire_dest_image (void *abstract_surface, cairo_rectangle_int_t *interest_rect, cairo_image_surface_t **image_out, cairo_rectangle_int_t *image_rect, void **image_extra) { cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; QImage *qimg = NULL; D(fprintf(stderr, "q[%p] acquire_dest_image\n", abstract_surface)); *image_extra = NULL; if (qs->image_equiv) { *image_out = (cairo_image_surface_t*) cairo_surface_reference (qs->image_equiv); image_rect->x = qs->window.x(); image_rect->y = qs->window.y(); image_rect->width = qs->window.width(); image_rect->height = qs->window.height(); return CAIRO_STATUS_SUCCESS; } QPoint offset; if (qs->pixmap) { qimg = new QImage(qs->pixmap->toImage()); } else { // Try to figure out what kind of QPaintDevice we have, and // how we can grab an image from it QPaintDevice *pd = qs->p->device(); if (!pd) return _cairo_error (CAIRO_STATUS_NO_MEMORY); QPaintDevice *rpd = QPainter::redirected(pd, &offset); if (rpd) pd = rpd; if (pd->devType() == QInternal::Image) { qimg = new QImage(((QImage*) pd)->copy()); } else if (pd->devType() == QInternal::Pixmap) { qimg = new QImage(((QPixmap*) pd)->toImage()); } else if (pd->devType() == QInternal::Widget) { qimg = new QImage(QPixmap::grabWindow(((QWidget*)pd)->winId()).toImage()); } } if (qimg == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); *image_out = (cairo_image_surface_t*) cairo_image_surface_create_for_data (qimg->bits(), _cairo_format_from_qimage_format (qimg->format()), qimg->width(), qimg->height(), qimg->bytesPerLine()); *image_extra = qimg; image_rect->x = qs->window.x() + offset.x(); image_rect->y = qs->window.y() + offset.y(); image_rect->width = qs->window.width() - offset.x(); image_rect->height = qs->window.height() - offset.y(); return CAIRO_STATUS_SUCCESS; }
/*! This function decodes some data into image changes. Returns the number of bytes consumed. */ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, int *nextFrameDelay, int *loopCount) { // We are required to state that // "The Graphics Interchange Format(c) is the Copyright property of // CompuServe Incorporated. GIF(sm) is a Service Mark property of // CompuServe Incorporated." if (!stack) { stack = new short[(1 << max_lzw_bits) * 4]; table[0] = &stack[(1 << max_lzw_bits) * 2]; table[1] = &stack[(1 << max_lzw_bits) * 3]; } image->detach(); int bpl = image->bytesPerLine(); unsigned char *bits = image->bits(); #define LM(l, m) (((m)<<8)|l) digress = false; const int initial = length; while (!digress && length) { length--; unsigned char ch=*buffer++; switch (state) { case Header: hold[count++]=ch; if (count==6) { // Header gif89=(hold[3]!='8' || hold[4]!='7'); state=LogicalScreenDescriptor; count=0; } break; case LogicalScreenDescriptor: hold[count++]=ch; if (count==7) { // Logical Screen Descriptor swidth=LM(hold[0], hold[1]); sheight=LM(hold[2], hold[3]); gcmap=!!(hold[4]&0x80); //UNUSED: bpchan=(((hold[4]&0x70)>>3)+1); //UNUSED: gcmsortflag=!!(hold[4]&0x08); gncols=2<<(hold[4]&0x7); bgcol=(gcmap) ? hold[5] : -1; //aspect=hold[6] ? double(hold[6]+15)/64.0 : 1.0; trans_index = -1; count=0; ncols=gncols; if (gcmap) { ccount=0; state=GlobalColorMap; globalcmap = new QRgb[gncols+1]; // +1 for trans_index globalcmap[gncols] = Q_TRANSPARENT; } else { state=Introducer; } } break; case GlobalColorMap: case LocalColorMap: hold[count++]=ch; if (count==3) { QRgb rgb = qRgb(hold[0], hold[1], hold[2]); if (state == LocalColorMap) { if (ccount < lncols) localcmap[ccount] = rgb; } else { globalcmap[ccount] = rgb; } if (++ccount >= ncols) { if (state == LocalColorMap) state=TableImageLZWSize; else state=Introducer; } count=0; } break; case Introducer: hold[count++]=ch; switch (ch) { case ',': state=ImageDescriptor; break; case '!': state=ExtensionLabel; break; case ';': // ### Changed: QRect(0, 0, swidth, sheight) state=Done; break; default: digress=true; // Unexpected Introducer - ignore block state=Error; } break; case ImageDescriptor: hold[count++]=ch; if (count==10) { int newleft=LM(hold[1], hold[2]); int newtop=LM(hold[3], hold[4]); int newwidth=LM(hold[5], hold[6]); int newheight=LM(hold[7], hold[8]); // disbelieve ridiculous logical screen sizes, // unless the image frames are also large. if (swidth/10 > qMax(newwidth,200)) swidth = -1; if (sheight/10 > qMax(newheight,200)) sheight = -1; if (swidth <= 0) swidth = newleft + newwidth; if (sheight <= 0) sheight = newtop + newheight; QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32; if (image->isNull()) { (*image) = QImage(swidth, sheight, format); bpl = image->bytesPerLine(); bits = image->bits(); memset(bits, 0, image->byteCount()); } // Check if the previous attempt to create the image failed. If it // did then the image is broken and we should give up. if (image->isNull()) { state = Error; return -1; } disposePrevious(image); disposed = false; left = newleft; top = newtop; width = newwidth; height = newheight; right=qMax(0, qMin(left+width, swidth)-1); bottom=qMax(0, qMin(top+height, sheight)-1); lcmap=!!(hold[9]&0x80); interlace=!!(hold[9]&0x40); //bool lcmsortflag=!!(hold[9]&0x20); lncols=lcmap ? (2<<(hold[9]&0x7)) : 0; if (lncols) { if (localcmap) delete [] localcmap; localcmap = new QRgb[lncols+1]; localcmap[lncols] = Q_TRANSPARENT; ncols = lncols; } else { ncols = gncols; } frame++; if (frame == 0) { if (left || top || width<swidth || height<sheight) { // Not full-size image - erase with bg or transparent if (trans_index >= 0) { fillRect(image, 0, 0, swidth, sheight, color(trans_index)); // ### Changed: QRect(0, 0, swidth, sheight) } else if (bgcol>=0) { fillRect(image, 0, 0, swidth, sheight, color(bgcol)); // ### Changed: QRect(0, 0, swidth, sheight) } } } if (disposal == RestoreImage) { int l = qMin(swidth-1,left); int r = qMin(swidth-1,right); int t = qMin(sheight-1,top); int b = qMin(sheight-1,bottom); int w = r-l+1; int h = b-t+1; if (backingstore.width() < w || backingstore.height() < h) { // We just use the backing store as a byte array backingstore = QImage(qMax(backingstore.width(), w), qMax(backingstore.height(), h), QImage::Format_RGB32); memset(bits, 0, image->byteCount()); } const int dest_bpl = backingstore.bytesPerLine(); unsigned char *dest_data = backingstore.bits(); for (int ln=0; ln<h; ln++) { memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln), FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb)); } } count=0; if (lcmap) { ccount=0; state=LocalColorMap; } else { state=TableImageLZWSize; } x = left; y = top; accum = 0; bitcount = 0; sp = stack; firstcode = oldcode = 0; needfirst = true; out_of_bounds = left>=swidth || y>=sheight; } break; case TableImageLZWSize: { lzwsize=ch; if (lzwsize > max_lzw_bits) { state=Error; } else { code_size=lzwsize+1; clear_code=1<<lzwsize; end_code=clear_code+1; max_code_size=2*clear_code; max_code=clear_code+2; int i; for (i=0; i<clear_code; i++) { table[0][i]=0; table[1][i]=i; } state=ImageDataBlockSize; } count=0; break; } case ImageDataBlockSize: expectcount=ch; if (expectcount) { state=ImageDataBlock; } else { state=Introducer; digress = true; newFrame = true; } break; case ImageDataBlock: count++; accum|=(ch<<bitcount); bitcount+=8; while (bitcount>=code_size && state==ImageDataBlock) { int code=accum&((1<<code_size)-1); bitcount-=code_size; accum>>=code_size; if (code==clear_code) { if (!needfirst) { code_size=lzwsize+1; max_code_size=2*clear_code; max_code=clear_code+2; } needfirst=true; } else if (code==end_code) { bitcount = -32768; // Left the block end arrive } else { if (needfirst) { firstcode=oldcode=code; if (!out_of_bounds && image->height() > y && ((frame == 0) || (firstcode != trans_index))) ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode); x++; if (x>=swidth) out_of_bounds = true; needfirst=false; if (x>=left+width) { x=left; out_of_bounds = left>=swidth || y>=sheight; nextY(bits, bpl); } } else { incode=code; if (code>=max_code) { *sp++=firstcode; code=oldcode; } while (code>=clear_code+2) { if (code >= max_code) { state = Error; return -1; } *sp++=table[1][code]; if (code==table[0][code]) { state=Error; return -1; } if (sp-stack>=(1<<(max_lzw_bits))*2) { state=Error; return -1; } code=table[0][code]; } if (code < 0) { state = Error; return -1; } *sp++=firstcode=table[1][code]; code=max_code; if (code<(1<<max_lzw_bits)) { table[0][code]=oldcode; table[1][code]=firstcode; max_code++; if ((max_code>=max_code_size) && (max_code_size<(1<<max_lzw_bits))) { max_code_size*=2; code_size++; } } oldcode=incode; const int h = image->height(); QRgb *line = 0; if (!out_of_bounds && h > y) line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y); while (sp>stack) { const uchar index = *(--sp); if (!out_of_bounds && h > y && ((frame == 0) || (index != trans_index))) { line[x] = color(index); } x++; if (x>=swidth) out_of_bounds = true; if (x>=left+width) { x=left; out_of_bounds = left>=swidth || y>=sheight; nextY(bits, bpl); if (!out_of_bounds && h > y) line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y); } } } } } partialNewFrame = true; if (count==expectcount) { count=0; state=ImageDataBlockSize; } break; case ExtensionLabel: switch (ch) { case 0xf9: state=GraphicControlExtension; break; case 0xff: state=ApplicationExtension; break; #if 0 case 0xfe: state=CommentExtension; break; case 0x01: break; #endif default: state=SkipBlockSize; } count=0; break; case ApplicationExtension: if (count<11) hold[count]=ch; count++; if (count==hold[0]+1) { if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) { // Looping extension state=NetscapeExtensionBlockSize; } else { state=SkipBlockSize; } count=0; } break; case NetscapeExtensionBlockSize: expectcount=ch; count=0; if (expectcount) state=NetscapeExtensionBlock; else state=Introducer; break; case NetscapeExtensionBlock: if (count<3) hold[count]=ch; count++; if (count==expectcount) { *loopCount = hold[1]+hold[2]*256; state=SkipBlockSize; // Ignore further blocks } break; case GraphicControlExtension: if (count<5) hold[count]=ch; count++; if (count==hold[0]+1) { disposePrevious(image); disposal=Disposal((hold[1]>>2)&0x7); //UNUSED: waitforuser=!!((hold[1]>>1)&0x1); int delay=count>3 ? LM(hold[2], hold[3]) : 1; // IE and mozilla use a minimum delay of 10. With the minimum delay of 10 // we are compatible to them and avoid huge loads on the app and xserver. *nextFrameDelay = (delay < 2 ? 10 : delay) * 10; bool havetrans=hold[1]&0x1; trans_index = havetrans ? hold[4] : -1; count=0; state=SkipBlockSize; } break; case SkipBlockSize: expectcount=ch; count=0; if (expectcount) state=SkipBlock; else state=Introducer; break; case SkipBlock: count++; if (count==expectcount) state=SkipBlockSize; break; case Done: digress=true; /* Netscape ignores the junk, so we do too. length++; // Unget state=Error; // More calls to this is an error */ break; case Error: return -1; // Called again after done. } }
bool ParupaintPanvasInputOutput::exportGIF(ParupaintPanvas * panvas, const QString & filename, QString & errorStr) { Q_ASSERT(panvas); if(filename.isEmpty()) return (errorStr = "Enter a filename to save to.").isEmpty(); #ifndef PARUPAINT_NOGIF int error = 0; GifFileType * gif = EGifOpenFileName(filename.toStdString().c_str(), false, &error); foreach(const QImage & image, panvas->mergedImageFrames(true)){ error = 0; bool alpha = false; QImage toWrite = convertToIndexed8(image, &alpha); QVector<QRgb> colorTable = toWrite.colorTable(); ColorMapObject cmap; int numColors = 1 << BitSize(toWrite.colorCount()); numColors = 256; cmap.ColorCount = numColors; cmap.BitsPerPixel = 8; /// @todo based on numColors (or not? we did ask for Format_Indexed8, so the data is always 8-bit, right?) GifColorType* colorValues = (GifColorType*)malloc(cmap.ColorCount * sizeof(GifColorType)); cmap.Colors = colorValues; int c = 0; for(; c < toWrite.colorCount(); ++c) { //qDebug("color %d has %02X%02X%02X", c, qRed(colorTable[c]), qGreen(colorTable[c]), qBlue(colorTable[c])); colorValues[c].Red = qRed(colorTable[c]); colorValues[c].Green = qGreen(colorTable[c]); colorValues[c].Blue = qBlue(colorTable[c]); } // In case we had an actual number of colors that's not a power of 2, // fill the rest with something (black perhaps). for (; c < numColors; ++c) { colorValues[c].Red = 0; colorValues[c].Green = 0; colorValues[c].Blue = 0; } /// @todo how to specify which version, or decide based on features in use // Because of this call, libgif is not re-entrant EGifSetGifVersion(gif, true); if ((error = EGifPutScreenDesc(gif, toWrite.width(), toWrite.height(), numColors, 0, &cmap)) == GIF_ERROR) qCritical("EGifPutScreenDesc returned error %d", error); int fps = (100.0/panvas->frameRate()); char flags = 1 << 3; if(alpha) flags |= 1; char graphics_ext[] = { flags, (char)(fps % 256), (char)(fps / 256), (char)(alpha ? 0x00 : 0xff) }; EGifPutExtension(gif, GRAPHICS_EXT_FUNC_CODE, 4, graphics_ext); if ((error = EGifPutImageDesc(gif, 0, 0, toWrite.width(), toWrite.height(), 0, &cmap)) == GIF_ERROR) qCritical("EGifPutImageDesc returned error %d", error); int lc = toWrite.height(); int llen = toWrite.bytesPerLine(); for (int l = 0; l < lc; ++l) { uchar* line = toWrite.scanLine(l); if ((error = EGifPutLine(gif, (GifPixelType*)line, llen)) == GIF_ERROR) { qCritical("EGifPutLine returned error %d", error); } } if(true){ // loop forever unsigned char loopblock[3] = {1, 0, 0}; EGifPutExtensionLeader(gif, APPLICATION_EXT_FUNC_CODE); EGifPutExtensionBlock(gif, 11, "NETSCAPE2.0"); EGifPutExtensionBlock(gif, 3, loopblock); EGifPutExtensionTrailer(gif); } } EGifCloseFile(gif, &error); return true; #endif return (errorStr = "GIF export not available.").isEmpty(); }
void blur( QImage& image, int radius ) { int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; int r1 = 0; int r2 = image.height() - 1; int c1 = 0; int c2 = image.width() - 1; int bpl = image.bytesPerLine(); int rgba[4]; unsigned char* p; int i1 = 0; int i2 = 3; for (int col = c1; col <= c2; col++) { p = image.scanLine(r1) + col * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p += bpl; for (int j = r1; j < r2; j++, p += bpl) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int row = r1; row <= r2; row++) { p = image.scanLine(row) + c1 * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p += 4; for (int j = c1; j < c2; j++, p += 4) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int col = c1; col <= c2; col++) { p = image.scanLine(r2) + col * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p -= bpl; for (int j = r1; j < r2; j++, p -= bpl) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int row = r1; row <= r2; row++) { p = image.scanLine(row) + c2 * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p -= 4; for (int j = c1; j < c2; j++, p -= 4) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } }
static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QByteArray &sourceFormat) { QByteArray str; QImage image = sourceImage; QByteArray format = sourceFormat; format = format.left(3); // ignore RAW part bool gray = format == "pgm"; if (format == "pbm") { image = image.convertToFormat(QImage::Format_Mono); } else if (image.depth() == 1) { image = image.convertToFormat(QImage::Format_Indexed8); } else { switch (image.format()) { case QImage::Format_RGB16: case QImage::Format_RGB666: case QImage::Format_RGB555: case QImage::Format_RGB888: case QImage::Format_RGB444: image = image.convertToFormat(QImage::Format_RGB32); break; case QImage::Format_ARGB8565_Premultiplied: case QImage::Format_ARGB6666_Premultiplied: case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_ARGB4444_Premultiplied: image = image.convertToFormat(QImage::Format_ARGB32); break; default: break; } } if (image.depth() == 1 && image.colorCount() == 2) { if (qGray(image.color(0)) < qGray(image.color(1))) { // 0=dark/black, 1=light/white - invert image.detach(); for (int y=0; y<image.height(); y++) { uchar *p = image.scanLine(y); uchar *end = p + image.bytesPerLine(); while (p < end) *p++ ^= 0xff; } } } uint w = image.width(); uint h = image.height(); str = "P\n"; str += QByteArray::number(w); str += ' '; str += QByteArray::number(h); str += '\n'; switch (image.depth()) { case 1: { str.insert(1, '4'); if (out->write(str, str.length()) != str.length()) return false; w = (w+7)/8; for (uint y=0; y<h; y++) { uchar* line = image.scanLine(y); if (w != (uint)out->write((char*)line, w)) return false; } } break; case 8: { str.insert(1, gray ? '5' : '6'); str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; QVector<QRgb> color = image.colorTable(); uint bpl = w*(gray ? 1 : 3); uchar *buf = new uchar[bpl]; for (uint y=0; y<h; y++) { uchar *b = image.scanLine(y); uchar *p = buf; uchar *end = buf+bpl; if (gray) { while (p < end) { uchar g = (uchar)qGray(color[*b++]); *p++ = g; } } else { while (p < end) { QRgb rgb = color[*b++]; *p++ = qRed(rgb); *p++ = qGreen(rgb); *p++ = qBlue(rgb); } } if (bpl != (uint)out->write((char*)buf, bpl)) return false; } delete [] buf; } break; case 32: { str.insert(1, gray ? '5' : '6'); str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; uint bpl = w*(gray ? 1 : 3); uchar *buf = new uchar[bpl]; for (uint y=0; y<h; y++) { QRgb *b = (QRgb*)image.scanLine(y); uchar *p = buf; uchar *end = buf+bpl; if (gray) { while (p < end) { uchar g = (uchar)qGray(*b++); *p++ = g; } } else { while (p < end) { QRgb rgb = *b++; *p++ = qRed(rgb); *p++ = qGreen(rgb); *p++ = qBlue(rgb); } } if (bpl != (uint)out->write((char*)buf, bpl)) return false; } delete [] buf; } break; default: return false; } return true; }
// Thanks StackOverflow for this algorithm (works like a charm without any changes) QImage ImageUtils::blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly) { int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); int r1 = rect.top(); int r2 = rect.bottom(); int c1 = rect.left(); int c2 = rect.right(); int bpl = result.bytesPerLine(); int rgba[4]; unsigned char* p; int i1 = 0; int i2 = 3; if (alphaOnly) i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); for (int col = c1; col <= c2; col++) { p = result.scanLine(r1) + col * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p += bpl; for (int j = r1; j < r2; j++, p += bpl) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int row = r1; row <= r2; row++) { p = result.scanLine(row) + c1 * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p += 4; for (int j = c1; j < c2; j++, p += 4) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int col = c1; col <= c2; col++) { p = result.scanLine(r2) + col * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p -= bpl; for (int j = r1; j < r2; j++, p -= bpl) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int row = r1; row <= r2; row++) { p = result.scanLine(row) + c2 * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p -= 4; for (int j = c1; j < c2; j++, p -= 4) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } return result; }
Mat qimage2mat(QImage& qimage) { cv::Mat tmp(qimage.height(),qimage.width(),CV_8UC3,(uchar*)qimage.bits(),qimage.bytesPerLine()); cv::Mat result; // deep copy just in case (my lack of knowledge with open cv) cvtColor(tmp, result,CV_BGR2RGB); return result; }
QImage Filter::process(const QImage &inputImage) { if (inputImage.isNull() || inputImage.format() != QImage::Format_ARGB32) return inputImage; ImageHistogram histogram; double inputBlackPoint[3], inputWhitePoint[3], inputGamma[3], outputBlackPoint[3], outputWhitePoint[3]; unsigned char mLuts[3][256]; double clippingShadows = mClippingShadows / 100., clippingHighlights = mClippingHighlights / 100.; double mean; if (mEnhanceChannelsSeparately) { histogram.computeHistogram(inputImage.bits(), inputImage.width(), inputImage.height(), ImageHistogram::RGB, inputImage.bytesPerLine()); for (int i = 0; i < 3; i++) { const ImageHistogram::Channel channel = (ImageHistogram::Channel)(1 << i); if (qFuzzyIsNull(clippingShadows)) inputBlackPoint[i] = histogram.limit(channel, ProbabilityMassFunction::A); else inputBlackPoint[i] = histogram.integrate2(channel, clippingShadows); if (qFuzzyIsNull(clippingHighlights)) inputWhitePoint[i] = histogram.limit(channel, ProbabilityMassFunction::B); else inputWhitePoint[i] = histogram.integrate2(channel, -clippingHighlights); if (mAdjustMidtones) { mean = (histogram.mean(channel) - inputBlackPoint[i]) / (inputWhitePoint[i] - inputBlackPoint[i]); inputGamma[i] = AT_clamp(.1, 1. / (log(i == 0 ? mTargetColorMidtones.blueF() : i == 1 ? mTargetColorMidtones.greenF() : mTargetColorMidtones.redF()) / log(mean)), 10.); } else inputGamma[i] = 1.; inputBlackPoint[i] /= 255.; inputWhitePoint[i] /= 255.; } } else { histogram.computeHistogram(inputImage.bits(), inputImage.width(), inputImage.height(), ImageHistogram::Luma, inputImage.bytesPerLine()); if (qFuzzyIsNull(clippingShadows)) inputBlackPoint[0] = inputBlackPoint[1] = inputBlackPoint[2] = histogram.limit(ImageHistogram::Luma, ProbabilityMassFunction::A); else inputBlackPoint[0] = inputBlackPoint[1] = inputBlackPoint[2] = histogram.integrate2(ImageHistogram::Luma, clippingShadows); if (qFuzzyIsNull(clippingHighlights)) inputWhitePoint[0] = inputWhitePoint[1] = inputWhitePoint[2] = histogram.limit(ImageHistogram::Luma, ProbabilityMassFunction::B); else inputWhitePoint[0] = inputWhitePoint[1] = inputWhitePoint[2] = histogram.integrate2(ImageHistogram::Luma, -clippingHighlights); if (mAdjustMidtones) { mean = (histogram.mean(ImageHistogram::Luma) - inputBlackPoint[0]) / (inputWhitePoint[0] - inputBlackPoint[0]); for (int i = 0; i < 3; i++) { inputGamma[i] = AT_clamp(.1, 1. / (log(i == 0 ? mTargetColorMidtones.blueF() : i == 1 ? mTargetColorMidtones.greenF() : mTargetColorMidtones.redF()) / log(mean)), 10.); } } else inputGamma[0] = inputGamma[1] = inputGamma[2] = 1.; inputBlackPoint[0] = inputBlackPoint[1] = inputBlackPoint[2] = inputBlackPoint[0] / 255.; inputWhitePoint[0] = inputWhitePoint[1] = inputWhitePoint[2] = inputWhitePoint[0] / 255.; } outputBlackPoint[0] = mTargetColorShadows.blueF(); outputBlackPoint[1] = mTargetColorShadows.greenF(); outputBlackPoint[2] = mTargetColorShadows.redF(); outputWhitePoint[0] = mTargetColorHighlights.blueF(); outputWhitePoint[1] = mTargetColorHighlights.greenF(); outputWhitePoint[2] = mTargetColorHighlights.redF(); generateLevelsLUT(mLuts[0], inputGamma[0], inputBlackPoint[0], inputWhitePoint[0], outputBlackPoint[0], outputWhitePoint[0]); generateLevelsLUT(mLuts[1], inputGamma[1], inputBlackPoint[1], inputWhitePoint[1], outputBlackPoint[1], outputWhitePoint[1]); generateLevelsLUT(mLuts[2], inputGamma[2], inputBlackPoint[2], inputWhitePoint[2], outputBlackPoint[2], outputWhitePoint[2]); QImage i = QImage(inputImage.width(), inputImage.height(), QImage::Format_ARGB32); register BGRA * bits = (BGRA*)inputImage.bits(); register BGRA * bits2 = (BGRA*)i.bits(); register int totalPixels = i.width() * i.height(); while (totalPixels--) { bits2->b = mLuts[0][bits->b]; bits2->g = mLuts[1][bits->g]; bits2->r = mLuts[2][bits->r]; bits2->a = bits->a; bits++; bits2++; } return i; }
/* You can also find a BSD version to this method from * http://gitorious.org/ofi-labs/x2/blobs/master/graphics/shadowblur/ */ void KoShapeShadow::Private::blurShadow(QImage &image, int radius, const QColor& shadowColor) { static const int BlurSumShift = 15; // Check http://www.w3.org/TR/SVG/filters.html# // As noted in the SVG filter specification, ru // approximates a real gaussian blur nicely. // See comments in http://webkit.org/b/40793, it seems sensible // to follow Skia's limit of 128 pixels for the blur radius. if (radius > 128) radius = 128; int channels[4] = { 3, 0, 1, 3 }; int dmax = radius >> 1; int dmin = dmax - 1 + (radius & 1); if (dmin < 0) dmin = 0; // Two stages: horizontal and vertical for (int k = 0; k < 2; ++k) { unsigned char* pixels = image.bits(); int stride = (k == 0) ? 4 : image.bytesPerLine(); int delta = (k == 0) ? image.bytesPerLine() : 4; int jfinal = (k == 0) ? image.height() : image.width(); int dim = (k == 0) ? image.width() : image.height(); for (int j = 0; j < jfinal; ++j, pixels += delta) { // For each step, we blur the alpha in a channel and store the result // in another channel for the subsequent step. // We use sliding window algorithm to accumulate the alpha values. // This is much more efficient than computing the sum of each pixels // covered by the box kernel size for each x. for (int step = 0; step < 3; ++step) { int side1 = (step == 0) ? dmin : dmax; int side2 = (step == 1) ? dmin : dmax; int pixelCount = side1 + 1 + side2; int invCount = ((1 << BlurSumShift) + pixelCount - 1) / pixelCount; int ofs = 1 + side2; int alpha1 = pixels[channels[step]]; int alpha2 = pixels[(dim - 1) * stride + channels[step]]; unsigned char* ptr = pixels + channels[step + 1]; unsigned char* prev = pixels + stride + channels[step]; unsigned char* next = pixels + ofs * stride + channels[step]; int i; int sum = side1 * alpha1 + alpha1; int limit = (dim < side2 + 1) ? dim : side2 + 1; for (i = 1; i < limit; ++i, prev += stride) sum += *prev; if (limit <= side2) sum += (side2 - limit + 1) * alpha2; limit = (side1 < dim) ? side1 : dim; for (i = 0; i < limit; ptr += stride, next += stride, ++i, ++ofs) { *ptr = (sum * invCount) >> BlurSumShift; sum += ((ofs < dim) ? *next : alpha2) - alpha1; } prev = pixels + channels[step]; for (; ofs < dim; ptr += stride, prev += stride, next += stride, ++i, ++ofs) { *ptr = (sum * invCount) >> BlurSumShift; sum += (*next) - (*prev); } for (; i < dim; ptr += stride, prev += stride, ++i) { *ptr = (sum * invCount) >> BlurSumShift; sum += alpha2 - (*prev); } } } } // "Colorize" with the right shadow color. QPainter p(&image); p.setCompositionMode(QPainter::CompositionMode_SourceIn); p.fillRect(image.rect(), shadowColor); p.end(); }
void GLWidget::paintGL() { if (data.currentFile != data.nextFile) { if (data.nextFile == -1) loadShaders(data.filePath); else loadShaders(fileList[data.nextFile]); data.currentFile = data.nextFile; data.zoom = 0; data.moveX = 0; data.moveY = 0; data.pause = false; updateTitle(); } double posX = (data.moveX + 1.) * float(DIM / 2); double posY = (data.moveY - 1.) * float(DIM / 2) * -1.; glUniform1ui(data.loc.dim, DIM); glUniform1f(data.loc.zoom, data.zoom); glUniform2d(data.loc.position, posX, posY); glVertexAttribPointer(data.loc.vertex, 2, GL_FLOAT, GL_FALSE, 0, data.vertex.constData()); if (data.loc.animation != -1 && !data.pause) { glUniform1f((float)data.loc.animation, (double)QTime::currentTime().msecsSinceStartOfDay() / 1000.); update(); } render(); if (!data.saving) return; data.saving = false; QImage *img = saveDialog->img; QImage imgRen(data.save.blockSize, QImage::Format_RGB888); if (img == 0) { saveDialog->failed(tr("img allocation failed")); return; } if (img->isNull()) { saveDialog->failed(tr("img is null")); return; } if (imgRen.isNull()) { saveDialog->failed(tr("imgRen is null")); return; } QOpenGLFramebufferObject fbo(data.save.blockSize); fbo.bind(); glViewport(0, 0, data.save.blockSize.width(), data.save.blockSize.height()); QPoint pos; int w = data.save.blockSize.width() * data.save.blockCount.width(); int h = data.save.blockSize.height() * data.save.blockCount.height(); float asp = (float)h / (float)w; render: // Select region data.projection.setToIdentity(); float left = float(2 * pos.x() - data.save.blockCount.width()) / data.save.blockCount.width(); float top = float(2 * pos.y() - data.save.blockCount.height()) / data.save.blockCount.height(); data.projection.ortho(left, left + 2. / data.save.blockCount.width(), asp * top, asp * (top + 2. / data.save.blockCount.height()), -1., 1.); render(); QPoint imgPos(pos.x() * data.save.blockSize.width(), pos.y() * data.save.blockSize.height()); glReadPixels(0, 0, imgRen.width(), imgRen.height(), GL_RGB, GL_UNSIGNED_BYTE, imgRen.bits()); unsigned char *imgPtr = img->scanLine(img->height() - imgPos.y() - 1) + imgPos.x() * 3; for (int i = 0; i < imgRen.height(); i++) { memcpy(imgPtr, imgRen.constScanLine(i), imgRen.bytesPerLine()); imgPtr -= img->bytesPerLine(); } if (pos.x() != data.save.blockCount.width() - 1) pos.setX(pos.x() + 1); else if (pos.y() != data.save.blockCount.height() - 1) { pos.setX(0); pos.setY(pos.y() + 1); } else { fbo.release(); resizeGL(width(), height()); saveDialog->done(); return; } goto render; }
QPixmap QPixmap::fromImage(const QImage &img, Qt::ImageConversionFlags flags) { QPixmap pixmap; if(img.isNull()) { qWarning("QPixmap::convertFromImage: Cannot convert a null image"); return pixmap; } QImage image = img; int d = image.depth(); int dd = defaultDepth(); bool force_mono = (dd == 1 || (flags & Qt::ColorMode_Mask)==Qt::MonoOnly); if(force_mono) { // must be monochrome if(d != 1) { image = image.convertToFormat(QImage::Format_MonoLSB, flags); // dither d = 1; } } else { // can be both bool conv8 = false; if(d > 8 && dd <= 8) { // convert to 8 bit if((flags & Qt::DitherMode_Mask) == Qt::AutoDither) flags = (flags & ~Qt::DitherMode_Mask) | Qt::PreferDither; conv8 = true; } else if((flags & Qt::ColorMode_Mask) == Qt::ColorOnly) { conv8 = d == 1; // native depth wanted } else if(d == 1) { if(image.numColors() == 2) { QRgb c0 = image.color(0); // Auto: convert to best QRgb c1 = image.color(1); conv8 = qMin(c0,c1) != qRgb(0,0,0) || qMax(c0,c1) != qRgb(255,255,255); } else { // eg. 1-color monochrome images (they do exist). conv8 = true; } } if(conv8) { image = image.convertToFormat(QImage::Format_Indexed8, flags); d = 8; } } if(image.depth()==1) { image.setColor(0, QColor(Qt::color0).rgba()); image.setColor(1, QColor(Qt::color1).rgba()); } if (d == 16) { QImage im = image.convertToFormat(QImage::Format_RGB32, flags); return fromImage(im); } int w = image.width(); int h = image.height(); // different size or depth, make a new pixmap if (d == 1) pixmap = QBitmap(w, h); else pixmap = QPixmap(w, h); quint32 *dptr = pixmap.data->pixels, *drow; const uint dbpr = pixmap.data->nbytes / h; const QImage::Format sfmt = image.format(); const unsigned short sbpr = image.bytesPerLine(); uchar *sptr = image.bits(), *srow; for(int y=0;y<h;y++) { drow = dptr + (y * (dbpr / 4)); srow = sptr + (y * sbpr); switch(sfmt) { case QImage::Format_MonoLSB: case QImage::Format_Mono:{ for(int x=0;x<w;++x) { char one_bit = *(srow + (x / 8)); if(sfmt == QImage::Format_Mono) one_bit = one_bit >> (7 - (x % 8)); else one_bit = one_bit >> (x % 8); if((one_bit & 0x01)) *(drow+x) = 0x00000000; else *(drow+x) = 0xFFFFFFFF; } break; } case QImage::Format_Indexed8: for(int x=0;x<w;++x) { *(drow+x) = PREMUL(image.color(*(srow + x))); } break; case QImage::Format_RGB32: for(int x=0;x<w;++x) *(drow+x) = *(((quint32*)srow) + x) | 0xFF000000; break; case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: for(int x=0;x<w;++x) { if(sfmt == QImage::Format_RGB32) *(drow+x) = 0xFF000000 | (*(((quint32*)srow) + x) & 0x00FFFFFF); else if(sfmt == QImage::Format_ARGB32_Premultiplied) *(drow+x) = *(((quint32*)srow) + x); else *(drow+x) = PREMUL(*(((quint32*)srow) + x)); } break; default: qWarning("Qt: internal: Oops: Forgot a format [%d] %s:%d", sfmt, __FILE__, __LINE__); break; } }
// mostly duplicated from qimage.cpp (QImageData::checkForAlphaPixels) static bool checkForAlphaPixels(const QImage &img) { const uchar *bits = img.bits(); const int bytes_per_line = img.bytesPerLine(); const uchar *end_bits = bits + bytes_per_line; const int width = img.width(); const int height = img.height(); switch (img.format()) { case QImage::Format_Indexed8: return img.hasAlphaChannel(); case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: for (int y=0; y<height; ++y) { for (int x=0; x<width; ++x) { if ((((uint *)bits)[x] & 0xff000000) != 0xff000000) { return true; } } bits += bytes_per_line; } break; case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_ARGB8565_Premultiplied: for (int y=0; y<height; ++y) { while (bits < end_bits) { if (bits[0] != 0) { return true; } bits += 3; } bits = end_bits; end_bits += bytes_per_line; } break; case QImage::Format_ARGB6666_Premultiplied: for (int y=0; y<height; ++y) { while (bits < end_bits) { if ((bits[0] & 0xfc) != 0) { return true; } bits += 3; } bits = end_bits; end_bits += bytes_per_line; } break; case QImage::Format_ARGB4444_Premultiplied: for (int y=0; y<height; ++y) { while (bits < end_bits) { if ((bits[0] & 0xf0) != 0) { return true; } bits += 2; } bits = end_bits; end_bits += bytes_per_line; } break; default: break; } return false; }
bool QWebpHandler::write(const QImage &image) { if (image.isNull()) { qWarning() << "source image is null."; return false; } QImage srcImage = image; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN if (srcImage.format() != QImage::Format_ARGB32) srcImage = srcImage.convertToFormat(QImage::Format_ARGB32); #else /* Q_BIG_ENDIAN */ if (srcImage.format() != QImage::Format_RGBA8888) srcImage = srcImage.convertToFormat(QImage::Format_RGBA8888); #endif WebPPicture picture; WebPConfig config; if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) { qWarning() << "failed to init webp picture and config"; return false; } picture.width = srcImage.width(); picture.height = srcImage.height(); picture.use_argb = 1; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN if (!WebPPictureImportBGRA(&picture, srcImage.bits(), srcImage.bytesPerLine())) { #else /* Q_BIG_ENDIAN */ if (!WebPPictureImportRGBA(&picture, srcImage.bits(), srcImage.bytesPerLine())) { #endif qWarning() << "failed to import image data to webp picture."; WebPPictureFree(&picture); return false; } config.lossless = m_lossless; config.quality = m_quality; picture.writer = pictureWriter; picture.custom_ptr = device(); if (!WebPEncode(&config, &picture)) { qWarning() << "failed to encode webp picture, error code: " << picture.error_code; WebPPictureFree(&picture); return false; } WebPPictureFree(&picture); return true; } QVariant QWebpHandler::option(ImageOption option) const { if (!supportsOption(option) || !ensureScanned()) return QVariant(); switch (option) { case Quality: return m_quality; case Size: return QSize(m_width, m_height); case Animation: return (m_flags & ANIMATION_FLAG) == ANIMATION_FLAG; default: return QVariant(); } } void QWebpHandler::setOption(ImageOption option, const QVariant &value) { switch (option) { case Quality: m_quality = qBound(0, value.toInt(), 100); m_lossless = (m_quality >= 100); return; default: break; } return QImageIOHandler::setOption(option, value); } bool QWebpHandler::supportsOption(ImageOption option) const { return option == Quality || option == Size || option == Animation; } QByteArray QWebpHandler::name() const { return QByteArrayLiteral("webp"); } int QWebpHandler::imageCount() const { if (!ensureScanned()) return 0; if ((m_flags & ANIMATION_FLAG) == 0) return 1; return m_frameCount; } int QWebpHandler::currentImageNumber() const { if (!ensureScanned()) return 0; return m_iter.frame_num; } QRect QWebpHandler::currentImageRect() const { if (!ensureScanned()) return QRect(); return QRect(m_iter.x_offset, m_iter.y_offset, m_iter.width, m_iter.height); } bool QWebpHandler::jumpToImage(int imageNumber) { if (!ensureScanned()) return false; WebPDemuxReleaseIterator(&m_iter); return WebPDemuxGetFrame(m_demuxer, imageNumber, &m_iter); } bool QWebpHandler::jumpToNextImage() { if (!ensureScanned()) return false; return WebPDemuxNextFrame(&m_iter); } int QWebpHandler::loopCount() const { if (!ensureScanned() || (m_flags & ANIMATION_FLAG) == 0) return 0; return m_loop; } int QWebpHandler::nextImageDelay() const { if (!ensureScanned()) return 0; return m_iter.duration; }
VideoFrame::VideoFrame(const QImage& image) : Frame(new VideoFramePrivate(image.width(), image.height(), VideoFormat(image.format()))) { setBits((uchar*)image.constBits(), 0); setBytesPerLine(image.bytesPerLine(), 0); }
/* Convert QImage to cv::Mat without data copy */ cv::Mat image2Mat_shared(const QImage &img, MatColorOrder *order) { if (img.isNull()) return cv::Mat(); switch (img.format()) { case QImage::Format_Indexed8: break; #if QT_VERSION >= 0x040400 case QImage::Format_RGB888: if (order) *order = MCO_RGB; break; #endif case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: if (order) *order = getColorOrderOfRGB32Format(); break; #if QT_VERSION >= 0x050200 case QImage::Format_RGBX8888: case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: if (order) *order = MCO_RGBA; break; #endif #if QT_VERSION >= 0x050500 case QImage::Format_Alpha8: case QImage::Format_Grayscale8: break; #endif default: return cv::Mat(); } return cv::Mat(img.height(), img.width(), CV_8UC(img.depth()/8), (uchar*)img.bits(), img.bytesPerLine()); }
void QAnimationWriter::appendFrame(const QImage& frm, const QPoint& offset) { if (!dev) return; const QImage frame = frm.convertToFormat(QImage::Format_RGB32); const int alignx = 1; if (prev.isNull() || !d->canCompose()) { d->setImage(frame); } else { bool done; int minx, maxx, miny, maxy; int w = frame.width(); int h = frame.height(); const quint32 *framePtr = reinterpret_cast<const quint32*>(frame.bits()); const quint32 *prevPtr = reinterpret_cast<const quint32*>(prev.bits()); const int frameStride = frame.bytesPerLine() / sizeof(quint32); const int prevStride = prev.bytesPerLine() / sizeof(quint32); // Find left edge of change done = false; for (minx = 0; minx < w && !done; ++minx) { const quint32 *p1 = framePtr + minx; const quint32 *p2 = prevPtr + minx + offset.x(); for (int y = 0; y < h; ++y) { if (*p1 != *p2) { done = true; break; } p1 += frameStride; p2 += prevStride; } } --minx; // Find right edge of change done = false; for (maxx = w-1; maxx >= 0 && !done; --maxx) { const quint32 *p1 = framePtr + maxx; const quint32 *p2 = prevPtr + maxx + offset.x(); for (int y = 0; y < h; ++y) { if (*p1 != *p2) { done = true; break; } p1 += frameStride; p2 += prevStride; } } ++maxx; // Find top edge of change done = false; for (miny = 0; miny < h && !done; ++miny) { const quint32 *p1 = framePtr + miny * frameStride; const quint32 *p2 = prevPtr + miny * prevStride + offset.x(); for (int x = 0; x < w; ++x) { if (*p1 != *p2) { done = true; break; } ++p1; ++p2; } } --miny; // Find right edge of change done = false; for (maxy = h-1; maxy >= 0 && !done; --maxy) { const quint32 *p1 = framePtr + maxy * frameStride; const quint32 *p2 = prevPtr + maxy * prevStride + offset.x(); for (int x = 0; x < w; ++x) { if (*p1 != *p2) { done = true; break; } ++p1; ++p2; } } ++maxy; if (minx > maxx) minx = maxx = 0; if (miny > maxy) miny = maxy = 0; if (alignx > 1) { minx -= minx % alignx; maxx = maxx - maxx % alignx + alignx - 1; } int dw = maxx - minx + 1; int dh = maxy - miny + 1; QImage diff(dw, dh, QImage::Format_ARGB32); int x, y; for (y = 0; y < dh; ++y) { QRgb* li = (QRgb*)frame.scanLine(y+miny)+minx; QRgb* lp = (QRgb*)prev.scanLine(y+miny+offset.y())+minx+offset.x(); QRgb* ld = (QRgb*)diff.scanLine(y); if (alignx) { for (x = 0; x < dw; x += alignx) { int i; for (i = 0; i < alignx; ++i) { if (li[x+i] != lp[x+i]) break; } if (i == alignx) { // All the same for (i = 0; i < alignx; ++i) ld[x+i] = qRgba(0,0,0,0); } else { // Some different for (i = 0; i < alignx; ++i) ld[x+i] = 0xff000000 | li[x+i]; } } } else { for (x = 0; x < dw; ++x) { if (li[x] != lp[x]) ld[x] = 0xff000000 | li[x]; else ld[x] = qRgba(0,0,0,0); } } } d->composeImage(diff, QPoint(minx, miny) + offset); } if (prev.isNull() || prev.size() == frame.size() && offset == QPoint(0,0)) { prev = frame; } else { QPainter p(&prev); p.drawImage(offset.x(), offset.y(), frame, 0, 0, frame.width(), frame.height()); } }
void flushImage(const QPoint &pos, const QImage &image, const QRect &destinationRect) { checkPauseApplication(); QMutexLocker locker(&m_surfaceMutex); if (!m_surface) return; AttachedJNIEnv env; if (!env.jniEnv) return; int bpp = 2; AndroidBitmapInfo info; int ret; if ((ret = AndroidBitmap_getInfo(env.jniEnv, m_surface, &info)) < 0) { qWarning() << "AndroidBitmap_getInfo() failed ! error=" << ret; m_javaVM->DetachCurrentThread(); return; } if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) { qWarning() << "Bitmap format is not RGB_565!"; m_javaVM->DetachCurrentThread(); return; } void *pixels; unsigned char *screenBits; if ((ret = AndroidBitmap_lockPixels(env.jniEnv, m_surface, &pixels)) < 0) { qWarning() << "AndroidBitmap_lockPixels() failed! error=" << ret; m_javaVM->DetachCurrentThread(); return; } screenBits = static_cast<unsigned char *>(pixels); int sbpl = info.stride; int swidth = info.width; int sheight = info.height; unsigned sposx = pos.x() + destinationRect.x(); unsigned sposy = pos.y() + destinationRect.y(); screenBits += sposy * sbpl; unsigned ibpl = image.bytesPerLine(); unsigned iposx = destinationRect.x(); unsigned iposy = destinationRect.y(); const unsigned char *imageBits = static_cast<const unsigned char *>(image.bits()); imageBits += iposy * ibpl; unsigned width = swidth - sposx < unsigned(destinationRect.width()) ? (swidth-sposx) : destinationRect.width(); unsigned height = sheight - sposy < unsigned(destinationRect.height()) ? (sheight - sposy) : destinationRect.height(); for (unsigned y = 0; y < height; y++) { memcpy(screenBits + y*sbpl + sposx*bpp, imageBits + y*ibpl + iposx*bpp, width*bpp); } AndroidBitmap_unlockPixels(env.jniEnv, m_surface); env.jniEnv->CallStaticVoidMethod(m_applicationClass, m_redrawSurfaceMethodID, jint(destinationRect.left()), jint(destinationRect.top()), jint(destinationRect.right() + 1), jint(destinationRect.bottom() + 1)); #warning FIXME dirty hack, figure out why it needs to add 1 to right and bottom !!!! }
// See https://code.woboq.org/qt5/qtbase/src/gui/image/qimage.cpp.html#_ZNK6QImage5pixelEii inline QRgb getPixel(const QImage& image, int x, int y) { uchar* line = const_cast<uchar*>(image.constBits()) + y * image.bytesPerLine(); return reinterpret_cast<QRgb*>(line)[x]; }
void QPF::addGlyphs(QFontEngine *fe, const QList<CharacterRange> &ranges) { const quint16 glyphCount = fe->glyphCount(); QByteArray gmap; gmap.resize(glyphCount * sizeof(quint32)); gmap.fill(char(0xff)); //qDebug() << "glyphCount" << glyphCount; QByteArray glyphs; if (options & RenderGlyphs) { // this is only a rough estimation glyphs.reserve(glyphCount * (sizeof(QFontEngineQPF::Glyph) + qRound(fe->maxCharWidth() * (fe->ascent() + fe->descent()).toReal()))); QGlyphLayout layout[10]; foreach (CharacterRange range, ranges) { if (debugVerbosity > 2) qDebug() << "rendering range from" << range.start << "to" << range.end; for (uint uc = range.start; uc < range.end; ++uc) { QChar ch(uc); int nglyphs = 10; if (!fe->stringToCMap(&ch, 1, &layout[0], &nglyphs, /*flags*/ 0)) continue; if (nglyphs != 1) continue; const quint32 glyphIndex = layout[0].glyph; if (!glyphIndex) continue; Q_ASSERT(glyphIndex < glyphCount); QImage img = fe->alphaMapForGlyph(glyphIndex).convertToFormat(QImage::Format_Indexed8); glyph_metrics_t metrics = fe->boundingBox(glyphIndex); const quint32 oldSize = glyphs.size(); glyphs.resize(glyphs.size() + sizeof(QFontEngineQPF::Glyph) + img.numBytes()); uchar *data = reinterpret_cast<uchar *>(glyphs.data() + oldSize); uchar *gmapPtr = reinterpret_cast<uchar *>(gmap.data() + glyphIndex * sizeof(quint32)); qToBigEndian(oldSize, gmapPtr); QFontEngineQPF::Glyph *glyph = reinterpret_cast<QFontEngineQPF::Glyph *>(data); glyph->width = img.width(); glyph->height = img.height(); glyph->bytesPerLine = img.bytesPerLine(); glyph->x = qRound(metrics.x); glyph->y = qRound(metrics.y); glyph->advance = qRound(metrics.xoff); data += sizeof(QFontEngineQPF::Glyph); if (debugVerbosity && uc >= 'A' && uc <= 'z' || debugVerbosity > 1) { qDebug() << "adding glyph with index" << glyphIndex << " uc =" << char(uc) << ":\n" << " glyph->x =" << glyph->x << "rounded from" << metrics.x << "\n" << " glyph->y =" << glyph->y << "rounded from" << metrics.y << "\n" << " width =" << glyph->width << "height =" << glyph->height << " advance =" << glyph->advance << "rounded from" << metrics.xoff ; } qMemCopy(data, img.bits(), img.numBytes()); } } }
cv::Mat qimg2img(const QImage &qimg) { cv::Mat img; img = cv::Mat(qimg.height(), qimg.width(), CV_8UC4, const_cast<uchar*>(qimg.bits()), qimg.bytesPerLine()); return img; }
Qt::HANDLE QMeeGoPixmapData::imageToEGLSharedImage(const QImage &image) { QGLShareContextScope ctx(qt_gl_share_widget()->context()); QMeeGoExtensions::ensureInitialized(); GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); if (image.hasAlphaChannel() && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels()) { void *converted = convertBGRA32_to_RGBA32(image.bits(), image.width(), image.height(), image.bytesPerLine()); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, converted); free(converted); } else { void *converted = convertRGB32_to_RGB565(image.bits(), image.width(), image.height(), image.bytesPerLine()); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, converted); free(converted); } glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); EGLImageKHR eglimage = QEgl::eglCreateImageKHR(QEgl::display(), QEglContext::currentContext(QEgl::OpenGL)->context(), EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer) textureId, preserved_image_attribs); glDeleteTextures(1, &textureId); if (eglimage) { EGLNativeSharedImageTypeNOK handle = QMeeGoExtensions::eglCreateSharedImageNOK(QEgl::display(), eglimage, NULL); QEgl::eglDestroyImageKHR(QEgl::display(), eglimage); return (Qt::HANDLE) handle; } else { qWarning("Failed to create shared image from pixmap/texture!"); return 0; } }
QVector<QRectF> SubtitleDrawer::draw(QImage &image, int &gap, const RichTextDocument &text, const QRectF &area, double dpr) { QVector<QRectF> bboxes; gap = 0; if (!(m_drawn = text.hasWords())) return bboxes; const double scale = this->scale(area)*dpr; const double fscale = m_style.font.height()*scale; auto make = [this, text, scale, area, dpr] (RichTextDocument &doc, const RichTextDocument &from) { doc = from; doc += text; doc.updateLayoutInfo(); doc.doLayout(area.width()/(scale/dpr)); }; RichTextDocument front, back; make(front, m_front); make(back, m_back); QPoint thick = m_style.bbox.enabled ? (fscale*m_style.bbox.padding).toPoint() : QPoint(0, 0); QPoint soffset = m_style.shadow.enabled ? (fscale*m_style.shadow.offset).toPoint() : QPoint(0, 0); QPoint offset(0, 0); const int blur = m_style.shadow.blur ? qRound(fscale*0.01) : 0; const auto nsize = front.naturalSize()*scale; QSize imageSize(nsize.width() + 1, nsize.height() + 1); QPoint pad = soffset; if (soffset.x() < 0) { pad.rx() = offset.rx() = -soffset.x(); soffset.rx() = 0; } if (soffset.y() < 0) { pad.ry() = offset.ry() = -soffset.y(); soffset.ry() = 0; } imageSize += {pad.rx() + (blur+thick.x())*2, pad.ry() + (blur+thick.y())*2}; const QPoint pblur(blur, blur); offset += pblur; offset += thick; image = QImage(imageSize, QImage::Format_ARGB32_Premultiplied); if (!image.isNull()) { QPointF origin(-(area.width()*dpr - nsize.width())*0.5 + offset.x(), offset.y()); image.setDevicePixelRatio(dpr); image.fill(0x0); QPainter painter(&image); painter.translate(origin/dpr); painter.scale(scale/dpr, scale/dpr); back.draw(&painter, QPointF(0, 0)); front.draw(&painter, QPointF(0, 0)); painter.end(); if (m_style.shadow.enabled) { QImage bg(image.size(), QImage::Format_ARGB32_Premultiplied); bg.setDevicePixelRatio(dpr); auto dest = bg.bits(); const quint32 sr = m_style.shadow.color.red(); const quint32 sg = m_style.shadow.color.green(); const quint32 sb = m_style.shadow.color.blue(); const quint32 sa = m_style.shadow.color.alpha(); for (int y=0; y<bg.height(); ++y) { const int ys = y - soffset.y(); if (ys < 0) { memset(dest, 0, bg.bytesPerLine()); dest += bg.bytesPerLine(); } else { auto src = image.bits() + image.bytesPerLine()*ys; for (int x=0; x<bg.width(); ++x) { const int xs = x-soffset.x(); if (xs < 0) { *dest++ = 0; *dest++ = 0; *dest++ = 0; *dest++ = 0; } else { *dest++ = sr*sa*src[3] >> 16; *dest++ = sg*sa*src[3] >> 16; *dest++ = sb*sa*src[3] >> 16; *dest++ = sa* src[3] >> 8; src += 4; } } } } if (blur) m_blur.applyTo(bg, Qt::black, blur); painter.begin(&bg); painter.drawImage(QPoint(0, 0), image); painter.end(); image.swap(bg); }
/* convert QImage to cv Mat, return the converted image */ cv::Mat ScribbleArea::QImage2CvMat(const QImage &inImage, bool inCloneImageData) { switch (inImage.format()) { // 8-bit, 4 channel case QImage::Format_RGB32: { cv::Mat mat(inImage.height(), inImage.width(), CV_8UC4, const_cast<uchar*>(inImage.bits()), inImage.bytesPerLine()); return (inCloneImageData ? mat.clone() : mat); } // 8-bit, 3 channel case QImage::Format_RGB888: { if (!inCloneImageData) qWarning() << "ASM::QImageToCvMat() - Conversion requires cloning since we use a temporary QImage"; QImage swapped = inImage.rgbSwapped(); return cv::Mat(swapped.height(), swapped.width(), CV_8UC3, const_cast<uchar*>(swapped.bits()), swapped.bytesPerLine()).clone(); } // 8-bit, 1 channel case QImage::Format_Indexed8: { cv::Mat mat(inImage.height(), inImage.width(), CV_8UC1, const_cast<uchar*>(inImage.bits()), inImage.bytesPerLine()); return (inCloneImageData ? mat.clone() : mat); } default: qWarning() << "ASM::QImageToCvMat() - QImage format not handled in switch:" << inImage.format(); break; } return cv::Mat(); }
QImage VectorscopeGenerator::calculateVectorscope(const QSize &vectorscopeSize, const QImage &image, const float &gain, const VectorscopeGenerator::PaintMode &paintMode, const VectorscopeGenerator::ColorSpace &colorSpace, bool, uint accelFactor) const { if (vectorscopeSize.width() <= 0 || vectorscopeSize.height() <= 0 || image.width() <= 0 || image.height() <= 0) { // Invalid size return QImage(); } // Prepare the vectorscope data const int cw = (vectorscopeSize.width() < vectorscopeSize.height()) ? vectorscopeSize.width() : vectorscopeSize.height(); QImage scope = QImage(cw, cw, QImage::Format_ARGB32); scope.fill(qRgba(0,0,0,0)); const uchar *bits = image.bits(); double dy, dr, dg, db, dmax; double /*y,*/ u, v; QPoint pt; QRgb px; const int stepsize = image.depth() / 8 * accelFactor; // Just an average for the number of image pixels per scope pixel. // NOTE: byteCount() has to be replaced by (img.bytesPerLine()*img.height()) for Qt 4.5 to compile, see: http://doc.trolltech.org/4.6/qimage.html#bytesPerLine double avgPxPerPx = (double) image.depth() / 8 *(image.bytesPerLine()*image.height())/scope.size().width()/scope.size().height()/accelFactor; for (int i = 0; i < (image.bytesPerLine()*image.height()); i+= stepsize) { QRgb *col = (QRgb *) bits; int r = qRed(*col); int g = qGreen(*col); int b = qBlue(*col); switch (colorSpace) { case VectorscopeGenerator::ColorSpace_YUV: // y = (double) 0.001173 * r +0.002302 * g +0.0004471* b; u = (double) -0.0005781* r -0.001135 * g +0.001713 * b; v = (double) 0.002411 * r -0.002019 * g -0.0003921* b; break; case VectorscopeGenerator::ColorSpace_YPbPr: default: // y = (double) 0.001173 * r +0.002302 * g +0.0004471* b; u = (double) -0.0006671* r -0.001299 * g +0.0019608* b; v = (double) 0.001961 * r -0.001642 * g -0.0003189* b; break; } pt = mapToCircle(vectorscopeSize, QPointF(SCALING*gain*u, SCALING*gain*v)); if (pt.x() >= scope.width() || pt.x() < 0 || pt.y() >= scope.height() || pt.y() < 0) { // Point lies outside (because of scaling), don't plot it } else { // Draw the pixel using the chosen draw mode. switch (paintMode) { case PaintMode_YUV: // see yuvColorWheel dy = 128; // Default Y value. Lower = darker. // Calculate the RGB values from YUV/YPbPr switch (colorSpace) { case VectorscopeGenerator::ColorSpace_YUV: dr = dy + 290.8*v; dg = dy - 100.6*u - 148*v; db = dy + 517.2*u; break; case VectorscopeGenerator::ColorSpace_YPbPr: default: dr = dy + 357.5*v; dg = dy - 87.75*u - 182*v; db = dy + 451.9*u; break; } if (dr < 0) dr = 0; if (dg < 0) dg = 0; if (db < 0) db = 0; if (dr > 255) dr = 255; if (dg > 255) dg = 255; if (db > 255) db = 255; scope.setPixel(pt, qRgba(dr, dg, db, 255)); break; case PaintMode_Chroma: dy = 200; // Default Y value. Lower = darker. // Calculate the RGB values from YUV/YPbPr switch (colorSpace) { case VectorscopeGenerator::ColorSpace_YUV: dr = dy + 290.8*v; dg = dy - 100.6*u - 148*v; db = dy + 517.2*u; break; case VectorscopeGenerator::ColorSpace_YPbPr: default: dr = dy + 357.5*v; dg = dy - 87.75*u - 182*v; db = dy + 451.9*u; break; } // Scale the RGB values back to max 255 dmax = dr; if (dg > dmax) dmax = dg; if (db > dmax) dmax = db; dmax = 255/dmax; dr *= dmax; dg *= dmax; db *= dmax; scope.setPixel(pt, qRgba(dr, dg, db, 255)); break; case PaintMode_Original: scope.setPixel(pt, *col); break; case PaintMode_Green: px = scope.pixel(pt); scope.setPixel(pt, qRgba(qRed(px)+(255-qRed(px))/(3*avgPxPerPx), qGreen(px)+20*(255-qGreen(px))/(avgPxPerPx), qBlue(px)+(255-qBlue(px))/(avgPxPerPx), qAlpha(px)+(255-qAlpha(px))/(avgPxPerPx))); break; case PaintMode_Green2: px = scope.pixel(pt); scope.setPixel(pt, qRgba(qRed(px)+ceil((255-(float)qRed(px))/(4*avgPxPerPx)), 255, qBlue(px)+ceil((255-(float)qBlue(px))/(avgPxPerPx)), qAlpha(px)+ceil((255-(float)qAlpha(px))/(avgPxPerPx)))); break; case PaintMode_Black: px = scope.pixel(pt); scope.setPixel(pt, qRgba(0,0,0, qAlpha(px)+(255-qAlpha(px))/20)); break; } } bits += stepsize; } return scope; }
void QMacPixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) { setSerialNumber(++qt_pixmap_serial); // the conversion code only handles format >= // Format_ARGB32_Premultiplied at the moment.. if (img.format() > QImage::Format_ARGB32_Premultiplied) { QImage image; if (img.hasAlphaChannel()) image = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); else image = img.convertToFormat(QImage::Format_RGB32); fromImage(image, flags); return; } w = img.width(); h = img.height(); is_null = (w <= 0 || h <= 0); d = (pixelType() == BitmapType ? 1 : img.depth()); QImage image = img; int dd = QPixmap::defaultDepth(); bool force_mono = (dd == 1 || (flags & Qt::ColorMode_Mask)==Qt::MonoOnly); if (force_mono) { // must be monochrome if (d != 1) { image = image.convertToFormat(QImage::Format_MonoLSB, flags); // dither d = 1; } } else { // can be both bool conv8 = false; if(d > 8 && dd <= 8) { // convert to 8 bit if ((flags & Qt::DitherMode_Mask) == Qt::AutoDither) flags = (flags & ~Qt::DitherMode_Mask) | Qt::PreferDither; conv8 = true; } else if ((flags & Qt::ColorMode_Mask) == Qt::ColorOnly) { conv8 = d == 1; // native depth wanted } else if (d == 1) { if (image.colorCount() == 2) { QRgb c0 = image.color(0); // Auto: convert to best QRgb c1 = image.color(1); conv8 = qMin(c0,c1) != qRgb(0,0,0) || qMax(c0,c1) != qRgb(255,255,255); } else { // eg. 1-color monochrome images (they do exist). conv8 = true; } } if (conv8) { image = image.convertToFormat(QImage::Format_Indexed8, flags); d = 8; } } if (image.depth()==1) { image.setColor(0, QColor(Qt::color0).rgba()); image.setColor(1, QColor(Qt::color1).rgba()); } if (d == 16 || d == 24) { image = image.convertToFormat(QImage::Format_RGB32, flags); fromImage(image, flags); return; } // different size or depth, make a new pixmap resize(w, h); quint32 *dptr = pixels, *drow; const uint dbpr = bytesPerRow; const QImage::Format sfmt = image.format(); const unsigned short sbpr = image.bytesPerLine(); // use const_cast to prevent a detach const uchar *sptr = const_cast<const QImage &>(image).bits(), *srow; for (int y = 0; y < h; ++y) { drow = dptr + (y * (dbpr / 4)); srow = sptr + (y * sbpr); switch(sfmt) { case QImage::Format_MonoLSB: case QImage::Format_Mono:{ for (int x = 0; x < w; ++x) { char one_bit = *(srow + (x / 8)); if (sfmt == QImage::Format_Mono) one_bit = one_bit >> (7 - (x % 8)); else one_bit = one_bit >> (x % 8); if ((one_bit & 0x01)) *(drow+x) = 0xFF000000; else *(drow+x) = 0xFFFFFFFF; } break; } case QImage::Format_Indexed8: { int numColors = image.numColors(); if (numColors > 0) { for (int x = 0; x < w; ++x) { int index = *(srow + x); *(drow+x) = PREMUL(image.color(qMin(index, numColors))); } } } break; case QImage::Format_RGB32: for (int x = 0; x < w; ++x) *(drow+x) = *(((quint32*)srow) + x) | 0xFF000000; break; case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: for (int x = 0; x < w; ++x) { if(sfmt == QImage::Format_RGB32) *(drow+x) = 0xFF000000 | (*(((quint32*)srow) + x) & 0x00FFFFFF); else if(sfmt == QImage::Format_ARGB32_Premultiplied) *(drow+x) = *(((quint32*)srow) + x); else *(drow+x) = PREMUL(*(((quint32*)srow) + x)); } break; default: qWarning("Qt: internal: Oops: Forgot a format [%d] %s:%d", sfmt, __FILE__, __LINE__); break; } }
bool loadPGFScaled(QImage& img, const QString& path, int maximumSize) { FILE* const file = fopen(QFile::encodeName(path), "rb"); if (!file) { kDebug() << "Error: Could not open source file."; return false; } unsigned char header[3]; if (fread(&header, 3, 1, file) != 1) { fclose(file); return false; } unsigned char pgfID[3] = { 0x50, 0x47, 0x46 }; if (memcmp(&header[0], &pgfID, 3) != 0) { // not a PGF file fclose(file); return false; } fclose(file); // ------------------------------------------------------------------- // Initialize PGF API. #ifdef WIN32 #ifdef UNICODE HANDLE fd = CreateFile((LPCWSTR)(QFile::encodeName(path).constData()), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); #else HANDLE fd = CreateFile(QFile::encodeName(path), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); #endif if (fd == INVALID_HANDLE_VALUE) { return false; } #else int fd = open(QFile::encodeName(path), O_RDONLY); if (fd == -1) { return false; } #endif try { CPGFFileStream stream(fd); CPGFImage pgf; pgf.Open(&stream); // Try to find the right PGF level to get reduced image accordingly // with preview size wanted. int i = 0; if (pgf.Levels() > 0) { for (i=pgf.Levels()-1 ; i>=0 ; --i) { if (qMin((int)pgf.Width(i), (int)pgf.Height(i)) >= maximumSize) { break; } } } if (i < 0) { i = 0; } pgf.Read(i); // Read PGF image at reduced level i. img = QImage(pgf.Width(i), pgf.Height(i), QImage::Format_RGB32); /* const PGFHeader* header = pgf.GetHeader(); kDebug() << "PGF width = " << header->width; kDebug() << "PGF height = " << header->height; kDebug() << "PGF bbp = " << header->bpp; kDebug() << "PGF channels = " << header->channels; kDebug() << "PGF quality = " << header->quality; kDebug() << "PGF mode = " << header->mode; kDebug() << "PGF levels = " << header->nLevels; kDebug() << "Level (w x h)= " << i << "(" << pgf.Width(i) << " x " << pgf.Height(i) << ")"; kDebug() << "QImage depth = " << img.depth(); */ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { int map[] = {3, 2, 1, 0}; pgf.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); } else { int map[] = {0, 1, 2, 3}; pgf.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); } } catch (IOException& e) { int err = e.error; if (err >= AppError) { err -= AppError; } kDebug() << "Error running libpgf (" << err << ")!"; return false; } return true; }