#include "imageutils.h" #include "ifapp.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // ImageMagick redefines off_t to long long #undef off_t #define off_t long long extern "C"{ #include }; // in compressedgif.cpp unsigned int WriteCompressedGIFImage(const ImageInfo *image_info, Image *image); // Returns the filename extension const char* extension(const char *str) { if(!str) return(NULL); const char *ptr = str; const char *last; while(*ptr != '\0') ++ptr; if(ptr == str) return(NULL); last = ptr; while(*ptr != '.' && ptr != str) --ptr; if(*ptr == '.' && ptr != last) return(++ptr); else return(NULL); } // A little global class. Right now it just contains the recognized image // filename extension list and a global dict for blended icons PixieGlobal::PixieGlobal() { int i, n; // // Do the image extensions. These need to be super fast because the // extension is checked when sorting directories if the "Images // on top" option is selected, (the default). The mimetype isn't checked // until later - checking them all when entering the folder is way too // slow. KDE doesn't check them all right away, either, but KDE also // doesn't sort by file type ;-) // // Because speed is important we don't use a normal array or QStrList. // Instead we create a array of 256 pointers, each of which can hold // up to 10 strings. Then we index by the first character of the // extension so "bmp" would only have to check against extensions that // begin with "b" - not all of them. A little more processing at // startup, a lot less when sorting. // for(i=0; i < 256; ++i){ for(n=0; n < 10; ++n){ extensions[i][n] = NULL; } } // Add extensions for KDE/Qt image formats. These are simply lowercase // format names. QStrList inputList = QImageIO::inputFormats(); QStrList skipList; const char *str; char buffer[32]; for(str = inputList.first(); str != NULL; str = inputList.next()){ for(i=0; str[i] != '\0'; ++i) buffer[i] = tolower(str[i]); buffer[i] = '\0'; insertExtension(buffer); skipList.append(buffer); } // Manually install jpg and tif extensions since Qt uses jpeg and tiff insertExtension("jpg"); insertExtension("tif"); // Other extensions we can do insertExtension("mif"); insertExtension("miff"); insertExtension("xcf"); insertExtension("pcx"); insertExtension("tga"); insertExtension("pnm"); insertExtension("ppm"); insertExtension("rs"); insertExtension("sgi"); insertExtension("sunras"); insertExtension("xwd"); insertExtension("wmf"); insertExtension("svg"); } // You shouldn't ever call these PixieGlobal methods void PixieGlobal::insertExtension(const char *str) { int i, idx=str[0]; for(i=0; i < 10; ++i){ if(!extensions[idx][i]){ extensions[idx][i] = (char *)malloc(strlen(str)+1); qstrcpy(extensions[idx][i], str); return; } } qWarning("Not enough space for %s!", str); return; } PixieGlobal::~PixieGlobal() { int i, n; for(i=0; i < 256; ++i){ for(n=0; n < 10; ++n){ if(extensions[i][n]) free(extensions[i][n]); } } } // Don't use these bool PixieGlobal::isImageExtension(const char *str) { if(!str) return(false); if(str[0] == '.') ++str; int i, idx = str[0]; for(i=0; i < 10; ++i){ if(!extensions[idx][i]) return(false); else if(strcasecmp(extensions[idx][i], str) == 0) return(true); } return(false); } bool PixieGlobal::isImageType(const QString &filename) { return(isImageExtension(extension(filename.lower().ascii()))); } // Use these ;-) // This checks the filename extension against the global list. Use // PixieBrowser::isImage() for mimetype support bool isImageType(const QString &fn) { return(kifapp()->globals()->isImageType(fn)); } bool isVideoType(const QString &fn) { const char *ext = extension(QFile::encodeName(fn)); if(!ext) return(false); if(qstricmp(ext, "avi") == 0 || qstricmp(ext, "mpg") == 0 || qstricmp(ext, "mpeg") == 0 || qstricmp(ext, "wmv") == 0 || qstricmp(ext, "asf") == 0 || qstricmp(ext, "viv") == 0 || qstricmp(ext, "asx") == 0 || qstricmp(ext, "rm") == 0 || qstricmp(ext, "mov") == 0 || qstricmp(ext, "asx") == 0) return(true); return(false); } const char* extensionForFormat(const char *format) { if(!format) return(NULL); if(qstrcmp(format, "APP1JPEG") == 0 || qstrcmp(format, "JPEG") == 0 || qstrcmp(format, "JPG") == 0) return(".jpg"); if(qstrcmp(format, "ICO") == 0 || qstrcmp(format, "ICON") == 0) return(".ico"); if(qstrcmp(format, "ICB") == 0 || qstrcmp(format, "TGA") == 0 || qstrcmp(format, "VDA") == 0 || qstrcmp(format, "VST") == 0) return(".tga"); if(qstrcmp(format, "GIF") == 0 || qstrcmp(format, "GIF87") == 0) return(".gif"); if(qstrcmp(format, "TIFF") == 0 || qstrcmp(format, "TIF") == 0) return(".tiff"); // Most extensions are just lowercase versions of the format name. I don't // want to just use that for everything, tho, since there are a lot of // formats I don't know the extension for. Returning NULL will prompt the // user to make sure. if(qstrcmp(format, "PNG") == 0) return(".png"); if(qstrcmp(format, "MNG") == 0) return(".mng"); if(qstrcmp(format, "BMP") == 0) return(".bmp"); if(qstrcmp(format, "MIFF") == 0) return(".miff"); if(qstrcmp(format, "XCF") == 0) return(".xcf"); if(qstrcmp(format, "XBM") == 0) return(".xbm"); if(qstrcmp(format, "XPM") == 0) return(".xpm"); if(qstrcmp(format, "XWD") == 0) return(".xwd"); if(qstrcmp(format, "WMF") == 0) return(".wmf"); if(qstrcmp(format, "SVG") == 0) return(".svg"); if(qstrcmp(format, "PCX") == 0) return(".pcx"); if(qstrcmp(format, "PNM") == 0) return(".pnm"); if(qstrcmp(format, "PPM") == 0) return(".ppm"); return(NULL); } bool displayFormat(const char *format) { // These are the only formats we display by default in dialogs. The // rest can be shown by clicking a button if(qstrcmp(format, "BMP") == 0 || qstrcmp(format, "CYMK") == 0 || qstrcmp(format, "CYMKA") == 0 || qstrcmp(format, "CUT") == 0 || qstrcmp(format, "DCM") == 0 || qstrcmp(format, "DIB") == 0 || qstrcmp(format, "FITS") == 0 || qstrcmp(format, "FPX") == 0 || qstrcmp(format, "GIF") == 0 || qstrcmp(format, "ICO") == 0 || qstrcmp(format, "JPEG") == 0 || qstrcmp(format, "MIFF") == 0 || qstrcmp(format, "MNG") == 0 || qstrcmp(format, "MAT") == 0 || qstrcmp(format, "PALM") == 0 || qstrcmp(format, "PCD") == 0 || qstrcmp(format, "PCT") == 0 || qstrcmp(format, "PCX") == 0 || qstrcmp(format, "PDB") == 0 || qstrcmp(format, "PM") == 0 || qstrcmp(format, "PNG") == 0 || qstrcmp(format, "PNM") == 0 || qstrcmp(format, "PPM") == 0 || qstrcmp(format, "RAS") == 0 || qstrcmp(format, "RGB") == 0 || qstrcmp(format, "RGBA") == 0 || qstrcmp(format, "SUN") == 0 || qstrcmp(format, "SVG") == 0 || qstrcmp(format, "TGA") == 0 || qstrcmp(format, "TIFF") == 0 || qstrcmp(format, "WPG") == 0 || qstrcmp(format, "X") == 0 || qstrcmp(format, "XBM") == 0 || qstrcmp(format, "XCF") == 0 || qstrcmp(format, "XPM") == 0 || qstrcmp(format, "XWD") == 0 || qstrcmp(format, "XBM") == 0 || qstrcmp(format, "XCF") == 0) return(true); return(false); } void outputFormats() { // This is a debugging method ExceptionInfo exception; GetExceptionInfo(&exception); const MagickInfo *i = GetMagickInfo(NULL, &exception); qWarning("Can save image formats: "); while(i){ if(i->encoder) qWarning("%s, %s", i->name, i->description); i = i->next; } i = GetMagickInfo(NULL, &exception); qWarning("\nCan read image formats: "); while(i){ if(i->decoder) qWarning("%s, %s", i->name, i->description); i = i->next; } qWarning("\n"); DestroyExceptionInfo(&exception); } const char* formatForFilename(const QString &filename) { const char *ext = extension(QFile::encodeName(filename)); if(!ext) return(NULL); if(qstrcmp(ext, "jpg") == 0 || qstrcmp(ext, "jpeg") == 0) return("JPEG"); if(qstrcmp(ext, "tif") == 0 || qstrcmp(ext, "tiff") == 0) return("TIFF"); if(qstrcmp(ext, "mif") == 0 || qstrcmp(ext, "miff") == 0) return("MIFF"); if(qstrcmp(ext, "gif") == 0) return("GIF"); if(qstrcmp(ext, "tga") == 0) return("TGA"); if(qstrcmp(ext, "ico") == 0) return("ICO"); if(qstrcmp(ext, "tga") == 0) return("TGA"); if(qstrcmp(ext, "png") == 0) return("PNG"); if(qstrcmp(ext, "mng") == 0) return("MNG"); if(qstrcmp(ext, "bmp") == 0) return("BMP"); if(qstrcmp(ext, "xcf") == 0) return("XCF"); if(qstrcmp(ext, "xbm") == 0) return("XBM"); if(qstrcmp(ext, "xpm") == 0) return("XPM"); if(qstrcmp(ext, "xwd") == 0) return("XWD"); if(qstrcmp(ext, "wmf") == 0) return("WMF"); if(qstrcmp(ext, "svg") == 0) return("SVG"); if(qstrcmp(ext, "pcx") == 0) return("PCX"); if(qstrcmp(ext, "pnm") == 0) return("PNM"); if(qstrcmp(ext, "PPM") == 0) return("ppm"); return(NULL); } bool formatUsesComment(const char *format) { if(qstrcmp(format, "PNG") == 0 || qstrcmp(format, "GIF") == 0 || qstrcmp(format, "JPEG") == 0 || qstrcmp(format, "JPG") == 0 || qstrcmp(format, "FPX") == 0 || qstrcmp(format, "MIFF") == 0 || qstrcmp(format, "PDB") == 0 || qstrcmp(format, "PNM") || qstrcmp(format, "TGA") == 0){ return(true); } return(false); } bool fileUsesComment(const QString &filename) { return(formatUsesComment(formatForFilename(filename))); } bool fileListUsesComment(const QStringList &fileList) { QStringList::ConstIterator it; for(it = fileList.begin(); it != fileList.end(); ++it){ if(fileUsesComment(*it)) return(true); } return(false); } // Loads an image using Qt if possible, otherwise ImageMagick. If // formatRet is != NULL it will try to copy the format used to load. Useful // for saveImage(). bool loadImage(QImage &img, const QString &filename, const char *format, char *formatRet) { bool tryQt = false; bool result; const char *str; // try using Qt first if there is no format given or a format name // that it recognizes if(format){ QStrList inputList = QImageIO::inputFormats(); for(str = inputList.first(); str != NULL; str = inputList.next()){ if(strcasecmp(str, format) == 0){ tryQt = true; break; } } } else tryQt = true; if(tryQt && img.load(filename, format)){ if(format && formatRet) qstrcpy(formatRet, format); else if(formatRet){ // ugh, really sucks that Qt doesn't let you query the format used // to load :P str = QImageIO::imageFormat(filename); if(str) qstrcpy(formatRet, str); else *formatRet ='\0'; } return(true); } // Okay, no Qt support - use ImageMagick! ExceptionInfo exception; ImageInfo *info = CloneImageInfo(NULL); Image *image; GetExceptionInfo(&exception); qstrcpy(info->filename, QFile::encodeName(filename)); image = ReadImage(info, &exception); if(!image){ if(formatRet) *formatRet = '\0'; DestroyImageInfo(info); DestroyExceptionInfo(&exception); return(false); } img.reset(); img.create(image->columns, image->rows, 32); result = DispatchImage(image, 0, 0, img.width(), img.height(), "BGRA", CharPixel, img.bits(), &exception); if(!result){ if(formatRet) *formatRet = '\0'; img.reset(); } else{ if(format && formatRet) qstrcpy(formatRet, format); else if(formatRet) qstrcpy(formatRet, image->magick); } if(image->next) DestroyImageList(image); else DestroyImage(image); DestroyImageInfo(info); DestroyExceptionInfo(&exception); return(result); } /* Temporary fix - ImageMagick's Constitute is just giving blank images! */ Image* myConstituteImage(QImage &srcImage) { int x, y; int w = srcImage.width(); int h = srcImage.height(); PixelPacket *destScanline; unsigned int pixel; ImageInfo *info = CloneImageInfo(NULL); QString sizeStr; sizeStr = sizeStr.sprintf("%dx%d", w, h); info->size = (char *)malloc(sizeStr.length()+1); strcpy(info->size, sizeStr.latin1()); Image *destImage = AllocateImage(info); if(!destImage){ DestroyImageInfo(info); return(NULL); } if(srcImage.depth() > 8){ unsigned int *srcScanline; for(y=0; y < h; ++y){ srcScanline = (unsigned int *)srcImage.scanLine(y); destScanline = GetImagePixels(destImage, 0, y, destImage->columns, 1); for(x=0; x < w; ++x){ pixel = srcScanline[x]; destScanline[x].red = ScaleCharToQuantum(qRed(pixel)); destScanline[x].green = ScaleCharToQuantum(qGreen(pixel)); destScanline[x].blue = ScaleCharToQuantum(qBlue(pixel)); destScanline[x].opacity = ScaleCharToQuantum(255-qAlpha(pixel)); } } } else{ unsigned char *srcScanline; unsigned char idx; unsigned int *colorTable = srcImage.colorTable(); for(y=0; y < h; ++y){ srcScanline = (unsigned char *)srcImage.scanLine(y); destScanline = GetImagePixels(destImage, 0, y, destImage->columns, 1); for(x=0; x < w; ++x){ idx = srcScanline[x]; pixel = colorTable[idx]; destScanline[x].red = ScaleCharToQuantum(qRed(pixel)); destScanline[x].green = ScaleCharToQuantum(qGreen(pixel)); destScanline[x].blue = ScaleCharToQuantum(qBlue(pixel)); destScanline[x].opacity = ScaleCharToQuantum(255-qAlpha(pixel)); } } } DestroyImageInfo(info); return(destImage); } // Saves an image using Qt if it recognizes the format, ImageMagick otherwise. bool saveImage(QImage &img, const QString &fileName, const char *format, int quality, const QString &comment) { bool tryQt = false; bool result; bool isGIF = format ? qstricmp(format, "GIF") == 0 : false; const char *str; // see if it's a format Qt recognizes if(format){ if(isGIF ||(comment != QString::null && qstricmp(format, "PNG") != 0)) tryQt = false; // use Pixie's ImageMagick writer else{ QStrList outputList = QImageIO::outputFormats(); tryQt = false; for(str=outputList.first(); str != NULL; str=outputList.next()){ if(strcasecmp(str, format) == 0){ tryQt = true; break; } } } } else if(comment == QString::null || qstricmp(format, "PNG") == 0) tryQt = true; if(tryQt){ if(!comment.isEmpty()) img.setText("Description", 0, comment.latin1()); if(img.save(fileName, format, quality)) return(true); } // Okay, not handled by Qt, let's do ImageMagick ExceptionInfo exception; ImageInfo *info; GetExceptionInfo(&exception); Image *image; if(img.depth() < 8) img = img.convertDepth(8); // This call is busted /*image = ConstituteImage(img.width(), img.height(), "BGRA", CharPixel, img.bits(), &exception); */ image = myConstituteImage(img); if(!image){ DestroyExceptionInfo(&exception); return(false); } info = CloneImageInfo(NULL); if(comment != QString::null) SetImageAttribute(image, "comment", comment.latin1()); // don't think I need to set both image and info, but better make sure :) qstrcpy(image->filename, QFile::encodeName(fileName)); qstrcpy(info->filename, image->filename); qstrcpy(info->magick, format); qstrcpy(image->magick, info->magick); if(quality != -1) info->quality = quality; // Just setting the magick format item doesn't seem to work - it is // still determined by extension. Iterate through known formats and use // the correct encoder result = false; if(isGIF){ qWarning("Using compressed GIF writer"); result = WriteCompressedGIFImage(info, image); } else{ const MagickInfo *i = GetMagickInfo(NULL, &exception); while(i){ if(i->encoder && qstricmp(i->name, format) == 0){ result = i->encoder(info, image); break; } i = i->next; } } result = WriteImage(info, image); if(image->next) DestroyImageList(image); else DestroyImage(image); DestroyImageInfo(info); DestroyExceptionInfo(&exception); return(result); } // these require 32bpp images and don't check values! void copyQImage(QImage &src, QImage &dest, int x, int y) { int srcx, destx, srcy, desty; unsigned int *input, *output; for(srcy=0, desty = y; srcy < src.height(); ++srcy, ++desty){ input = (unsigned int *)src.scanLine(srcy); output = (unsigned int *)dest.scanLine(desty); for(srcx=0, destx = x; srcx < src.width(); ++srcx, ++destx) output[destx] = input[srcx]; } } void copyQImageWithAlpha(QImage &src, QImage &dest, int x, int y) { int srcx, destx, srcy, desty; unsigned int *input, *output; int alpha, r, g, b; for(srcy=0, desty = y; srcy < src.height(); ++srcy, ++desty){ input = (unsigned int *)src.scanLine(srcy); output = (unsigned int *)dest.scanLine(desty); for(srcx=0, destx = x; srcx < src.width(); ++srcx, ++destx){ alpha = qAlpha(input[srcx]); if(alpha == 0){ ; } else if(alpha != 255){ float srcPercent = ((float)alpha)/255.0; float destPercent = 1.0-srcPercent; r = (int)((srcPercent*qRed(input[srcx])) + (destPercent*qRed(output[destx]))); g = (int)((srcPercent*qGreen(input[srcx])) + (destPercent*qGreen(output[destx]))); b = (int)((srcPercent*qBlue(input[srcx])) + (destPercent*qBlue(output[destx]))); output[destx] = qRgba(r, g, b, 255); } else output[destx] = input[srcx]; } } } void tileQImage(QImage &tile, QImage &dest) { int sx, sy, dx, dy; unsigned int *srcData, *destData; for(sy=0, dy=0; dy < dest.height(); ++sy, ++dy){ if(sy >= tile.height()) sy = 0; srcData = (unsigned int *)tile.scanLine(sy); destData = (unsigned int *)dest.scanLine(dy); for(sx=0, dx=0; dx < dest.width(); ++sx, ++dx){ if(sx >= tile.width()) sx = 0; destData[dx] = srcData[sx]; } } } void tileQImage(QImage &dest, int dx, int dy, int dw, int dh, QImage &src, int sx, int sy, int sw, int sh) { unsigned int *srcData, *destData; int orig_sx = sx; int orig_sy = sy; int orig_dx = dx; //int orig_dy = dy; int sx2 = sx+sw-1; int sy2 = sy+sh-1; int dx2 = dx+dw-1; int dy2 = dy+dh-1; for(;dy < dy2; ++sy, ++dy){ if(sy > sy2) sy = orig_sy; srcData = (unsigned int *)src.scanLine(sy); destData = (unsigned int *)dest.scanLine(dy); for(sx=orig_sx, dx=orig_dx; dx < dx2; ++sx, ++dx){ if(sx > sx2) sx = orig_sx; destData[dx] = srcData[sx]; } } } void copyQImageSecondaryAlpha(QImage &dest, int dx, int dy, int dw, int dh, QImage &src, int sx, int sy, int sw, int sh) { unsigned int *srcData, *destData; int orig_sx = sx; int orig_sy = sy; int orig_dx = dx; //int orig_dy = dy; int sx2 = sx+sw-1; int sy2 = sy+sh-1; int dx2 = dx+dw-1; int dy2 = dy+dh-1; int r, g, b, alpha; for(;dy < dy2; ++sy, ++dy){ if(sy > sy2) sy = orig_sy; srcData = (unsigned int *)src.scanLine(sy); destData = (unsigned int *)dest.scanLine(dy); for(sx=orig_sx, dx=orig_dx; dx < dx2; ++sx, ++dx){ if(sx > sx2) sx = orig_sx; r = qRed(destData[dx]); g = qGreen(destData[dx]); b = qBlue(destData[dx]); alpha = qAlpha(srcData[sx]); destData[dx] = qRgba(r, g, b, alpha); } } } // MITSHM stuff bool useMITSHM = true; Pixmap tempPix = 0; GC tempGC = 0; XImage *shmimage = 0; XShmSegmentInfo xshared_segment_info; int highest_bit(unsigned int v) { int i; unsigned int b = (unsigned int)1 << 31; for(i=31; ((b & v) == 0) && i>=0; i--) b >>= 1; return i; } void clearData() { Display *dpy = QPaintDevice::x11AppDisplay(); if(tempPix){ XFreePixmap(dpy, tempPix); tempPix = 0; } if(tempGC){ XFreeGC(dpy, tempGC); tempGC = 0; } if(useMITSHM && shmimage){ XShmDetach(dpy, &xshared_segment_info); shmimage->data = NULL; XDestroyImage(shmimage); shmimage = NULL; shmdt(xshared_segment_info.shmaddr); shmctl(xshared_segment_info.shmid, IPC_RMID, 0); } } void allocateXImage(int w, int h) { if(!useMITSHM) return; if(shmimage && shmimage->width >= w && shmimage->height >= h) return; Display *dpy = QPaintDevice::x11AppDisplay(); Visual *vis = (Visual *)QPaintDevice::x11AppVisual(); int depth = QPaintDevice::x11AppDepth(); clearData(); shmimage = XShmCreateImage(dpy, vis, depth, ZPixmap, 0, &xshared_segment_info, w, h); if(shmimage){ xshared_segment_info.shmid = shmget(IPC_PRIVATE, shmimage->bytes_per_line * shmimage->height, IPC_CREAT | 0777 ); bool okay = xshared_segment_info.shmid != -1; if(okay){ shmimage->data = (char*)shmat(xshared_segment_info.shmid, 0, 0 ); xshared_segment_info.shmaddr = shmimage->data; okay = xshared_segment_info.shmaddr != 0; } xshared_segment_info.readOnly = false; if(okay) okay = XShmAttach(dpy, &xshared_segment_info); if(!okay){ shmimage->data = NULL; XDestroyImage(shmimage); shmimage = NULL; if(xshared_segment_info.shmaddr) shmdt(xshared_segment_info.shmaddr); if(xshared_segment_info.shmid != -1) shmctl(xshared_segment_info.shmid, IPC_RMID, 0); } else{ tempPix = XShmCreatePixmap(dpy, DefaultRootWindow(dpy), shmimage->data, &xshared_segment_info, w, h, depth); } } if(!shmimage) useMITSHM = false; } void convertImageToPixmapPaletteBlend(QImage &image, QImage &tile, int start_x, int start_y, QPixmap &pix) { XImage *ximage; unsigned int *tileData; unsigned char *srcData; unsigned char alpha; char *destData; unsigned int pixel; unsigned int *colorTable; unsigned int r, g, b; int x, y, tx, ty; float srcPercent, destPercent; bool hasAlphaBuffer = image.hasAlphaBuffer(); Display *dpy = QPaintDevice::x11AppDisplay(); Visual *visual = (Visual *)QPaintDevice::x11AppVisual(); int depth = QPaintDevice::x11AppDepth(); allocateXImage(image.width(), image.height()); if(shmimage){ ximage = shmimage; } else{ ximage = XCreateImage(dpy, visual, depth, ZPixmap, 0, 0, image.width(), image.height(), 32, 0); if(!ximage){ qWarning("convertImageToPixmap: Unable to allocate memory for XImage!"); return; } ximage->data = (char *)malloc(ximage->bytes_per_line*image.height()); if(!ximage->data){ qWarning("convertImageToPixmap: Unable to allocate memory for XImage data!"); ximage->data = NULL; XDestroyImage(ximage); ximage = NULL; return; } } unsigned int red_mask, green_mask, blue_mask; int red_shift, green_shift, blue_shift; red_mask = (unsigned int)visual->red_mask; green_mask = (unsigned int)visual->green_mask; blue_mask = (unsigned int)visual->blue_mask; red_shift = highest_bit(red_mask) - 7; green_shift = highest_bit(green_mask) - 7; blue_shift = highest_bit(blue_mask) - 7; int bppc = ximage->bits_per_pixel; if(bppc > 8 && ximage->byte_order == LSBFirst) bppc++; colorTable = (unsigned int *)image.colorTable(); // There is a lot of code duplication here but we want to keep the // check for bpp out of the main loop or else we would be running a // case for every pixel, (which is what Qt does) if(bppc == 16){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = *(colorTable+srcData[x]); alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = (pixel >> 8); *destData++ = pixel; } } } else if(bppc == 17){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = *(colorTable+srcData[x]); alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; } } } else if(bppc == 24){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = *(colorTable+srcData[x]); alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel >> 16; *destData++ = pixel >> 8; *destData++ = pixel; } } } else if(bppc == 25){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = *(colorTable+srcData[x]); alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; *destData++ = pixel >> 16; } } } else if(bppc == 32){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = *(colorTable+srcData[x]); alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel >> 24; *destData++ = pixel >> 16; *destData++ = pixel >> 8; *destData++ = pixel; } } } else if(bppc == 33){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = *(colorTable+srcData[x]); alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; *destData++ = pixel >> 16; *destData++ = pixel >> 24; } } } if(pix.mask()){ // don't reset mask with a null bitmap because Qt makes annoying // messages if you resize pix = QPixmap(image.width(), image.height()); } else if(pix.width() != image.width() || pix.height() != image.height()) pix.resize(image.width(), image.height()); if(!tempGC) tempGC = XCreateGC(dpy, DefaultRootWindow(dpy), 0, 0); if(shmimage){ XCopyArea(dpy, tempPix, pix.handle(), tempGC, 0, 0, image.width(), image.height(), 0, 0); QApplication::syncX(); } else{ XPutImage(dpy, pix.handle(), tempGC, ximage, 0, 0, 0, 0, image.width(), image.height()); free(ximage->data); ximage->data = NULL; XDestroyImage(ximage); } } void convertImageToPixmapBlend(QImage &image, QImage &tile, int start_x, int start_y, QPixmap &pix) { if(image.isNull()) return; if(image.depth() < 32){ convertImageToPixmapPaletteBlend(image, tile, start_x, start_y, pix); return; } XImage *ximage; unsigned int *srcData, *tileData; char *destData; unsigned char alpha; unsigned int pixel; unsigned int r, g, b; int x, y, tx, ty; float srcPercent, destPercent; bool hasAlphaBuffer = image.hasAlphaBuffer(); Display *dpy = QPaintDevice::x11AppDisplay(); Visual *visual = (Visual *)QPaintDevice::x11AppVisual(); int depth = QPaintDevice::x11AppDepth(); allocateXImage(image.width(), image.height()); if(shmimage){ ximage = shmimage; } else{ ximage = XCreateImage(dpy, visual, depth, ZPixmap, 0, 0, image.width(), image.height(), 32, 0); if(!ximage){ qWarning("convertImageToPixmap: Unable to allocate memory for XImage!"); return; } ximage->data = (char *)malloc(ximage->bytes_per_line*image.height()); if(!ximage->data){ qWarning("convertImageToPixmap: Unable to allocate memory for XImage data!"); ximage->data = NULL; XDestroyImage(ximage); ximage = NULL; return; } } unsigned int red_mask, green_mask, blue_mask; int red_shift, green_shift, blue_shift; red_mask = (unsigned int)visual->red_mask; green_mask = (unsigned int)visual->green_mask; blue_mask = (unsigned int)visual->blue_mask; red_shift = highest_bit(red_mask) - 7; green_shift = highest_bit(green_mask) - 7; blue_shift = highest_bit(blue_mask) - 7; int bppc = ximage->bits_per_pixel; if(bppc > 8 && ximage->byte_order == LSBFirst) bppc++; // There is a lot of code duplication here but we want to keep the // check for bpp out of the main loop or else we would be running a // case for every pixel, (which is what Qt does) if(bppc == 16){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = (unsigned int *)image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = srcData[x]; alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = (pixel >> 8); *destData++ = pixel; } } } else if(bppc == 17){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = (unsigned int *)image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = srcData[x]; alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; } } } else if(bppc == 24){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = (unsigned int *)image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = srcData[x]; alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel >> 16; *destData++ = pixel >> 8; *destData++ = pixel; } } } else if(bppc == 25){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = (unsigned int *)image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = srcData[x]; alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; *destData++ = pixel >> 16; } } } else if(bppc == 32){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = (unsigned int *)image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = srcData[x]; alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel >> 24; *destData++ = pixel >> 16; *destData++ = pixel >> 8; *destData++ = pixel; } } } else if(bppc == 33){ for(y=0, ty=start_y; y < image.height(); ++y, ++ty){ srcData = (unsigned int *)image.scanLine(y); tileData = (unsigned int *)tile.scanLine(ty); destData = ximage->data + ximage->bytes_per_line*y; for(x=0, tx=start_x; x < image.width(); ++x, ++tx){ pixel = srcData[x]; alpha = hasAlphaBuffer ? qAlpha(pixel) : 255; if(alpha == 0) pixel = tileData[tx]; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*qRed(tileData[tx]))), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*qGreen(tileData[tx]))), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*qBlue(tileData[tx])))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; *destData++ = pixel >> 16; *destData++ = pixel >> 24; } } } if(pix.mask()){ // don't reset mask with a null bitmap because Qt makes annoying // messages if you resize pix = QPixmap(image.width(), image.height()); } else if(pix.width() != image.width() || pix.height() != image.height()) pix.resize(image.width(), image.height()); if(!tempGC) tempGC = XCreateGC(dpy, DefaultRootWindow(dpy), 0, 0); if(shmimage){ XCopyArea(dpy, tempPix, pix.handle(), tempGC, 0, 0, image.width(), image.height(), 0, 0); QApplication::syncX(); } else{ XPutImage(dpy, pix.handle(), tempGC, ximage, 0, 0, 0, 0, image.width(), image.height()); free(ximage->data); ximage->data = NULL; XDestroyImage(ximage); } } void convertImageToPixmapPalette(QImage &image, QPixmap &pix, unsigned int bgcolor) { XImage *ximage; unsigned char *srcData; unsigned char alpha; char *destData; unsigned int pixel=0; unsigned int *colorTable; float srcPercent, destPercent; unsigned int r, g, b; int x, y; Display *dpy = QPaintDevice::x11AppDisplay(); Visual *visual = (Visual *)QPaintDevice::x11AppVisual(); int depth = QPaintDevice::x11AppDepth(); allocateXImage(image.width(), image.height()); if(shmimage){ ximage = shmimage; } else{ ximage = XCreateImage(dpy, visual, depth, ZPixmap, 0, 0, image.width(), image.height(), 32, 0); if(!ximage){ qWarning("convertImageToPixmap: Unable to allocate memory for XImage!"); return; } ximage->data = (char *)malloc(ximage->bytes_per_line*image.height()); if(!ximage->data){ qWarning("convertImageToPixmap: Unable to allocate memory for XImage data!"); ximage->data = NULL; XDestroyImage(ximage); ximage = NULL; return; } } unsigned int red_mask, green_mask, blue_mask; int red_shift, green_shift, blue_shift; red_mask = (unsigned int)visual->red_mask; green_mask = (unsigned int)visual->green_mask; blue_mask = (unsigned int)visual->blue_mask; red_shift = highest_bit(red_mask) - 7; green_shift = highest_bit(green_mask) - 7; blue_shift = highest_bit(blue_mask) - 7; int bppc = ximage->bits_per_pixel; if(bppc > 8 && ximage->byte_order == LSBFirst) bppc++; colorTable = (unsigned int *)image.colorTable(); if(image.hasAlphaBuffer()){ // With paletted images if your alphablending to a solid background // color it's better to just blend the palette. r = qRed(bgcolor); g = qGreen(bgcolor); b = qBlue(bgcolor); unsigned int *convertedTable = (unsigned int *) malloc(sizeof(unsigned int)*image.numColors()); for(x=0; x < image.numColors(); ++x){ alpha = qAlpha(colorTable[x]); if(alpha == 0) pixel = bgcolor; else if(alpha != 255){ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgba((unsigned char)((srcPercent*qRed(pixel))+ (destPercent*r)), (unsigned char)((srcPercent*qGreen(pixel))+ (destPercent*g)), (unsigned char)((srcPercent*qBlue(pixel))+ (destPercent*b)), 255); } convertedTable[x] = pixel; } colorTable = convertedTable; } // There is a lot of code duplication here but we want to keep the // check for bpp out of the main loop or else we would be running a // case for every pixel, (which is what Qt does) if(bppc == 16){ for(y=0; y < image.height(); ++y){ srcData = image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ pixel = *(colorTable+srcData[x]); r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = (pixel >> 8); *destData++ = pixel; } } } else if(bppc == 17){ for(y=0; y < image.height(); ++y){ srcData = image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ pixel = *(colorTable+srcData[x]); r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; } } } else if(bppc == 24){ for(y=0; y < image.height(); ++y){ srcData = image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ pixel = *(colorTable+srcData[x]); r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel >> 16; *destData++ = pixel >> 8; *destData++ = pixel; } } } else if(bppc == 25){ for(y=0; y < image.height(); ++y){ srcData = image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ pixel = *(colorTable+srcData[x]); r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; *destData++ = pixel >> 16; } } } else if(bppc == 32){ for(y=0; y < image.height(); ++y){ srcData = image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ pixel = *(colorTable+srcData[x]); r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel >> 24; *destData++ = pixel >> 16; *destData++ = pixel >> 8; *destData++ = pixel; } } } else if(bppc == 33){ for(y=0; y < image.height(); ++y){ srcData = image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ pixel = *(colorTable+srcData[x]); r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; *destData++ = pixel >> 16; *destData++ = pixel >> 24; } } } if(pix.mask()){ // don't reset mask with a null bitmap because Qt makes annoying // messages if you resize pix = QPixmap(image.width(), image.height()); } else if(pix.width() != image.width() || pix.height() != image.height()) pix.resize(image.width(), image.height()); if(!tempGC) tempGC = XCreateGC(dpy, DefaultRootWindow(dpy), 0, 0); if(shmimage){ XCopyArea(dpy, tempPix, pix.handle(), tempGC, 0, 0, image.width(), image.height(), 0, 0); QApplication::syncX(); } else{ XPutImage(dpy, pix.handle(), tempGC, ximage, 0, 0, 0, 0, image.width(), image.height()); free(ximage->data); ximage->data = NULL; XDestroyImage(ximage); } if(image.hasAlphaBuffer()) free(colorTable); } // Converts a image to a pixmap using the global MITSHM buffer. void convertImageToPixmap(QImage &image, QPixmap &pix, unsigned int bgcolor) { if(image.isNull()) return; // everything should be 32bpp anyways so we don't bother w/ other depths if(image.depth() < 32){ convertImageToPixmapPalette(image, pix, bgcolor); return; } XImage *ximage; unsigned int *srcData; char *destData; unsigned char alpha; float srcPercent, destPercent; unsigned int pixel; unsigned int r, g, b; int x, y; bool hasAlphaBuffer = image.hasAlphaBuffer(); Display *dpy = QPaintDevice::x11AppDisplay(); Visual *visual = (Visual *)QPaintDevice::x11AppVisual(); int depth = QPaintDevice::x11AppDepth(); allocateXImage(image.width(), image.height()); if(shmimage){ ximage = shmimage; } else{ ximage = XCreateImage(dpy, visual, depth, ZPixmap, 0, 0, image.width(), image.height(), 32, 0); if(!ximage){ qWarning("convertImageToPixmap: Unable to allocate memory for XImage!"); return; } ximage->data = (char *)malloc(ximage->bytes_per_line*image.height()); if(!ximage->data){ qWarning("convertImageToPixmap: Unable to allocate memory for XImage data!"); ximage->data = NULL; XDestroyImage(ximage); ximage = NULL; return; } } unsigned int red_mask, green_mask, blue_mask; int red_shift, green_shift, blue_shift; red_mask = (unsigned int)visual->red_mask; green_mask = (unsigned int)visual->green_mask; blue_mask = (unsigned int)visual->blue_mask; red_shift = highest_bit(red_mask) - 7; green_shift = highest_bit(green_mask) - 7; blue_shift = highest_bit(blue_mask) - 7; int bppc = ximage->bits_per_pixel; if(bppc > 8 && ximage->byte_order == LSBFirst) bppc++; // There is a lot of code duplication here but we want to keep the // check for bpp out of the main loop or else we would be running a // case for every pixel, (which is what Qt does) if(bppc == 16){ for(y=0; y < image.height(); ++y){ srcData = (unsigned int *)image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ alpha = hasAlphaBuffer ? qAlpha(srcData[x]) : 255; if(alpha == 0){ pixel = bgcolor; } else if(alpha == 255){ pixel = srcData[x]; } else{ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)(srcPercent*qRed(srcData[x])+ (destPercent*qRed(bgcolor))), (unsigned char)(srcPercent*qGreen(srcData[x])+ (destPercent*qGreen(bgcolor))), (unsigned char)(srcPercent*qBlue(srcData[x])+ (destPercent*qBlue(bgcolor)))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = (pixel >> 8); *destData++ = pixel; } } } else if(bppc == 17){ for(y=0; y < image.height(); ++y){ srcData = (unsigned int *)image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ alpha = hasAlphaBuffer ? qAlpha(srcData[x]) : 255; if(alpha == 0){ pixel = bgcolor; } else if(alpha == 255){ pixel = srcData[x]; } else{ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)(srcPercent*qRed(srcData[x])+ (destPercent*qRed(bgcolor))), (unsigned char)(srcPercent*qGreen(srcData[x])+ (destPercent*qGreen(bgcolor))), (unsigned char)(srcPercent*qBlue(srcData[x])+ (destPercent*qBlue(bgcolor)))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; } } } else if(bppc == 24){ for(y=0; y < image.height(); ++y){ srcData = (unsigned int *)image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ alpha = hasAlphaBuffer ? qAlpha(srcData[x]) : 255; if(alpha == 0){ pixel = bgcolor; } else if(alpha == 255){ pixel = srcData[x]; } else{ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)(srcPercent*qRed(srcData[x])+ (destPercent*qRed(bgcolor))), (unsigned char)(srcPercent*qGreen(srcData[x])+ (destPercent*qGreen(bgcolor))), (unsigned char)(srcPercent*qBlue(srcData[x])+ (destPercent*qBlue(bgcolor)))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel >> 16; *destData++ = pixel >> 8; *destData++ = pixel; } } } else if(bppc == 25){ for(y=0; y < image.height(); ++y){ srcData = (unsigned int *)image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ alpha = hasAlphaBuffer ? qAlpha(srcData[x]) : 255; if(alpha == 0){ pixel = bgcolor; } else if(alpha == 255){ pixel = srcData[x]; } else{ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)(srcPercent*qRed(srcData[x])+ (destPercent*qRed(bgcolor))), (unsigned char)(srcPercent*qGreen(srcData[x])+ (destPercent*qGreen(bgcolor))), (unsigned char)(srcPercent*qBlue(srcData[x])+ (destPercent*qBlue(bgcolor)))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; *destData++ = pixel >> 16; } } } else if(bppc == 32){ for(y=0; y < image.height(); ++y){ srcData = (unsigned int *)image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ alpha = hasAlphaBuffer ? qAlpha(srcData[x]) : 255; if(alpha == 0){ pixel = bgcolor; } else if(alpha == 255){ pixel = srcData[x]; } else{ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)(srcPercent*qRed(srcData[x])+ (destPercent*qRed(bgcolor))), (unsigned char)(srcPercent*qGreen(srcData[x])+ (destPercent*qGreen(bgcolor))), (unsigned char)(srcPercent*qBlue(srcData[x])+ (destPercent*qBlue(bgcolor)))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel >> 24; *destData++ = pixel >> 16; *destData++ = pixel >> 8; *destData++ = pixel; } } } else if(bppc == 33){ for(y=0; y < image.height(); ++y){ srcData = (unsigned int *)image.scanLine(y); destData = ximage->data + ximage->bytes_per_line*y; for(x=0; x < image.width(); ++x){ alpha = hasAlphaBuffer ? qAlpha(srcData[x]) : 255; if(alpha == 0){ pixel = bgcolor; } else if(alpha == 255){ pixel = srcData[x]; } else{ srcPercent = ((float)alpha)/255.0; destPercent = 1.0-srcPercent; pixel = qRgb((unsigned char)(srcPercent*qRed(srcData[x])+ (destPercent*qRed(bgcolor))), (unsigned char)(srcPercent*qGreen(srcData[x])+ (destPercent*qGreen(bgcolor))), (unsigned char)(srcPercent*qBlue(srcData[x])+ (destPercent*qBlue(bgcolor)))); } r = red_shift > 0 ? qRed(pixel) << red_shift : qRed(pixel) >> -red_shift; g = green_shift > 0 ? qGreen(pixel) << green_shift : qGreen(pixel) >> -green_shift; b = blue_shift > 0 ? qBlue(pixel) << blue_shift : qBlue(pixel) >> -blue_shift; pixel = (b & blue_mask) | (g & green_mask) | (r & red_mask); *destData++ = pixel; *destData++ = pixel >> 8; *destData++ = pixel >> 16; *destData++ = pixel >> 24; } } } if(pix.mask()){ // don't reset mask with a null bitmap because Qt makes annoying // messages if you resize pix = QPixmap(image.width(), image.height()); } else if(pix.width() != image.width() || pix.height() != image.height()) pix.resize(image.width(), image.height()); if(!tempGC) tempGC = XCreateGC(dpy, DefaultRootWindow(dpy), 0, 0); if(shmimage){ XCopyArea(dpy, tempPix, pix.handle(), tempGC, 0, 0, image.width(), image.height(), 0, 0); QApplication::syncX(); } else{ XPutImage(dpy, pix.handle(), tempGC, ximage, 0, 0, 0, 0, image.width(), image.height()); free(ximage->data); ximage->data = NULL; XDestroyImage(ximage); } }