Skip to content

Commit 721c41e

Browse files
authored
feat(iv): flip, rotate and save image (AcademySoftwareFoundation#5003)
Fixes AcademySoftwareFoundation#4715 - Added save functionality - Added flipping and rotation capabilities via metadata. - Hotkeys: Ctrl-Shift-R and L to rotate the image left and right. Note that the actual pixel data remains unchanged, so only image formats that support the rotation metadata will reflect the changes. I thought that it made sense for the flip and rotate to be under the tool section, similar to where the macbook Preview app places it. Keyboard shortcuts also follow the shortcuts that Preview uses. Tests Used a .jpeg photo to test: - saving - making changes with/without saving and re-opening the image - flipping and rotation from different initial rotation/mirrored states Otherwise there doesn't seem to be a test suite for iv? Signed-off-by: valery <71804886+vangeliq@users.noreply.github.com>
1 parent 0839a38 commit 721c41e

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

src/iv/imageviewer.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,22 @@ ImageViewer::createActions()
520520
closeupAvgPixelsBox->setToolTip(closeupAvgPixelsTooltip);
521521
closeupAvgPixelsLabel->setToolTip(closeupAvgPixelsTooltip);
522522

523+
524+
rotateLeftAct = new QAction(tr("&Rotate Left"), this);
525+
rotateLeftAct->setShortcut(tr("Ctrl+Shift+L"));
526+
connect(rotateLeftAct, SIGNAL(triggered()), this, SLOT(rotateLeft()));
527+
528+
rotateRightAct = new QAction(tr("&Rotate Right"), this);
529+
rotateRightAct->setShortcut(tr("Ctrl+Shift+R"));
530+
connect(rotateRightAct, SIGNAL(triggered()), this, SLOT(rotateRight()));
531+
532+
flipHorizontalAct = new QAction(tr("&Flip Horizontal"), this);
533+
connect(flipHorizontalAct, SIGNAL(triggered()), this,
534+
SLOT(flipHorizontal()));
535+
536+
flipVerticalAct = new QAction(tr("&Flip Vertical"), this);
537+
connect(flipVerticalAct, SIGNAL(triggered()), this, SLOT(flipVertical()));
538+
523539
// Connect signals to ensure closeupAvgPixelsBox value is always <= closeupPixelsBox value
524540
connect(closeupPixelsBox, QOverload<int>::of(&QSpinBox::valueChanged),
525541
[this](int value) {
@@ -780,6 +796,11 @@ ImageViewer::createMenus()
780796
toolsMenu->addAction(toggleAreaSampleAct);
781797
toolsMenu->addMenu(slideMenu);
782798
toolsMenu->addMenu(sortMenu);
799+
toolsMenu->addSeparator();
800+
toolsMenu->addAction(rotateLeftAct);
801+
toolsMenu->addAction(rotateRightAct);
802+
toolsMenu->addAction(flipHorizontalAct);
803+
toolsMenu->addAction(flipVerticalAct);
783804

784805
// Menus, toolbars, & status
785806
// Annotate
@@ -2455,3 +2476,82 @@ ImageViewer::areaSampleMode() const
24552476
{
24562477
return m_areaSampleMode;
24572478
}
2479+
2480+
2481+
void
2482+
ImageViewer::rotateLeft()
2483+
{
2484+
IvImage* img = cur();
2485+
if (!img)
2486+
return;
2487+
2488+
ImageSpec* spec = curspecmod();
2489+
2490+
int curr_orientation = spec->get_int_attribute("Orientation", 1);
2491+
2492+
if (curr_orientation >= 1 && curr_orientation <= 8) {
2493+
static int next_orientation[] = { 0, 8, 5, 6, 7, 4, 1, 2, 3 };
2494+
curr_orientation = next_orientation[curr_orientation];
2495+
spec->attribute("Orientation", curr_orientation);
2496+
}
2497+
displayCurrentImage();
2498+
}
2499+
2500+
2501+
void
2502+
ImageViewer::rotateRight()
2503+
{
2504+
IvImage* img = cur();
2505+
if (!img)
2506+
return;
2507+
2508+
ImageSpec* spec = curspecmod();
2509+
int curr_orientation = spec->get_int_attribute("Orientation", 1);
2510+
2511+
if (curr_orientation >= 1 && curr_orientation <= 8) {
2512+
static int next_orientation[] = { 0, 6, 7, 8, 5, 2, 3, 4, 1 };
2513+
curr_orientation = next_orientation[curr_orientation];
2514+
spec->attribute("Orientation", curr_orientation);
2515+
}
2516+
displayCurrentImage();
2517+
}
2518+
2519+
2520+
void
2521+
ImageViewer::flipHorizontal()
2522+
{
2523+
IvImage* img = cur();
2524+
if (!img)
2525+
return;
2526+
2527+
ImageSpec* spec = curspecmod();
2528+
2529+
int curr_orientation = spec->get_int_attribute("Orientation", 1);
2530+
2531+
if (curr_orientation >= 1 && curr_orientation <= 8) {
2532+
static int next_orientation[] = { 0, 2, 1, 4, 3, 6, 5, 8, 7 };
2533+
curr_orientation = next_orientation[curr_orientation];
2534+
spec->attribute("Orientation", curr_orientation);
2535+
}
2536+
displayCurrentImage();
2537+
}
2538+
2539+
2540+
void
2541+
ImageViewer::flipVertical()
2542+
{
2543+
IvImage* img = cur();
2544+
if (!img)
2545+
return;
2546+
2547+
ImageSpec* spec = curspecmod();
2548+
2549+
int curr_orientation = spec->get_int_attribute("Orientation", 1);
2550+
2551+
if (curr_orientation >= 1 && curr_orientation <= 8) {
2552+
static int next_orientation[] = { 0, 4, 3, 2, 1, 8, 7, 6, 5 };
2553+
curr_orientation = next_orientation[curr_orientation];
2554+
spec->attribute("Orientation", curr_orientation);
2555+
}
2556+
displayCurrentImage();
2557+
}

src/iv/imageviewer.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ class ImageViewer final : public QMainWindow {
219219
return img ? &img->spec() : NULL;
220220
}
221221

222+
/// Return a modifiable ref to the current image spec, or NULL if there is no
223+
/// current image.
224+
ImageSpec* curspecmod(void) const
225+
{
226+
IvImage* img = cur();
227+
return img ? &img->specmod() : NULL;
228+
}
229+
222230
bool pixelviewOn(void) const
223231
{
224232
return showPixelviewWindowAct && showPixelviewWindowAct->isChecked();
@@ -334,6 +342,11 @@ private slots:
334342
void editPreferences(); ///< Edit viewer preferences
335343
void toggleAreaSample(); ///< Use area probe
336344

345+
void rotateLeft();
346+
void rotateRight();
347+
void flipHorizontal();
348+
void flipVertical();
349+
337350
void useOCIOAction(bool checked);
338351
void ocioColorSpaceAction();
339352
void ocioDisplayViewAction();
@@ -404,6 +417,8 @@ private slots:
404417
QAction* showPixelviewWindowAct;
405418
QAction* toggleAreaSampleAct;
406419
QAction* toggleWindowGuidesAct;
420+
QAction *rotateLeftAct, *rotateRightAct, *flipHorizontalAct,
421+
*flipVerticalAct;
407422
QMenu *fileMenu, *editMenu, /**imageMenu,*/ *viewMenu, *toolsMenu,
408423
*helpMenu;
409424
QMenu* openRecentMenu;

0 commit comments

Comments
 (0)