diff options
Diffstat (limited to 'src/imageplugins/freerotation/freerotation.cpp')
-rw-r--r-- | src/imageplugins/freerotation/freerotation.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/imageplugins/freerotation/freerotation.cpp b/src/imageplugins/freerotation/freerotation.cpp new file mode 100644 index 00000000..3f8803d5 --- /dev/null +++ b/src/imageplugins/freerotation/freerotation.cpp @@ -0,0 +1,263 @@ +/* ============================================================ + * + * 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; + 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 |