void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags, QPainter * destPainter, const QRect & limits, int width, int height ) { QPixmap * pixmap = 0; // if a pixmap is present for given id, use it if ( page->m_pixmaps.contains( id ) ) pixmap = page->m_pixmaps[ id ]; // else find the closest match using pixmaps of other IDs (great optim!) else if ( !page->m_pixmaps.isEmpty() && width != -1 ) { int minDistance = -1; QMap< int,QPixmap * >::const_iterator it = page->m_pixmaps.begin(), end = page->m_pixmaps.end(); for ( ; it != end; ++it ) { int pixWidth = (*it)->width(), distance = pixWidth > width ? pixWidth - width : width - pixWidth; if ( minDistance == -1 || distance < minDistance ) { pixmap = *it; minDistance = distance; } } } // if have no pixmap, draw blank page with gray cross and exit if ( !pixmap ) { QColor color = Qt::white; if ( KpdfSettings::changeColors() ) { switch ( KpdfSettings::renderMode() ) { case KpdfSettings::EnumRenderMode::Inverted: color = Qt::black; break; case KpdfSettings::EnumRenderMode::Paper: color = KpdfSettings::paperColor(); break; case KpdfSettings::EnumRenderMode::Recolor: color = KpdfSettings::recolorBackground(); break; default: ; } } destPainter->fillRect( limits, color ); // draw a cross (to that the pixmap as not yet been loaded) // helps a lot on pages that take much to render destPainter->setPen( Qt::gray ); destPainter->drawLine( 0, 0, width-1, height-1 ); destPainter->drawLine( 0, height-1, width-1, 0 ); // idea here: draw a hourglass (or kpdf icon :-) on top-left corner return; } // find out what to paint over the pixmap (manipulations / overlays) bool paintAccessibility = (flags & Accessibility) && KpdfSettings::changeColors() && (KpdfSettings::renderMode() != KpdfSettings::EnumRenderMode::Paper); bool paintHighlights = (flags & Highlights) && !page->m_highlights.isEmpty(); bool enhanceLinks = (flags & EnhanceLinks) && KpdfSettings::highlightLinks(); bool enhanceImages = (flags & EnhanceImages) && KpdfSettings::highlightImages(); // check if there are really some highlightRects to paint if ( paintHighlights ) { // precalc normalized 'limits rect' for intersection double nXMin = (double)limits.left() / (double)width, nXMax = (double)limits.right() / (double)width, nYMin = (double)limits.top() / (double)height, nYMax = (double)limits.bottom() / (double)height; // if no rect intersects limits, disable paintHighlights paintHighlights = false; QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); for ( ; hIt != hEnd; ++hIt ) { if ( (*hIt)->intersects( nXMin, nYMin, nXMax, nYMax ) ) { paintHighlights = true; break; } } } // use backBuffer if 'pixmap direct manipulation' is needed bool backBuffer = paintAccessibility || paintHighlights; QPixmap * backPixmap = 0; QPainter * p = destPainter; if ( backBuffer ) { // let's paint using a buffered painter backPixmap = new QPixmap( limits.width(), limits.height() ); p = new QPainter( backPixmap ); p->translate( -limits.left(), -limits.top() ); } // 1. fast blit the pixmap if it has the right size.. if ( pixmap->width() == width && pixmap->height() == height ) p->drawPixmap( limits.topLeft(), *pixmap, limits ); // ..else set a scale matrix to the painter and paint a quick 'zoomed' pixmap else { p->save(); // TODO paint only the needed part (note: hope that Qt4 transforms are faster) p->scale( width / (double)pixmap->width(), height / (double)pixmap->height() ); p->drawPixmap( 0,0, *pixmap, 0,0, pixmap->width(), pixmap->height() ); p->restore(); } // 2. mangle pixmap: convert it to 32-bit qimage and perform pixel-level manipulations if ( backBuffer ) { QImage backImage = backPixmap->convertToImage(); // 2.1. modify pixmap following accessibility settings if ( paintAccessibility ) { switch ( KpdfSettings::renderMode() ) { case KpdfSettings::EnumRenderMode::Inverted: // Invert image pixels using QImage internal function backImage.invertPixels(false); break; case KpdfSettings::EnumRenderMode::Recolor: // Recolor image using KImageEffect::flatten with dither:0 KImageEffect::flatten( backImage, KpdfSettings::recolorForeground(), KpdfSettings::recolorBackground() ); break; case KpdfSettings::EnumRenderMode::BlackWhite: // Manual Gray and Contrast unsigned int * data = (unsigned int *)backImage.bits(); int val, pixels = backImage.width() * backImage.height(), con = KpdfSettings::bWContrast(), thr = 255 - KpdfSettings::bWThreshold(); for( int i = 0; i < pixels; ++i ) { val = qGray( data[i] ); if ( val > thr ) val = 128 + (127 * (val - thr)) / (255 - thr); else if ( val < thr ) val = (128 * val) / thr; if ( con > 2 ) { val = con * ( val - thr ) / 2 + thr; if ( val > 255 ) val = 255; else if ( val < 0 ) val = 0; } data[i] = qRgba( val, val, val, 255 ); } break; } } // 2.2. highlight rects in page if ( paintHighlights ) { // draw highlights that are inside the 'limits' paint region QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); for ( ; hIt != hEnd; ++hIt ) { HighlightRect * r = *hIt; QRect highlightRect = r->geometry( width, height ); if ( highlightRect.isValid() && highlightRect.intersects( limits ) ) { // find out the rect to highlight on pixmap highlightRect = highlightRect.intersect( limits ); highlightRect.moveBy( -limits.left(), -limits.top() ); // highlight composition (product: highlight color * destcolor) unsigned int * data = (unsigned int *)backImage.bits(); int val, newR, newG, newB, rh = r->color.red(), gh = r->color.green(), bh = r->color.blue(), offset = highlightRect.top() * backImage.width(); for( int y = highlightRect.top(); y <= highlightRect.bottom(); ++y ) { for( int x = highlightRect.left(); x <= highlightRect.right(); ++x ) { val = data[ x + offset ]; newR = (qRed(val) * rh) / 255; newG = (qGreen(val) * gh) / 255; newB = (qBlue(val) * bh) / 255; data[ x + offset ] = qRgba( newR, newG, newB, 255 ); } offset += backImage.width(); } } } } backPixmap->convertFromImage( backImage ); } // 3. visually enchance links and images if requested if ( enhanceLinks || enhanceImages ) { QColor normalColor = QApplication::palette().active().highlight(); QColor lightColor = normalColor.light( 140 ); // enlarging limits for intersection is like growing the 'rectGeometry' below QRect limitsEnlarged = limits; limitsEnlarged.addCoords( -2, -2, 2, 2 ); // draw rects that are inside the 'limits' paint region as opaque rects QValueList< ObjectRect * >::const_iterator lIt = page->m_rects.begin(), lEnd = page->m_rects.end(); for ( ; lIt != lEnd; ++lIt ) { ObjectRect * rect = *lIt; if ( (enhanceLinks && rect->objectType() == ObjectRect::Link) || (enhanceImages && rect->objectType() == ObjectRect::Image) ) { QRect rectGeometry = rect->geometry( width, height ); if ( rectGeometry.intersects( limitsEnlarged ) ) { // expand rect and draw inner border rectGeometry.addCoords( -1,-1,1,1 ); p->setPen( lightColor ); p->drawRect( rectGeometry ); // expand rect to draw outer border rectGeometry.addCoords( -1,-1,1,1 ); p->setPen( normalColor ); p->drawRect( rectGeometry ); } } } } // 4. if was backbuffering, copy the backPixmap to destination if ( backBuffer ) { delete p; destPainter->drawPixmap( limits.left(), limits.top(), *backPixmap ); delete backPixmap; } }
void doMagicIn(QString path, QString q, QString OPath) { QRegExp isMask = QRegExp("*m.gif"); isMask.setPatternSyntax(QRegExp::Wildcard); QRegExp isBackupDir = QRegExp("*/_backup/"); isBackupDir.setPatternSyntax(QRegExp::Wildcard); if(isBackupDir.exactMatch(path)) return; //Skip backup directories if(isMask.exactMatch(q)) return; QImage target; QString imgFileM; QStringList tmp = q.split(".", QString::SkipEmptyParts); if(tmp.size()==2) imgFileM = tmp[0] + "m." + tmp[1]; else return; //skip unexists pairs if(!QFile(path+q).exists()) return; if(!QFile(path+imgFileM).exists()) { QString saveTo; QImage image = loadQImage(path+q); if(image.isNull()) return; QTextStream(stdout) << QString(path+q+"\n").toUtf8().data(); saveTo = QString(OPath+(tmp[0].toLower())+".gif"); //overwrite source image (convert BMP to GIF) if(toGif( image, saveTo ) ) //Write gif { QTextStream(stdout) <<"GIF-1 only\n"; } else { QTextStream(stdout) <<"BMP-1 only\n"; image.save(saveTo, "BMP"); //If failed, write BMP } return; } if(!noBackUp) { //create backup dir QDir backup(path+"_backup/"); if(!backup.exists()) { QTextStream(stdout) << QString("Create backup with path %1\n").arg(path+"_backup"); if(!backup.mkdir(".")) QTextStream(stderr) << QString("WARNING! Can't create backup directory %1\n").arg(path+"_backup"); } //create Back UP of source images if(!QFile(path+"_backup/"+q).exists()) QFile::copy(path+q, path+"_backup/"+q); if(!QFile(path+"_backup/"+imgFileM).exists()) QFile::copy(path+imgFileM, path+"_backup/"+imgFileM); } QImage image = loadQImage(path+q); QImage mask = loadQImage(path+imgFileM); if(mask.isNull()) //Skip null masks return; target = setAlphaMask(image, mask); if(!target.isNull()) { //Save before fix //target.save(OPath+tmp[0]+"_before.png"); //mask.save(OPath+tmp[0]+"_mask_before.png"); QTextStream(stdout) << QString(path+q+"\n").toUtf8().data(); //fix if(image.size()!= mask.size()) mask = mask.copy(0,0, image.width(), image.height()); mask = target.alphaChannel(); mask.invertPixels(); //Save after fix //target.save(OPath+tmp[0]+"_after.bmp", "BMP"); QString saveTo; saveTo = QString(OPath+(tmp[0].toLower())+".gif"); //overwrite source image (convert BMP to GIF) if(toGif(image, saveTo ) ) //Write gif { QTextStream(stdout) <<"GIF-1 "; } else { QTextStream(stdout) <<"BMP-1 "; image.save(saveTo, "BMP"); //If failed, write BMP } saveTo = QString(OPath+(tmp[0].toLower())+"m.gif"); //overwrite mask image if( toGif(mask, saveTo ) ) //Write gif { QTextStream(stdout) <<"GIF-2\n"; } else { mask.save(saveTo, "BMP"); //If failed, write BMP QTextStream(stdout) <<"BMP-2\n"; } } else QTextStream(stderr) << path+q+" - WRONG!\n"; }
void CPixmap::toInvertedColors() { m_effects.push_back(CEffect::InvertColors); QImage img = this->toImage(); img.invertPixels(); updateImage(img); }
void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subPixelPosition) { QImage mask = textureMapForGlyph(g, subPixelPosition); #ifdef CACHE_DEBUG printf("fillTexture of %dx%d at %d,%d in the cache of %dx%d\n", c.w, c.h, c.x, c.y, m_image.width(), m_image.height()); if (mask.width() > c.w || mask.height() > c.h) { printf(" ERROR; mask is bigger than reserved space! %dx%d instead of %dx%d\n", mask.width(), mask.height(), c.w,c.h); return; } #endif if (m_type == QFontEngineGlyphCache::Raster_RGBMask) { QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()), qMax(mask.width(), c.w), qMax(mask.height(), c.h), m_image.bytesPerLine(), m_image.format()); QPainter p(&ref); p.setCompositionMode(QPainter::CompositionMode_Source); p.fillRect(0, 0, c.w, c.h, QColor(0,0,0,0)); // TODO optimize this p.drawImage(0, 0, mask); p.end(); } else if (m_type == QFontEngineGlyphCache::Raster_Mono) { if (mask.depth() > 1) { // TODO optimize this mask = mask.alphaChannel(); mask.invertPixels(); mask = mask.convertToFormat(QImage::Format_Mono); } int mw = qMin(mask.width(), c.w); int mh = qMin(mask.height(), c.h); uchar *d = m_image.bits(); int dbpl = m_image.bytesPerLine(); for (int y = 0; y < c.h; ++y) { uchar *dest = d + (c.y + y) *dbpl + c.x/8; if (y < mh) { uchar *src = mask.scanLine(y); for (int x = 0; x < c.w/8; ++x) { if (x < (mw+7)/8) dest[x] = src[x]; else dest[x] = 0; } } else { for (int x = 0; x < c.w/8; ++x) dest[x] = 0; } } } else { // A8 int mw = qMin(mask.width(), c.w); int mh = qMin(mask.height(), c.h); uchar *d = m_image.bits(); int dbpl = m_image.bytesPerLine(); if (mask.depth() == 1) { for (int y = 0; y < c.h; ++y) { uchar *dest = d + (c.y + y) *dbpl + c.x; if (y < mh) { uchar *src = (uchar *) mask.scanLine(y); for (int x = 0; x < c.w; ++x) { if (x < mw) dest[x] = (src[x >> 3] & (1 << (7 - (x & 7)))) > 0 ? 255 : 0; } } } } else if (mask.depth() == 8) {
void ImageEffect::invert(QImage &i) { i.invertPixels(); }
void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) { if (type == QPixmapData::SgImage && pixmap) { #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap); destroyImages(); prevSize = QSize(); TInt err = 0; RSgDriver driver; err = driver.Open(); if (err != KErrNone) { cleanup(); return; } if (sgImage->IsNull()) { cleanup(); driver.Close(); return; } TSgImageInfo sgImageInfo; err = sgImage->GetInfo(sgImageInfo); if (err != KErrNone) { cleanup(); driver.Close(); return; } pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); if (eglGetError() != EGL_SUCCESS || !(QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) || !vgCreateEGLImageTargetKHR) { cleanup(); driver.Close(); return; } const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; EGLImageKHR eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)sgImage, (EGLint*)KEglImageAttribs); if (eglGetError() != EGL_SUCCESS) { cleanup(); driver.Close(); return; } vgImage = vgCreateEGLImageTargetKHR(eglImage); if (vgGetError() != VG_NO_ERROR) { cleanup(); QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); driver.Close(); return; } w = sgImageInfo.iSizeInPixels.iWidth; h = sgImageInfo.iSizeInPixels.iHeight; d = 32; // We always use ARGB_Premultiplied for VG pixmaps. is_null = (w <= 0 || h <= 0); source = QImage(); recreate = false; prevSize = QSize(w, h); setSerialNumber(++qt_vg_pixmap_serial); // release stuff QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); driver.Close(); #endif } else if (type == QPixmapData::FbsBitmap) { CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap); bool deleteSourceBitmap = false; #ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE // Rasterize extended bitmaps TUid extendedBitmapType = bitmap->ExtendedBitmapType(); if (extendedBitmapType != KNullUid) { bitmap = createBlitCopy(bitmap); deleteSourceBitmap = true; } #endif if (bitmap->IsCompressedInRAM()) { bitmap = createBlitCopy(bitmap); deleteSourceBitmap = true; } TDisplayMode displayMode = bitmap->DisplayMode(); QImage::Format format = qt_TDisplayMode2Format(displayMode); TSize size = bitmap->SizeInPixels(); bitmap->BeginDataAccess(); uchar *bytes = (uchar*)bitmap->DataAddress(); QImage img = QImage(bytes, size.iWidth, size.iHeight, format); img = img.copy(); bitmap->EndDataAccess(); if(displayMode == EGray2) { //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid //So invert mono bitmaps so that masks work correctly. img.invertPixels(); } else if(displayMode == EColor16M) { img = img.rgbSwapped(); // EColor16M is BGR } fromImage(img, Qt::AutoColor); if(deleteSourceBitmap) delete bitmap; } }
void Worker::run() { while (1) { res->requestSemaphore.acquire(1); if (die) { break; } // get next page to render res->requestMutex.lock(); int page, width, index; map<int,pair<int,int> >::iterator less = res->requests.lower_bound(res->center_page); map<int,pair<int,int> >::iterator greater = less--; if (greater != res->requests.end()) { if (greater != res->requests.begin()) { // favour nearby page, go down first if (greater->first + less->first <= res->center_page * 2) { page = greater->first; index = greater->second.first; width = greater->second.second; res->requests.erase(greater); } else { page = less->first; index = less->second.first; width = less->second.second; res->requests.erase(less); } } else { page = greater->first; index = greater->second.first; width = greater->second.second; res->requests.erase(greater); } } else { page = less->first; index = less->second.first; width = less->second.second; res->requests.erase(less); } res->requestMutex.unlock(); // check for duplicate requests res->k_page[page].mutex.lock(); if (res->k_page[page].status[index] == width && res->k_page[page].rotation[index] == res->rotation) { res->k_page[page].mutex.unlock(); continue; } int rotation = res->rotation; res->k_page[page].mutex.unlock(); // open page #ifdef DEBUG cerr << " rendering page " << page << " for index " << index << endl; #endif Poppler::Page *p = res->doc->page(page); if (p == NULL) { cerr << "failed to load page " << page << endl; continue; } // render page float dpi = 72.0 * width / res->get_page_width(page); QImage img = p->renderToImage(dpi, dpi, -1, -1, -1, -1, static_cast<Poppler::Page::Rotation>(rotation)); if (img.isNull()) { cerr << "failed to render page " << page << endl; continue; } // invert to current color setting if (res->inverted_colors) { img.invertPixels(); } // put page res->k_page[page].mutex.lock(); if (!res->k_page[page].img[index].isNull()) { res->k_page[page].img[index] = QImage(); // assign null image } // adjust all available images to current color setting if (res->k_page[page].inverted_colors != res->inverted_colors) { res->k_page[page].inverted_colors = res->inverted_colors; for (int i = 0; i < 3; i++) { res->k_page[page].img[i].invertPixels(); } res->k_page[page].thumbnail.invertPixels(); } res->k_page[page].img[index] = img; res->k_page[page].status[index] = width; res->k_page[page].rotation[index] = rotation; res->k_page[page].mutex.unlock(); res->garbageMutex.lock(); res->garbage.insert(page); // TODO add index information? res->garbageMutex.unlock(); emit page_rendered(page); // collect goto links res->link_mutex.lock(); if (res->k_page[page].links == NULL) { res->link_mutex.unlock(); QList<Poppler::Link *> *links = new QList<Poppler::Link *>; QList<Poppler::Link *> l = p->links(); links->swap(l); res->link_mutex.lock(); res->k_page[page].links = links; } if (res->k_page[page].text == NULL) { res->link_mutex.unlock(); QList<Poppler::TextBox *> text = p->textList(); // assign boxes to lines // make single parts from chained boxes set<Poppler::TextBox *> used; QList<SelectionPart *> selection_parts; Q_FOREACH(Poppler::TextBox *box, text) { if (used.find(box) != used.end()) { continue; } used.insert(box); SelectionPart *p = new SelectionPart(box); selection_parts.push_back(p); Poppler::TextBox *next = box->nextWord(); while (next != NULL) { used.insert(next); p->add_word(next); next = next->nextWord(); } } // sort by y coordinate qStableSort(selection_parts.begin(), selection_parts.end(), selection_less_y); QRectF line_box; QList<SelectionLine *> *lines = new QList<SelectionLine *>(); Q_FOREACH(SelectionPart *part, selection_parts) { QRectF box = part->get_bbox(); // box fits into line_box's line if (!lines->empty() && box.y() <= line_box.center().y() && box.bottom() > line_box.center().y()) { float ratio_w = box.width() / line_box.width(); float ratio_h = box.height() / line_box.height(); if (ratio_w < 1.0f) { ratio_w = 1.0f / ratio_w; } if (ratio_h < 1.0f) { ratio_h = 1.0f / ratio_h; } if (ratio_w > 1.3f && ratio_h > 1.3f) { lines->back()->sort(); lines->push_back(new SelectionLine(part)); line_box = part->get_bbox(); } else { lines->back()->add_part(part); } // it doesn't fit, create new line } else { if (!lines->empty()) { lines->back()->sort(); } lines->push_back(new SelectionLine(part)); line_box = part->get_bbox(); } } if (!lines->empty()) { lines->back()->sort(); } res->link_mutex.lock(); res->k_page[page].text = lines; }
// static QPixmap QPixmap::fromPmHBITMAP(HBITMAP hbm, HBITMAP hbmMask) { QPixmap res; if (hbm == NULLHANDLE) return res; // bitmap header + 2 palette entries (for the monochrome bitmap) char bmi[sizeof(BITMAPINFOHEADER2) + 4 * 2]; memset(bmi, 0, sizeof(bmi)); PBITMAPINFOHEADER2 bmh = (PBITMAPINFOHEADER2)bmi; bmh->cbFix = sizeof(BITMAPINFOHEADER2); PULONG pal = (PULONG)(bmi + sizeof(BITMAPINFOHEADER2)); if (!GpiQueryBitmapInfoHeader(hbm, bmh)) return res; HPS hps = qt_alloc_mem_ps(bmh->cx, bmh->cy * 2); if (hps == NULLHANDLE) return res; GpiSetBitmap(hps, hbm); QImage img; bool succeeded = false; if (bmh->cPlanes == 1 && bmh->cBitCount == 1) { // monochrome bitmap img = QImage(bmh->cx, bmh->cy, QImage::Format_Mono); if (GpiQueryBitmapBits(hps, 0, img.height(), (PBYTE)img.bits(), (PBITMAPINFO2)&bmi) != GPI_ALTERROR) { succeeded = true; // take the palette QVector<QRgb> colors(2); colors[0] = QRgb(pal[0]); colors[1] = QRgb(pal[1]); img.setColorTable(colors); } } else { // always convert to 32-bit otherwise img = QImage(bmh->cx, bmh->cy, QImage::Format_RGB32); bmh->cPlanes = 1; bmh->cBitCount = 32; if (GpiQueryBitmapBits(hps, 0, img.height(), (PBYTE)img.bits(), (PBITMAPINFO2)&bmi) != GPI_ALTERROR) { succeeded = true; // try to auto-detect if there is a real alpha channel bool allZero = true; for (int i = 0; i < img.numBytes(); ++i) { if (img.bits()[i] & 0xFF000000) { allZero = false; break; } } if (!allZero) { // assume we've got the alpha channel QImage alphaImg = QImage(bmh->cx, bmh->cy, QImage::Format_ARGB32); memcpy(alphaImg.bits(), img.bits(), img.numBytes()); img = alphaImg; } // flip the bitmap top to bottom to cancel PM inversion img = img.mirrored(); } } QImage mask; if (hbmMask != NULLHANDLE && GpiQueryBitmapInfoHeader(hbmMask, bmh)) { // get the AND+XOR mask if ((int)bmh->cx == img.width() && (int)bmh->cy == img.height() * 2 && bmh->cPlanes == 1 && bmh->cBitCount == 1) { GpiSetBitmap(hps, hbmMask); mask = QImage(bmh->cx, bmh->cy, QImage::Format_Mono); if (GpiQueryBitmapBits(hps, 0, mask.height(), (PBYTE)mask.bits(), (PBITMAPINFO2)&bmi) != GPI_ALTERROR) { // take the palette QVector<QRgb> colors(2); colors[0] = QRgb(pal[0]); colors[1] = QRgb(pal[1]); mask.setColorTable(colors); // flip the bitmap top to bottom to cancel PM inversion mask = mask.mirrored(false, true); // drop the XOR mask mask = mask.copy(0, 0, mask.width(), mask.height() / 2); // create a normal mask from the AND mask mask.invertPixels(); } else { mask = QImage(); } GpiSetBitmap(hps, NULLHANDLE); } else { Q_ASSERT(false); } } qt_free_mem_ps(hps); if (succeeded) { res = QPixmap::fromImage(img); if (!mask.isNull()) res.setMask(QBitmap::fromImage(mask)); } return res; }
int doMagicIn(QString path, QString q, QString OPath) { //skip unexists pairs if(!QFile(path+q).exists()) return CNV_SKIPPED; QImage ImgSrc; QImage image; QImage mask; ImgSrc = loadQImage(path+q); if(ImgSrc.isNull()) //Skip null images return CNV_FAILED; QString bname = QFileInfo(path+q).baseName(); QString saveToImg = QString(OPath+(bname.toLower())+".gif"); QString saveToMask = QString(OPath+(bname.toLower())+"m.gif"); QTextStream(stdout) << path+q+"\n"; mask = ImgSrc.alphaChannel(); mask.invertPixels(); //Write mask image if( toGif(mask, saveToMask ) ) //Write gif { QTextStream(stdout) <<"GIF-1\n"; } else { mask.save(saveToMask, "BMP"); //If failed, write BMP QTextStream(stdout) <<"BMP-1\n"; } image = ImgSrc.convertToFormat(QImage::Format_RGB32); mask = ImgSrc.alphaChannel(); mask.invertPixels(); for(int w=0; w < mask.width(); w++) for(int h=0; h < mask.height(); h++) { if(mask.pixel(w,h)==qRgb(0xFF,0xFF,0xFF)) //Fill white pixel into black on image { image.setPixel(w,h, qRgb(0,0,0)); } else if(mask.pixel(w,h)!=qRgb(0,0,0)) //Fill non-black pixel color into black on mask { mask.setPixel(w,h, qGray(0,0,0)); } } mask.invertPixels(); image.setAlphaChannel(mask); //Write mask image if( toGif(image, saveToImg ) ) //Write gif { QTextStream(stdout) <<"GIF-2\n"; } else { image.save(saveToImg, "BMP"); //If failed, write BMP QTextStream(stdout) <<"BMP-2\n"; } if(removeSource) QFile(path+q).remove(); return CNV_SUCCESS; }
/*! Creates a \c HBITMAP equivalent to the QPixmap. Returns the \c HBITMAP handle. If \a mask is not NULL, the mask mode is turned on. In this mode, the bitmap mask is also created from the QPixmap's mask and returned in the given variable. This bitmap mask will contain two vertically adjacent sections, the first of which is the AND mask and the second one is the XOR mask (according to WinCreatePointer() specification). Also, in mask mode, the HBITMAP returned for the pixmap itself will be prepared for masking (with transparent pixels made black). This mode is useful for creating system icons and pointers (\sa toPmHPOINTER()). if \a embedRealAlpha is \c true, the real alpha chennel (not the 1bpp mask) will be embedded in the high 8 bits of the 32-bit pixel value for each pixel in the created bitmap (which always has 1 plane and the 32-bit depth). This extra information isn't touched by PM/GPI but may be used by custom drawing routines to do real alpha blending. Note that if \a mask is not NULL but the pixmap does neither have a mask nor the alpha channel, an emptpy bitmap mask with no transparency (zeroed AND and XOR parts) will be created and returned. It is the caller's responsibility to free both returned \c HBITMAP handes after use. \warning This function is only available on OS/2. \sa fromPmHBITMAP(), toPmHPOINTER() */ HBITMAP QPixmap::toPmHBITMAP(HBITMAP *mask, bool embedRealAlpha) const { if (data->classId() != QPixmapData::RasterClass) { QPixmapData *data = new QRasterPixmapData(depth() == 1 ? QPixmapData::BitmapType : QPixmapData::PixmapType); data->fromImage(toImage(), Qt::AutoColor); return QPixmap(data).toPmHBITMAP(mask, embedRealAlpha); } QRasterPixmapData* d = static_cast<QRasterPixmapData*>(data.data()); int w = d->image.width(); int h = d->image.height(); HPS hps = qt_alloc_mem_ps(w, h * 2); if (hps == NULLHANDLE) return NULLHANDLE; HBITMAP hbm = NULLHANDLE; HBITMAP hbmMask = NULLHANDLE; // Note that we always use ARGB32 even if embedRealAlpha is false because // in this case we will use the alpha channel to dither the 1bpp mask QImage image = d->image.convertToFormat(QImage::Format_ARGB32); // flip the bitmap top to bottom for PM image = image.mirrored(); // bitmap header + 2 palette entries (for the mask) char bmi[sizeof(BITMAPINFOHEADER2) + 4 * 2]; memset(bmi, 0, sizeof(bmi)); PBITMAPINFOHEADER2 bmh = (PBITMAPINFOHEADER2)bmi; bmh->cbFix = sizeof(BITMAPINFOHEADER2); PULONG pal = (PULONG)(bmi + sizeof(BITMAPINFOHEADER2)); // create the normal bitmap from the pixmap data bmh->cx = w; bmh->cy = h; bmh->cPlanes = 1; bmh->cBitCount = 32; hbm = GpiCreateBitmap(hps, bmh, CBM_INIT, (PBYTE)(const uchar *)image.bits(), (PBITMAPINFO2)&bmi); if (mask) { // get the mask QImage mask; if (hasAlpha()) { if (!embedRealAlpha) { // We prefer QImage::createAlphaMask() over QPixmap::mask() // since the former will dither while the latter will convert any // non-zero alpha value to an opaque pixel mask = image.createAlphaMask().convertToFormat(QImage::Format_Mono); // note: for some strange reason, createAlphaMask() (as opposed to // mask().toImage()) returns an image already flipped top to bottom, // so take it into account // create the AND mask mask.invertPixels(); // add the XOR mask (and leave it zeroed) mask = mask.copy(0, -h, w, h * 2); } else { // if we embedded real alpha, we still need a mask if we are going // to create a pointer out of this pixmap (WinCreatePointerIndirect() // requirement), but we will use QPixmap::mask() because it won't be // able to destroy the alpha channel of non-fully transparent pixels // when preparing the color bitmap for masking later. We could also // skip this prepare step, but well, let's go this way, it won't hurt. mask = this->mask().toImage().convertToFormat(QImage::Format_Mono); // create the AND mask mask.invertPixels(); // add the XOR mask (and leave it zeroed) mask = mask.copy(0, 0, w, h * 2); // flip the bitmap top to bottom for PM mask = mask.mirrored(false, true); } } else { mask = QImage(w, h * 2, QImage::Format_Mono); mask.fill(0); } // create the mask bitmap bmh->cbFix = sizeof(BITMAPINFOHEADER2); bmh->cx = w; bmh->cy = h * 2; bmh->cPlanes = 1; bmh->cBitCount = 1; bmh->cclrUsed = 2; pal[0] = 0; pal[1] = 0x00FFFFFF; hbmMask = GpiCreateBitmap(hps, bmh, CBM_INIT, (PBYTE)(const uchar *)mask.bits(), (PBITMAPINFO2)&bmi); // prepare the bitmap for masking by setting transparent pixels to black GpiSetBitmap(hps, hbm); POINTL ptls[] = { { 0, 0 }, { w - 1, h - 1 }, // dst: inclusive-inclusive { 0, h }, { w, h * 2 }, // src: inclusive-exclusive }; ptls[0].y -= h; ptls[1].y -= h; enum { AllImageAttrs = IBB_COLOR | IBB_BACK_COLOR | IBB_MIX_MODE | IBB_BACK_MIX_MODE }; IMAGEBUNDLE ib = { CLR_TRUE, CLR_FALSE, FM_OVERPAINT, BM_OVERPAINT }; GpiSetAttrs(hps, PRIM_IMAGE, AllImageAttrs, 0, (PBUNDLE)&ib); GpiDrawBits(hps, (PBYTE)(const uchar *)mask.bits(), (PBITMAPINFO2)&bmi, 4, ptls, ROP_SRCAND, BBO_IGNORE); } qt_free_mem_ps(hps); if (mask) *mask = hbmMask; return hbm; }
// ------------------------------------------------------------------------- void ctkQImageView::update( bool zoomChanged, bool sizeChanged ) { Q_D( ctkQImageView ); if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() ) { const QImage * img = & ( d->ImageList[ d->SliceNumber ] ); if( zoomChanged || sizeChanged ) { if( this->width() > 0 && this->height() > 0 && d->TmpXMax > d->TmpXMin && d->TmpYMax > d->TmpYMin) { int tmpXRange = d->TmpXMax - d->TmpXMin; int tmpYRange = d->TmpYMax - d->TmpYMin; double tmpAspectRatio = static_cast<double>(tmpYRange) / tmpXRange; double screenAspectRatio = static_cast<double>(this->height()) / this->width(); if( screenAspectRatio > tmpAspectRatio ) { int extraTmpYAbove = d->TmpYMin; int extraTmpYBelow = img->height() - d->TmpYMax; int extraTmpYNeeded = tmpXRange * screenAspectRatio - tmpYRange; int minExtra = extraTmpYAbove; if( extraTmpYBelow < minExtra ) { minExtra = extraTmpYBelow; } if(2 * minExtra >= extraTmpYNeeded) { int minNeeded = extraTmpYNeeded / 2.0; int maxNeeded = extraTmpYNeeded - minNeeded; d->TmpYMin -= minNeeded; d->TmpYMax += maxNeeded; } else if(extraTmpYAbove + extraTmpYBelow >= extraTmpYNeeded) { if(extraTmpYAbove < extraTmpYBelow) { d->TmpYMin = 0; d->TmpYMax += extraTmpYNeeded - extraTmpYAbove; } else { d->TmpYMax = img->height(); d->TmpYMin -= extraTmpYNeeded - extraTmpYBelow; } } else { d->TmpYMin = 0; d->TmpYMax = img->height(); } d->TmpImage = QPixmap( this->width(), static_cast<unsigned int>( static_cast<double>(d->TmpYMax - d->TmpYMin) / (d->TmpXMax - d->TmpXMin) * this->width() + 0.5 ) ); } else if(screenAspectRatio < tmpAspectRatio) { int extraTmpXLeft = d->TmpXMin; int extraTmpXRight = img->width() - d->TmpXMax; int extraTmpXNeeded = static_cast<double>(tmpYRange) / screenAspectRatio - tmpXRange; int minExtra = extraTmpXLeft; if( extraTmpXRight < minExtra ) { minExtra = extraTmpXRight; } if(2 * minExtra >= extraTmpXNeeded) { int minNeeded = extraTmpXNeeded / 2.0; int maxNeeded = extraTmpXNeeded - minNeeded; d->TmpXMin -= minNeeded; d->TmpXMax += maxNeeded; } else if(extraTmpXLeft + extraTmpXRight >= extraTmpXNeeded) { if(extraTmpXLeft < extraTmpXRight) { d->TmpXMin = 0; d->TmpXMax += extraTmpXNeeded - extraTmpXLeft; } else { d->TmpXMax = img->width(); d->TmpXMin -= extraTmpXNeeded - extraTmpXRight; } } else { d->TmpXMin = 0; d->TmpXMax = img->width(); } d->TmpImage = QPixmap( static_cast<unsigned int>( this->height() / ( static_cast<double>(d->TmpYMax - d->TmpYMin) / (d->TmpXMax - d->TmpXMin) ) + 0.5 ), this->height() ); } else { d->TmpImage = QPixmap( this->width(), this->height() ); } } } if( d->TmpImage.width() > 0 && d->TmpImage.height() > 0) { QRectF target( 0, 0, d->TmpImage.width(), d->TmpImage.height() ); double sourceX = d->TmpXMin; double sourceY = d->TmpYMin; double sourceW = d->TmpXMax - d->TmpXMin; double sourceH = d->TmpYMax - d->TmpYMin; QPainter painter( &(d->TmpImage) ); QImage tmpI = *img; if( d->InvertImage ) { tmpI.invertPixels(); } if( d->FlipXAxis || d->FlipYAxis ) { tmpI = tmpI.mirrored( d->FlipXAxis, d->FlipYAxis ); if( d->FlipXAxis ) { sourceX = tmpI.width() - (d->TmpXMax - d->TmpXMin) - d->TmpXMin; } if( d->FlipYAxis ) { sourceY = tmpI.height() - (d->TmpYMax - d->TmpYMin) - d->TmpYMin; } } QRectF source( sourceX, sourceY, sourceW, sourceH ); painter.drawPixmap( target, QPixmap::fromImage( tmpI ), source ); //if( ! sizeChanged ) { int maxNumCharsPerLine = 50; int fontPointSize = 12; if( fontPointSize * maxNumCharsPerLine > this->width() ) { fontPointSize = this->width() / maxNumCharsPerLine; } if( fontPointSize > 7 ) { QString fontFamily( "Helvetica" ); QFont textFont( fontFamily, fontPointSize ); painter.setFont( textFont ); QColor textColor; textColor.setNamedColor( "lime" ); textColor.setAlpha( 128 ); painter.setPen( textColor ); int textFlags = Qt::AlignLeft | Qt::TextDontClip; QRectF pointRect( 0, 0, 1, 1 ); QRectF spaceBound = painter.boundingRect( pointRect, textFlags, "X" ); if( img->isGrayscale() ) { QString intString = "Intensity Range = "; intString.append( QString::number( d->IntensityMin, 'f', 3 ) ); intString.append( " - " ); intString.append( QString::number( d->IntensityMax, 'f', 3 ) ); QRectF intBound = painter.boundingRect( pointRect, textFlags, intString ); QRectF intRect( spaceBound.width()/2, spaceBound.height()/8, intBound.width(), intBound.height() ); painter.drawText( intRect, textFlags, intString, &intBound ); QString wlString = "W / L = "; wlString.append( QString::number( this->intensityWindow(), 'f', 3 ) ); wlString.append( " / " ); wlString.append( QString::number( this->intensityLevel(), 'f', 3 ) ); QRectF wlBound = painter.boundingRect( pointRect, textFlags, wlString ); QRectF wlRect( spaceBound.width()/2, intRect.y() + intRect.height() + spaceBound.height()/8, wlBound.width(), wlBound.height() ); painter.drawText( wlRect, textFlags, wlString, &wlBound ); } QString spacingString = "Spacing = "; spacingString.append( QString::number( this->xSpacing(), 'f', 3 ) ); spacingString.append( ", " ); spacingString.append( QString::number( this->ySpacing(), 'f', 3 ) ); spacingString.append( ", " ); spacingString.append( QString::number( this->sliceThickness(), 'f', 3 ) ); QRectF spacingBound = painter.boundingRect( pointRect, textFlags, spacingString ); QRectF spacingRect( this->width() - spacingBound.width() - spaceBound.width()/2, this->height() - spacingBound.height() - spaceBound.height()/8, spacingBound.width(), spacingBound.height() ); painter.drawText( spacingRect, textFlags, spacingString, &spacingBound ); QString dimString = "Size = "; dimString.append( QString::number( d->ImageList[ d->SliceNumber ].width() ) ); dimString.append( ", " ); dimString.append( QString::number( d->ImageList[ d->SliceNumber ].height() ) ); dimString.append( ", " ); dimString.append( QString::number( d->ImageList.size() ) ); QRectF dimBound = painter.boundingRect( pointRect, textFlags, dimString ); QRectF dimRect( this->width() - dimBound.width() - spaceBound.width()/2, spacingBound.y() - dimBound.height() - spaceBound.height()/8, dimBound.width(), dimBound.height() ); painter.drawText( dimRect, textFlags, dimString, &dimBound ); QString rasString = "RAS = "; rasString.append( QString::number( this->xPosition() * this->xSpacing(), 'f', 3 ) ); rasString.append( ", " ); rasString.append( QString::number( this->yPosition() * this->ySpacing(), 'f', 3 ) ); rasString.append( ", " ); rasString.append( QString::number( this->slicePosition() * this->sliceSpacing(), 'f', 3 ) ); QRectF rasBound = painter.boundingRect( pointRect, textFlags, rasString ); QRectF rasRect( spaceBound.width()/2, this->height() - rasBound.height() - spaceBound.height()/8, rasBound.width(), rasBound.height() ); painter.drawText( rasRect, textFlags, rasString, &rasBound ); QString ijkString = "IJK = "; ijkString.append( QString::number( this->xPosition() ) ); ijkString.append( ", " ); ijkString.append( QString::number( this->yPosition() ) ); ijkString.append( ", " ); ijkString.append( QString::number( this->slicePosition() ) ); QRectF ijkBound = painter.boundingRect( pointRect, textFlags, ijkString ); QRectF ijkRect( spaceBound.width()/2, rasBound.y() - ijkBound.height() - spaceBound.height()/8, ijkBound.width(), ijkBound.height() ); painter.drawText( ijkRect, textFlags, ijkString, &ijkBound ); QString valString = "Value = "; valString.append( QString::number( this->positionValue(), 'f', 3 ) ); QRectF valBound = painter.boundingRect( pointRect, textFlags, valString ); QRectF valRect( spaceBound.width()/2, ijkBound.y() - valBound.height() - spaceBound.height()/8, valBound.width(), valBound.height() ); painter.drawText( valRect, textFlags, valString, &valBound ); } QColor lineColor; lineColor.setNamedColor( "red" ); lineColor.setAlpha( 128 ); painter.setPen( lineColor ); double x = ( this->xPosition() - d->TmpXMin ) / (d->TmpXMax - d->TmpXMin) * this->width(); double y = ( this->yPosition() - d->TmpYMin ) / (d->TmpYMax - d->TmpYMin) * this->height(); if( d->FlipXAxis ) { x = this->width() - x; } if( d->FlipYAxis ) { y = this->height() - y; } QLine lineX( x, 0, x, this->height() ); painter.drawLine( lineX ); QLine lineY( 0, y, this->width(), y ); painter.drawLine( lineY ); } } d->Window->setPixmap( d->TmpImage ); } else { d->Window->setText( "No Image Loaded." ); } }
// Hàm dùng lọc ảnh bằng các filter tương ứng QImage ExtraFiltersPlugin::filterImage(const QString &filter, const QImage &image, QWidget *parent) { // Chuyển đổi định dạng ảnh sang RGB 32-bit để các hàm làm việc như mong // đợi QImage original = image.convertToFormat(QImage::Format_RGB32); QImage result = original; if (filter == tr("Lật ngang")) { // Nếu filter là "Lật ngang" thì hoán đổi các pixel của ảnh theo chiều // ngang của ảnh for (int y = 0; y < original.height(); ++y) { for (int x = 0; x < original.width(); ++x) { int pixel = original.pixel(original.width() - x - 1, y); result.setPixel(x, y, pixel); } } } else if (filter == tr("Lật dọc")) { // Nếu filter là "Lật dọc" thì hoán đổi các pixel của ảnh theo chiều // dọc của ảnh for (int y = 0; y < original.height(); ++y) { for (int x = 0; x < original.width(); ++x) { int pixel = original.pixel(x, original.height() - y - 1); result.setPixel(x, y, pixel); } } } else if (filter == tr("Làm mờ")) { // Ta sẽ nhân từng điểm ảnh với ma trận tích chập để làm mờ // trừ các điểm ở biên. int kernel[5][5] = {{0, 0, 1, 0, 0}, {0, 1, 3, 1, 0}, {1, 3, 7, 3, 1}, {0, 1, 3, 1, 0}, {0, 0, 1, 0, 0} }; int kernelSize = 5; int sumKernel = 27; int r, g, b; int pixel; for (int x = kernelSize / 2; x < original.width() - (kernelSize / 2); ++x) { for (int y = kernelSize / 2; y < original.height() - (kernelSize / 2); ++y) { r = 0; g = 0; b = 0; // Tính tổng giá trị màu của điểm pixel và các điểm ảnh xung quanh for ( int i = -kernelSize / 2 ; i <= kernelSize / 2 ; ++i) { for ( int j = -kernelSize / 2 ; j <= kernelSize / 2 ; ++j) { pixel = original.pixel ( x + i , y + j ); r += qRed(pixel) * kernel[kernelSize / 2 + i][kernelSize / 2 + j] ; g += qGreen(pixel) * kernel[kernelSize / 2 + i][kernelSize / 2 + j]; b += qBlue(pixel) * kernel[kernelSize / 2 + i][kernelSize / 2 + j]; } } // Kiểm tra giá trị các màu trong khoảng giới hạn r = qBound ( 0 , r / sumKernel , 255 ); g = qBound ( 0 , g / sumKernel , 255 ); b = qBound ( 0 , b / sumKernel , 255 ); result.setPixel ( x, y, qRgba(r , g , b, qAlpha(pixel))); } } } else if (filter == tr("Ảnh nhị phân")) { // Nếu filter là "Ảnh nhị phân" thì bật QInputDialog lên cho người dùng // nhập vào giá trị ngưỡng, nằm trong khoảng 0 đến 255 bool ok; // Kiểm tra giá trị nhập int threshold = QInputDialog::getInt(parent, tr("Ảnh nhị phân"), tr("Nhập ngưỡng:"), 85, 0, 255, 1, &ok); // Đầu tiên ta chuyển ảnh về ảnh đa mức xám rồi so sánh từng pixel của // ảnh với giá trị ngưỡng. if (ok) { for (int y = 0; y < original.height(); ++y) { for (int x = 0; x < original.width(); ++x) { int pixel = original.pixel(x, y); int gray = qGray(pixel); gray = gray > threshold ? 255 : 0; pixel = qRgb(gray, gray, gray); result.setPixel(x, y, pixel); } } } } else if (filter == tr("Ảnh âm bản")) { // Dùng hàm invertPixels() để đảo ngược các pixel. result.invertPixels(); } else if (filter == tr("Đảo màu (RGB->BGR)")) { // Dùng hàm rgbSwapped() để chuyển kênh màu của ảnh từ RGB sang BGR result = result.rgbSwapped(); } else if (filter == tr("Đa mức xám")) { // for (int y = 0; y < result.height(); ++y) { for (int x = 0; x < result.width(); ++x) { int pixel = result.pixel(x, y); int gray = qGray(pixel); int alpha = qAlpha(pixel); result.setPixel(x, y, qRgba(gray, gray, gray, alpha)); } } } else if (filter == tr("Độ sáng")) { // Nếu filter là "Độ sáng" thì bật QInputDialog lên cho người dùng // nhập vào giá trị ngưỡng, giá trị này trong khoảng -255 đến 255 bool ok; // Kiểm tra giá trị nhập int brighness = QInputDialog::getInt(parent, tr("Độ sáng"), tr("Nhập độ sáng:"), 10, -255, 255, 1, &ok); // Ta tăng hoặc giảm giá trị các màu của từng pixel if (ok) { int r, g, b; for (int x = 0; x < original.width(); x++) { for (int y = 0; y < original.height(); y++) { int pixel = original.pixel(x, y); r = qRed(pixel) + brighness; g = qGreen(pixel) + brighness; b = qBlue(pixel) + brighness; //Ta kiểm tra các giá trị mới trong khoảng cho phép. r = qBound(0, r, 255); g = qBound(0, g, 255); b = qBound(0, b, 255); result.setPixel(x, y, qRgba(r, g, b, qAlpha(pixel))); } } } } else if (filter == tr("Làm ấm")) { // Nếu filter là "Làm ấm" thì bật QInputDialog lên cho người dùng // nhập vào giá trị, giá trị này trong khoảng 1 đến 255 bool ok; // Kiểm tra giá trị nhập int delta = QInputDialog::getInt(parent, tr("Lầm ấm"), tr("Nhập mức độ ấm:"), 10, 1, 255, 1, &ok); // Hình sẽ trong ấm hơn nếu ta tăng độ vàng của ảnh, và màu vàng được // tổng hợp từ màu đỏ và xanh lục trong kênh màu RGB if (ok) { int r, g, b; for (int x = 0; x < original.width(); x++) { for (int y = 0; y < original.height(); y++) { int pixel = original.pixel(x, y); r = qRed(pixel) + delta; g = qGreen(pixel) + delta; b = qBlue(pixel); //Ta kiểm tra các giá trị mới trong khoảng cho phép. r = qBound(0, r, 255); g = qBound(0, g, 255); result.setPixel(x, y, qRgba(r, g, b, qAlpha(pixel))); } } } } else if (filter == tr("Làm mát...")) { // Nếu filter là "Làm mát" thì bật QInputDialog lên cho người dùng // nhập vào giá trị, giá trị này trong khoảng 1 đến 255 bool ok; // Kiểm tra giá trị nhập int delta = QInputDialog::getInt(parent, tr("Lầm mát"), tr("Nhập mức độ mát:"), 10, 1, 256, 1, &ok); // Hình sẽ có cảm giác mát hơn khi ta tăng giá trị kênh màu xanh lam if (ok) { int r, g, b; for (int x = 0; x < original.width(); x++) { for (int y = 0; y < original.height(); y++) { int pixel = original.pixel(x, y); r = qRed(pixel); g = qGreen(pixel); b = qBlue(pixel) + delta; //Ta kiểm tra giá trị mới trong khoảng cho phép. b = qBound(0, b, 255); result.setPixel(x, y, qRgba(r, g, b, qAlpha(pixel))); } } } } else if (filter == tr("Độ bão hòa")) { // Nếu filter là "Độ bão hòa" thì bật QInputDialog lên cho người dùng // nhập vào giá trị, giá trị này trong khoảng -255 đến 255 bool ok; // Kiểm tra giá trị nhập vào int delta = QInputDialog::getInt(parent, tr("Độ bão hòa"), tr("Nhập độ bão hòa:"), 10, -255, 255, 1, &ok); QColor newClolor; QColor oldColor; int h, s, l; // Ta chuyển hình về kênh màu HSL rồi sau đó tăng hoặc giảm kênh // saturation để tăng hoặc giảm độ bão hòa sau đó lại chuyển ảnh về RGB if (ok) { for (int y = 0; y < original.height(); ++y) { for (int x = 0; x < original.width(); ++x) { oldColor = QColor(original.pixel(x, y)); newClolor = oldColor.toHsl(); h = newClolor.hue(); s = newClolor.saturation() + delta; l = newClolor.lightness(); // Ta kiểm tra giá trị mới trong khoảng cho phép s = qBound(0, s, 255); newClolor.setHsl(h, s, l); result.setPixel(x, y, qRgba(newClolor.red(), newClolor.green(), newClolor.blue(), newClolor.alpha())); } } } } return result; }
QImage Invertir::executa(QImage &I) const { I.invertPixels(); return I; }
QCursor createCursor(QString path) { if (path.isEmpty()) return QCursor(); // read file headers QFile curFile(path); curFile.open(QIODevice::ReadOnly); QDataStream curStream(&curFile); curStream.setByteOrder(QDataStream::LittleEndian); struct { quint16 zero; quint16 type; quint16 icons; } header2; curStream >> header2.zero >> header2.type >> header2.icons; struct { quint8 width; quint8 height; quint8 ncolours; quint8 zero; quint16 xhot; quint16 yhot; quint32 bytes; quint32 dibOffset; } directory2; curStream >> directory2.width >> directory2.height >> directory2.ncolours >> directory2.zero >> directory2.xhot >> directory2.yhot >> directory2.bytes >> directory2.dibOffset; curFile.seek(directory2.dibOffset); // prepare a .bmp for delegating decoding to qt struct { unsigned char magic[2]; quint32 size; quint32 zero; quint32 rdataOffset; } bmpHeader; int bmpHeaderSize = (2+4+4+4); struct { quint32 hdrSize; quint32 width; quint32 height; quint16 planes; quint16 bpp; quint32 compression; quint32 dataSize; quint32 unused1; quint32 unused2; quint32 unused3; quint32 unused4; } dibHeader; int dibHeaderSize = (4+4+4+2+2+4+4+4+4+4+4); bmpHeader.magic[0] = 'B'; bmpHeader.magic[1] = 'M'; bmpHeader.zero = 0; bmpHeader.size = bmpHeaderSize + directory2.bytes; bmpHeader.rdataOffset = bmpHeaderSize + dibHeaderSize + directory2.ncolours * 4; curStream >> dibHeader.hdrSize >> dibHeader.width >> dibHeader.height >> dibHeader.planes >> dibHeader.bpp >> dibHeader.compression >> dibHeader.dataSize >> dibHeader.unused1 >> dibHeader.unused2 >> dibHeader.unused3 >> dibHeader.unused4; dibHeader.height >>= 1; // the bmp bytes are in 'bmpData' QByteArray bmpData; QDataStream bmpStream(&bmpData, QIODevice::WriteOnly); bmpStream.setByteOrder(QDataStream::LittleEndian); bmpStream.writeRawData((char*) bmpHeader.magic, 2); bmpStream << bmpHeader.size << bmpHeader.zero << bmpHeader.rdataOffset; bmpStream << dibHeader.hdrSize << dibHeader.width << dibHeader.height << dibHeader.planes << dibHeader.bpp << dibHeader.compression << dibHeader.dataSize << dibHeader.unused1 << dibHeader.unused2 << dibHeader.unused3 << dibHeader.unused4; bmpData.append(curFile.read(directory2.bytes - dibHeaderSize)); // decode the image into 'pix' int width = directory2.width; int height = directory2.height; QImage image; image.loadFromData(bmpData); //qDebug() << image.rect() << path; QPixmap pix = QPixmap::fromImage(image); // now we need the mask (transparency) QByteArray maskData = bmpData.right((width * height) / 8); QImage maskImage = QBitmap::fromData(QSize(width, height), (const uchar*) maskData.constData(), QImage::Format_Mono).toImage().mirrored(false, true); maskImage.invertPixels(); pix.setMask(QBitmap::fromImage(maskImage)); return QCursor(pix, directory2.xhot, directory2.yhot); }