diff options
Diffstat (limited to 'src/imageplugins/perspective')
-rw-r--r-- | src/imageplugins/perspective/Makefile.am | 35 | ||||
-rw-r--r-- | src/imageplugins/perspective/digikamimageplugin_perspective.desktop | 52 | ||||
-rw-r--r-- | src/imageplugins/perspective/digikamimageplugin_perspective_ui.rc | 20 | ||||
-rw-r--r-- | src/imageplugins/perspective/imageeffect_perspective.cpp | 252 | ||||
-rw-r--r-- | src/imageplugins/perspective/imageeffect_perspective.h | 89 | ||||
-rw-r--r-- | src/imageplugins/perspective/imageplugin_perspective.cpp | 69 | ||||
-rw-r--r-- | src/imageplugins/perspective/imageplugin_perspective.h | 56 | ||||
-rw-r--r-- | src/imageplugins/perspective/matrix.cpp | 177 | ||||
-rw-r--r-- | src/imageplugins/perspective/matrix.h | 106 | ||||
-rw-r--r-- | src/imageplugins/perspective/perspectivetool.cpp | 244 | ||||
-rw-r--r-- | src/imageplugins/perspective/perspectivetool.h | 100 | ||||
-rw-r--r-- | src/imageplugins/perspective/perspectivewidget.cpp | 839 | ||||
-rw-r--r-- | src/imageplugins/perspective/perspectivewidget.h | 172 | ||||
-rw-r--r-- | src/imageplugins/perspective/triangle.cpp | 65 | ||||
-rw-r--r-- | src/imageplugins/perspective/triangle.h | 57 |
15 files changed, 2333 insertions, 0 deletions
diff --git a/src/imageplugins/perspective/Makefile.am b/src/imageplugins/perspective/Makefile.am new file mode 100644 index 00000000..028add37 --- /dev/null +++ b/src/imageplugins/perspective/Makefile.am @@ -0,0 +1,35 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_perspective_la_SOURCES = imageplugin_perspective.cpp \ + perspectivetool.cpp \ + perspectivewidget.cpp triangle.cpp matrix.cpp + +digikamimageplugin_perspective_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_perspective_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_perspective.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_perspective.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_perspective_ui.rc + diff --git a/src/imageplugins/perspective/digikamimageplugin_perspective.desktop b/src/imageplugins/perspective/digikamimageplugin_perspective.desktop new file mode 100644 index 00000000..a6fcc4d3 --- /dev/null +++ b/src/imageplugins/perspective/digikamimageplugin_perspective.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_Perspective +Name[bg]=Приставка за снимки - Перспектива +Name[da]=Billedplugin_Perspektivværktøj +Name[el]=ΠρόσθετοΕικόνας_Προοπτική +Name[fi]=Perspektiivimuunnos +Name[hr]=Perspektiva +Name[it]=PluginImmagini_Prospettiva +Name[nl]=Afbeeldingsplugin_Perspectief +Name[sr]=Перспектива +Name[sr@Latn]=Perspektiva +Name[sv]=Insticksprogram för perspektiv +Name[tr]=ResimEklentisi_Perspektif +Name[xx]=xxImagePlugin_Perspectivexx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Perspective tool plugin for digiKam +Comment[bg]=Приставка на digiKam за промяна на перспективата +Comment[ca]=Connector pel digiKam d'eina de perspectiva +Comment[da]=Perspektivværktøjs-plugin for Digikam +Comment[de]=digiKam-Modul zum Justieren der Perspektive eines Bildes +Comment[el]=Πρόσθετο εργαλείο προοπτικής για το digiKam +Comment[es]=Plugin para digiKam de herramientas de perspectiva +Comment[et]=DigiKami perspektiiviplugin +Comment[fa]=وصلۀ ابزار منظره برای digiKam +Comment[fi]=Vääristää kuvan perspektiiviä +Comment[fr]=Module externe pour modifier la perspective dans digiKam +Comment[gl]=Un plugin de digiKam para a ferramenta de perspectiva +Comment[hr]=digiKam dodatak za perspektivu +Comment[it]=Plugin per lo strumento di prospettiva per digiKam +Comment[ja]=digiKam 視点調整プラグイン +Comment[ms]=Plugin alatan perspektif untuk digiKam +Comment[nds]=digiKam-Moduul för den Kietwinkel +Comment[nl]=Digikam-plugin voor perspectiefaanpassing +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਪਰੋਸਪੈਕਟਿਵ ਸੰਦ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam umożliwiająca korekcję perspektywy +Comment[pt]=Um 'plugin' do digiKam para a ferramenta de perspectiva +Comment[pt_BR]=Plugin de ferramenta de Perspectiva +Comment[ru]=Модуль изменения перспективы для digiKam +Comment[sk]=digiKam plugin pre nástroj s perspektívou +Comment[sr]=digiKam-ов прикључак за перспективу +Comment[sr@Latn]=digiKam-ov priključak za perspektivu +Comment[sv]=Digikam insticksprogram med perspektivverktyg +Comment[tr]=digiKam için perspektif aracı eklentisi +Comment[uk]=Втулок засобу побудови перспективи для digiKam +Comment[vi]=Phần bổ sung công cụ phối cảnh cho digiKam +Comment[xx]=xxPerspective tool plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_perspective +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/perspective/digikamimageplugin_perspective_ui.rc b/src/imageplugins/perspective/digikamimageplugin_perspective_ui.rc new file mode 100644 index 00000000..0f3bca57 --- /dev/null +++ b/src/imageplugins/perspective/digikamimageplugin_perspective_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="4" name="digikamimageplugin_perspective" > + + <MenuBar> + + <Menu name="Transform" ><text>Tra&nsform</text> + <Action name="imageplugin_perspective" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_perspective" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/perspective/imageeffect_perspective.cpp b/src/imageplugins/perspective/imageeffect_perspective.cpp new file mode 100644 index 00000000..15bef877 --- /dev/null +++ b/src/imageplugins/perspective/imageeffect_perspective.cpp @@ -0,0 +1,252 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective . + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqspinbox.h> +#include <tqpushbutton.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqcheckbox.h> + +// KDE includes. + +#include <kcolorbutton.h> +#include <kcursor.h> +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> +#include <kseparator.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "perspectivewidget.h" +#include "imageeffect_perspective.h" +#include "imageeffect_perspective.moc" + +namespace DigikamPerspectiveImagesPlugin +{ + +ImageEffect_Perspective::ImageEffect_Perspective(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Adjust Photograph Perspective"), + "perspective", false, false) +{ + TQString whatsThis; + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Perspective"), + digikam_version, + I18N_NOOP("A digiKam image plugin to process image perspective adjustment."), + TDEAboutData::License_GPL, + "(c) 2005-2006, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(plainPage()); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l = new TQVBoxLayout(frame, 5, 0); + m_previewWidget = new PerspectiveWidget(525, 350, frame); + l->addWidget(m_previewWidget); + TQWhatsThis::add( m_previewWidget, i18n("<p>This is the perspective transformation operation preview. " + "You can use the mouse for dragging the corner to adjust the " + "perspective transformation area.")); + setPreviewAreaWidget(frame); + + // ------------------------------------------------------------- + + TQString temp; + Digikam::ImageIface iface(0, 0); + + TQWidget *gbox2 = new TQWidget(plainPage()); + TQGridLayout *gridLayout = new TQGridLayout( gbox2, 13, 2, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("New width:"), gbox2); + m_newWidthLabel = new TQLabel(temp.setNum( iface.originalWidth()) + i18n(" px"), gbox2); + m_newWidthLabel->setAlignment( AlignBottom | AlignRight ); + + TQLabel *label2 = new TQLabel(i18n("New height:"), gbox2); + m_newHeightLabel = new TQLabel(temp.setNum( iface.originalHeight()) + i18n(" px"), gbox2); + m_newHeightLabel->setAlignment( AlignBottom | AlignRight ); + + gridLayout->addMultiCellWidget(label1, 0, 0, 0, 0); + gridLayout->addMultiCellWidget(m_newWidthLabel, 0, 0, 1, 2); + gridLayout->addMultiCellWidget(label2, 1, 1, 0, 0); + gridLayout->addMultiCellWidget(m_newHeightLabel, 1, 1, 1, 2); + + // ------------------------------------------------------------- + + KSeparator *line = new KSeparator(Horizontal, gbox2); + + TQLabel *angleLabel = new TQLabel(i18n("Angles (in degrees):"), gbox2); + TQLabel *label3 = new TQLabel(i18n(" Top left:"), gbox2); + m_topLeftAngleLabel = new TQLabel(gbox2); + TQLabel *label4 = new TQLabel(i18n(" Top right:"), gbox2); + m_topRightAngleLabel = new TQLabel(gbox2); + TQLabel *label5 = new TQLabel(i18n(" Bottom left:"), gbox2); + m_bottomLeftAngleLabel = new TQLabel(gbox2); + TQLabel *label6 = new TQLabel(i18n(" Bottom right:"), gbox2); + m_bottomRightAngleLabel = new TQLabel(gbox2); + + gridLayout->addMultiCellWidget(line, 2, 2, 0, 2); + gridLayout->addMultiCellWidget(angleLabel, 3, 3, 0, 2); + gridLayout->addMultiCellWidget(label3, 4, 4, 0, 0); + gridLayout->addMultiCellWidget(m_topLeftAngleLabel, 4, 4, 1, 2); + gridLayout->addMultiCellWidget(label4, 5, 5, 0, 0); + gridLayout->addMultiCellWidget(m_topRightAngleLabel, 5, 5, 1, 2); + gridLayout->addMultiCellWidget(label5, 6, 6, 0, 0); + gridLayout->addMultiCellWidget(m_bottomLeftAngleLabel, 6, 6, 1, 2); + gridLayout->addMultiCellWidget(label6, 7, 7, 0, 0); + gridLayout->addMultiCellWidget(m_bottomRightAngleLabel, 7, 7, 1, 2); + + // ------------------------------------------------------------- + + KSeparator *line2 = new KSeparator(Horizontal, gbox2); + + m_drawWhileMovingCheckBox = new TQCheckBox(i18n("Draw preview while moving"), gbox2); + gridLayout->addMultiCellWidget(line2, 8, 8, 0, 2); + gridLayout->addMultiCellWidget(m_drawWhileMovingCheckBox, 9, 9, 0, 2); + + m_drawGridCheckBox = new TQCheckBox(i18n("Draw grid"), gbox2); + gridLayout->addMultiCellWidget(m_drawGridCheckBox, 10, 10, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label7 = new TQLabel(i18n("Guide color:"), gbox2); + m_guideColorBt = new KColorButton( TQColor( TQt::red ), gbox2 ); + TQWhatsThis::add( m_guideColorBt, i18n("<p>Set here the color used to draw guides dashed-lines.")); + gridLayout->addMultiCellWidget(label7, 11, 11, 0, 0); + gridLayout->addMultiCellWidget(m_guideColorBt, 11, 11, 2, 2); + + TQLabel *label8 = new TQLabel(i18n("Guide width:"), gbox2); + m_guideSize = new TQSpinBox( 1, 5, 1, gbox2); + TQWhatsThis::add( m_guideSize, i18n("<p>Set here the width in pixels used to draw guides dashed-lines.")); + gridLayout->addMultiCellWidget(label8, 12, 12, 0, 0); + gridLayout->addMultiCellWidget(m_guideSize, 12, 12, 2, 2); + + gridLayout->setColStretch(1, 10); + gridLayout->setRowStretch(13, 10); + + setUserAreaWidget(gbox2); + + // ------------------------------------------------------------- + + connect(m_previewWidget, TQ_SIGNAL(signalPerspectiveChanged(TQRect, float, float, float, float)), + this, TQ_SLOT(slotUpdateInfo(TQRect, float, float, float, float))); + + connect(m_drawWhileMovingCheckBox, TQ_SIGNAL(toggled(bool)), + m_previewWidget, TQ_SLOT(slotToggleDrawWhileMoving(bool))); + + connect(m_drawGridCheckBox, TQ_SIGNAL(toggled(bool)), + m_previewWidget, TQ_SLOT(slotToggleDrawGrid(bool))); + + connect(m_guideColorBt, TQ_SIGNAL(changed(const TQColor &)), + m_previewWidget, TQ_SLOT(slotChangeGuideColor(const TQColor &))); + + connect(m_guideSize, TQ_SIGNAL(valueChanged(int)), + m_previewWidget, TQ_SLOT(slotChangeGuideSize(int))); +} + +ImageEffect_Perspective::~ImageEffect_Perspective() +{ +} + +void ImageEffect_Perspective::readUserSettings(void) +{ + TQColor defaultGuideColor(TQt::red); + TDEConfig *config = kapp->config(); + config->setGroup("perspective Tool Dialog"); + m_drawWhileMovingCheckBox->setChecked(config->readBoolEntry("Draw While Moving", true)); + m_drawGridCheckBox->setChecked(config->readBoolEntry("Draw Grid", false)); + m_guideColorBt->setColor(config->readColorEntry("Guide Color", &defaultGuideColor)); + m_guideSize->setValue(config->readNumEntry("Guide Width", 1)); + m_previewWidget->slotToggleDrawWhileMoving(m_drawWhileMovingCheckBox->isChecked()); + m_previewWidget->slotToggleDrawGrid(m_drawGridCheckBox->isChecked()); + m_previewWidget->slotChangeGuideColor(m_guideColorBt->color()); + m_previewWidget->slotChangeGuideSize(m_guideSize->value()); +} + +void ImageEffect_Perspective::writeUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("perspective Tool Dialog"); + config->writeEntry("Draw While Moving", m_drawWhileMovingCheckBox->isChecked()); + config->writeEntry("Draw Grid", m_drawGridCheckBox->isChecked()); + config->writeEntry("Guide Color", m_guideColorBt->color()); + config->writeEntry("Guide Width", m_guideSize->value()); + config->sync(); +} + +void ImageEffect_Perspective::resetValues() +{ + m_previewWidget->reset(); +} + +void ImageEffect_Perspective::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + m_previewWidget->applyPerspectiveAdjustment(); + accept(); + kapp->restoreOverrideCursor(); +} + +void ImageEffect_Perspective::slotUpdateInfo(TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle) +{ + TQString temp; + m_newWidthLabel->setText(temp.setNum( newSize.width()) + i18n(" px") ); + m_newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") ); + + m_topLeftAngleLabel->setText(temp.setNum( topLeftAngle, 'f', 1 )); + m_topRightAngleLabel->setText(temp.setNum( topRightAngle, 'f', 1 )); + m_bottomLeftAngleLabel->setText(temp.setNum( bottomLeftAngle, 'f', 1 )); + m_bottomRightAngleLabel->setText(temp.setNum( bottomRightAngle, 'f', 1 )); +} + +} // NameSpace DigikamPerspectiveImagesPlugin + diff --git a/src/imageplugins/perspective/imageeffect_perspective.h b/src/imageplugins/perspective/imageeffect_perspective.h new file mode 100644 index 00000000..41388aa7 --- /dev/null +++ b/src/imageplugins/perspective/imageeffect_perspective.h @@ -0,0 +1,89 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective . + * + * Copyright (C) 2005-2008 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_PERSPECTIVE_H +#define IMAGEEFFECT_PERSPECTIVE_H + +// TQt includes. + +#include <tqrect.h> + +// Digikam includes. + +#include "imagedlgbase.h" + +class TQLabel; +class TQCheckBox; +class TQSpinBox; + +class KColorButton; + +namespace DigikamPerspectiveImagesPlugin +{ + +class PerspectiveWidget; + +class ImageEffect_Perspective : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_Perspective(TQWidget* parent); + ~ImageEffect_Perspective(); + +private slots: + + void slotUpdateInfo(TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void finalRendering(); + +private: + + TQLabel *m_newWidthLabel; + TQLabel *m_newHeightLabel; + TQLabel *m_topLeftAngleLabel; + TQLabel *m_topRightAngleLabel; + TQLabel *m_bottomLeftAngleLabel; + TQLabel *m_bottomRightAngleLabel; + + TQCheckBox *m_drawWhileMovingCheckBox; + TQCheckBox *m_drawGridCheckBox; + + TQSpinBox *m_guideSize; + + KColorButton *m_guideColorBt; + + PerspectiveWidget *m_previewWidget; +}; + +} // NameSpace DigikamPerspectiveImagesPlugin + +#endif /* IMAGEEFFECT_PERSPECTIVE_H */ diff --git a/src/imageplugins/perspective/imageplugin_perspective.cpp b/src/imageplugins/perspective/imageplugin_perspective.cpp new file mode 100644 index 00000000..bb5d0444 --- /dev/null +++ b/src/imageplugins/perspective/imageplugin_perspective.cpp @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective . + * + * Copyright (C) 2005-2008 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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "perspectivetool.h" +#include "imageplugin_perspective.h" +#include "imageplugin_perspective.moc" + +using namespace DigikamPerspectiveImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_perspective, + KGenericFactory<ImagePlugin_Perspective>("digikamimageplugin_perspective")); + +ImagePlugin_Perspective::ImagePlugin_Perspective(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_Perspective") +{ + m_perspectiveAction = new TDEAction(i18n("Perspective Adjustment..."), "perspective", 0, + this, TQ_SLOT(slotPerspective()), + actionCollection(), "imageplugin_perspective"); + + setXMLFile("digikamimageplugin_perspective_ui.rc"); + + DDebug() << "ImagePlugin_Perspective plugin loaded" << endl; +} + +ImagePlugin_Perspective::~ImagePlugin_Perspective() +{ +} + +void ImagePlugin_Perspective::setEnabledActions(bool enable) +{ + m_perspectiveAction->setEnabled(enable); +} + +void ImagePlugin_Perspective::slotPerspective() +{ + PerspectiveTool *tool = new PerspectiveTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/perspective/imageplugin_perspective.h b/src/imageplugins/perspective/imageplugin_perspective.h new file mode 100644 index 00000000..5dee7b1b --- /dev/null +++ b/src/imageplugins/perspective/imageplugin_perspective.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective . + * + * Copyright (C) 2005-2008 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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_PERSPECTIVE_H +#define IMAGEPLUGIN_PERSPECTIVE_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_Perspective : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_Perspective(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_Perspective(); + + void setEnabledActions(bool enable); + +private slots: + + void slotPerspective(); + +private: + + TDEAction *m_perspectiveAction; +}; + +#endif /* IMAGEPLUGIN_PERSPECTIVE_H */ diff --git a/src/imageplugins/perspective/matrix.cpp b/src/imageplugins/perspective/matrix.cpp new file mode 100644 index 00000000..65723c56 --- /dev/null +++ b/src/imageplugins/perspective/matrix.cpp @@ -0,0 +1,177 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a matrix implementation for image + * perspective adjustment. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Matrix3 implementation inspired from gimp 2.0 + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + * + * ============================================================ */ + +// C++ includes. + +#include <cstring> + +// Local includes. + +#include "matrix.h" + +namespace DigikamPerspectiveImagesPlugin +{ + +static double identityMatrix[3][3] = { { 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 }, + { 0.0, 0.0, 1.0 } }; + +Matrix::Matrix() +{ + memcpy(coeff, identityMatrix, sizeof(coeff)); +} + +void Matrix::translate (double x, double y) +{ + double g, h, i; + + g = coeff[2][0]; + h = coeff[2][1]; + i = coeff[2][2]; + + coeff[0][0] += x * g; + coeff[0][1] += x * h; + coeff[0][2] += x * i; + coeff[1][0] += y * g; + coeff[1][1] += y * h; + coeff[1][2] += y * i; +} + +void Matrix::scale(double x, double y) +{ + coeff[0][0] *= x; + coeff[0][1] *= x; + coeff[0][2] *= x; + + coeff[1][0] *= y; + coeff[1][1] *= y; + coeff[1][2] *= y; +} + +void Matrix::multiply(const Matrix &matrix) +{ + int i, j; + Matrix tmp; + double t1, t2, t3; + + for (i = 0; i < 3; i++) + { + t1 = matrix.coeff[i][0]; + t2 = matrix.coeff[i][1]; + t3 = matrix.coeff[i][2]; + + for (j = 0; j < 3; j++) + { + tmp.coeff[i][j] = t1 * coeff[0][j]; + tmp.coeff[i][j] += t2 * coeff[1][j]; + tmp.coeff[i][j] += t3 * coeff[2][j]; + } + } + + *this = tmp; +} + +void Matrix::transformPoint(double x, double y, double *newx, double *newy) const +{ + double w; + + w = coeff[2][0] * x + coeff[2][1] * y + coeff[2][2]; + + if (w == 0.0) + w = 1.0; + else + w = 1.0/w; + + *newx = (coeff[0][0] * x + + coeff[0][1] * y + + coeff[0][2]) * w; + *newy = (coeff[1][0] * x + + coeff[1][1] * y + + coeff[1][2]) * w; +} + +void Matrix::invert() +{ + Matrix inv; + double det; + + det = determinant(); + + if (det == 0.0) + return; + + det = 1.0 / det; + + inv.coeff[0][0] = (coeff[1][1] * coeff[2][2] - + coeff[1][2] * coeff[2][1]) * det; + + inv.coeff[1][0] = - (coeff[1][0] * coeff[2][2] - + coeff[1][2] * coeff[2][0]) * det; + + inv.coeff[2][0] = (coeff[1][0] * coeff[2][1] - + coeff[1][1] * coeff[2][0]) * det; + + inv.coeff[0][1] = - (coeff[0][1] * coeff[2][2] - + coeff[0][2] * coeff[2][1]) * det; + + inv.coeff[1][1] = (coeff[0][0] * coeff[2][2] - + coeff[0][2] * coeff[2][0]) * det; + + inv.coeff[2][1] = - (coeff[0][0] * coeff[2][1] - + coeff[0][1] * coeff[2][0]) * det; + + inv.coeff[0][2] = (coeff[0][1] * coeff[1][2] - + coeff[0][2] * coeff[1][1]) * det; + + inv.coeff[1][2] = - (coeff[0][0] * coeff[1][2] - + coeff[0][2] * coeff[1][0]) * det; + + inv.coeff[2][2] = (coeff[0][0] * coeff[1][1] - + coeff[0][1] * coeff[1][0]) * det; + + *this = inv; +} + +double Matrix::determinant() const +{ + double determinant; + + determinant = (coeff[0][0] * + (coeff[1][1] * coeff[2][2] - + coeff[1][2] * coeff[2][1])); + determinant -= (coeff[1][0] * + (coeff[0][1] * coeff[2][2] - + coeff[0][2] * coeff[2][1])); + determinant += (coeff[2][0] * + (coeff[0][1] * coeff[1][2] - + coeff[0][2] * coeff[1][1])); + + return determinant; +} + +} // namespace DigikamPerspectiveImagesPlugin diff --git a/src/imageplugins/perspective/matrix.h b/src/imageplugins/perspective/matrix.h new file mode 100644 index 00000000..fbc5a1aa --- /dev/null +++ b/src/imageplugins/perspective/matrix.h @@ -0,0 +1,106 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a matrix implementation for image + * perspective adjustment. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_PERSPECTIVE_MATRIX_H +#define IMAGEEFFECT_PERSPECTIVE_MATRIX_H + +namespace DigikamPerspectiveImagesPlugin +{ + +class Matrix +{ +public: + + /** + * Matrix: + * + * Initializes matrix to the identity matrix. + */ + Matrix(); + + /** + * translate: + * @x: Translation in X direction. + * @y: Translation in Y direction. + * + * Translates the matrix by x and y. + */ + void translate(double x, double y); + + /** + * scale: + * @x: X scale factor. + * @y: Y scale factor. + * + * Scales the matrix by x and y + */ + void scale(double x, double y); + + /** + * invert: + * + * Inverts this matrix. + */ + void invert(); + + /** + * multiply: + * @matrix: The other input matrix. + * + * Multiplies this matrix with another matrix + */ + void multiply(const Matrix &matrix1); + + /** + * transformPoint: + * @x: The source X coordinate. + * @y: The source Y coordinate. + * @newx: The transformed X coordinate. + * @newy: The transformed Y coordinate. + * + * Transforms a point in 2D as specified by the transformation matrix. + */ + void transformPoint(double x, double y, double *newx, double *newy) const; + + /** + * determinant: + * + * Calculates the determinant of this matrix. + * + * Returns: The determinant. + */ + double determinant() const; + + /** + * coeff: + * + * The 3x3 matrix data + */ + double coeff[3][3]; +}; + +} // namespace DigikamPerspectiveImagesPlugin + +#endif // IMAGEEFFECT_PERSPECTIVE_MATRIX_H diff --git a/src/imageplugins/perspective/perspectivetool.cpp b/src/imageplugins/perspective/perspectivetool.cpp new file mode 100644 index 00000000..30d0a2cf --- /dev/null +++ b/src/imageplugins/perspective/perspectivetool.cpp @@ -0,0 +1,244 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kcolorbutton.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdepopupmenu.h> +#include <kseparator.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "editortoolsettings.h" +#include "perspectivewidget.h" +#include "perspectivetool.h" +#include "perspectivetool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamPerspectiveImagesPlugin +{ + +PerspectiveTool::PerspectiveTool(TQObject* parent) + : EditorTool(parent) +{ + setName("perspective"); + setToolName(i18n("Perspective")); + setToolIcon(SmallIcon("perspective")); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(0); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l = new TQVBoxLayout(frame, 5, 0); + m_previewWidget = new PerspectiveWidget(525, 350, frame); + l->addWidget(m_previewWidget); + TQWhatsThis::add(m_previewWidget, i18n("<p>This is the perspective transformation operation preview. " + "You can use the mouse for dragging the corner to adjust the " + "perspective transformation area.")); + setToolView(frame); + + // ------------------------------------------------------------- + + TQString temp; + Digikam::ImageIface iface(0, 0); + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout *gridLayout = new TQGridLayout( m_gboxSettings->plainPage(), 13, 2); + + TQLabel *label1 = new TQLabel(i18n("New width:"), m_gboxSettings->plainPage()); + m_newWidthLabel = new TQLabel(temp.setNum( iface.originalWidth()) + i18n(" px"), m_gboxSettings->plainPage()); + m_newWidthLabel->setAlignment( AlignBottom | AlignRight ); + + TQLabel *label2 = new TQLabel(i18n("New height:"), m_gboxSettings->plainPage()); + m_newHeightLabel = new TQLabel(temp.setNum( iface.originalHeight()) + i18n(" px"), m_gboxSettings->plainPage()); + m_newHeightLabel->setAlignment( AlignBottom | AlignRight ); + + // ------------------------------------------------------------- + + KSeparator *line = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + TQLabel *angleLabel = new TQLabel(i18n("Angles (in degrees):"), m_gboxSettings->plainPage()); + TQLabel *label3 = new TQLabel(i18n(" Top left:"), m_gboxSettings->plainPage()); + m_topLeftAngleLabel = new TQLabel(m_gboxSettings->plainPage()); + TQLabel *label4 = new TQLabel(i18n(" Top right:"), m_gboxSettings->plainPage()); + m_topRightAngleLabel = new TQLabel(m_gboxSettings->plainPage()); + TQLabel *label5 = new TQLabel(i18n(" Bottom left:"), m_gboxSettings->plainPage()); + m_bottomLeftAngleLabel = new TQLabel(m_gboxSettings->plainPage()); + TQLabel *label6 = new TQLabel(i18n(" Bottom right:"), m_gboxSettings->plainPage()); + m_bottomRightAngleLabel = new TQLabel(m_gboxSettings->plainPage()); + + // ------------------------------------------------------------- + + KSeparator *line2 = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + m_drawWhileMovingCheckBox = new TQCheckBox(i18n("Draw preview while moving"), m_gboxSettings->plainPage()); + gridLayout->addMultiCellWidget(line2, 8, 8, 0, 2); + gridLayout->addMultiCellWidget(m_drawWhileMovingCheckBox, 9, 9, 0, 2); + + m_drawGridCheckBox = new TQCheckBox(i18n("Draw grid"), m_gboxSettings->plainPage()); + + // ------------------------------------------------------------- + + TQLabel *label7 = new TQLabel(i18n("Guide color:"), m_gboxSettings->plainPage()); + m_guideColorBt = new KColorButton( TQColor( TQt::red ), m_gboxSettings->plainPage() ); + TQWhatsThis::add( m_guideColorBt, i18n("<p>Set here the color used to draw guides dashed-lines.")); + gridLayout->addMultiCellWidget(label7, 11, 11, 0, 0); + gridLayout->addMultiCellWidget(m_guideColorBt, 11, 11, 2, 2); + + TQLabel *label8 = new TQLabel(i18n("Guide width:"), m_gboxSettings->plainPage()); + m_guideSize = new RIntNumInput(m_gboxSettings->plainPage()); + m_guideSize->input()->setRange(1, 5, 1, false); + m_guideSize->setDefaultValue(1); + TQWhatsThis::add( m_guideSize, i18n("<p>Set here the width in pixels used to draw guides dashed-lines.")); + + gridLayout->addMultiCellWidget(label1, 0, 0, 0, 0); + gridLayout->addMultiCellWidget(m_newWidthLabel, 0, 0, 1, 2); + gridLayout->addMultiCellWidget(label2, 1, 1, 0, 0); + gridLayout->addMultiCellWidget(m_newHeightLabel, 1, 1, 1, 2); + gridLayout->addMultiCellWidget(line, 2, 2, 0, 2); + gridLayout->addMultiCellWidget(angleLabel, 3, 3, 0, 2); + gridLayout->addMultiCellWidget(label3, 4, 4, 0, 0); + gridLayout->addMultiCellWidget(m_topLeftAngleLabel, 4, 4, 1, 2); + gridLayout->addMultiCellWidget(label4, 5, 5, 0, 0); + gridLayout->addMultiCellWidget(m_topRightAngleLabel, 5, 5, 1, 2); + gridLayout->addMultiCellWidget(label5, 6, 6, 0, 0); + gridLayout->addMultiCellWidget(m_bottomLeftAngleLabel, 6, 6, 1, 2); + gridLayout->addMultiCellWidget(label6, 7, 7, 0, 0); + gridLayout->addMultiCellWidget(m_bottomRightAngleLabel, 7, 7, 1, 2); + gridLayout->addMultiCellWidget(m_drawGridCheckBox, 10, 10, 0, 2); + gridLayout->addMultiCellWidget(label8, 12, 12, 0, 0); + gridLayout->addMultiCellWidget(m_guideSize, 12, 12, 2, 2); + gridLayout->setColStretch(1, 10); + gridLayout->setRowStretch(13, 10); + gridLayout->setMargin(m_gboxSettings->spacingHint()); + gridLayout->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_previewWidget, TQ_SIGNAL(signalPerspectiveChanged(TQRect, float, float, float, float)), + this, TQ_SLOT(slotUpdateInfo(TQRect, float, float, float, float))); + + connect(m_drawWhileMovingCheckBox, TQ_SIGNAL(toggled(bool)), + m_previewWidget, TQ_SLOT(slotToggleDrawWhileMoving(bool))); + + connect(m_drawGridCheckBox, TQ_SIGNAL(toggled(bool)), + m_previewWidget, TQ_SLOT(slotToggleDrawGrid(bool))); + + connect(m_guideColorBt, TQ_SIGNAL(changed(const TQColor&)), + m_previewWidget, TQ_SLOT(slotChangeGuideColor(const TQColor&))); + + connect(m_guideSize, TQ_SIGNAL(valueChanged(int)), + m_previewWidget, TQ_SLOT(slotChangeGuideSize(int))); +} + +PerspectiveTool::~PerspectiveTool() +{ +} + +void PerspectiveTool::readSettings() +{ + TQColor defaultGuideColor(TQt::red); + TDEConfig *config = kapp->config(); + config->setGroup("perspective Tool"); + m_drawWhileMovingCheckBox->setChecked(config->readBoolEntry("Draw While Moving", true)); + m_drawGridCheckBox->setChecked(config->readBoolEntry("Draw Grid", false)); + m_guideColorBt->setColor(config->readColorEntry("Guide Color", &defaultGuideColor)); + m_guideSize->setValue(config->readNumEntry("Guide Width", m_guideSize->defaultValue())); + m_previewWidget->slotToggleDrawWhileMoving(m_drawWhileMovingCheckBox->isChecked()); + m_previewWidget->slotToggleDrawGrid(m_drawGridCheckBox->isChecked()); + m_previewWidget->slotChangeGuideColor(m_guideColorBt->color()); + m_previewWidget->slotChangeGuideSize(m_guideSize->value()); +} + +void PerspectiveTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("perspective Tool"); + config->writeEntry("Draw While Moving", m_drawWhileMovingCheckBox->isChecked()); + config->writeEntry("Draw Grid", m_drawGridCheckBox->isChecked()); + config->writeEntry("Guide Color", m_guideColorBt->color()); + config->writeEntry("Guide Width", m_guideSize->value()); + config->sync(); +} + +void PerspectiveTool::slotResetSettings() +{ + m_previewWidget->reset(); +} + +void PerspectiveTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + m_previewWidget->applyPerspectiveAdjustment(); + kapp->restoreOverrideCursor(); +} + +void PerspectiveTool::slotUpdateInfo(TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle) +{ + TQString temp; + m_newWidthLabel->setText(temp.setNum( newSize.width()) + i18n(" px") ); + m_newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") ); + + m_topLeftAngleLabel->setText(temp.setNum( topLeftAngle, 'f', 1 )); + m_topRightAngleLabel->setText(temp.setNum( topRightAngle, 'f', 1 )); + m_bottomLeftAngleLabel->setText(temp.setNum( bottomLeftAngle, 'f', 1 )); + m_bottomRightAngleLabel->setText(temp.setNum( bottomRightAngle, 'f', 1 )); +} + +} // NameSpace DigikamPerspectiveImagesPlugin diff --git a/src/imageplugins/perspective/perspectivetool.h b/src/imageplugins/perspective/perspectivetool.h new file mode 100644 index 00000000..6186712f --- /dev/null +++ b/src/imageplugins/perspective/perspectivetool.h @@ -0,0 +1,100 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective. + * + * Copyright (C) 2005-2008 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_PERSPECTIVE_H +#define IMAGEEFFECT_PERSPECTIVE_H + +// TQt includes. + +#include <tqrect.h> + +// Digikam includes. + +#include "editortool.h" + +class TQLabel; +class TQCheckBox; + +class KColorButton; + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +} + +namespace DigikamPerspectiveImagesPlugin +{ + +class PerspectiveWidget; + +class PerspectiveTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + PerspectiveTool(TQObject* parent); + ~PerspectiveTool(); + +private slots: + + void slotResetSettings(); + void slotUpdateInfo(TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + +private: + + TQLabel *m_newWidthLabel; + TQLabel *m_newHeightLabel; + TQLabel *m_topLeftAngleLabel; + TQLabel *m_topRightAngleLabel; + TQLabel *m_bottomLeftAngleLabel; + TQLabel *m_bottomRightAngleLabel; + + TQCheckBox *m_drawWhileMovingCheckBox; + TQCheckBox *m_drawGridCheckBox; + + KDcrawIface::RIntNumInput *m_guideSize; + + KColorButton *m_guideColorBt; + + PerspectiveWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamPerspectiveImagesPlugin + +#endif /* IMAGEEFFECT_PERSPECTIVE_H */ diff --git a/src/imageplugins/perspective/perspectivewidget.cpp b/src/imageplugins/perspective/perspectivewidget.cpp new file mode 100644 index 00000000..ae2c5c03 --- /dev/null +++ b/src/imageplugins/perspective/perspectivewidget.cpp @@ -0,0 +1,839 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-18 + * Description : a widget class to edit perspective. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Matrix3 implementation inspired from gimp 2.0 + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + * + * ============================================================ */ + +// C++ includes. + +#include <cstdio> +#include <cstdlib> +#include <cmath> + +// TQt includes. + +#include <tqregion.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqbrush.h> +#include <tqpixmap.h> +#include <tqimage.h> +#include <tqpointarray.h> + +// KDE includes. + +#include <kstandarddirs.h> +#include <kcursor.h> +#include <tdeglobal.h> +#include <tdeapplication.h> + +// Local includes. + +#include "triangle.h" +#include "ddebug.h" +#include "imageiface.h" +#include "dimgimagefilters.h" +#include "perspectivewidget.h" +#include "perspectivewidget.moc" + +namespace DigikamPerspectiveImagesPlugin +{ + +PerspectiveWidget::PerspectiveWidget(int w, int h, TQWidget *parent) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + setBackgroundMode(TQt::NoBackground); + setMinimumSize(w, h); + setMouseTracking(true); + + m_drawGrid = false; + m_drawWhileMoving = true; + m_currentResizing = ResizingNone; + m_guideColor = TQt::red; + m_guideSize = 1; + + m_iface = new Digikam::ImageIface(w, h); + uchar *data = m_iface->setPreviewImageSize(w, h); + m_w = m_iface->previewWidth(); + m_h = m_iface->previewHeight(); + m_origW = m_iface->originalWidth(); + m_origH = m_iface->originalHeight(); + m_previewImage = Digikam::DImg(m_w, m_h, m_iface->previewSixteenBit(), m_iface->previewHasAlpha(), data, false); + + m_pixmap = new TQPixmap(w, h); + + m_rect = TQRect(w/2-m_w/2, h/2-m_h/2, m_w, m_h); + m_grid = TQPointArray(60); + + reset(); +} + +PerspectiveWidget::~PerspectiveWidget() +{ + delete m_iface; + delete m_pixmap; +} + +Digikam::ImageIface* PerspectiveWidget::imageIface() +{ + return m_iface; +} + +TQPoint PerspectiveWidget::getTopLeftCorner(void) +{ + return TQPoint( lroundf((float)(m_topLeftPoint.x()*m_origW) / (float)m_w), + lroundf((float)(m_topLeftPoint.y()*m_origH) / (float)m_h)); +} + +TQPoint PerspectiveWidget::getTopRightCorner(void) +{ + return TQPoint( lroundf((float)(m_topRightPoint.x()*m_origW) / (float)m_w), + lroundf((float)(m_topRightPoint.y()*m_origH) / (float)m_h)); +} + +TQPoint PerspectiveWidget::getBottomLeftCorner(void) +{ + return TQPoint( lroundf((float)(m_bottomLeftPoint.x()*m_origW) / (float)m_w), + lroundf((float)(m_bottomLeftPoint.y()*m_origH) / (float)m_h)); +} + +TQPoint PerspectiveWidget::getBottomRightCorner(void) +{ + return TQPoint( lroundf((float)(m_bottomRightPoint.x()*m_origW) / (float)m_w), + lroundf((float)(m_bottomRightPoint.y()*m_origH) / (float)m_h)); +} + +TQRect PerspectiveWidget::getTargetSize(void) +{ + TQPointArray perspectiveArea; + + perspectiveArea.putPoints( 0, 4, + getTopLeftCorner().x(), getTopLeftCorner().y(), + getTopRightCorner().x(), getTopRightCorner().y(), + getBottomRightCorner().x(), getBottomRightCorner().y(), + getBottomLeftCorner().x(), getBottomLeftCorner().y() ); + + return perspectiveArea.boundingRect(); +} + +float PerspectiveWidget::getAngleTopLeft(void) +{ + Triangle topLeft(getTopLeftCorner(), getTopRightCorner(), getBottomLeftCorner()); + return topLeft.angleBAC(); +} + +float PerspectiveWidget::getAngleTopRight(void) +{ + Triangle topLeft(getTopRightCorner(), getBottomRightCorner(), getTopLeftCorner()); + return topLeft.angleBAC(); +} + +float PerspectiveWidget::getAngleBottomLeft(void) +{ + Triangle topLeft(getBottomLeftCorner(), getTopLeftCorner(), getBottomRightCorner()); + return topLeft.angleBAC(); +} + +float PerspectiveWidget::getAngleBottomRight(void) +{ + Triangle topLeft(getBottomRightCorner(), getBottomLeftCorner(), getTopRightCorner()); + return topLeft.angleBAC(); +} + +void PerspectiveWidget::reset(void) +{ + m_topLeftPoint.setX(0); + m_topLeftPoint.setY(0); + + m_topRightPoint.setX(m_w-1); + m_topRightPoint.setY(0); + + m_bottomLeftPoint.setX(0); + m_bottomLeftPoint.setY(m_h-1); + + m_bottomRightPoint.setX(m_w-1); + m_bottomRightPoint.setY(m_h-1); + + m_spot.setX(m_w / 2); + m_spot.setY(m_h / 2); + + m_antiAlias = true; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::applyPerspectiveAdjustment(void) +{ + Digikam::DImg *orgImage = m_iface->getOriginalImg(); + Digikam::DImg destImage(orgImage->width(), orgImage->height(), orgImage->sixteenBit(), orgImage->hasAlpha()); + + Digikam::DColor background(0, 0, 0, orgImage->hasAlpha() ? 0 : 255, orgImage->sixteenBit()); + + // Perform perspective adjustment. + + buildPerspective(TQPoint(0, 0), TQPoint(m_origW, m_origH), + getTopLeftCorner(), getTopRightCorner(), + getBottomLeftCorner(), getBottomRightCorner(), + orgImage, &destImage, background); + + // Perform an auto-croping around the image. + + Digikam::DImg targetImg = destImage.copy(getTargetSize()); + + // Update target image. + m_iface->putOriginalImage(i18n("Perspective Adjustment"), + targetImg.bits(), targetImg.width(), targetImg.height()); +} + +void PerspectiveWidget::slotToggleAntiAliasing(bool a) +{ + m_antiAlias = a; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::slotToggleDrawWhileMoving(bool draw) +{ + m_drawWhileMoving = draw; +} + +void PerspectiveWidget::slotToggleDrawGrid(bool grid) +{ + m_drawGrid = grid; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::slotChangeGuideColor(const TQColor &color) +{ + m_guideColor = color; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::slotChangeGuideSize(int size) +{ + m_guideSize = size; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::updatePixmap(void) +{ + m_topLeftCorner.setRect(m_topLeftPoint.x() + m_rect.topLeft().x(), + m_topLeftPoint.y() + m_rect.topLeft().y(), 8, 8); + m_topRightCorner.setRect(m_topRightPoint.x() - 7 + m_rect.topLeft().x(), + m_topRightPoint.y() + m_rect.topLeft().y(), 8, 8); + m_bottomLeftCorner.setRect(m_bottomLeftPoint.x() + m_rect.topLeft().x(), + m_bottomLeftPoint.y() - 7 + m_rect.topLeft().y(), 8, 8); + m_bottomRightCorner.setRect(m_bottomRightPoint.x() - 7 + m_rect.topLeft().x(), + m_bottomRightPoint.y() - 7 + m_rect.topLeft().y(), 8, 8); + + // Compute the grid array + + int gXS = m_w / 15; + int gYS = m_h / 15; + + for (int i = 0 ; i < 15 ; i++) + { + int j = i*4; + + //Horizontal line. + m_grid.setPoint(j , 0, i*gYS); + m_grid.setPoint(j+1, m_w, i*gYS); + + //Vertical line. + m_grid.setPoint(j+2, i*gXS, 0); + m_grid.setPoint(j+3, i*gXS, m_h); + } + + // Draw background + + m_pixmap->fill(colorGroup().background()); + + // if we are resizing with the mouse, compute and draw only if drawWhileMoving is set + if (m_currentResizing == ResizingNone || m_drawWhileMoving) + { + // Create preview image + + Digikam::DImg destImage(m_previewImage.width(), m_previewImage.height(), + m_previewImage.sixteenBit(), m_previewImage.hasAlpha()); + + Digikam::DColor background(colorGroup().background()); + + m_transformedCenter = buildPerspective(TQPoint(0, 0), TQPoint(m_w, m_h), + m_topLeftPoint, m_topRightPoint, + m_bottomLeftPoint, m_bottomRightPoint, + &m_previewImage, &destImage, background); + + m_iface->putPreviewImage(destImage.bits()); + + // Draw image + + m_iface->paint(m_pixmap, m_rect.x(), m_rect.y(), + m_rect.width(), m_rect.height()); + } + else + { + m_transformedCenter = buildPerspective(TQPoint(0, 0), TQPoint(m_w, m_h), + m_topLeftPoint, m_topRightPoint, + m_bottomLeftPoint, m_bottomRightPoint); + } + + // Drawing selection borders. + + TQPainter p(m_pixmap); + p.setPen(TQPen(TQColor(255, 64, 64), 1, TQt::SolidLine)); + p.drawLine(m_topLeftPoint+m_rect.topLeft(), m_topRightPoint+m_rect.topLeft()); + p.drawLine(m_topRightPoint+m_rect.topLeft(), m_bottomRightPoint+m_rect.topLeft()); + p.drawLine(m_bottomRightPoint+m_rect.topLeft(), m_bottomLeftPoint+m_rect.topLeft()); + p.drawLine(m_bottomLeftPoint+m_rect.topLeft(), m_topLeftPoint+m_rect.topLeft()); + + // Drawing selection corners. + + TQBrush brush(TQColor(255, 64, 64)); + p.fillRect(m_topLeftCorner, brush); + p.fillRect(m_topRightCorner, brush); + p.fillRect(m_bottomLeftCorner, brush); + p.fillRect(m_bottomRightCorner, brush); + + // Drawing the grid. + + if (m_drawGrid) + { + for (uint i = 0 ; i < m_grid.size() ; i += 4) + { + //Horizontal line. + p.drawLine(m_grid.point(i)+m_rect.topLeft(), m_grid.point(i+1)+m_rect.topLeft()); + + //Vertical line. + p.drawLine(m_grid.point(i+2)+m_rect.topLeft(), m_grid.point(i+3)+m_rect.topLeft()); + } + } + + // Drawing transformed center. + + p.setPen(TQPen(TQColor(255, 64, 64), 3, TQt::SolidLine)); + p.drawEllipse( m_transformedCenter.x()+m_rect.topLeft().x()-2, + m_transformedCenter.y()+m_rect.topLeft().y()-2, 4, 4 ); + + // Drawing vertical and horizontal guide lines. + + int xspot = m_spot.x() + m_rect.x(); + int yspot = m_spot.y() + m_rect.y(); + p.setPen(TQPen(TQt::white, m_guideSize, TQt::SolidLine)); + p.drawLine(xspot, m_rect.top(), xspot, m_rect.bottom()); + p.drawLine(m_rect.left(), yspot, m_rect.right(), yspot); + p.setPen(TQPen(m_guideColor, m_guideSize, TQt::DotLine)); + p.drawLine(xspot, m_rect.top(), xspot, m_rect.bottom()); + p.drawLine(m_rect.left(), yspot, m_rect.right(), yspot); + + p.end(); + + emit signalPerspectiveChanged(getTargetSize(), getAngleTopLeft(), getAngleTopRight(), + getAngleBottomLeft(), getAngleBottomRight()); +} + +TQPoint PerspectiveWidget::buildPerspective(TQPoint orignTopLeft, TQPoint orignBottomRight, + TQPoint transTopLeft, TQPoint transTopRight, + TQPoint transBottomLeft, TQPoint transBottomRight, + Digikam::DImg *orgImage, Digikam::DImg *destImage, + Digikam::DColor background) +{ + Matrix matrix, transform; + double scalex; + double scaley; + + double x1 = (double)orignTopLeft.x(); + double y1 = (double)orignTopLeft.y(); + + double x2 = (double)orignBottomRight.x(); + double y2 = (double)orignBottomRight.y(); + + double tx1 = (double)transTopLeft.x(); + double ty1 = (double)transTopLeft.y(); + + double tx2 = (double)transTopRight.x(); + double ty2 = (double)transTopRight.y(); + + double tx3 = (double)transBottomLeft.x(); + double ty3 = (double)transBottomLeft.y(); + + double tx4 = (double)transBottomRight.x(); + double ty4 = (double)transBottomRight.y(); + + scalex = scaley = 1.0; + + if ((x2 - x1) > 0) + scalex = 1.0 / (double) (x2 - x1); + + if ((y2 - y1) > 0) + scaley = 1.0 / (double) (y2 - y1); + + // Determine the perspective transform that maps from + // the unit cube to the transformed coordinates + + double dx1, dx2, dx3, dy1, dy2, dy3; + + dx1 = tx2 - tx4; + dx2 = tx3 - tx4; + dx3 = tx1 - tx2 + tx4 - tx3; + + dy1 = ty2 - ty4; + dy2 = ty3 - ty4; + dy3 = ty1 - ty2 + ty4 - ty3; + + // Is the mapping affine? + + if ((dx3 == 0.0) && (dy3 == 0.0)) + { + matrix.coeff[0][0] = tx2 - tx1; + matrix.coeff[0][1] = tx4 - tx2; + matrix.coeff[0][2] = tx1; + matrix.coeff[1][0] = ty2 - ty1; + matrix.coeff[1][1] = ty4 - ty2; + matrix.coeff[1][2] = ty1; + matrix.coeff[2][0] = 0.0; + matrix.coeff[2][1] = 0.0; + } + else + { + double det1, det2; + + det1 = dx3 * dy2 - dy3 * dx2; + det2 = dx1 * dy2 - dy1 * dx2; + + if (det1 == 0.0 && det2 == 0.0) + matrix.coeff[2][0] = 1.0; + else + matrix.coeff[2][0] = det1 / det2; + + det1 = dx1 * dy3 - dy1 * dx3; + + if (det1 == 0.0 && det2 == 0.0) + matrix.coeff[2][1] = 1.0; + else + matrix.coeff[2][1] = det1 / det2; + + matrix.coeff[0][0] = tx2 - tx1 + matrix.coeff[2][0] * tx2; + matrix.coeff[0][1] = tx3 - tx1 + matrix.coeff[2][1] * tx3; + matrix.coeff[0][2] = tx1; + + matrix.coeff[1][0] = ty2 - ty1 + matrix.coeff[2][0] * ty2; + matrix.coeff[1][1] = ty3 - ty1 + matrix.coeff[2][1] * ty3; + matrix.coeff[1][2] = ty1; + } + + matrix.coeff[2][2] = 1.0; + + // transform is initialized to the identity matrix + transform.translate(-x1, -y1); + transform.scale (scalex, scaley); + transform.multiply (matrix); + + // Compute perspective transformation to image if image data containers exist. + if (orgImage && destImage) + transformAffine(orgImage, destImage, transform, background); + + // Calculate the grid array points. + double newX, newY; + for (uint i = 0 ; i < m_grid.size() ; i++) + { + transform.transformPoint(m_grid.point(i).x(), m_grid.point(i).y(), &newX, &newY); + m_grid.setPoint(i, lround(newX), lround(newY)); + } + + // Calculate and return new image center. + double newCenterX, newCenterY; + transform.transformPoint(x2/2.0, y2/2.0, &newCenterX, &newCenterY); + + return TQPoint(lround(newCenterX), lround(newCenterY)); +} + +void PerspectiveWidget::transformAffine(Digikam::DImg *orgImage, Digikam::DImg *destImage, + const Matrix &matrix, Digikam::DColor background) +{ + Matrix m(matrix), inv(matrix); + + int x1, y1, x2, y2; // target bounding box + int x, y; // target coordinates + int u1, v1, u2, v2; // source bounding box + double uinc, vinc, winc; // increments in source coordinates + // pr horizontal target coordinate + + double u[5],v[5]; // source coordinates, + // 2 + // / \ 0 is sample in the center of pixel + // 1 0 3 1..4 is offset 1 pixel in each + // \ / direction (in target space) + // 4 + + double tu[5],tv[5],tw[5]; // undivided source coordinates and divisor + + uchar *data, *newData; + bool sixteenBit; + int coords; + int width, height; + int bytesDepth; + int offset; + uchar *dest, *d; + Digikam::DColor color; + + bytesDepth = orgImage->bytesDepth(); + data = orgImage->bits(); + sixteenBit = orgImage->sixteenBit(); + width = orgImage->width(); + height = orgImage->height(); + newData = destImage->bits(); + + if (sixteenBit) + background.convertToSixteenBit(); + + //destImage->fill(background); + + Digikam::DImgImageFilters filters; + + // Find the inverse of the transformation matrix + m.invert(); + + u1 = 0; + v1 = 0; + u2 = u1 + width; + v2 = v1 + height; + + x1 = u1; + y1 = v1; + x2 = u2; + y2 = v2; + + dest = new uchar[width * bytesDepth]; + + uinc = m.coeff[0][0]; + vinc = m.coeff[1][0]; + winc = m.coeff[2][0]; + + coords = 1; + + // these loops could be rearranged, depending on which bit of code + // you'd most like to write more than once. + + for (y = y1; y < y2; y++) + { + // set up inverse transform steps + + tu[0] = uinc * (x1 + 0.5) + m.coeff[0][1] * (y + 0.5) + m.coeff[0][2] - 0.5; + tv[0] = vinc * (x1 + 0.5) + m.coeff[1][1] * (y + 0.5) + m.coeff[1][2] - 0.5; + tw[0] = winc * (x1 + 0.5) + m.coeff[2][1] * (y + 0.5) + m.coeff[2][2]; + + d = dest; + + for (x = x1; x < x2; x++) + { + int i; // normalize homogeneous coords + + for (i = 0; i < coords; i++) + { + if (tw[i] == 1.0) + { + u[i] = tu[i]; + v[i] = tv[i]; + } + else if (tw[i] != 0.0) + { + u[i] = tu[i] / tw[i]; + v[i] = tv[i] / tw[i]; + } + else + { + DDebug() << "homogeneous coordinate = 0...\n" << endl; + } + } + + // Set the destination pixels + + int iu = lround( u [0] ); + int iv = lround( v [0] ); + + if (iu >= u1 && iu < u2 && iv >= v1 && iv < v2) + { + // u, v coordinates into source + + int u = iu - u1; + int v = iv - v1; + + //TODO: Check why antialiasing shows no effect + /*if (m_antiAlias) + { + if (sixteenBit) + { + unsigned short *d16 = (unsigned short *)d; + filters.pixelAntiAliasing16((unsigned short *)data, + width, height, u, v, d16+3, d16+2, d16+1, d16); + } + else + { + filters.pixelAntiAliasing(data, width, height, u, v, + d+3, d+2, d+1, d); + } + } + else + {*/ + offset = (v * width * bytesDepth) + (u * bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(d); + //} + + d += bytesDepth; + } + else // not in source range + { + // set to background color + + background.setPixel(d); + d += bytesDepth; + } + + for (i = 0; i < coords; i++) + { + tu[i] += uinc; + tv[i] += vinc; + tw[i] += winc; + } + } + + // set the pixel region row + + offset = (y - y1) * width * bytesDepth; + memcpy(newData + offset, dest, width * bytesDepth); + } + + delete [] dest; +} + +void PerspectiveWidget::paintEvent( TQPaintEvent * ) +{ + bitBlt(this, 0, 0, m_pixmap); +} + +void PerspectiveWidget::resizeEvent(TQResizeEvent * e) +{ + int old_w = m_w; + int old_h = m_h; + + delete m_pixmap; + int w = e->size().width(); + int h = e->size().height(); + uchar *data = m_iface->setPreviewImageSize(w, h); + m_w = m_iface->previewWidth(); + m_h = m_iface->previewHeight(); + m_previewImage = Digikam::DImg(m_w, m_h, m_iface->previewSixteenBit(), m_iface->previewHasAlpha(), data, false); + + m_pixmap = new TQPixmap(w, h); + TQRect oldRect = m_rect; + m_rect = TQRect(w/2-m_w/2, h/2-m_h/2, m_w, m_h); + + float xFactor = (float)m_rect.width()/(float)(oldRect.width()); + float yFactor = (float)m_rect.height()/(float)(oldRect.height()); + + m_topLeftPoint = TQPoint(lroundf(m_topLeftPoint.x()*xFactor), + lroundf(m_topLeftPoint.y()*yFactor)); + m_topRightPoint = TQPoint(lroundf(m_topRightPoint.x()*xFactor), + lroundf(m_topRightPoint.y()*yFactor)); + m_bottomLeftPoint = TQPoint(lroundf(m_bottomLeftPoint.x()*xFactor), + lroundf(m_bottomLeftPoint.y()*yFactor)); + m_bottomRightPoint = TQPoint(lroundf(m_bottomRightPoint.x()*xFactor), + lroundf(m_bottomRightPoint.y()*yFactor)); + m_transformedCenter = TQPoint(lroundf(m_transformedCenter.x()*xFactor), + lroundf(m_transformedCenter.y()*yFactor)); + + m_spot.setX((int)((float)m_spot.x() * ( (float)m_w / (float)old_w))); + m_spot.setY((int)((float)m_spot.y() * ( (float)m_h / (float)old_h))); + + updatePixmap(); +} + +void PerspectiveWidget::mousePressEvent ( TQMouseEvent * e ) +{ + if ( e->button() == TQt::LeftButton && + m_rect.contains( e->x(), e->y() )) + { + if ( m_topLeftCorner.contains( e->x(), e->y() ) ) + m_currentResizing = ResizingTopLeft; + else if ( m_bottomRightCorner.contains( e->x(), e->y() ) ) + m_currentResizing = ResizingBottomRight; + else if ( m_topRightCorner.contains( e->x(), e->y() ) ) + m_currentResizing = ResizingTopRight; + else if ( m_bottomLeftCorner.contains( e->x(), e->y() ) ) + m_currentResizing = ResizingBottomLeft; + else + { + m_spot.setX(e->x()-m_rect.x()); + m_spot.setY(e->y()-m_rect.y()); + } + } +} + +void PerspectiveWidget::mouseReleaseEvent ( TQMouseEvent * e ) +{ + if ( m_currentResizing != ResizingNone ) + { + unsetCursor(); + m_currentResizing = ResizingNone; + + // in this case, the pixmap has not been drawn on mouse move + if (!m_drawWhileMoving) + { + updatePixmap(); + repaint(false); + } + } + else + { + m_spot.setX(e->x()-m_rect.x()); + m_spot.setY(e->y()-m_rect.y()); + updatePixmap(); + repaint(false); + } +} + +void PerspectiveWidget::mouseMoveEvent ( TQMouseEvent * e ) +{ + if ( e->state() == TQt::LeftButton ) + { + if ( m_currentResizing != ResizingNone ) + { + TQPointArray unsablePoints; + TQPoint pm(e->x(), e->y()); + + if (!m_rect.contains( pm )) + { + if (pm.x() > m_rect.right()) + pm.setX(m_rect.right()); + else if (pm.x() < m_rect.left()) + pm.setX(m_rect.left()); + + if (pm.y() > m_rect.bottom()) + pm.setY(m_rect.bottom()); + else if (pm.y() < m_rect.top()) + pm.setY(m_rect.top()); + } + + if ( m_currentResizing == ResizingTopLeft ) + { + unsablePoints.putPoints(0, 7, + m_w-1, m_h-1, + 0, m_h-1, + 0, m_bottomLeftPoint.y()-10, + m_bottomLeftPoint.x(), m_bottomLeftPoint.y()-10, + m_topRightPoint.x()-10, m_topRightPoint.y(), + m_topRightPoint.x()-10, 0, + m_w-1, 0 ); + TQRegion unsableArea(unsablePoints); + + if ( unsableArea.contains(pm) ) return; + + m_topLeftPoint = pm - m_rect.topLeft(); + setCursor( KCursor::sizeFDiagCursor() ); + } + + else if ( m_currentResizing == ResizingTopRight ) + { + unsablePoints.putPoints(0, 7, + 0, m_h-1, + 0, 0, + m_topLeftPoint.x()+10, 0, + m_topLeftPoint.x()+10, m_topLeftPoint.y(), + m_bottomRightPoint.x(), m_bottomRightPoint.y()-10, + m_w-1, m_bottomRightPoint.y()-10, + m_w-1, m_h-1); + TQRegion unsableArea(unsablePoints); + + if ( unsableArea.contains(pm) ) return; + + m_topRightPoint = pm - m_rect.topLeft(); + setCursor( KCursor::sizeBDiagCursor() ); + } + + else if ( m_currentResizing == ResizingBottomLeft ) + { + unsablePoints.putPoints(0, 7, + m_w-1, 0, + m_w-1, m_h-1, + m_bottomRightPoint.x()-10, m_h-1, + m_bottomRightPoint.x()-10, m_bottomRightPoint.y()+10, + m_topLeftPoint.x(), m_topLeftPoint.y()+10, + 0, m_topLeftPoint.y(), + 0, 0); + TQRegion unsableArea(unsablePoints); + + if ( unsableArea.contains(pm) ) return; + + m_bottomLeftPoint = pm - m_rect.topLeft(); + setCursor( KCursor::sizeBDiagCursor() ); + } + + else if ( m_currentResizing == ResizingBottomRight ) + { + unsablePoints.putPoints(0, 7, + 0, 0, + m_w-1, 0, + m_w-1, m_topRightPoint.y()+10, + m_topRightPoint.x(), m_topRightPoint.y()+10, + m_bottomLeftPoint.x()+10, m_bottomLeftPoint.y(), + m_bottomLeftPoint.x()+10, m_w-1, + 0, m_w-1); + TQRegion unsableArea(unsablePoints); + + if ( unsableArea.contains(pm) ) return; + + m_bottomRightPoint = pm - m_rect.topLeft(); + setCursor( KCursor::sizeFDiagCursor() ); + } + + else + { + m_spot.setX(e->x()-m_rect.x()); + m_spot.setY(e->y()-m_rect.y()); + } + + updatePixmap(); + repaint(false); + } + } + else + { + if ( m_topLeftCorner.contains( e->x(), e->y() ) || + m_bottomRightCorner.contains( e->x(), e->y() ) ) + setCursor( KCursor::sizeFDiagCursor() ); + + else if ( m_topRightCorner.contains( e->x(), e->y() ) || + m_bottomLeftCorner.contains( e->x(), e->y() ) ) + setCursor( KCursor::sizeBDiagCursor() ); + else + unsetCursor(); + } +} + +} // NameSpace DigikamPerspectiveImagesPlugin + diff --git a/src/imageplugins/perspective/perspectivewidget.h b/src/imageplugins/perspective/perspectivewidget.h new file mode 100644 index 00000000..0047c3e8 --- /dev/null +++ b/src/imageplugins/perspective/perspectivewidget.h @@ -0,0 +1,172 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-18 + * Description : a widget class to edit perspective. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef PERSPECTIVEWIDGET_H +#define PERSPECTIVEWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqpoint.h> +#include <tqpointarray.h> +#include <tqcolor.h> +#include <tqrect.h> + +// Digikam includes. + +#include "dimg.h" + +// Local includes. + +#include "matrix.h" + +class TQPixmap; + +namespace Digikam +{ +class ImageIface; +} + +namespace DigikamPerspectiveImagesPlugin +{ + +class PerspectiveWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + PerspectiveWidget(int width, int height, TQWidget *parent=0); + ~PerspectiveWidget(); + + TQRect getTargetSize(void); + TQPoint getTopLeftCorner(void); + TQPoint getTopRightCorner(void); + TQPoint getBottomLeftCorner(void); + TQPoint getBottomRightCorner(void); + void reset(void); + + float getAngleTopLeft(void); + float getAngleTopRight(void); + float getAngleBottomLeft(void); + float getAngleBottomRight(void); + + void applyPerspectiveAdjustment(void); + + Digikam::ImageIface* imageIface(); + +public slots: + + void slotToggleAntiAliasing(bool a); + void slotToggleDrawWhileMoving(bool draw); + void slotToggleDrawGrid(bool grid); + + void slotChangeGuideColor(const TQColor &color); + void slotChangeGuideSize(int size); + +signals: + + void signalPerspectiveChanged( TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle ); + +protected: + + void paintEvent( TQPaintEvent *e ); + void resizeEvent( TQResizeEvent * e ); + void mousePressEvent ( TQMouseEvent * e ); + void mouseReleaseEvent ( TQMouseEvent * e ); + void mouseMoveEvent ( TQMouseEvent * e ); + +private: // Widget methods. + + void updatePixmap(void); + + void transformAffine(Digikam::DImg *orgImage, Digikam::DImg *destImage, + const Matrix &matrix, Digikam::DColor background); + + TQPoint buildPerspective(TQPoint orignTopLeft, TQPoint orignBottomRight, + TQPoint transTopLeft, TQPoint transTopRight, + TQPoint transBottomLeft, TQPoint transBottomRight, + Digikam::DImg *orgImage=0, Digikam::DImg *destImage=0, + Digikam::DColor background=Digikam::DColor()); + +private: + + enum ResizingMode + { + ResizingNone = 0, + ResizingTopLeft, + ResizingTopRight, + ResizingBottomLeft, + ResizingBottomRight + }; + + bool m_antiAlias; + bool m_drawWhileMoving; + bool m_drawGrid; + + uint *m_data; + int m_w; + int m_h; + int m_origW; + int m_origH; + + int m_currentResizing; + + int m_guideSize; + + TQRect m_rect; + + // Tranformed center area for mouse position control. + + TQPoint m_transformedCenter; + + // Draggable local region selection corners. + + TQRect m_topLeftCorner; + TQRect m_topRightCorner; + TQRect m_bottomLeftCorner; + TQRect m_bottomRightCorner; + + TQPoint m_topLeftPoint; + TQPoint m_topRightPoint; + TQPoint m_bottomLeftPoint; + TQPoint m_bottomRightPoint; + TQPoint m_spot; + + TQColor m_guideColor; + + // 60 points will be stored to compute a grid of 15x15 lines. + TQPointArray m_grid; + + TQPixmap *m_pixmap; + + Digikam::ImageIface *m_iface; + Digikam::DImg m_previewImage; +}; + +} // NameSpace DigikamPerspectiveImagesPlugin + +#endif /* PERSPECTIVEWIDGET_H */ diff --git a/src/imageplugins/perspective/triangle.cpp b/src/imageplugins/perspective/triangle.cpp new file mode 100644 index 00000000..84f80a07 --- /dev/null +++ b/src/imageplugins/perspective/triangle.cpp @@ -0,0 +1,65 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-18 + * Description : triangle geometry calculation class. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// C++ includes. + +#include <cstdio> +#include <cstdlib> +#include <cmath> + +// Local includes. + +#include "triangle.h" + +namespace DigikamPerspectiveImagesPlugin +{ + +Triangle::Triangle(TQPoint A, TQPoint B, TQPoint C) +{ + m_a = distanceP2P(B, C); + m_b = distanceP2P(A, C); + m_c = distanceP2P(A, B); +} + +float Triangle::angleABC(void) +{ + return( 57.295779513082 * acos( (m_b*m_b - m_a*m_a - m_c*m_c ) / (-2*m_a*m_c ) ) ); +} + +float Triangle::angleACB(void) +{ + return( 57.295779513082 * acos( (m_c*m_c - m_a*m_a - m_b*m_b ) / (-2*m_a*m_b ) ) ); +} + +float Triangle::angleBAC(void) +{ + return( 57.295779513082 * acos( (m_a*m_a - m_b*m_b - m_c*m_c ) / (-2*m_b*m_c ) ) ); +} + +float Triangle::distanceP2P(const TQPoint& p1, const TQPoint& p2) +{ + return(sqrt( abs( p2.x()-p1.x() ) * abs( p2.x()-p1.x() ) + + abs( p2.y()-p1.y() ) * abs( p2.y()-p1.y() ) )); +} + +} // NameSpace DigikamPerspectiveImagesPlugin diff --git a/src/imageplugins/perspective/triangle.h b/src/imageplugins/perspective/triangle.h new file mode 100644 index 00000000..27fcc087 --- /dev/null +++ b/src/imageplugins/perspective/triangle.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-18 + * Description : triangle geometry calculation class. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef TRIANGLE_H +#define TRIANGLE_H + +// TQt includes. + +#include <tqpoint.h> + +namespace DigikamPerspectiveImagesPlugin +{ + +class Triangle +{ + +public: + + Triangle(TQPoint A, TQPoint B, TQPoint C); + ~Triangle(){}; + + float angleABC(void); + float angleACB(void); + float angleBAC(void); + +private: + + float m_a; + float m_b; + float m_c; + + float distanceP2P(const TQPoint& p1, const TQPoint& p2); +}; + +} // NameSpace DigikamPerspectiveImagesPlugin + +#endif /* TRIANGLE_H */ |