You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kuickshow/kuickshow/src/kuickimage.cpp

528 lines
12 KiB

#include "kuickimage.h"
KuickImage::KuickImage( const KuickFile * file, ImlibImage *im, ImlibData *id)
: TQObject( 0L, 0L )
{
myFile = file;
myOrigIm = 0L;
myIm = im;
myId = id;
myPixmap = 0L;
myWidth = im->rgb_width;
myHeight = im->rgb_height;
myIsDirty = true;
myOrigWidth = myWidth;
myOrigHeight = myHeight;
myRotation = ROT_0;
myFlipMode = FlipNone;
}
KuickImage::~KuickImage()
{
if ( myPixmap )
Imlib_free_pixmap( myId, myPixmap );
if ( myOrigIm )
{
Imlib_destroy_image( myId, myOrigIm );
Imlib_kill_image( myId, myIm ); // kill scaled image (### really? analyze!)
}
else
Imlib_destroy_image( myId, myIm );
}
Pixmap& KuickImage::pixmap()
{
if ( myIsDirty )
renderPixmap();
return myPixmap;
}
void KuickImage::renderPixmap()
{
if ( !myIsDirty )
return;
// tqDebug("### rendering: %s", myFilename.latin1());
if ( myPixmap )
Imlib_free_pixmap( myId, myPixmap );
emit startRendering();
// #ifndef NDEBUG
// struct timeval tms1, tms2;
// gettimeofday( &tms1, NULL );
// #endif
Imlib_render( myId, myIm, myWidth, myHeight );
myPixmap = Imlib_move_image( myId, myIm );
// #ifndef NDEBUG
// gettimeofday( &tms2, NULL );
// tqDebug("*** rendering image: %s, took %ld ms", myFilename.latin1(),
// (tms2.tv_usec - tms1.tv_usec)/1000);
// #endif
emit stoppedRendering();
myIsDirty = false;
}
void KuickImage::rotate( Rotation rot )
{
if ( rot == ROT_180 ) { // rotate 180 degrees
Imlib_flip_image_horizontal( myId, myIm );
Imlib_flip_image_vertical( myId, myIm );
}
else if ( rot == ROT_90 || rot == ROT_270 ) {
tqSwap( myWidth, myHeight );
Imlib_rotate_image( myId, myIm, -1 );
if ( rot == ROT_90 ) // rotate 90 degrees
Imlib_flip_image_horizontal( myId, myIm );
else if ( rot == ROT_270 ) // rotate 270 degrees
Imlib_flip_image_vertical( myId, myIm );
}
myRotation = (Rotation) ((myRotation + rot) % 4);
myIsDirty = true;
}
bool KuickImage::rotateAbs( Rotation rot )
{
if ( myRotation == rot )
return false;
int diff = rot - myRotation;
bool clockWise = (diff > 0);
switch( abs(diff) ) {
case ROT_90:
rotate( clockWise ? ROT_90 : ROT_270 );
break;
case ROT_180:
rotate( ROT_180 );
break;
case ROT_270:
rotate( clockWise ? ROT_270 : ROT_90 );
break;
}
return true;
}
void KuickImage::flip( FlipMode flipMode )
{
if ( flipMode & FlipHorizontal )
Imlib_flip_image_horizontal( myId, myIm );
if ( flipMode & FlipVertical )
Imlib_flip_image_vertical( myId, myIm );
myFlipMode = (FlipMode) (myFlipMode ^ flipMode);
myIsDirty = true;
}
bool KuickImage::flipAbs( int mode )
{
if ( myFlipMode == mode )
return false;
bool changed = false;
if ( ((myFlipMode & FlipHorizontal) && !(mode & FlipHorizontal)) ||
(!(myFlipMode & FlipHorizontal) && (mode & FlipHorizontal)) ) {
Imlib_flip_image_horizontal( myId, myIm );
changed = true;
}
if ( ((myFlipMode & FlipVertical) && !(mode & FlipVertical)) ||
(!(myFlipMode & FlipVertical) && (mode & FlipVertical)) ) {
Imlib_flip_image_vertical( myId, myIm );
changed = true;
}
if ( changed ) {
myFlipMode = (FlipMode) mode;
myIsDirty = true;
return true;
}
return false;
}
void KuickImage::restoreOriginalSize()
{
if (myWidth == myOrigWidth && myHeight == myOrigHeight)
return;
// tqDebug("-- restoreOriginalSize");
if ( myOrigIm != 0L )
{
Imlib_destroy_image( myId, myIm );
myIm = myOrigIm;
myOrigIm = 0L;
}
myWidth = myOrigWidth;
myHeight = myOrigHeight;
myIsDirty = true;
if ( myRotation == ROT_90 || myRotation == ROT_270 )
tqSwap( myWidth, myHeight );
}
void KuickImage::resize( int width, int height, KuickImage::ResizeMode mode )
{
if ( myWidth == width && myHeight == height )
return;
if ( mode == KuickImage::SMOOTH )
{
if ( !smoothResize( width, height ) )
fastResize( width, height );
}
else
{
fastResize( width, height );
}
}
void KuickImage::fastResize( int width, int height )
{
// tqDebug("-- fastResize: %i x %i", width, height );
// lazy resizing (only done when rendering pixmap)
myWidth = width;
myHeight = height;
myIsDirty = true;
}
bool KuickImage::smoothResize( int newWidth, int newHeight )
{
// tqDebug("-- smoothResize: %i x %i", newWidth, newHeight);
TQImage *image = newTQImage();
// Note: TQ_ScaleMin seems to have a bug (off-by-one, sometimes results in width being 1 pixel too small)
TQImage scaledImage = image->smoothScale(newWidth, newHeight, TQ_ScaleFree);
delete image;
ImlibImage *newIm = toImage( myId, scaledImage );
if ( newIm )
{
if ( myOrigIm == 0 )
myOrigIm = myIm;
myIm = newIm;
myWidth = newWidth;
myHeight = newHeight;
myIsDirty = true;
return true;
}
return false;
}
TQImage * KuickImage::newTQImage() const
{
ImlibImage *im;
// tqDebug("-- newTQImage");
if ( myOrigIm != 0L && myRotation == ROT_0 && myFlipMode == FlipNone )
{
// use original image if no other modifications have been applied
// ### use orig image always and reapply mods?
im = myOrigIm;
}
else
{
im = myIm;
}
int w = im->rgb_width;
int h = im->rgb_height;
TQImage *image = new TQImage( w, h, 32 );
uchar *rgb = im->rgb_data;
TQRgb **destImageData = reinterpret_cast<TQRgb**>( image->jumpTable() );
int byteIndex = 0;
int destLineIndex = 0;
int destByteIndex = 0;
for ( int pixel = 0; pixel < (w * h); pixel++ )
{
if ( pixel != 0 && (pixel % w) == 0 )
{
destLineIndex++;
destByteIndex = 0;
}
uchar r = rgb[byteIndex++];
uchar g = rgb[byteIndex++];
uchar b = rgb[byteIndex++];
TQRgb rgbPixel = tqRgb( r, g, b );
destImageData[destLineIndex][destByteIndex++] = rgbPixel;
}
return image;
}
ImlibImage * KuickImage::toImage( ImlibData *id, TQImage& image )
{
if ( image.isNull() )
return 0L;
if ( image.depth() != 32 )
{
image.setAlphaBuffer(false);
image = image.convertDepth(32);
if ( image.isNull() )
return 0L;
}
// convert to 24 bpp (discard alpha)
int numPixels = image.width() * image.height();
const int NUM_BYTES_NEW = 3; // 24 bpp
uchar *newImageData = new uchar[numPixels * NUM_BYTES_NEW];
uchar *newData = newImageData;
int w = image.width();
int h = image.height();
for (int y = 0; y < h; y++) {
TQRgb *scanLine = reinterpret_cast<TQRgb *>( image.scanLine(y) );
for (int x = 0; x < w; x++) {
const TQRgb& pixel = scanLine[x];
*(newData++) = tqRed(pixel);
*(newData++) = tqGreen(pixel);
*(newData++) = tqBlue(pixel);
}
}
ImlibImage *im = Imlib_create_image_from_data( id, newImageData, NULL,
image.width(), image.height() );
delete [] newImageData;
return im;
}
#if 0
bool KuickImage::smoothResize( int newWidth, int newHeight )
{
int numPixels = newWidth * newHeight;
const int NUM_BYTES_NEW = 3; // 24 bpp
uchar *newImageData = new uchar[numPixels * NUM_BYTES_NEW];
// ### endianness
// myIm : old image, old size
/////////////////////////////////////////////////
// int w = myOrigWidth; //myViewport.width();
//int h = myOrigHeight; //myViewport.height();
//TQImage dst(w, h, myIm->depth(), myIm->numColors(), myIm->bitOrder());
//TQRgb *scanline;
int basis_ox, basis_oy, basis_xx, basis_yy;
// ### we only scale with a fixed factor for x and y anyway
double scalex = newWidth / (double) myOrigWidth;
double scaley = newHeight / (double) myOrigHeight;
// basis_ox=(int) (myViewport.left() * 4096.0 / scalex);
// basis_oy=(int) (myViewport.top() * 4096.0 / scaley);
basis_ox = 0;
basis_oy = 0;
basis_xx = (int) (4096.0 / scalex);
basis_yy = (int) (4096.0 / scaley);
//tqDebug("Basis: (%d, %d), (%d, 0), (0, %d)", basis_ox, basis_oy, basis_xx, basis_yy);
int x2, y2;
int max_x2 = (myOrigWidth << 12);
int max_y2 = (myOrigHeight << 12);
// TQRgb background = idata->backgroundColor.rgb();
// TQRgb **imdata = (TQRgb **) myIm->jumpTable();
// TQRgb *imdata = reinterpret_cast<TQRgb*>( myIm->rgb_data );
uchar *imdata = myIm->rgb_data;
int y = 0;
// for (;;) //fill the top of the target pixmap with the background color
// {
// y2 = basis_oy + y * basis_yy;
//
// if ((y2 >= 0 && (y2 >> 12) < myIm->height()) || y >= h)
// break;
//
// scanline = (TQRgb*) dst.scanLine(y);
// for (int i = 0; i < w; i++)
// *(scanline++) = background; //tqRgb(0,255,0);
// y++;
// }
for (; y < newHeight; y++)
{
// scanline = (TQRgb*) dst.scanLine(y);
x2 = basis_ox;
y2 = basis_oy + y * basis_yy;
if (y2 >= max_y2)
break;
int x = 0;
// while ((x2 < 0 || (x2 >> 12) >= myIm->width()) && x < w) //fill the left of the target pixmap with the background color
// {
// *(scanline++) = background; //tqRgb(0,0,255);
// x2 += basis_xx;
// x++;
// }
int top = y2 >> 12;
int bottom = top + 1;
if (bottom >= myOrigHeight)
bottom--;
// for (; x < w; x++)
for (; x < newWidth; x++) // ### myOrigWidth orig
{
int left = x2 >> 12;
int right = left + 1;
if (right >= myOrigWidth)
right = myOrigWidth - 1;
unsigned int wx = x2 & 0xfff; //12 bits of precision for reasons which will become clear
unsigned int wy = y2 & 0xfff; //12 bits of precision
unsigned int iwx = 0xfff - wx;
unsigned int iwy = 0xfff - wy;
TQRgb tl = 0, tr = 0, bl = 0, br = 0;
int ind = 0;
ind = (left + top * myOrigWidth) * 3;
tl = (imdata[ind] << 16);
tl |= (imdata[ind + 1] << 8);
tl |= (imdata[ind + 2] << 0);
int bar = imdata[ind + 2] << 8;
bar = tqBlue(bar);
ind = (right + top * myOrigWidth) * 3;
tr = (imdata[ind] << 16);
tr |= (imdata[ind + 1] << 8);
tr |= (imdata[ind + 2] << 0);
bar = imdata[ind + 2] << 8;
ind = (left + bottom * myOrigWidth) * 3;
bl = (imdata[ind] << 16);
bl |= (imdata[ind + 1] << 8);
bl |= (imdata[ind + 2] << 0);
bar = imdata[ind + 2] << 8;
ind = (right + bottom * myOrigWidth) * 3;
br = (imdata[ind] << 16);
br |= (imdata[ind + 1] << 8);
br |= (imdata[ind + 2] << 0);
// tl=imdata[top][left];
// tr=imdata[top][right];
// bl=imdata[bottom][left];
// br=imdata[bottom][right];
/*
tl=getValidPixel(myIm, left, top, x, y); //these calls are expensive
tr=getValidPixel(myIm, right, top, x, y); //use them to debug segfaults in this function
bl=getValidPixel(myIm, left, bottom, x, y);
br=getValidPixel(myIm, right, bottom, x, y);
*/
unsigned int r = (unsigned int) (tqRed(tl) * iwx * iwy + tqRed(tr) * wx* iwy + tqRed(bl) * iwx * wy + tqRed(br) * wx * wy); // NB 12+12+8 == 32
unsigned int g = (unsigned int) (tqGreen(tl) * iwx * iwy + tqGreen(tr) * wx * iwy + tqGreen(bl) * iwx * wy + tqGreen(br) * wx * wy);
unsigned int b = (unsigned int) (tqBlue(tl) * iwx * iwy + tqBlue(tr) * wx * iwy + tqBlue(bl) * iwx * wy + tqBlue(br) * wx * wy);
// ### endianness
//we're actually off by one in 255 here! (254 instead of 255)
int foo = r >> 24;
foo = g >> 24;
foo = b >> 24;
newImageData[(y * newWidth * 3) + (x * 3) + 0] = (r >> 24);
newImageData[(y * newWidth * 3) + (x * 3) + 1] = (g >> 24);
newImageData[(y * newWidth * 3) + (x * 3) + 2] = (b >> 24);
// *(scanline++) = tqRgb(r >> 24, g >> 24, b >> 24); //we're actually off by one in 255 here
x2 += basis_xx;
if (x2 > max_x2)
{
x++;
break;
}
}
// while (x < w) //fill the right of each scanline with the background colour
// {
// *(scanline++) = background; //tqRgb(255,0,0);
// x++;
// }
}
// for (;;) //fill the bottom of the target pixmap with the background color
// {
// y2 = basis_oy + y * basis_yy;
//
// if (y >= h)
// break;
//
// scanline = (TQRgb*) dst.scanLine(y);
// for (int i = 0; i < w; i++)
// *(scanline++) = background; //tqRgb(255,255,0);
// y++;
// }
// ### keep orig image somewhere but delete all scaled images!
ImlibImage *newIm = Imlib_create_image_from_data( myId, newImageData, NULL,
newWidth, newHeight );
delete[] newImageData;
if ( newIm )
{
myScaledIm = newIm;
myIsDirty = true;
myWidth = newWidth;
myHeight = newHeight;
}
return myIm != 0L;
// return dst.copy();
}
#endif
#include "kuickimage.moc"