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.
264 lines
9.1 KiB
264 lines
9.1 KiB
/* ============================================================
|
|
*
|
|
* This file is a part of digiKam project
|
|
* http://www.digikam.org
|
|
*
|
|
* Date : 2005-07-18
|
|
* Description : Free rotation threaded image filter.
|
|
*
|
|
* Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
|
|
*
|
|
* 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 2, 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.
|
|
*
|
|
* ============================================================ */
|
|
|
|
// Degrees to radian convertion coeff (PI/180). To optimize computation.
|
|
#define DEG2RAD 0.017453292519943
|
|
|
|
// C++ includes.
|
|
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
|
|
// Local includes.
|
|
|
|
#include "dimg.h"
|
|
#include "dimgimagefilters.h"
|
|
#include "freerotation.h"
|
|
|
|
namespace DigikamFreeRotationImagesPlugin
|
|
{
|
|
|
|
FreeRotation::FreeRotation(Digikam::DImg *orgImage, TQObject *parent, double angle, bool antialiasing,
|
|
int autoCrop, TQColor backgroundColor, int orgW, int orgH)
|
|
: Digikam::DImgThreadedFilter(orgImage, parent, "FreeRotation")
|
|
{
|
|
m_angle = angle;
|
|
m_orgW = orgW;
|
|
m_orgH = orgH;
|
|
m_antiAlias = antialiasing;
|
|
m_autoCrop = autoCrop;
|
|
m_backgroundColor = backgroundColor;
|
|
|
|
initFilter();
|
|
}
|
|
|
|
void FreeRotation::filterImage(void)
|
|
{
|
|
int progress;
|
|
register int w, h, nw, nh, j, i = 0;
|
|
int nNewHeight, nNewWidth;
|
|
int nhdx, nhdy, nhsx, nhsy;
|
|
double lfSin, lfCos, lfx, lfy;
|
|
|
|
int nWidth = m_orgImage.width();
|
|
int nHeight = m_orgImage.height();
|
|
|
|
uchar *pBits = m_orgImage.bits();
|
|
unsigned short *pBits16 = (unsigned short*)m_orgImage.bits();
|
|
|
|
// first of all, we need to calcule the sin and cos of the given angle
|
|
|
|
lfSin = sin (m_angle * -DEG2RAD);
|
|
lfCos = cos (m_angle * -DEG2RAD);
|
|
|
|
// now, we have to calc the new size for the destination image
|
|
|
|
if ((lfSin * lfCos) < 0)
|
|
{
|
|
nNewWidth = ROUND (fabs (nWidth * lfCos - nHeight * lfSin));
|
|
nNewHeight = ROUND (fabs (nWidth * lfSin - nHeight * lfCos));
|
|
}
|
|
else
|
|
{
|
|
nNewWidth = ROUND (fabs (nWidth * lfCos + nHeight * lfSin));
|
|
nNewHeight = ROUND (fabs (nWidth * lfSin + nHeight * lfCos));
|
|
}
|
|
|
|
// getting the destination's center position
|
|
|
|
nhdx = nNewWidth / 2;
|
|
nhdy = nNewHeight / 2;
|
|
|
|
// getting the source's center position
|
|
|
|
nhsx = nWidth / 2;
|
|
nhsy = nHeight / 2;
|
|
|
|
// now, we have to alloc a new image
|
|
|
|
bool sixteenBit = m_orgImage.sixteenBit();
|
|
|
|
m_destImage = Digikam::DImg(nNewWidth, nNewHeight, sixteenBit, m_orgImage.hasAlpha());
|
|
m_destImage.fill( Digikam::DColor(m_backgroundColor.rgb(), sixteenBit) );
|
|
|
|
uchar *pResBits = m_destImage.bits();
|
|
unsigned short *pResBits16 = (unsigned short *)m_destImage.bits();
|
|
|
|
Digikam::DImgImageFilters filters;
|
|
|
|
// main loop
|
|
|
|
for (h = 0; !m_cancel && (h < nNewHeight); h++)
|
|
{
|
|
nh = h - nhdy;
|
|
|
|
for (w = 0; !m_cancel && (w < nNewWidth); w++)
|
|
{
|
|
nw = w - nhdx;
|
|
|
|
i = setPosition (nNewWidth, w, h);
|
|
|
|
lfx = (double)nw * lfCos - (double)nh * lfSin + nhsx;
|
|
lfy = (double)nw * lfSin + (double)nh * lfCos + nhsy;
|
|
|
|
if (isInside (nWidth, nHeight, (int)lfx, (int)lfy))
|
|
{
|
|
if (m_antiAlias)
|
|
{
|
|
if (!sixteenBit)
|
|
filters.pixelAntiAliasing(pBits, nWidth, nHeight, lfx, lfy,
|
|
&pResBits[i+3], &pResBits[i+2],
|
|
&pResBits[i+1], &pResBits[i]);
|
|
else
|
|
filters.pixelAntiAliasing16(pBits16, nWidth, nHeight, lfx, lfy,
|
|
&pResBits16[i+3], &pResBits16[i+2],
|
|
&pResBits16[i+1], &pResBits16[i]);
|
|
}
|
|
else
|
|
{
|
|
j = setPosition (nWidth, (int)lfx, (int)lfy);
|
|
|
|
for (int p = 0 ; p < 4 ; p++)
|
|
{
|
|
if (!sixteenBit)
|
|
pResBits[i] = pBits[j];
|
|
else
|
|
pResBits16[i] = pBits16[j];
|
|
|
|
i++;
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the progress bar in dialog.
|
|
progress = (int)(((double)h * 100.0) / nNewHeight);
|
|
if (progress%5 == 0)
|
|
postProgress( progress );
|
|
}
|
|
|
|
// Compute the rotated destination image size using original image dimensions.
|
|
int W, H;
|
|
double absAngle = fabs(m_angle);
|
|
|
|
if (absAngle < 90.0)
|
|
{
|
|
W = (int)(m_orgW * cos(absAngle * DEG2RAD) + m_orgH * sin(absAngle * DEG2RAD));
|
|
H = (int)(m_orgH * cos(absAngle * DEG2RAD) + m_orgW * sin(absAngle * DEG2RAD));
|
|
}
|
|
else
|
|
{
|
|
H = (int)(m_orgW * cos((absAngle-90.0) * DEG2RAD) + m_orgH * sin((absAngle-90.0) * DEG2RAD));
|
|
W = (int)(m_orgH * cos((absAngle-90.0) * DEG2RAD) + m_orgW * sin((absAngle-90.0) * DEG2RAD));
|
|
}
|
|
|
|
// Auto-cropping destination image without black holes around.
|
|
TQRect autoCrop;
|
|
|
|
switch(m_autoCrop)
|
|
{
|
|
case WidestArea:
|
|
{
|
|
// 'Widest Area' method (by Renchi Raju).
|
|
|
|
autoCrop.setX( (int)(nHeight * sin(absAngle * DEG2RAD)) );
|
|
autoCrop.setY( (int)(nWidth * sin(absAngle * DEG2RAD)) );
|
|
autoCrop.setWidth( (int)(nNewWidth - 2*nHeight * sin(absAngle * DEG2RAD)) );
|
|
autoCrop.setHeight( (int)(nNewHeight - 2*nWidth * sin(absAngle * DEG2RAD)) );
|
|
|
|
if (!autoCrop.isValid())
|
|
{
|
|
m_destImage = Digikam::DImg(m_orgImage.width(), m_orgImage.height(),
|
|
m_orgImage.sixteenBit(), m_orgImage.hasAlpha());
|
|
m_destImage.fill( Digikam::DColor(m_backgroundColor.rgb(), sixteenBit) );
|
|
m_newSize = TQSize();
|
|
}
|
|
else
|
|
{
|
|
m_destImage = m_destImage.copy(autoCrop);
|
|
m_newSize.setWidth( (int)(W - 2*m_orgH * sin(absAngle * DEG2RAD)) );
|
|
m_newSize.setHeight( (int)(H - 2*m_orgW * sin(absAngle * DEG2RAD)) );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LargestArea:
|
|
{
|
|
// 'Largest Area' method (by Gerhard Kulzer).
|
|
|
|
float gamma = atan((float)nHeight / (float)nWidth);
|
|
|
|
if (absAngle < 90.0)
|
|
{
|
|
autoCrop.setWidth( (int)((float)nHeight / cos(absAngle*DEG2RAD) /
|
|
( tan(gamma) + tan(absAngle*DEG2RAD) )) );
|
|
autoCrop.setHeight( (int)((float)autoCrop.width() * tan(gamma)) );
|
|
}
|
|
else
|
|
{
|
|
autoCrop.setHeight( (int)((float)nHeight / cos((absAngle-90.0)*DEG2RAD) /
|
|
( tan(gamma) + tan((absAngle-90.0)*DEG2RAD) )) );
|
|
autoCrop.setWidth( (int)((float)autoCrop.height() * tan(gamma)) );
|
|
}
|
|
|
|
autoCrop.moveCenter( TQPoint(nNewWidth/2, nNewHeight/2));
|
|
|
|
if (!autoCrop.isValid())
|
|
{
|
|
m_destImage = Digikam::DImg(m_orgImage.width(), m_orgImage.height(),
|
|
m_orgImage.sixteenBit(), m_orgImage.hasAlpha());
|
|
m_destImage.fill( Digikam::DColor(m_backgroundColor.rgb(), sixteenBit) );
|
|
m_newSize = TQSize();
|
|
}
|
|
else
|
|
{
|
|
m_destImage = m_destImage.copy(autoCrop);
|
|
gamma = atan((float)m_orgH / (float)m_orgW);
|
|
|
|
if (absAngle < 90.0)
|
|
{
|
|
m_newSize.setWidth( (int)((float)m_orgH / cos(absAngle*DEG2RAD) /
|
|
( tan(gamma) + tan(absAngle*DEG2RAD) )) );
|
|
m_newSize.setHeight( (int)((float)m_newSize.width() * tan(gamma)) );
|
|
}
|
|
else
|
|
{
|
|
m_newSize.setHeight( (int)((float)m_orgH / cos((absAngle-90.0)*DEG2RAD) /
|
|
( tan(gamma) + tan((absAngle-90.0)*DEG2RAD) )) );
|
|
m_newSize.setWidth( (int)((float)m_newSize.height() * tan(gamma)) );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: // No auto croping.
|
|
{
|
|
m_newSize.setWidth( W );
|
|
m_newSize.setHeight( H );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // NameSpace DigikamFreeRotationImagesPlugin
|