/*************************************************************************** CImage.cpp (c) 2000-2007 Benoit Minisini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #define __CIMAGE_CPP #include #include #include #include #include #include #include #include #ifdef OS_SOLARIS /* Make math.h define M_PI and a few other things */ #define __EXTENSIONS__ /* Get definition for finite() */ #include #endif #include #include "gambas.h" #include "main.h" #include "CScreen.h" #include "CPicture.h" #include "CDraw.h" #include "CImage.h" static void create(CIMAGE **pimage) { static GB_CLASS class_id = NULL; if (!class_id) class_id = GB.FindClass("Image"); GB.New(POINTER(pimage), class_id, NULL, NULL); } const char *CIMAGE_get_format(QString path) { int pos; pos = path.findRev('.'); if (pos < 0) return NULL; path = path.mid(pos + 1).lower(); if (path == "png") return "PNG"; else if (path == "jpg" || path == "jpeg") return "JPEG"; else if (path == "gif") return "GIF"; else if (path == "bmp") return "BMP"; else if (path == "xpm") return "XPM"; else return NULL; } // bool CIMAGE_load_image(QImage &p, char *path, int lenp) // { // char *addr; // int len; // bool ok; // char *path_theme; // int pos; // // if (CAPPLICATION_Theme && lenp > 0 && path[0] != '/') // { // pos = lenp - 1; // while (pos >= 0) // { // if (path[pos] == '.') // break; // pos--; // } // GB.NewString(&path_theme, path, pos >= 0 ? pos : lenp); // GB.AddString(&path_theme, "_", 1); // GB.AddString(&path_theme, CAPPLICATION_Theme, GB.StringLength(CAPPLICATION_Theme)); // if (pos >= 0) // GB.AddString(&path_theme, &path[pos], lenp - pos); // ok = !GB.LoadFile(path_theme, GB.StringLength(path_theme), &addr, &len); // GB.FreeString(&path_theme); // if (ok) // goto __LOAD; // } // // GB.Error(NULL); // if (GB.LoadFile(path, lenp, &addr, &len)) // return FALSE; // // __LOAD: // // ok = p.loadFromData((const uchar *)addr, (uint)len); // if (ok) // { // //create((CIMAGE **)&_object); // // if (p.depth() < 32) // p = p.convertDepth(32); // // //p.setAlphaBuffer(true); // } // // GB.ReleaseFile(&addr, len); // return ok; // } // /******************************************************************************* Image *******************************************************************************/ BEGIN_METHOD(CIMAGE_new, GB_INTEGER w; GB_INTEGER h; GB_BOOLEAN trans) int w, h; THIS->image = new QImage(); if (!MISSING(w) && !MISSING(h)) { w = VARG(w); h = VARG(h); if (h <= 0 || w <= 0) { GB.Error("Bad dimension"); return; } THIS->image->create(w, h, 32); THIS->image->setAlphaBuffer(VARGOPT(trans, false)); } END_METHOD BEGIN_METHOD_VOID(CIMAGE_free) delete THIS->image; THIS->image = 0; END_METHOD BEGIN_PROPERTY(CIMAGE_picture) CPICTURE *pict; GB.New(POINTER(&pict), GB.FindClass("Picture"), NULL, NULL); pict->pixmap->convertFromImage(*(THIS->image)); GB.ReturnObject(pict); END_PROPERTY BEGIN_METHOD(CIMAGE_resize, GB_INTEGER width; GB_INTEGER height) if (THIS->image->isNull()) { THIS->image->create(VARG(width), VARG(height), 32); THIS->image->setAlphaBuffer(true); } else { QImage img = THIS->image->copy(0, 0, VARG(width), VARG(height)); delete THIS->image; THIS->image = new QImage(img); } END_METHOD BEGIN_PROPERTY(CIMAGE_width) GB.ReturnInteger(THIS->image->width()); END_PROPERTY BEGIN_PROPERTY(CIMAGE_height) GB.ReturnInteger(THIS->image->height()); END_PROPERTY BEGIN_PROPERTY(CIMAGE_depth) //if (READ_PROPERTY) GB.ReturnInteger(THIS->image->depth()); /*else { if (!THIS->image->isNull()) { int depth = VPROP(GB_INTEGER); if (depth != THIS->image->depth()) { QImage img = THIS->image->convertDepth(depth); if (!img.isNull()) { delete THIS->image; THIS->image = new QImage(img); } } } }*/ END_PROPERTY BEGIN_PROPERTY(CIMAGE_transparent) if (READ_PROPERTY) GB.ReturnBoolean(THIS->image->hasAlphaBuffer()); else THIS->image->setAlphaBuffer(VPROP(GB_BOOLEAN)); END_PROPERTY BEGIN_METHOD(CIMAGE_load, GB_STRING path) QImage *p; CIMAGE *img; if (CPICTURE_load_image(&p, STRING(path), LENGTH(path))) { create(&img); delete img->image; img->image = p; GB.ReturnObject(img); } else GB.Error("Unable to load image"); END_METHOD BEGIN_METHOD(CIMAGE_save, GB_STRING path; GB_INTEGER quality) QString path = TO_QSTRING(GB.FileName(STRING(path), LENGTH(path))); bool ok = false; const char *fmt = CIMAGE_get_format(path); if (!fmt) { GB.Error("Unknown format"); return; } ok = THIS->image->save(path, fmt, VARGOPT(quality, -1)); if (!ok) GB.Error("Unable to save picture"); END_METHOD BEGIN_METHOD_VOID(CIMAGE_clear) delete THIS->image; THIS->image = new QImage(); END_METHOD BEGIN_METHOD(CIMAGE_fill, GB_INTEGER col) //bool a; int col = VARG(col); //a = THIS->image->hasAlphaBuffer(); THIS->image->setAlphaBuffer(false); col ^= 0xFF000000; THIS->image->fill(col); THIS->image->setAlphaBuffer(true); END_METHOD BEGIN_METHOD(CIMAGE_copy, GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h) CIMAGE *img; int x = VARGOPT(x, 0); int y = VARGOPT(y, 0); int w = VARGOPT(w, THIS->image->width()); int h = VARGOPT(h, THIS->image->height()); create(&img); img->image->create(w, h, 32); bool a = THIS->image->hasAlphaBuffer(); THIS->image->setAlphaBuffer(false); img->image->setAlphaBuffer(false); bitBlt(img->image, 0, 0, THIS->image, x, y, w, h); THIS->image->setAlphaBuffer(a); img->image->setAlphaBuffer(a); GB.ReturnObject(img); END_METHOD BEGIN_METHOD(CIMAGE_stretch, GB_INTEGER width; GB_INTEGER height; GB_BOOLEAN smooth) CIMAGE *img; QImage stretch; create(&img); if (THIS->image->isNull()) { img->image->create(VARG(width), VARG(height), 32); img->image->setAlphaBuffer(true); } else { if (VARGOPT(smooth, TRUE)) *(img->image) = THIS->image->smoothScale(VARG(width), VARG(height)); else *(img->image) = THIS->image->scale(VARG(width), VARG(height)); } GB.ReturnObject(img); END_METHOD BEGIN_METHOD_VOID(CIMAGE_flip) CIMAGE *img; create(&img); *(img->image) = THIS->image->mirror(true, false); GB.ReturnObject(img); END_METHOD BEGIN_METHOD_VOID(CIMAGE_mirror) CIMAGE *img; create(&img); *(img->image) = THIS->image->mirror(false, true); GB.ReturnObject(img); END_METHOD BEGIN_METHOD(CIMAGE_rotate, GB_FLOAT angle) CIMAGE *img; QWMatrix mat; bool a = THIS->image->hasAlphaBuffer(); create(&img); mat.rotate(VARG(angle) * -360.0 / 2 / M_PI); THIS->image->setAlphaBuffer(true); *(img->image) = THIS->image->xForm(mat); THIS->image->setAlphaBuffer(a); GB.ReturnObject(img); END_METHOD BEGIN_METHOD(CIMAGE_replace, GB_INTEGER src; GB_INTEGER dst; GB_BOOLEAN noteq) uint *p; uint i, n, src, dst; THIS->image->setAlphaBuffer(true); src = VARG(src) ^ 0xFF000000; dst = VARG(dst) ^ 0xFF000000; p = (uint *)THIS->image->bits(); n = THIS->image->height() * THIS->image->width(); if (VARGOPT(noteq, false)) { for (i = 0; i < n; i++, p++) { if (*p != src) *p = dst; } } else { for (i = 0; i < n; i++,p ++) { if (*p == src) *p = dst; } } END_METHOD /******************************************************************************* .ImagePixels *******************************************************************************/ BEGIN_METHOD(CIMAGE_pixels_get, GB_INTEGER x; GB_INTEGER y) int col; int x, y; //unsigned char r, g, b, a; x = VARG(x); y = VARG(y); if (!THIS->image->valid(x, y)) { GB.ReturnInteger(-1); return; } col = THIS->image->pixel(x, y) ^ 0xFF000000; GB.ReturnInteger(col); #if 0 a = (col >> 24); //qDebug("[%d,%d] = (%d %d %d) / %d", x, y, r, g, b, a); if (!THIS->image->hasAlphaBuffer() || a == 255) GB.ReturnInteger( col & 0xFFFFFF); else if (a == 0) GB.ReturnInteger(-1); else { r = col & 0xFF; g = (col >> 8) & 0xFF; b = (col >> 16) & 0xFF; r = 255 - ((255 - r) * a) / 255; g = 255 - ((255 - g) * a) / 255; b = 255 - ((255 - b) * a) / 255; GB.ReturnInteger(r + (g << 8) + (b << 16)); } #endif END_METHOD BEGIN_METHOD(CIMAGE_pixels_put, GB_INTEGER col; GB_INTEGER x; GB_INTEGER y) int x, y; int col; x = VARG(x); y = VARG(y); if (!THIS->image->valid(x, y)) return; col = VARG(col) ^ 0xFF000000; THIS->image->setPixel(x, y, col); END_METHOD BEGIN_PROPERTY(CIMAGE_data) GB.ReturnPointer((void *)THIS->image->bits()); END_PROPERTY BEGIN_METHOD(CIMAGE_draw, GB_OBJECT img; GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h; GB_INTEGER sx; GB_INTEGER sy; GB_INTEGER sw; GB_INTEGER sh) int x, y, w, h, sx, sy, sw, sh; CIMAGE *image = (CIMAGE *)VARG(img); QImage img; double scale_x, scale_y; if (GB.CheckObject(image)) return; img = *(image->image); x = VARGOPT(x, 0); y = VARGOPT(y, 0); w = VARGOPT(w, -1); h = VARGOPT(h, -1); sx = VARGOPT(sx, 0); sy = VARGOPT(sy, 0); sw = VARGOPT(sw, img.width()); sh = VARGOPT(sh, img.height()); DRAW_NORMALIZE(x, y, w, h, sx, sy, sw, sh, img.width(), img.height()); if (w != sw || h != sh) { scale_x = (double)w / sw; scale_y = (double)h / sh; img = img.smoothScale((int)(img.width() * scale_x + 0.5), (int)(img.height() * scale_y + 0.5)); sx = (int)(sx * scale_x + 0.5); sy = (int)(sy * scale_y + 0.5); sw = w; sh = h; } bitBlt(THIS->image, x, y, &img, sx, sy, sw, sh, Qt::AutoColor); END_METHOD GB_DESC CImageDesc[] = { GB_DECLARE("Image", sizeof(CIMAGE)), //GB_STATIC_METHOD("_exit", NULL, CPICTURE_flush, NULL), //GB_CONSTANT("None", "i", TYPE_NONE), //GB_CONSTANT("Bitmap", "i", TYPE_PIXMAP), //GB_CONSTANT("Pixmap", "i", TYPE_PIXMAP), //GB_CONSTANT("Vector", "i", TYPE_PICTURE), //GB_CONSTANT("Metafile", "i", TYPE_PICTURE), //GB_CONSTANT("Image", "i", TYPE_IMAGE), GB_METHOD("_new", NULL, CIMAGE_new, "[(Width)i(Height)i(Transparent)b]"), GB_METHOD("_free", NULL, CIMAGE_free, NULL), GB_METHOD("_get", "i", CIMAGE_pixels_get, "(X)i(Y)i"), GB_METHOD("_put", NULL, CIMAGE_pixels_put, "(Color)i(X)i(Y)i"), //GB_STATIC_METHOD("_get", "Picture", CPICTURE_get, "(Path)s"), //GB_STATIC_METHOD("_put", NULL, CPICTURE_put, "(Picture)Picture;(Path)s"), //GB_STATIC_METHOD("Flush", NULL, CPICTURE_flush, NULL), //GB_PROPERTY("Type", "i", CPICTURE_type), GB_PROPERTY_READ("W", "i", CIMAGE_width), GB_PROPERTY_READ("Width", "i", CIMAGE_width), GB_PROPERTY_READ("H", "i", CIMAGE_height), GB_PROPERTY_READ("Height", "i", CIMAGE_height), GB_PROPERTY_READ("Depth", "i", CIMAGE_depth), GB_PROPERTY("Transparent", "b", CIMAGE_transparent), GB_STATIC_METHOD("Load", "Image", CIMAGE_load, "(Path)s"), GB_METHOD("Save", NULL, CIMAGE_save, "(Path)s[(Quality)i]"), GB_METHOD("Resize", NULL, CIMAGE_resize, "(Width)i(Height)i"), GB_METHOD("Clear", NULL, CIMAGE_clear, NULL), GB_METHOD("Fill", NULL, CIMAGE_fill, "(Color)i"), GB_METHOD("Replace", NULL, CIMAGE_replace, "(OldColor)i(NewColor)i[(NotEqual)b]"), //GB_METHOD("Mask", NULL, CPICTURE_mask, "[(Color)i]"), GB_METHOD("Copy", "Image", CIMAGE_copy, "[(X)i(Y)i(Width)i(Height)i]"), GB_METHOD("Stretch", "Image", CIMAGE_stretch, "(Width)i(Height)i[(Smooth)b]"), GB_METHOD("Flip", "Image", CIMAGE_flip, NULL), GB_METHOD("Mirror", "Image", CIMAGE_mirror, NULL), GB_METHOD("Rotate", "Image", CIMAGE_rotate, "(Angle)f"), GB_METHOD("Draw", NULL, CIMAGE_draw, "(Image)Image;(X)i(Y)i[(Width)i(Height)i(SrcX)i(SrcY)i(SrcWidth)i(SrcHeight)i]"), GB_PROPERTY_READ("Picture", "Picture", CIMAGE_picture), GB_PROPERTY_READ("Data", "p", CIMAGE_data), //GB_PROPERTY_SELF("Pixels", ".ImagePixels"), //GB_PROPERTY_SELF("Colors", ".PictureColors"), GB_END_DECLARE };