Merge lp:~artmello/gallery-app/gallery-app-remove_local_photoeditor into lp:gallery-app

Proposed by Arthur Mello on 2015-12-16
Status: Merged
Approved by: Bill Filler on 2015-12-17
Approved revision: 1256
Merged at revision: 1258
Proposed branch: lp:~artmello/gallery-app/gallery-app-remove_local_photoeditor
Merge into: lp:gallery-app
Diff against target: 3650 lines (+3/-3449)
28 files modified
rc/qml/MediaViewer/GalleryPhotoEditorPage.qml (+0/-42)
rc/qml/MediaViewer/MediaViewer.qml (+3/-4)
rc/qml/MediaViewer/PhotoEditor.qml (+0/-230)
rc/qml/MediaViewer/PhotoEditor/ActionsBar.qml (+0/-88)
rc/qml/MediaViewer/PhotoEditor/BusyIndicator.qml (+0/-56)
rc/qml/MediaViewer/PhotoEditor/CropCorner.qml (+0/-66)
rc/qml/MediaViewer/PhotoEditor/CropDragArea.qml (+0/-56)
rc/qml/MediaViewer/PhotoEditor/CropInteractor.qml (+0/-140)
rc/qml/MediaViewer/PhotoEditor/CropOverlay.qml (+0/-581)
rc/qml/MediaViewer/PhotoEditor/EditStack.qml (+0/-134)
rc/qml/MediaViewer/PhotoEditor/ExposureAdjuster.qml (+0/-104)
rc/qml/MediaViewer/PhotoEditor/GraphicsRoutines.js (+0/-108)
src/gallery-application.cpp (+0/-13)
src/gallery-application.h (+0/-2)
src/photoeditor/CMakeLists.txt (+0/-13)
src/photoeditor/file-utils.cpp (+0/-97)
src/photoeditor/file-utils.h (+0/-42)
src/photoeditor/imaging.cpp (+0/-363)
src/photoeditor/imaging.h (+0/-169)
src/photoeditor/orientation.cpp (+0/-152)
src/photoeditor/orientation.h (+0/-64)
src/photoeditor/photo-caches.cpp (+0/-183)
src/photoeditor/photo-caches.h (+0/-76)
src/photoeditor/photo-data.cpp (+0/-275)
src/photoeditor/photo-data.h (+0/-92)
src/photoeditor/photo-edit-command.h (+0/-58)
src/photoeditor/photo-edit-thread.cpp (+0/-185)
src/photoeditor/photo-edit-thread.h (+0/-56)
To merge this branch: bzr merge lp:~artmello/gallery-app/gallery-app-remove_local_photoeditor
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing on 2015-12-16
Ubuntu Phablet Team 2015-12-16 Pending
Review via email: mp+280715@code.launchpad.net

Commit message

Remove local copy of PhotoEditor and keep using only the Ubuntu Extras one

Description of the change

Remove local copy of PhotoEditor and keep using only the Ubuntu Extras one

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'rc/qml/MediaViewer/GalleryPhotoEditorPage.qml'
2--- rc/qml/MediaViewer/GalleryPhotoEditorPage.qml 2015-11-05 18:10:29 +0000
3+++ rc/qml/MediaViewer/GalleryPhotoEditorPage.qml 1970-01-01 00:00:00 +0000
4@@ -1,42 +0,0 @@
5-/*
6- * Copyright (C) 2014-2015 Canonical Ltd
7- *
8- * This program is free software: you can redistribute it and/or modify
9- * it under the terms of the GNU General Public License version 3 as
10- * published by the Free Software Foundation.
11- *
12- * This program is distributed in the hope that it will be useful,
13- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15- * GNU General Public License for more details.
16- *
17- * You should have received a copy of the GNU General Public License
18- * along with this program. If not, see <http://www.gnu.org/licenses/>.
19- */
20-
21-import QtQuick 2.4
22-import Ubuntu.Components 1.3
23-
24-Page {
25- id: page
26- property string photo
27- signal done(bool photoWasModified)
28-
29- title: i18n.tr("Edit Photo")
30-
31- head.backAction: Action {
32- iconName: "back"
33- onTriggered: editor.close(true)
34- }
35- head.actions: editor.actions
36-
37- PhotoEditor {
38- id: editor
39- anchors.fill: parent
40- onClosed: page.done(photoWasModified)
41- }
42-
43- onActiveChanged: {
44- if (active) editor.open(page.photo)
45- }
46-}
47
48=== modified file 'rc/qml/MediaViewer/MediaViewer.qml'
49--- rc/qml/MediaViewer/MediaViewer.qml 2015-11-05 18:10:29 +0000
50+++ rc/qml/MediaViewer/MediaViewer.qml 2015-12-16 13:52:17 +0000
51@@ -325,11 +325,10 @@
52 var editor;
53 try {
54 Qt.createQmlObject('import QtQuick 2.4; import Ubuntu.Components.Extras 0.2; Item {}', viewerWrapper);
55- console.log("Loading PhotoEditor Components from Extras");
56- editor = overview.pushPage(Qt.resolvedUrl("ExtrasPhotoEditorPage.qml"), { photo: path });
57+ editor = overview.pushPage(Qt.resolvedUrl("PhotoEditorPage.qml"), { photo: path });
58 } catch (e) {
59- console.log("Loading PhotoEditor Components from Gallery code");
60- editor = overview.pushPage(Qt.resolvedUrl("GalleryPhotoEditorPage.qml"), { photo: path });
61+ console.log("WARNING: Unable to load PhotoEditor from Ubuntu.Components.Extras");
62+ return;
63 }
64 editor.done.connect(function(photoWasModified) {
65 if (photoWasModified) galleryPhotoViewer.media.dataChanged();
66
67=== removed directory 'rc/qml/MediaViewer/PhotoEditor'
68=== removed file 'rc/qml/MediaViewer/PhotoEditor.qml'
69--- rc/qml/MediaViewer/PhotoEditor.qml 2015-11-05 19:04:22 +0000
70+++ rc/qml/MediaViewer/PhotoEditor.qml 1970-01-01 00:00:00 +0000
71@@ -1,230 +0,0 @@
72-/*
73- * Copyright (C) 2014-2015 Canonical Ltd
74- *
75- * This program is free software: you can redistribute it and/or modify
76- * it under the terms of the GNU General Public License version 3 as
77- * published by the Free Software Foundation.
78- *
79- * This program is distributed in the hope that it will be useful,
80- * but WITHOUT ANY WARRANTY; without even the implied warranty of
81- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
82- * GNU General Public License for more details.
83- *
84- * You should have received a copy of the GNU General Public License
85- * along with this program. If not, see <http://www.gnu.org/licenses/>.
86- */
87-
88-import QtQuick 2.4
89-import Ubuntu.Components 1.3
90-import Ubuntu.Components.Popups 1.3
91-import Gallery 1.0
92-import "PhotoEditor"
93-
94-Item {
95- id: editor
96- property string photo
97- property bool modified: stack.modified
98-
99- signal closed(bool photoWasModified)
100-
101- property list<Action> actions
102- actions: [stack.undoAction, stack.redoAction]
103-
104- EditStack {
105- id: stack
106- data: photoData
107- actionsEnabled: !exposureSelector.visible && !cropper.visible && !photoData.busy
108- onRevertRequested: PopupUtils.open(revertPromptComponent)
109- }
110-
111- property list<Action> toolActions: [
112- Action {
113- objectName: "cropButton"
114- text: i18n.tr("Crop")
115- iconSource: Qt.resolvedUrl("PhotoEditor/assets/edit_crop.png")
116- onTriggered: {
117- photoData.isLongOperation = false;
118- cropper.start("image://photo/" + photoData.path);
119- }
120- },
121- Action {
122- objectName: "rotateButton"
123- text: i18n.tr("Rotate")
124- iconSource: Qt.resolvedUrl("PhotoEditor/assets/edit_rotate_left.png")
125- onTriggered: {
126- photoData.isLongOperation = false;
127- photoData.rotateRight()
128- }
129- }
130- ]
131-
132- function close(saveIfModified) {
133- stack.endEditingSession(saveIfModified);
134- editor.closed(editor.modified);
135- }
136-
137- function open(photo) {
138- editor.photo = photo;
139- stack.startEditingSession(photo);
140- photoData.path = stack.currentFile;
141- image.source = "image://photo/" + photoData.path;
142- }
143-
144- Rectangle {
145- color: "black"
146- anchors.fill: parent
147- }
148-
149- Image {
150- id: image
151- anchors.fill: parent
152- asynchronous: true
153- cache: false
154- source: photoData.path ? "image://photo/" + photoData.path : ""
155- fillMode: Image.PreserveAspectFit
156- sourceSize {
157- width: image.width
158- height: image.height
159- }
160-
161- function reload() {
162- image.asynchronous = false;
163- image.source = "";
164- image.asynchronous = true;
165- image.source = "image://photo/" + photoData.path;
166- }
167- }
168-
169- GalleryPhotoData {
170- id: photoData
171- onDataChanged: image.reload()
172- property bool isLongOperation: false
173-
174- onEditFinished: {
175- console.log("Edit finished")
176- // If we are editing exposure we don't need to checkpoint at every
177- // edit, and the exposure UI will checkpoint when the user confirms.
178- if (exposureSelector.opacity > 0) exposureSelector.reload()
179- else stack.checkpoint()
180- }
181- }
182-
183- Loader {
184- id: cropper
185-
186- anchors.fill: parent
187-
188- opacity: 0.0
189- visible: opacity > 0
190- Behavior on opacity { UbuntuNumberAnimation { } }
191-
192- Connections {
193- target: cropper.item
194- ignoreUnknownSignals: true
195- onCropped: {
196- var qtRect = Qt.rect(rect.x, rect.y, rect.width, rect.height);
197- photoData.crop(qtRect);
198- cropper.opacity = 0.0;
199- cropper.source = ""
200- }
201- onCanceled: {
202- cropper.opacity = 0.0;
203- cropper.source = ""
204- }
205- }
206-
207- function start(target) {
208- source = "PhotoEditor/CropInteractor.qml";
209- item.targetPhoto = target;
210- }
211-
212- onLoaded: opacity = 1.0
213- }
214-
215- ExposureAdjuster {
216- id: exposureSelector
217- anchors.fill: parent
218- opacity: 0.0
219- enabled: !photoData.busy
220- onExposureChanged: {
221- // Restore the starting version of the image, otherwise we will
222- // accumulate compensations over the previous ones.
223- stack.restoreSnapshot(stack.level)
224- photoData.exposureCompensation(exposure)
225- }
226- onConfirm: {
227- stack.checkpoint();
228- exposureSelector.opacity = 0.0
229- }
230- onCancel: {
231- stack.restoreSnapshot(stack.level)
232- exposureSelector.opacity = 0.0
233- }
234- visible: opacity > 0
235- }
236-
237- ActionsBar {
238- id: actionsBar
239- objectName: "editorActionsBar"
240- anchors.bottom: parent.bottom
241- anchors.left: parent.left
242- anchors.right: parent.right
243-
244- visible: opacity > 0.0
245- opacity: (exposureSelector.opacity == 0 && cropper.opacity == 0) ? 1.0 : 0.0
246-
247- enabled: !photoData.busy
248- toolActions: {
249- // This is necessary because QML does not let us declare a list with
250- // mixed component declarations and identifiers, like this:
251- // property list<Action> foo: { Action{}, someOtherAction }
252- var list = [];
253- for (var i = 0; i < editor.toolActions.length; i++)
254- list.push(editor.toolActions[i]);
255- list.push(stack.revertAction);
256- return list;
257- }
258-
259- Behavior on opacity { UbuntuNumberAnimation {} }
260- }
261-
262- Component {
263- id: revertPromptComponent
264- Dialog {
265- id: revertPrompt
266- objectName: "revertPromptDialog"
267- title: i18n.tr("Revert to original")
268- text: i18n.tr("This will undo all edits, including those from previous sessions.")
269-
270- Row {
271- id: row
272- width: parent.width
273- spacing: units.gu(1)
274- Button {
275- objectName: "cancelRevertButton"
276- width: parent.width/2
277- text: i18n.tr("Cancel")
278- onClicked: PopupUtils.close(revertPrompt)
279- }
280- Button {
281- objectName: "confirmRevertButton"
282- width: parent.width/2
283- text: i18n.tr("Revert Photo")
284- color: UbuntuColors.green
285- onClicked: {
286- PopupUtils.close(revertPrompt)
287- stack.revertToPristine()
288- }
289- }
290- }
291- }
292- }
293-
294- BusyIndicator {
295- id: busyIndicator
296- anchors.centerIn: parent
297- text: i18n.tr("Enhancing photo...")
298- running: photoData.busy
299- longOperation: photoData.isLongOperation
300- }
301-}
302
303=== removed file 'rc/qml/MediaViewer/PhotoEditor/ActionsBar.qml'
304--- rc/qml/MediaViewer/PhotoEditor/ActionsBar.qml 2015-11-05 19:04:22 +0000
305+++ rc/qml/MediaViewer/PhotoEditor/ActionsBar.qml 1970-01-01 00:00:00 +0000
306@@ -1,88 +0,0 @@
307-/*
308- * Copyright (C) 2014-2015 Canonical Ltd
309- *
310- * This program is free software: you can redistribute it and/or modify
311- * it under the terms of the GNU General Public License version 3 as
312- * published by the Free Software Foundation.
313- *
314- * This program is distributed in the hope that it will be useful,
315- * but WITHOUT ANY WARRANTY; without even the implied warranty of
316- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
317- * GNU General Public License for more details.
318- *
319- * You should have received a copy of the GNU General Public License
320- * along with this program. If not, see <http://www.gnu.org/licenses/>.
321- */
322-
323-import QtQuick 2.4
324-import Ubuntu.Components 1.3
325-import Ubuntu.Components.ListItems 1.3 as ListItem
326-
327-Column {
328- id: bar
329- property list<Action> toolActions
330- property list<Action> filterActions
331- property bool enabled
332-
333- height: (filtersBar.visible) ? units.gu(20) : units.gu(6)
334-
335- Item {
336- anchors.left: parent.left
337- anchors.right: parent.right
338- height: units.gu(6)
339-
340- Rectangle {
341- anchors.fill: parent
342- color: "black"
343- opacity: 0.6
344- }
345-
346- ListView {
347- id: toolsBar
348- anchors.fill: parent
349- orientation: ListView.Horizontal
350- model: toolActions
351-
352- delegate: AbstractButton {
353- width: units.gu(8)
354- anchors.top: parent.top
355- anchors.bottom: parent.bottom
356- action: modelData
357- enabled: bar.enabled
358-
359- Icon {
360- anchors.centerIn: parent
361- name: modelData.iconName
362- source: modelData.iconSource
363- width: units.gu(3)
364- height: units.gu(3)
365- opacity: modelData.enabled && parent.enabled ? 1.0 : 0.5
366- }
367- }
368- }
369- }
370-
371- Rectangle {
372- anchors.left: parent.left
373- anchors.right: parent.right
374- height: units.gu(14)
375- color: "black"
376-
377- ListView {
378- id: filtersBar
379- visible: filterActions.length > 0
380-
381- orientation: ListView.Horizontal
382- model: filterActions
383-
384- delegate: ListItem.Standard {
385- width: parent.height
386- anchors.top: parent.top
387- anchors.bottom: parent.bottom
388- action: modelData
389- iconFrame: false
390- enabled: bar.enabled
391- }
392- }
393- }
394-}
395
396=== removed file 'rc/qml/MediaViewer/PhotoEditor/BusyIndicator.qml'
397--- rc/qml/MediaViewer/PhotoEditor/BusyIndicator.qml 2015-11-05 18:10:29 +0000
398+++ rc/qml/MediaViewer/PhotoEditor/BusyIndicator.qml 1970-01-01 00:00:00 +0000
399@@ -1,56 +0,0 @@
400-/*
401- * Copyright (C) 2015 Canonical Ltd
402- *
403- * This program is free software: you can redistribute it and/or modify
404- * it under the terms of the GNU General Public License version 3 as
405- * published by the Free Software Foundation.
406- *
407- * This program is distributed in the hope that it will be useful,
408- * but WITHOUT ANY WARRANTY; without even the implied warranty of
409- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
410- * GNU General Public License for more details.
411- *
412- * You should have received a copy of the GNU General Public License
413- * along with this program. If not, see <http://www.gnu.org/licenses/>.
414- */
415-
416-import QtQuick 2.4
417-import Ubuntu.Components 1.3
418-
419-Item {
420- id: busy
421- width: childrenRect.width
422- height: childrenRect.height
423- property alias text: label.text
424- property alias running: spinner.running
425- property bool longOperation: false
426-
427- visible: running
428-
429- UbuntuShape {
430- color: "white"
431- anchors.centerIn: parent
432- width: parent.width + units.gu(4)
433- height: parent.height + units.gu(4)
434- opacity: longOperation ? 0.75 : 0
435- }
436-
437- Column {
438- id: column
439- anchors.centerIn: parent
440- width: childrenRect.width
441- spacing: units.gu(2)
442-
443- ActivityIndicator {
444- id: spinner
445- anchors.horizontalCenter: parent.horizontalCenter
446- }
447-
448- Label {
449- id: label
450- anchors.horizontalCenter: parent.horizontalCenter
451- horizontalAlignment: Text.AlignHCenter
452- visible: longOperation
453- }
454- }
455-}
456
457=== removed file 'rc/qml/MediaViewer/PhotoEditor/CropCorner.qml'
458--- rc/qml/MediaViewer/PhotoEditor/CropCorner.qml 2015-11-05 19:04:22 +0000
459+++ rc/qml/MediaViewer/PhotoEditor/CropCorner.qml 1970-01-01 00:00:00 +0000
460@@ -1,66 +0,0 @@
461-/*
462- * Copyright (C) 2012-2015 Canonical Ltd
463- *
464- * This program is free software: you can redistribute it and/or modify
465- * it under the terms of the GNU General Public License version 3 as
466- * published by the Free Software Foundation.
467- *
468- * This program is distributed in the hope that it will be useful,
469- * but WITHOUT ANY WARRANTY; without even the implied warranty of
470- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
471- * GNU General Public License for more details.
472- *
473- * You should have received a copy of the GNU General Public License
474- * along with this program. If not, see <http://www.gnu.org/licenses/>.
475- *
476- * Authors:
477- * Charles Lindsay <chaz@yorba.org>
478- */
479-
480-import QtQuick 2.4
481-import Ubuntu.Components 1.3
482-
483-// A corner of a CropFrame.
484-Item {
485- id: cropCorner
486-
487- /*!
488- */
489- signal dragged(real dx, real dy)
490- /*!
491- */
492- signal dragStarted()
493- /*!
494- */
495- signal dragCompleted()
496-
497- /*!
498- */
499- property bool isLeft: true
500- /*!
501- */
502- property bool isTop: true
503-
504- x: isLeft ? -(width/2) : parent.width - (width/2)
505- y: isTop ? -(width/2) : parent.height - (width/2)
506- width: handle.width
507- height: handle.height
508-
509- Image {
510- id: handle
511- anchors.centerIn: parent
512- source: Qt.resolvedUrl("assets/crop-handle.png")
513- }
514-
515- CropDragArea {
516- anchors.centerIn: parent
517- width: handle.width + units.gu(2)
518- height: handle.height + units.gu(2)
519-
520- onDragged: cropCorner.dragged(dx, dy)
521-
522- onDragStarted: cropCorner.dragStarted()
523-
524- onDragCompleted: cropCorner.dragCompleted()
525- }
526-}
527
528=== removed file 'rc/qml/MediaViewer/PhotoEditor/CropDragArea.qml'
529--- rc/qml/MediaViewer/PhotoEditor/CropDragArea.qml 2015-11-05 19:04:22 +0000
530+++ rc/qml/MediaViewer/PhotoEditor/CropDragArea.qml 1970-01-01 00:00:00 +0000
531@@ -1,56 +0,0 @@
532-/*
533- * Copyright (C) 2012-2015 Canonical Ltd
534- *
535- * This program is free software: you can redistribute it and/or modify
536- * it under the terms of the GNU General Public License version 3 as
537- * published by the Free Software Foundation.
538- *
539- * This program is distributed in the hope that it will be useful,
540- * but WITHOUT ANY WARRANTY; without even the implied warranty of
541- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
542- * GNU General Public License for more details.
543- *
544- * You should have received a copy of the GNU General Public License
545- * along with this program. If not, see <http://www.gnu.org/licenses/>.
546- *
547- * Authors:
548- * Charles Lindsay <chaz@yorba.org>
549- */
550-
551-import QtQuick 2.4
552-
553-// A MouseArea meant to drag a corner/edge of a crop area.
554-MouseArea {
555- id: cropDragArea
556-
557- /*!
558- */
559- signal dragged(real dx, real dy)
560- /*!
561- */
562- signal dragStarted()
563- /*!
564- */
565- signal dragCompleted()
566-
567- // Since we're usually moving this area with the mouse in response to
568- // dragging, we don't need to capture the last x/y, just where it was
569- // grabbed.
570- property real grabX: -1
571- /*!
572- */
573- property real grabY: -1
574-
575- onPressed: {
576- dragStarted();
577-
578- grabX = mouse.x;
579- grabY = mouse.y;
580- }
581-
582- onReleased: {
583- dragCompleted();
584- }
585-
586- onPositionChanged: cropDragArea.dragged(mouse.x - grabX, mouse.y - grabY)
587-}
588
589=== removed file 'rc/qml/MediaViewer/PhotoEditor/CropInteractor.qml'
590--- rc/qml/MediaViewer/PhotoEditor/CropInteractor.qml 2015-11-05 19:04:22 +0000
591+++ rc/qml/MediaViewer/PhotoEditor/CropInteractor.qml 1970-01-01 00:00:00 +0000
592@@ -1,140 +0,0 @@
593-/*
594- * Copyright (C) 2012-2015 Canonical Ltd
595- *
596- * This program is free software: you can redistribute it and/or modify
597- * it under the terms of the GNU General Public License version 3 as
598- * published by the Free Software Foundation.
599- *
600- * This program is distributed in the hope that it will be useful,
601- * but WITHOUT ANY WARRANTY; without even the implied warranty of
602- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
603- * GNU General Public License for more details.
604- *
605- * You should have received a copy of the GNU General Public License
606- * along with this program. If not, see <http://www.gnu.org/licenses/>.
607- *
608- * Authors:
609- * Charles Lindsay <chaz@yorba.org>
610- * Lucas Beeler <lucas@yorba.org>
611- */
612-
613-import QtQuick 2.4
614-import Ubuntu.Components 1.3
615-import "GraphicsRoutines.js" as GraphicsRoutines
616-
617-/*!
618-*/
619-Rectangle {
620- id: cropInteractor
621- objectName: "cropInteractor"
622-
623- color: "black"
624-
625- property alias targetPhoto: original.source
626-
627- property string matteColor: "black"
628- property real matteOpacity: 0.6
629-
630- // Note: each element of the cropped rect will be in the range [0,1], since
631- // in the UI we aren't using direct photo pixel values.
632- signal cropped(variant rect)
633- signal canceled()
634-
635- function computeRectSet() {
636- var actualImage = Qt.rect(
637- (original.width - original.paintedWidth) / 2.0,
638- (original.height - original.paintedHeight) / 2.0,
639- original.paintedWidth,
640- original.paintedHeight
641- );
642- var photoPreview = GraphicsRoutines.fitRect(viewport, actualImage);
643-
644- var unfitCrop = Qt.rect(0, 0, photoPreview.width, photoPreview.height);
645- var cropFrame = GraphicsRoutines.fitRect(viewport, unfitCrop);
646-
647- var photoExtent = Qt.rect(cropFrame.x, cropFrame.y,
648- cropFrame.scaleFactor * photoPreview.width,
649- cropFrame.scaleFactor * photoPreview.height);
650-
651- return {
652- photoPreview: photoPreview,
653- cropFrame: cropFrame,
654- photoExtent: photoExtent,
655- photoExtentScale: cropFrame.scaleFactor
656- };
657- }
658-
659- Item {
660- id: viewport
661-
662- anchors.fill: parent
663- anchors.margins: units.gu(6)
664- z: 1
665- }
666-
667- CropOverlay {
668- id: overlay
669- objectName: "cropOverlay"
670-
671- property real minSize: units.gu(4)
672-
673- anchors.fill: parent;
674- visible: false;
675-
676- photo: original
677- viewport: viewport
678-
679- matteColor: cropInteractor.matteColor
680- matteOpacity: cropInteractor.matteOpacity
681-
682- z: 16
683-
684- onMatteRegionPressed: {
685- cropInteractor.canceled();
686- }
687-
688- onCropButtonPressed: {
689- original.visible = false;
690- overlay.visible = false;
691- original.scale = 1.0;
692- var r = overlay.getRelativeFrameRect()
693- cropInteractor.cropped(overlay.getRelativeFrameRect());
694- }
695- }
696-
697- Image {
698- id: original
699-
700- x: viewport.x
701- y: viewport.y
702- width: viewport.width
703- height: viewport.height
704- transformOrigin: Item.TopLeft
705- fillMode: Image.PreserveAspectFit
706- cache: false
707- sourceSize {
708- width: original.width
709- height: original.height
710- }
711-
712- onStatusChanged: {
713- if (status == Image.Ready) {
714- var rects = computeRectSet();
715-
716- overlay.initialFrameX = rects.cropFrame.x;
717- overlay.initialFrameY = rects.cropFrame.y;
718- overlay.initialFrameWidth = rects.cropFrame.width;
719- overlay.initialFrameHeight = rects.cropFrame.height;
720-
721- overlay.resetFor(rects);
722- overlay.visible = true;
723-
724- x = rects.photoExtent.x;
725- y = rects.photoExtent.y;
726- width = rects.photoPreview.width;
727- height = rects.photoPreview.height;
728- scale = rects.photoExtentScale;
729- }
730- }
731- }
732-}
733
734=== removed file 'rc/qml/MediaViewer/PhotoEditor/CropOverlay.qml'
735--- rc/qml/MediaViewer/PhotoEditor/CropOverlay.qml 2015-11-05 19:04:22 +0000
736+++ rc/qml/MediaViewer/PhotoEditor/CropOverlay.qml 1970-01-01 00:00:00 +0000
737@@ -1,581 +0,0 @@
738-/*
739- * Copyright (C) 2012-2015 Canonical Ltd
740- *
741- * This program is free software: you can redistribute it and/or modify
742- * it under the terms of the GNU General Public License version 3 as
743- * published by the Free Software Foundation.
744- *
745- * This program is distributed in the hope that it will be useful,
746- * but WITHOUT ANY WARRANTY; without even the implied warranty of
747- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
748- * GNU General Public License for more details.
749- *
750- * You should have received a copy of the GNU General Public License
751- * along with this program. If not, see <http://www.gnu.org/licenses/>.
752- *
753- * Authors:
754- * Charles Lindsay <chaz@yorba.org>
755- * Lucas Beeler <lucas@yorba.org>
756- */
757-
758-import QtQuick 2.4
759-import Ubuntu.Components 1.3
760-import "GraphicsRoutines.js" as GraphicsRoutines
761-
762-/* A CropOverlay is a semi-transparent surface that floats over the photo. It
763- * serves two purposes. First, it provides visual cueing as to what region of
764- * the photo's surface will be preserved when the crop operation is applied.
765- * The preserved region is the region that falls inside of the CropOverlay's
766- * frame. Second, the CropOverlay allows the user to manipulate the
767- * geometry of the crop frame, to chage its location, width, and height. The
768- * geometry of the crop frame is reinforced by a key visual cue: the region of
769- * the photo outside of the crop frame is drawn with a semi-transparent, smoked
770- * matte on top of it. This matte surrounds the crop frame.
771- */
772-Item {
773- id: cropOverlay
774-
775- // public properties
776- /*!
777- */
778- property Item viewport
779- /*!
780- */
781- property Item photo
782- /*!
783- */
784- property string matteColor: "red"
785- /*!
786- */
787- property real matteOpacity: 0.85
788- /*!
789- */
790- property int initialFrameX: -1
791- /*!
792- */
793- property int initialFrameY: -1
794- /*!
795- */
796- property int initialFrameWidth: -1
797- /*!
798- */
799- property int initialFrameHeight: -1
800-
801- // private properties -- Frame Fit Animation parameters
802- property real interpolationFactor: 1.0
803- /*!
804- */
805- property variant startFrame
806- /*!
807- */
808- property variant endFrame
809- /*!
810- */
811- property variant startPhoto
812- /*!
813- */
814- property real referencePhotoWidth: -1
815- /*!
816- */
817- property real referencePhotoHeight: -1
818- /*!
819- */
820- property real endPhotoX
821- /*!
822- */
823- property real endPhotoY
824- /*!
825- */
826- property real endPhotoWidth
827- /*!
828- */
829- property real endPhotoHeight
830-
831- /*!
832- */
833- signal userAlteredFrame()
834- /*!
835- */
836- signal runFrameFitAnimation()
837- /*!
838- */
839- signal matteRegionPressed()
840- /*!
841- */
842- signal cropButtonPressed()
843-
844- /*!
845- */
846- function resetFor(rectSet) {
847- if (initialFrameX != -1 && initialFrameY != -1 && initialFrameWidth != -1 &&
848- initialFrameHeight != -1) {
849- frame.x = rectSet.cropFrame.x;
850- frame.y = rectSet.cropFrame.y;
851- frame.width = rectSet.cropFrame.width;
852- frame.height = rectSet.cropFrame.height;
853- photoExtent.x = rectSet.photoExtent.x;
854- photoExtent.y = rectSet.photoExtent.y;
855- photoExtent.width = rectSet.photoExtent.width;
856- photoExtent.height = rectSet.photoExtent.height;
857- referencePhotoWidth = rectSet.photoPreview.width;
858- referencePhotoHeight = rectSet.photoPreview.height;
859- }
860- }
861-
862- /* Return the (x, y) position and the width and height of the viewport
863- */
864- function getViewportExtentRect() {
865- return GraphicsRoutines.cloneRect(viewport);
866- }
867-
868- /* Return the (x, y) position and the width and height of the photoExtent.
869- * The photoExtent is the on-screen region that holds the original photo
870- * preview.
871- */
872- function getPhotoExtentRect() {
873- return GraphicsRoutines.cloneRect(photoExtent);
874- }
875-
876- /*!
877- */
878- function getRelativeFrameRect() {
879- return GraphicsRoutines.getRelativeRect(frame.getExtentRect(),
880- getPhotoExtentRect());
881- }
882-
883- anchors.fill: parent
884-
885- Item {
886- id: photoExtent
887-
888- property real panStartX
889- property real panStartY
890-
891- function startPan() {
892- panStartX = x;
893- panStartY = y;
894- }
895-
896- // 'deltaX' and 'deltaY' are offsets relative to the pan start point
897- function updatePan(deltaX, deltaY) {
898- var newX = panStartX + deltaX;
899- var newY = panStartY + deltaY;
900-
901- x = GraphicsRoutines.clamp(newX, frame.x + frame.width -
902- photoExtent.width, frame.x);
903- y = GraphicsRoutines.clamp(newY, frame.y + frame.height -
904- photoExtent.height, frame.y);
905- }
906-
907- function stopPan() {
908- }
909-
910- x: initialFrameX
911- y: initialFrameY
912- width: initialFrameWidth
913- height: initialFrameHeight
914- z: 1
915-
916- onXChanged: {
917- if (photo)
918- photo.x = x;
919- }
920-
921- onYChanged: {
922- if (photo)
923- photo.y = y;
924- }
925-
926- onWidthChanged: {
927- if (photo && referencePhotoWidth > 0)
928- photo.scale = width / referencePhotoWidth;
929- }
930-
931- onHeightChanged: {
932- if (photo && referencePhotoHeight > 0)
933- photo.scale = height / referencePhotoHeight;
934- }
935- }
936-
937- //
938- // The following four Rectangles are used to "matte out" the area of the photo
939- // preview that falls outside the frame. This "matting out" visual cue is
940- // accomplished by darkening the matted-out area with a translucent, smoked
941- // overlay.
942- //
943- Rectangle {
944- id: leftMatte
945-
946- color: cropOverlay.matteColor
947- opacity: cropOverlay.matteOpacity
948-
949- anchors.top: topMatte.bottom
950- anchors.bottom: frame.bottom
951- anchors.left: parent.left
952- anchors.right: frame.left
953-
954- MouseArea {
955- anchors.fill: parent;
956-
957- onPressed: cropOverlay.matteRegionPressed();
958- }
959- }
960-
961- Rectangle {
962- id: topMatte
963-
964- color: cropOverlay.matteColor
965- opacity: cropOverlay.matteOpacity
966-
967- anchors.top: parent.top
968- anchors.bottom: frame.top
969- anchors.left: parent.left
970- anchors.right: parent.right
971-
972- MouseArea {
973- anchors.fill: parent;
974-
975- onPressed: cropOverlay.matteRegionPressed();
976- }
977- }
978-
979- Rectangle {
980- id: rightMatte
981-
982- color: cropOverlay.matteColor
983- opacity: cropOverlay.matteOpacity
984-
985- anchors.top: topMatte.bottom
986- anchors.bottom: bottomMatte.top
987- anchors.left: frame.right
988- anchors.right: parent.right
989-
990- MouseArea {
991- anchors.fill: parent;
992-
993- onPressed: cropOverlay.matteRegionPressed();
994- }
995- }
996-
997- Rectangle {
998- id: bottomMatte
999-
1000- color: cropOverlay.matteColor
1001- opacity: cropOverlay.matteOpacity
1002-
1003- anchors.top: frame.bottom
1004- anchors.bottom: parent.bottom
1005- anchors.left: parent.left
1006- anchors.right: parent.right
1007-
1008- MouseArea {
1009- anchors.fill: parent;
1010-
1011- onPressed: cropOverlay.matteRegionPressed();
1012- }
1013- }
1014-
1015- //
1016- // The frame is a grey rectangle with associated drag corners that
1017- // frames the region of the photo that will remain when the crop operation is
1018- // applied.
1019- //
1020- // NB: the frame can be in two states, although the QML state mechanism
1021- // isn't sufficiently expressive to describe them. The frame can be
1022- // in the FIT state, in which case it is optimally fit inside the
1023- // frame constraint region (see getFrameConstraintRect( ) above for
1024- // a description of the frame constraint region). Or, the frame can
1025- // be in the USER state. In the user state, the user has the mouse button
1026- // held down and is actively performing a drag operation to change the
1027- // geometry of the frame.
1028- //
1029- Rectangle {
1030- id: frame
1031-
1032- signal resizedX(bool left, real dx)
1033- signal resizedY(bool top, real dy)
1034-
1035- property variant dragStartRect
1036-
1037- function getExtentRect() {
1038- var result = { };
1039-
1040- result.x = x;
1041- result.y = y;
1042- result.width = width;
1043- result.height = height;
1044-
1045- return result;
1046- }
1047-
1048- x: cropOverlay.initialFrameX
1049- y: cropOverlay.initialFrameY
1050- width: cropOverlay.initialFrameWidth
1051- height: cropOverlay.initialFrameHeight
1052-
1053- color: "transparent"
1054-
1055- border.width: units.gu(0.2)
1056- border.color: "#19B6EE"
1057-
1058- MouseArea {
1059- id: panArea
1060-
1061- property int dragStartX;
1062- property int dragStartY;
1063-
1064- anchors.fill: parent
1065- anchors.margins: 2
1066-
1067- onPressed: {
1068- dragStartX = mouse.x;
1069- dragStartY = mouse.y;
1070-
1071- photoExtent.startPan();
1072- }
1073-
1074- onReleased: {
1075- photoExtent.stopPan();
1076- }
1077-
1078- onPositionChanged: {
1079- photoExtent.updatePan(mouse.x - dragStartX, mouse.y - dragStartY);
1080- }
1081- }
1082-
1083- Button {
1084- objectName: "centerCropIcon"
1085- anchors.centerIn: parent
1086- text: i18n.tr("Crop")
1087- color: frame.border.color
1088- opacity: 0.9
1089- onClicked: cropOverlay.cropButtonPressed()
1090- }
1091-
1092- // Left drag bar.
1093- CropDragArea {
1094- x: -units.gu(2)
1095- width: units.gu(3)
1096- anchors.verticalCenter: parent.center
1097- height: parent.height - units.gu(2)
1098-
1099- onDragged: {
1100- frame.resizedX(true, dx);
1101- frame.updateOnAltered(false);
1102- }
1103-
1104- onDragStarted: frame.dragStartRect = frame.getExtentRect();
1105- onDragCompleted: frame.updateOnAltered(true);
1106- }
1107-
1108- // Top drag bar.
1109- CropDragArea {
1110- y: -units.gu(2)
1111- height: units.gu(3)
1112- anchors.horizontalCenter: parent.center
1113- width: parent.width - units.gu(2)
1114-
1115- onDragged: {
1116- frame.resizedY(true, dy);
1117- frame.updateOnAltered(false);
1118- }
1119-
1120- onDragStarted: frame.dragStartRect = frame.getExtentRect();
1121- onDragCompleted: frame.updateOnAltered(true);
1122- }
1123-
1124- // Right drag bar.
1125- CropDragArea {
1126- x: parent.width - units.gu(1)
1127- width: units.gu(3)
1128- anchors.verticalCenter: parent.center
1129- height: parent.height - units.gu(2)
1130-
1131- onDragged: {
1132- frame.resizedX(false, dx);
1133- frame.updateOnAltered(false);
1134- }
1135-
1136- onDragStarted: frame.dragStartRect = frame.getExtentRect();
1137- onDragCompleted: frame.updateOnAltered(true);
1138- }
1139-
1140- // Bottom drag bar.
1141- CropDragArea {
1142- y: parent.height - units.gu(1)
1143- height: units.gu(3)
1144- anchors.horizontalCenter: parent.center
1145- width: parent.width - units.gu(2)
1146-
1147- onDragged: {
1148- frame.resizedY(false, dy);
1149- frame.updateOnAltered(false);
1150- }
1151-
1152- onDragStarted: frame.dragStartRect = frame.getExtentRect();
1153- onDragCompleted: frame.updateOnAltered(true);
1154- }
1155-
1156- // Top-left corner.
1157- CropCorner {
1158- objectName: "topLeftCropCorner"
1159- isLeft: true
1160- isTop: true
1161-
1162- onDragged: {
1163- frame.resizedX(isLeft, dx);
1164- frame.resizedY(isTop, dy);
1165- frame.updateOnAltered(false);
1166- }
1167-
1168- onDragStarted: frame.dragStartRect = frame.getExtentRect();
1169- onDragCompleted: frame.updateOnAltered(true);
1170- }
1171-
1172- // Top-right corner.
1173- CropCorner {
1174- objectName: "topRightCropCorner"
1175- isLeft: false
1176- isTop: true
1177-
1178- onDragged: {
1179- frame.resizedX(isLeft, dx);
1180- frame.resizedY(isTop, dy);
1181- frame.updateOnAltered(false);
1182- }
1183-
1184- onDragStarted: frame.dragStartRect = frame.getExtentRect();
1185- onDragCompleted: frame.updateOnAltered(true);
1186- }
1187-
1188- // Bottom-left corner.
1189- CropCorner {
1190- objectName: "bottonLeftCropCorner"
1191- isLeft: true
1192- isTop: false
1193-
1194- onDragged: {
1195- frame.resizedX(isLeft, dx);
1196- frame.resizedY(isTop, dy);
1197- frame.updateOnAltered(false);
1198- }
1199-
1200- onDragStarted: frame.dragStartRect = frame.getExtentRect();
1201- onDragCompleted: frame.updateOnAltered(true);
1202- }
1203-
1204- // Bottom-right corner.
1205- CropCorner {
1206- id: bottomRightCrop
1207- objectName: "bottomRightCropCorner"
1208- isLeft: false
1209- isTop: false
1210-
1211- onDragged: {
1212- frame.resizedX(isLeft, dx);
1213- frame.resizedY(isTop, dy);
1214- frame.updateOnAltered(false);
1215- }
1216-
1217- onDragStarted: frame.dragStartRect = frame.getExtentRect();
1218- onDragCompleted: frame.updateOnAltered(true);
1219- }
1220-
1221- // This handles resizing in both dimensions. first is whether we're
1222- // resizing the "first" edge, e.g. left or top (in which case we
1223- // adjust both position and span) vs. right or bottom (where we just
1224- // adjust the span). position should be either "x" or "y", and span
1225- // is either "width" or "height". This is a little complicated, and
1226- // coule probably be optimized with a little more thought.
1227- function resizeFrame(first, delta, position, span) {
1228- var constraintRegion = cropOverlay.getPhotoExtentRect();
1229-
1230- if (first) {
1231- // Left/top side.
1232- if (frame[position] + delta < constraintRegion[position])
1233- delta = constraintRegion[position] - frame[position]
1234-
1235- if (frame[span] - delta < minSize)
1236- delta = frame[span] - minSize;
1237-
1238- frame[position] += delta;
1239- frame[span] -= delta;
1240- } else {
1241- // Right/bottom side.
1242- if (frame[span] + delta < minSize)
1243- delta = minSize - frame[span];
1244-
1245- if ((frame[position] + frame[span] + delta) >
1246- (constraintRegion[position] + constraintRegion[span]))
1247- delta = constraintRegion[position] + constraintRegion[span] -
1248- frame[position] - frame[span];
1249-
1250- frame[span] += delta;
1251- }
1252- }
1253-
1254- onResizedX: resizeFrame(left, dx, "x", "width")
1255- onResizedY: resizeFrame(top, dy, "y", "height")
1256-
1257- function updateOnAltered(finalUpdate) {
1258- var start = frame.dragStartRect;
1259- var end = frame.getExtentRect();
1260- if (!GraphicsRoutines.areEqual(end, start)) {
1261- if (finalUpdate ||
1262- (end.width * end.height >= start.width * start.height)) {
1263- cropOverlay.userAlteredFrame();
1264- cropOverlay.runFrameFitAnimation();
1265- }
1266- }
1267- }
1268- }
1269-
1270- /* Invoked when the user has changed the geometry of the frame by dragging
1271- * one of its corners or edges. Expressed in terms of the states of the
1272- * frame described above, the userAlteredFrame signal is fired
1273- * when the user stops dragging. This triggers a change of the frame
1274- * from the USER state to the FIT state
1275- */
1276- onUserAlteredFrame: {
1277- // since the geometry of the frame in the FIT state depends on both
1278- // how the user resized the frame when it was in the USER state as well
1279- // as the size of the frame constraint region, we have to recompute the
1280- // geometry of of the frame for the FIT state every time.
1281-
1282- startFrame = GraphicsRoutines.cloneRect(frame);
1283-
1284- endFrame = GraphicsRoutines.fitRect(getViewportExtentRect(),
1285- frame.getExtentRect());
1286-
1287- startPhoto = GraphicsRoutines.cloneRect(photoExtent);
1288-
1289- var frameRelativeToPhoto = getRelativeFrameRect();
1290- var scaleFactor = endFrame.width / frame.width;
1291-
1292- endPhotoWidth = photoExtent.width * scaleFactor;
1293- endPhotoHeight = photoExtent.height * scaleFactor;
1294- endPhotoX = endFrame.x - (frameRelativeToPhoto.x * endPhotoWidth);
1295- endPhotoY = endFrame.y - (frameRelativeToPhoto.y * endPhotoHeight)
1296-
1297- photo.transformOrigin = Item.TopLeft;
1298- }
1299-
1300- onRunFrameFitAnimation: NumberAnimation { target: cropOverlay;
1301- property: "interpolationFactor"; from: 0.0; to: 1.0 }
1302-
1303- onInterpolationFactorChanged: {
1304- var endPhotoRect = { };
1305- endPhotoRect.x = endPhotoX;
1306- endPhotoRect.y = endPhotoY;
1307- endPhotoRect.width = endPhotoWidth;
1308- endPhotoRect.height = endPhotoHeight;
1309-
1310- var interpolatedRect = GraphicsRoutines.interpolateRect(startFrame,
1311- endFrame, interpolationFactor);
1312- GraphicsRoutines.sizeToRect(interpolatedRect, frame);
1313-
1314- interpolatedRect = GraphicsRoutines.interpolateRect(startPhoto,
1315- endPhotoRect, interpolationFactor);
1316- GraphicsRoutines.sizeToRect(interpolatedRect, photoExtent);
1317- }
1318-}
1319
1320=== removed file 'rc/qml/MediaViewer/PhotoEditor/EditStack.qml'
1321--- rc/qml/MediaViewer/PhotoEditor/EditStack.qml 2015-11-05 19:04:22 +0000
1322+++ rc/qml/MediaViewer/PhotoEditor/EditStack.qml 1970-01-01 00:00:00 +0000
1323@@ -1,134 +0,0 @@
1324-/*
1325- * Copyright (C) 2014-2015 Canonical Ltd
1326- *
1327- * This program is free software: you can redistribute it and/or modify
1328- * it under the terms of the GNU General Public License version 3 as
1329- * published by the Free Software Foundation.
1330- *
1331- * This program is distributed in the hope that it will be useful,
1332- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1333- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1334- * GNU General Public License for more details.
1335- *
1336- * You should have received a copy of the GNU General Public License
1337- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1338- */
1339-
1340-import QtQuick 2.4
1341-import Ubuntu.Components 1.3
1342-import Gallery 1.0
1343-
1344-Item {
1345- property GalleryPhotoData data
1346- property bool actionsEnabled: true
1347- property var items: []
1348- property int level: 0
1349- property string editingSessionPath
1350- property string currentFile
1351- property string originalFile
1352- property string pristineFile
1353- property bool modified: level > 0 || _revertedInThisSession
1354-
1355- property bool _revertedInThisSession
1356- property bool _pristineFileExists
1357-
1358- signal revertRequested
1359-
1360- function startEditingSession(original) {
1361- var originalFileName = GalleryFileUtils.nameFromPath(original);
1362- var baseName = GalleryFileUtils.parentDirectory(original) +
1363- "/.photo_editing." + originalFileName + ".";
1364- editingSessionPath = GalleryFileUtils.createTemporaryDirectory(baseName);
1365- if (editingSessionPath == "") return false;
1366-
1367- originalFile = original;
1368- currentFile = editingSessionPath + "/current";
1369-
1370- pristineFile = GalleryFileUtils.parentDirectory(original) +
1371- "/.original/" + originalFileName
1372- _revertedInThisSession = false;
1373- _pristineFileExists = GalleryFileUtils.exists(pristineFile)
1374-
1375- GalleryFileUtils.copy(originalFile, currentFile)
1376-
1377- items = [createSnapshot(0)];
1378- level = 0;
1379- return true;
1380- }
1381-
1382- function endEditingSession(saveIfModified) {
1383- if (saveIfModified && modified) { // file modified
1384- // if we don't have a copy of the very first original, create one
1385- if (!_pristineFileExists) {
1386- GalleryFileUtils.createDirectory(GalleryFileUtils.parentDirectory(pristineFile));
1387- GalleryFileUtils.copy(originalFile, pristineFile);
1388- } else {
1389- // if we reverted to original (and made no other changes)
1390- // we don't need to keep the pristine copy around
1391- if (_revertedInThisSession && level <= 0) {
1392- GalleryFileUtils.remove(pristineFile);
1393- }
1394- }
1395-
1396- GalleryFileUtils.copy(currentFile, originalFile); // actually save
1397- }
1398-
1399- GalleryFileUtils.removeDirectory(editingSessionPath, true); // clear editing cache
1400- editingSessionPath = originalFile = pristineFile = currentFile = "";
1401- }
1402-
1403- function createSnapshot(name) {
1404- var snapshotFile = editingSessionPath + "/edit." + name;
1405- GalleryFileUtils.copy(currentFile, snapshotFile);
1406- return snapshotFile;
1407- }
1408-
1409- function restoreSnapshot(name) {
1410- var snapshotFile = editingSessionPath + "/edit." + name;
1411- GalleryFileUtils.copy(snapshotFile, currentFile);
1412- data.refreshFromDisk();
1413- }
1414-
1415- function checkpoint() {
1416- level++;
1417- items = items.slice(0, level);
1418- items.push(createSnapshot(items.length));
1419- }
1420-
1421- function revertToPristine() {
1422- if (!GalleryFileUtils.exists(pristineFile)) {
1423- restoreSnapshot(0);
1424- items = items.slice(0, 1);
1425- level = 0;
1426- } else {
1427- GalleryFileUtils.copy(pristineFile, currentFile);
1428- data.refreshFromDisk();
1429- items = [];
1430- checkpoint();
1431- level = 0;
1432- _revertedInThisSession = true;
1433- }
1434- }
1435-
1436- property Action undoAction: Action {
1437- text: i18n.tr("Undo")
1438- iconName: "undo"
1439- enabled: items.length > 0 && level > 0 && actionsEnabled
1440- onTriggered: restoreSnapshot(--level);
1441- }
1442-
1443- property Action redoAction: Action {
1444- text: i18n.tr("Redo")
1445- iconName: "redo"
1446- enabled: level < items.length - 1 && actionsEnabled
1447- onTriggered: restoreSnapshot(++level);
1448- }
1449-
1450- property Action revertAction: Action {
1451- text: i18n.tr("Revert to Original")
1452- iconSource: Qt.resolvedUrl("assets/edit_revert.png")
1453- enabled: actionsEnabled &&
1454- (level > 0 || (!_revertedInThisSession && _pristineFileExists))
1455- onTriggered: revertRequested()
1456- }
1457-}
1458
1459=== removed file 'rc/qml/MediaViewer/PhotoEditor/ExposureAdjuster.qml'
1460--- rc/qml/MediaViewer/PhotoEditor/ExposureAdjuster.qml 2015-11-05 19:04:22 +0000
1461+++ rc/qml/MediaViewer/PhotoEditor/ExposureAdjuster.qml 1970-01-01 00:00:00 +0000
1462@@ -1,104 +0,0 @@
1463-/*
1464- * Copyright (C) 2014-2015 Canonical Ltd
1465- *
1466- * This program is free software: you can redistribute it and/or modify
1467- * it under the terms of the GNU General Public License version 3 as
1468- * published by the Free Software Foundation.
1469- *
1470- * This program is distributed in the hope that it will be useful,
1471- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1472- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1473- * GNU General Public License for more details.
1474- *
1475- * You should have received a copy of the GNU General Public License
1476- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1477- */
1478-
1479-import QtQuick 2.4
1480-import Ubuntu.Components 1.3
1481-
1482-// When the photo editor uses a proper PageStack this will switch back to being
1483-// an Item as it will not need to cover what is below it.
1484-Rectangle {
1485- id: adjuster
1486- color:"black"
1487-
1488- property alias exposure: exposureSelector.value
1489- property bool enabled
1490-
1491- signal confirm()
1492- signal cancel()
1493-
1494- Image {
1495- id: targetImage
1496- anchors.fill: parent
1497- fillMode: Image.PreserveAspectFit
1498- asynchronous: true
1499- cache: false
1500- sourceSize {
1501- width: targetImage.width
1502- height: targetImage.height
1503- }
1504- }
1505-
1506- Column {
1507- anchors.left: parent.left
1508- anchors.right: parent.right
1509- anchors.bottom: parent.bottom
1510- anchors.margins: units.gu(2)
1511- spacing: units.gu(2)
1512-
1513- Slider {
1514- id: exposureSelector
1515- live: false
1516- minimumValue: -1.0
1517- maximumValue: +1.0
1518- value: 0.0
1519- enabled: adjuster.enabled
1520-
1521- anchors.left: parent.left
1522- anchors.right: parent.right
1523- height: units.gu(2)
1524-
1525- function formatValue(value) {
1526- return (Math.round(value * 100) / 100).toString()
1527- }
1528- }
1529- Row {
1530- anchors.horizontalCenter: parent.horizontalCenter
1531- spacing: units.gu(2)
1532- Button {
1533- text: i18n.tr("Done")
1534- color: UbuntuColors.green
1535- enabled: adjuster.enabled
1536- onTriggered: {
1537- targetImage.source = "";
1538- confirm();
1539- }
1540- }
1541- Button {
1542- text: i18n.tr("Cancel")
1543- color: UbuntuColors.red
1544- enabled: adjuster.enabled
1545- onTriggered: {
1546- targetImage.source = "";
1547- cancel();
1548- }
1549- }
1550- }
1551- }
1552-
1553- function start(target) {
1554- targetImage.source = target;
1555- exposure = 0.0;
1556- opacity = 1.0;
1557- }
1558-
1559- function reload() {
1560- var path = targetImage.source;
1561- targetImage.asynchronous = false;
1562- targetImage.source = "";
1563- targetImage.asynchronous = true;
1564- targetImage.source = path;
1565- }
1566-}
1567
1568=== removed file 'rc/qml/MediaViewer/PhotoEditor/GraphicsRoutines.js'
1569--- rc/qml/MediaViewer/PhotoEditor/GraphicsRoutines.js 2015-02-26 21:00:19 +0000
1570+++ rc/qml/MediaViewer/PhotoEditor/GraphicsRoutines.js 1970-01-01 00:00:00 +0000
1571@@ -1,108 +0,0 @@
1572-/*
1573- * Copyright (C) 2012 Canonical Ltd
1574- *
1575- * This program is free software: you can redistribute it and/or modify
1576- * it under the terms of the GNU General Public License version 3 as
1577- * published by the Free Software Foundation.
1578- *
1579- * This program is distributed in the hope that it will be useful,
1580- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1581- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1582- * GNU General Public License for more details.
1583- *
1584- * You should have received a copy of the GNU General Public License
1585- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1586- *
1587- * Authors:
1588- * Lucas Beeler <lucas@yorba.org>
1589- */
1590-
1591-/* Given 'input', constrain the value of 'input' to range between
1592- * 'lowConstraint' and 'highConstraint', inclusive. Return the constrained
1593- * value without modifying 'input'.
1594- */
1595-function clamp(input, lowConstraint, highConstraint) {
1596- if (input < lowConstraint)
1597- return lowConstraint;
1598- else if (input > highConstraint)
1599- return highConstraint;
1600- else
1601- return input;
1602-}
1603-
1604-function cloneRect(source) {
1605- var ret = { };
1606- ret.x = source.x;
1607- ret.y = source.y;
1608- ret.width = source.width;
1609- ret.height = source.height;
1610-
1611- return ret;
1612-}
1613-
1614-function interpolateRect(start, end, factor) {
1615- var result = { };
1616-
1617- result.x = start.x + factor * (end.x - start.x);
1618- result.y = start.y + factor * (end.y - start.y);
1619- result.width = start.width + factor * (end.width - start.width);
1620- result.height = start.height + factor * (end.height - start.height);
1621-
1622- return result;
1623-}
1624-
1625-/* Forces Geometry object 'item' to fit centered inside Geometry object
1626- * 'viewport', preserving the aspect of ratio of 'item' but potentially scaling
1627- * and translating it so that it snugly fits centered inside of 'viewport'.
1628- * Return the new scaled-up and translated Geometry for 'item'.
1629- */
1630-function fitRect(viewport, item) {
1631- if (item.width == 0 || item.height == 0) {
1632- return viewport;
1633- }
1634-
1635- var itemAspectRatio = item.width / item.height;
1636- var viewportAspectRatio = viewport.width / viewport.height;
1637-
1638- var result = { };
1639- if (itemAspectRatio > viewportAspectRatio) {
1640- var scaleFactor = viewport.width / item.width;
1641- result.width = viewport.width;
1642- result.height = item.height * scaleFactor
1643- } else {
1644- scaleFactor = viewport.height / item.height;
1645- result.width = item.width * scaleFactor
1646- result.height = viewport.height;
1647- }
1648-
1649- result.width = clamp(result.width, 0, viewport.width);
1650- result.height = clamp(result.height, 0, viewport.height);
1651- result.x = viewport.x + (viewport.width - result.width) / 2;
1652- result.y = viewport.y + (viewport.height - result.height) / 2;
1653- result.scaleFactor = scaleFactor;
1654-
1655- return result;
1656-}
1657-
1658-function getRelativeRect(geom, relativeTo) {
1659- var result = { };
1660-
1661- result.x = (geom.x - relativeTo.x) / relativeTo.width;
1662- result.y = (geom.y - relativeTo.y) / relativeTo.height;
1663- result.width = geom.width / relativeTo.width;
1664- result.height = geom.height / relativeTo.height;
1665-
1666- return result;
1667-}
1668-
1669-function sizeToRect(rect, qmlItem) {
1670- qmlItem.x = rect.x;
1671- qmlItem.y = rect.y;
1672- qmlItem.width = rect.width;
1673- qmlItem.height = rect.height;
1674-}
1675-
1676-function areEqual(geom1, geom2) {
1677- return (geom1.x === geom2.x && geom1.y === geom2.y && geom1.width ===
1678- geom2.width && geom1.height === geom2.height);
1679-}
1680
1681=== removed directory 'rc/qml/MediaViewer/PhotoEditor/assets'
1682=== removed file 'rc/qml/MediaViewer/PhotoEditor/assets/crop-handle@20.png'
1683Binary files rc/qml/MediaViewer/PhotoEditor/assets/crop-handle@20.png 2015-02-26 21:00:19 +0000 and rc/qml/MediaViewer/PhotoEditor/assets/crop-handle@20.png 1970-01-01 00:00:00 +0000 differ
1684=== removed file 'rc/qml/MediaViewer/PhotoEditor/assets/edit_autocorrect@27.png'
1685Binary files rc/qml/MediaViewer/PhotoEditor/assets/edit_autocorrect@27.png 2015-02-26 21:00:19 +0000 and rc/qml/MediaViewer/PhotoEditor/assets/edit_autocorrect@27.png 1970-01-01 00:00:00 +0000 differ
1686=== removed file 'rc/qml/MediaViewer/PhotoEditor/assets/edit_crop@27.png'
1687Binary files rc/qml/MediaViewer/PhotoEditor/assets/edit_crop@27.png 2015-02-26 21:00:19 +0000 and rc/qml/MediaViewer/PhotoEditor/assets/edit_crop@27.png 1970-01-01 00:00:00 +0000 differ
1688=== removed file 'rc/qml/MediaViewer/PhotoEditor/assets/edit_exposure@27.png'
1689Binary files rc/qml/MediaViewer/PhotoEditor/assets/edit_exposure@27.png 2015-02-26 21:00:19 +0000 and rc/qml/MediaViewer/PhotoEditor/assets/edit_exposure@27.png 1970-01-01 00:00:00 +0000 differ
1690=== removed file 'rc/qml/MediaViewer/PhotoEditor/assets/edit_revert@27.png'
1691Binary files rc/qml/MediaViewer/PhotoEditor/assets/edit_revert@27.png 2015-02-26 21:00:19 +0000 and rc/qml/MediaViewer/PhotoEditor/assets/edit_revert@27.png 1970-01-01 00:00:00 +0000 differ
1692=== removed file 'rc/qml/MediaViewer/PhotoEditor/assets/edit_rotate_left@27.png'
1693Binary files rc/qml/MediaViewer/PhotoEditor/assets/edit_rotate_left@27.png 2015-02-26 21:00:19 +0000 and rc/qml/MediaViewer/PhotoEditor/assets/edit_rotate_left@27.png 1970-01-01 00:00:00 +0000 differ
1694=== renamed file 'rc/qml/MediaViewer/ExtrasPhotoEditorPage.qml' => 'rc/qml/MediaViewer/PhotoEditorPage.qml'
1695=== modified file 'src/gallery-application.cpp'
1696--- src/gallery-application.cpp 2015-04-30 22:00:38 +0000
1697+++ src/gallery-application.cpp 2015-12-16 13:52:17 +0000
1698@@ -37,8 +37,6 @@
1699 #include "photo.h"
1700
1701 // photoeditor
1702-#include "photo-data.h"
1703-#include "file-utils.h"
1704 #include "photo-image-provider.h"
1705
1706 // qml
1707@@ -175,8 +173,6 @@
1708 qmlRegisterType<QmlEventCollectionModel>("Gallery", 1, 0, "EventCollectionModel");
1709 qmlRegisterType<QmlEventOverviewModel>("Gallery", 1, 0, "EventOverviewModel");
1710 qmlRegisterType<QmlMediaCollectionModel>("Gallery", 1, 0, "MediaCollectionModel");
1711- qmlRegisterType<PhotoData>("Gallery", 1, 0, "GalleryPhotoData");
1712- qmlRegisterSingletonType<FileUtils>("Gallery", 1, 0, "GalleryFileUtils", exportFileUtilsSingleton);
1713
1714 qRegisterMetaType<QList<MediaSource*> >("MediaSourceList");
1715 qRegisterMetaType<QSet<DataObject*> >("QSet<DataObject*>");
1716@@ -269,15 +265,6 @@
1717 setMediaFile(m_cmdLineParser->mediaFile());
1718 }
1719
1720-QObject* GalleryApplication::exportFileUtilsSingleton(QQmlEngine *engine,
1721- QJSEngine *scriptEngine)
1722-{
1723- Q_UNUSED(engine);
1724- Q_UNUSED(scriptEngine);
1725-
1726- return new FileUtils();
1727-}
1728-
1729 /*!
1730 * \brief GalleryApplication::initCollections
1731 */
1732
1733=== modified file 'src/gallery-application.h'
1734--- src/gallery-application.h 2015-02-26 20:28:06 +0000
1735+++ src/gallery-application.h 2015-12-16 13:52:17 +0000
1736@@ -93,8 +93,6 @@
1737 private:
1738 void registerQML();
1739 void createView();
1740- static QObject* exportFileUtilsSingleton(QQmlEngine *engine,
1741- QJSEngine *scriptEngine);
1742
1743 QQuickView *m_view;
1744 GalleryManager *m_galleryManager;
1745
1746=== modified file 'src/photoeditor/CMakeLists.txt'
1747--- src/photoeditor/CMakeLists.txt 2015-02-26 20:34:48 +0000
1748+++ src/photoeditor/CMakeLists.txt 2015-12-16 13:52:17 +0000
1749@@ -14,24 +14,11 @@
1750 )
1751
1752 set(gallery_photoeditor_HDRS
1753- file-utils.h
1754- imaging.h
1755- orientation.h
1756- photo-caches.h
1757- photo-data.h
1758- photo-edit-command.h
1759- photo-edit-thread.h
1760 photo-image-provider.h
1761 photo-metadata.h
1762 )
1763
1764 set(gallery_photoeditor_SRCS
1765- file-utils.cpp
1766- imaging.cpp
1767- orientation.cpp
1768- photo-caches.cpp
1769- photo-data.cpp
1770- photo-edit-thread.cpp
1771 photo-image-provider.cpp
1772 photo-metadata.cpp
1773 )
1774
1775=== removed file 'src/photoeditor/file-utils.cpp'
1776--- src/photoeditor/file-utils.cpp 2015-02-26 20:28:06 +0000
1777+++ src/photoeditor/file-utils.cpp 1970-01-01 00:00:00 +0000
1778@@ -1,97 +0,0 @@
1779-/*
1780- * Copyright (C) 2014 Canonical Ltd
1781- *
1782- * This program is free software: you can redistribute it and/or modify
1783- * it under the terms of the GNU General Public License version 3 as
1784- * published by the Free Software Foundation.
1785- *
1786- * This program is distributed in the hope that it will be useful,
1787- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1788- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1789- * GNU General Public License for more details.
1790- *
1791- * You should have received a copy of the GNU General Public License
1792- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1793- */
1794-
1795-#include "file-utils.h"
1796-
1797-#include <QDebug>
1798-#include <QDir>
1799-#include <QFile>
1800-#include <QFileInfo>
1801-#include <QTemporaryDir>
1802-
1803-FileUtils::FileUtils(QObject *parent) :
1804- QObject(parent)
1805-{
1806-}
1807-
1808-bool FileUtils::createDirectory(QString path) const
1809-{
1810- if (path.isEmpty()) return false;
1811-
1812- return QDir(path).mkpath(".");
1813-}
1814-
1815-QString FileUtils::createTemporaryDirectory(QString pathTemplate) const
1816-{
1817- QTemporaryDir dir(pathTemplate);
1818- if (!dir.isValid()) return QString();
1819-
1820- dir.setAutoRemove(false);
1821- return dir.path();
1822-}
1823-
1824-bool FileUtils::removeDirectory(QString path, bool recursive) const
1825-{
1826- if (path.isEmpty()) return false;
1827-
1828- QDir dir(path);
1829- return (recursive) ? dir.removeRecursively() : dir.rmdir(".");
1830-}
1831-
1832-bool FileUtils::remove(QString path) const
1833-{
1834- if (path.isEmpty()) return false;
1835- return QFile::remove(path);
1836-}
1837-
1838-bool FileUtils::copy(QString sourceFile, QString destinationFile) const
1839-{
1840- if (sourceFile.isEmpty() || destinationFile.isEmpty()) return false;
1841-
1842- if (QFileInfo(destinationFile).exists()) QFile::remove(destinationFile);
1843- return QFile::copy(sourceFile, destinationFile);
1844-}
1845-
1846-bool FileUtils::rename(QString sourceFile, QString destinationFile) const
1847-{
1848- if (sourceFile.isEmpty() || destinationFile.isEmpty()) return false;
1849-
1850- if (QFileInfo(destinationFile).exists()) QFile::remove(destinationFile);
1851- return QFile::rename(sourceFile, destinationFile);
1852-}
1853-
1854-QString FileUtils::parentDirectory(QString path) const
1855-{
1856- if (QFileInfo(path).isDir()) {
1857- QDir dir(path);
1858- dir.cdUp();
1859- return dir.absolutePath();
1860- } else {
1861- return QFileInfo(path).dir().absolutePath();
1862- }
1863-}
1864-
1865-QString FileUtils::nameFromPath(QString path) const
1866-{
1867- QString name = QFileInfo(path).fileName();
1868- if (name.isEmpty()) name = QDir(path).dirName();
1869- return name;
1870-}
1871-
1872-bool FileUtils::exists(QString path) const
1873-{
1874- return QFileInfo::exists(path);
1875-}
1876
1877=== removed file 'src/photoeditor/file-utils.h'
1878--- src/photoeditor/file-utils.h 2015-02-26 20:28:06 +0000
1879+++ src/photoeditor/file-utils.h 1970-01-01 00:00:00 +0000
1880@@ -1,42 +0,0 @@
1881-/*
1882- * Copyright (C) 2014 Canonical Ltd
1883- *
1884- * This program is free software: you can redistribute it and/or modify
1885- * it under the terms of the GNU General Public License version 3 as
1886- * published by the Free Software Foundation.
1887- *
1888- * This program is distributed in the hope that it will be useful,
1889- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1890- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1891- * GNU General Public License for more details.
1892- *
1893- * You should have received a copy of the GNU General Public License
1894- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1895- */
1896-
1897-#ifndef PHOTOUTILS_H
1898-#define PHOTOUTILS_H
1899-
1900-#include <QObject>
1901-
1902-class FileUtils : public QObject
1903-{
1904- Q_OBJECT
1905-public:
1906- explicit FileUtils(QObject *parent = 0);
1907-
1908- Q_INVOKABLE bool createDirectory(QString path) const;
1909- Q_INVOKABLE bool removeDirectory(QString path, bool recursive = false) const;
1910- Q_INVOKABLE QString createTemporaryDirectory(QString pathTemplate) const;
1911-
1912- Q_INVOKABLE bool remove(QString path) const;
1913- Q_INVOKABLE bool copy(QString sourceFile, QString destinationFile) const;
1914- Q_INVOKABLE bool rename(QString sourceFile, QString destinationFile) const;
1915-
1916- Q_INVOKABLE QString parentDirectory(QString path) const;
1917- Q_INVOKABLE QString nameFromPath(QString path) const;
1918-
1919- Q_INVOKABLE bool exists(QString path) const;
1920-};
1921-
1922-#endif // PHOTOUTILS_H
1923
1924=== removed file 'src/photoeditor/imaging.cpp'
1925--- src/photoeditor/imaging.cpp 2015-02-26 20:28:06 +0000
1926+++ src/photoeditor/imaging.cpp 1970-01-01 00:00:00 +0000
1927@@ -1,363 +0,0 @@
1928-/*
1929- * Copyright (C) 2012 Canonical Ltd
1930- *
1931- * This program is free software: you can redistribute it and/or modify
1932- * it under the terms of the GNU General Public License version 3 as
1933- * published by the Free Software Foundation.
1934- *
1935- * This program is distributed in the hope that it will be useful,
1936- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1937- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1938- * GNU General Public License for more details.
1939- *
1940- * You should have received a copy of the GNU General Public License
1941- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1942- *
1943- * Authors:
1944- * Lucas Beeler <lucas@yorba.org>
1945- */
1946-
1947-
1948-#include <QApplication>
1949-#include <qmath.h>
1950-
1951-#include "imaging.h"
1952-
1953-/*!
1954- * \brief HSVTransformation::transformPixel
1955- * \param pixel_color
1956- * \return
1957- */
1958-QColor HSVTransformation::transformPixel(const QColor &pixel_color) const
1959-{
1960- QColor result;
1961-
1962- int h, s, v;
1963- pixel_color.getHsv(&h, &s, &v);
1964-
1965- v = remap_table_[v];
1966-
1967- result.setHsv(h, s, v);
1968-
1969- return result;
1970-}
1971-
1972-/*!
1973- * \brief IntensityHistogram::IntensityHistogram
1974- * \param basis_image
1975- */
1976-IntensityHistogram::IntensityHistogram(const QImage& basis_image)
1977-{
1978- for (int i = 0; i < 256; i++)
1979- m_counts[i] = 0;
1980-
1981- int width = basis_image.width();
1982- int height = basis_image.height();
1983-
1984- for (int j = 0; j < height; j++) {
1985- QApplication::processEvents();
1986-
1987- for (int i = 0; i < width; i++) {
1988- QColor c = QColor(basis_image.pixel(i, j));
1989- int intensity = c.value();
1990- m_counts[intensity]++;
1991- }
1992- }
1993-
1994- float pixel_count = (float)(width * height);
1995- float accumulator = 0.0f;
1996- for (int i = 0; i < 256; i++) {
1997- m_probabilities[i] = ((float) m_counts[i]) / pixel_count;
1998- accumulator += m_probabilities[i];
1999- m_cumulativeProbabilities[i] = accumulator;
2000- }
2001-}
2002-
2003-/*!
2004- * \brief IntensityHistogram::getCumulativeProbability
2005- * \param level
2006- * \return
2007- */
2008-float IntensityHistogram::getCumulativeProbability(int level)
2009-{
2010- return m_cumulativeProbabilities[level];
2011-}
2012-
2013-
2014-const float ToneExpansionTransformation::DEFAULT_LOW_DISCARD_MASS = 0.02f;
2015-const float ToneExpansionTransformation::DEFAULT_HIGH_DISCARD_MASS = 0.98f;
2016-/*!
2017- * \brief ToneExpansionTransformation::ToneExpansionTransformation
2018- * \param h
2019- * \param low_discard_mass
2020- * \param high_discard_mass
2021- */
2022-ToneExpansionTransformation::ToneExpansionTransformation(IntensityHistogram h,
2023- float low_discard_mass, float high_discard_mass)
2024-{
2025- if (low_discard_mass == -1.0f)
2026- low_discard_mass = DEFAULT_LOW_DISCARD_MASS;
2027- if (high_discard_mass == -1.0f)
2028- high_discard_mass = DEFAULT_HIGH_DISCARD_MASS;
2029-
2030- m_lowDiscardMass = low_discard_mass;
2031- m_highDiscardMass = high_discard_mass;
2032-
2033- m_lowKink = 0;
2034- m_highKink = 255;
2035-
2036- while (h.getCumulativeProbability(m_lowKink) < low_discard_mass)
2037- m_lowKink++;
2038-
2039- while (h.getCumulativeProbability(m_highKink) > high_discard_mass)
2040- m_highKink--;
2041-
2042- m_lowKink = clampi(m_lowKink, 0, 255);
2043- m_highKink = clampi(m_highKink, 0, 255);
2044-
2045- buildRemapTable();
2046-}
2047-
2048-/*!
2049- * \brief ToneExpansionTransformation::isIdentity
2050- * \return
2051- */
2052-bool ToneExpansionTransformation::isIdentity() const
2053-{
2054- return ((m_lowKink == 0) && (m_highKink == 255));
2055-}
2056-
2057-/*!
2058- * \brief ToneExpansionTransformation::buildRemapTable
2059- */
2060-void ToneExpansionTransformation::buildRemapTable()
2061-{
2062- float low_kink_f = ((float) m_lowKink) / 255.0f;
2063- float high_kink_f = ((float) m_highKink) / 255.0f;
2064-
2065- float slope = 1.0f / (high_kink_f - low_kink_f);
2066- float intercept = -(low_kink_f / (high_kink_f - low_kink_f));
2067-
2068- int i = 0;
2069- for ( ; i <= m_lowKink; i++)
2070- remap_table_[i] = 0;
2071-
2072- for ( ; i < m_highKink; i++)
2073- remap_table_[i] = (int) ((255.0f * (slope * (((float) i) / 255.0f) +
2074- intercept)) + 0.5);
2075-
2076- for ( ; i < 256; i++)
2077- remap_table_[i] = 255;
2078-}
2079-
2080-/*!
2081- * \brief ToneExpansionTransformation::lowDiscardMass
2082- * \return
2083- */
2084-float ToneExpansionTransformation::lowDiscardMass() const
2085-{
2086- return m_lowDiscardMass;
2087-}
2088-
2089-/*!
2090- * \brief ToneExpansionTransformation::highDiscardMass
2091- * \return
2092- */
2093-float ToneExpansionTransformation::highDiscardMass() const
2094-{
2095- return m_highDiscardMass;
2096-}
2097-
2098-
2099-/*!
2100- * \brief HermiteGammaApproximationFunction::HermiteGammaApproximationFunction
2101- * \param user_interval_upper
2102- */
2103-HermiteGammaApproximationFunction::HermiteGammaApproximationFunction(
2104- float user_interval_upper)
2105-{
2106- m_nonzeroIntervalUpper = clampf(user_interval_upper, 0.1f, 1.0f);
2107- m_xScale = 1.0f / m_nonzeroIntervalUpper;
2108-}
2109-
2110-/*!
2111- * \brief HermiteGammaApproximationFunction::evaluate
2112- * \param x
2113- * \return
2114- */
2115-float HermiteGammaApproximationFunction::evaluate(float x)
2116-{
2117- if (x < 0.0f)
2118- return 0.0f;
2119- else if (x > m_nonzeroIntervalUpper)
2120- return 0.0f;
2121- else {
2122- float indep_var = m_xScale * x;
2123-
2124- float dep_var = 6.0f * ((indep_var * indep_var * indep_var) -
2125- (2.0f * (indep_var * indep_var)) + (indep_var));
2126-
2127- return clampf(dep_var, 0.0f, 1.0f);
2128- }
2129-}
2130-
2131-
2132-const float ShadowDetailTransformation::MAX_EFFECT_SHIFT = 0.5f;
2133-const float ShadowDetailTransformation::MIN_TONAL_WIDTH = 0.1f;
2134-const float ShadowDetailTransformation::MAX_TONAL_WIDTH = 1.0f;
2135-const float ShadowDetailTransformation::TONAL_WIDTH = 1.0f;
2136-/*!
2137- * \brief ShadowDetailTransformation::ShadowDetailTransformation
2138- * \param intensity
2139- */
2140-ShadowDetailTransformation::ShadowDetailTransformation(float intensity)
2141-{
2142- m_intensity = intensity;
2143- float effect_shift = MAX_EFFECT_SHIFT * intensity;
2144-
2145- HermiteGammaApproximationFunction func =
2146- HermiteGammaApproximationFunction(TONAL_WIDTH);
2147-
2148- for (int i = 0; i < 256; i++) {
2149- float x = ((float) i) / 255.0f;
2150- float weight = func.evaluate(x);
2151-
2152- int remapped = (int) ((255.0f * (weight * (x + effect_shift)) + ((1.0f -
2153- weight) * x)) + 0.5f);
2154- remap_table_[i] = clampi(remapped, i, 255);
2155- }
2156-}
2157-
2158-/*!
2159- * \brief ShadowDetailTransformation::isIdentity
2160- * \return
2161- */
2162-bool ShadowDetailTransformation::isIdentity() const
2163-{
2164- return (m_intensity == 0.0f);
2165-}
2166-
2167-
2168-const int AutoEnhanceTransformation::SHADOW_DETECT_MIN_INTENSITY = 2;
2169-const int AutoEnhanceTransformation::SHADOW_DETECT_MAX_INTENSITY = 90;
2170-const int AutoEnhanceTransformation::SHADOW_DETECT_INTENSITY_RANGE =
2171- AutoEnhanceTransformation::SHADOW_DETECT_MAX_INTENSITY -
2172- AutoEnhanceTransformation::SHADOW_DETECT_MIN_INTENSITY;
2173-const int AutoEnhanceTransformation::EMPIRICAL_DARK = 40;
2174-const float AutoEnhanceTransformation::SHADOW_AGGRESSIVENESS_MUL = 0.45f;
2175-/*!
2176- * \brief AutoEnhanceTransformation::AutoEnhanceTransformation
2177- * \param basis
2178- */
2179-AutoEnhanceTransformation::AutoEnhanceTransformation(const QImage& basis)
2180- : m_shadowTransform(0), m_toneExpansionTransform(0)
2181-{
2182- IntensityHistogram histogram = IntensityHistogram(basis);
2183-
2184- /* compute the percentage of pixels in the image that fall into the
2185- shadow range -- this measures "of the pixels in the image, how many of
2186- them are in shadow?" */
2187- float pct_in_range = 100.0f *
2188- (histogram.getCumulativeProbability(SHADOW_DETECT_MAX_INTENSITY) -
2189- histogram.getCumulativeProbability(SHADOW_DETECT_MIN_INTENSITY));
2190-
2191- /* compute the mean intensity of the pixels that are in the shadow range --
2192- this measures "of those pixels that are in shadow, just how dark are
2193- they?" */
2194- float sh_prob_mu =
2195- (histogram.getCumulativeProbability(SHADOW_DETECT_MIN_INTENSITY) +
2196- histogram.getCumulativeProbability(SHADOW_DETECT_MAX_INTENSITY)) * 0.5f;
2197- int sh_intensity_mu = SHADOW_DETECT_MIN_INTENSITY;
2198- for ( ; sh_intensity_mu <= SHADOW_DETECT_MAX_INTENSITY; sh_intensity_mu++) {
2199- if (histogram.getCumulativeProbability(sh_intensity_mu) >= sh_prob_mu)
2200- break;
2201- }
2202-
2203- /* if more than 30 percent of the pixels in the image are in the shadow
2204- detection range, or if the mean intensity within the shadow range is less
2205- than an empirically determined threshold below which pixels appear very
2206- dark, regardless of the percent of pixels in it, then perform shadow
2207- detail enhancement. Otherwise, skip shadow detail enhancement and perform
2208- contrast expansion only */
2209- if ((pct_in_range > 30.0f) || ((pct_in_range > 10.0f) &&
2210- (sh_intensity_mu < EMPIRICAL_DARK))) {
2211- float shadow_trans_effect_size = ((((float) SHADOW_DETECT_MAX_INTENSITY) -
2212- ((float) sh_intensity_mu)) /
2213- ((float) SHADOW_DETECT_INTENSITY_RANGE));
2214- shadow_trans_effect_size *= SHADOW_AGGRESSIVENESS_MUL;
2215-
2216- m_shadowTransform
2217- = new ShadowDetailTransformation(shadow_trans_effect_size);
2218-
2219- QImage shadow_corrected_image = QImage(basis);
2220- // Can't write into indexed images, due to a limitation in Qt.
2221- if (shadow_corrected_image.format() == QImage::Format_Indexed8)
2222- shadow_corrected_image = shadow_corrected_image.convertToFormat(
2223- QImage::Format_RGB32);
2224-
2225- for (int j = 0; j < shadow_corrected_image.height(); j++) {
2226- QApplication::processEvents();
2227-
2228- for (int i = 0; i < shadow_corrected_image.width(); i++) {
2229- QColor px = m_shadowTransform->transformPixel(
2230- QColor(shadow_corrected_image.pixel(i, j)));
2231- shadow_corrected_image.setPixel(i, j, px.rgb());
2232- }
2233- }
2234-
2235- m_toneExpansionTransform = new ToneExpansionTransformation(
2236- IntensityHistogram(shadow_corrected_image), 0.005f, 0.995f);
2237-
2238- } else {
2239- m_toneExpansionTransform = new ToneExpansionTransformation(
2240- IntensityHistogram(basis));
2241- }
2242-}
2243-
2244-/*!
2245- * \brief AutoEnhanceTransformation::~AutoEnhanceTransformation
2246- */
2247-AutoEnhanceTransformation::~AutoEnhanceTransformation()
2248-{
2249- if (m_shadowTransform)
2250- delete m_shadowTransform;
2251- delete m_toneExpansionTransform;
2252-}
2253-
2254-/*!
2255- * \brief AutoEnhanceTransformation::transformPixel
2256- * \param pixel_color
2257- * \return
2258- */
2259-QColor AutoEnhanceTransformation::transformPixel(
2260- const QColor& pixel_color) const
2261-{
2262- QColor px = pixel_color;
2263-
2264- if (m_shadowTransform)
2265- px = m_shadowTransform->transformPixel(px);
2266-
2267- px = m_toneExpansionTransform->transformPixel(px);
2268-
2269- /* if tone expansion occurs, boost saturation to compensate for boosted
2270- dynamic range */
2271- if (!m_toneExpansionTransform->isIdentity()) {
2272- int h, s, v;
2273- px.getHsv(&h, &s, &v);
2274-
2275- float compensation_multiplier =
2276- (m_toneExpansionTransform->lowDiscardMass() < 0.01f) ? 1.02f : 1.10f;
2277-
2278- s = (int) (((float) s) * compensation_multiplier);
2279- s = clampi(s, 0, 255);
2280-
2281- px.setHsv(h, s, v);
2282- }
2283-
2284- return px;
2285-}
2286-
2287-bool AutoEnhanceTransformation::isIdentity() const
2288-{
2289- return false;
2290-}
2291
2292=== removed file 'src/photoeditor/imaging.h'
2293--- src/photoeditor/imaging.h 2015-02-26 20:28:06 +0000
2294+++ src/photoeditor/imaging.h 1970-01-01 00:00:00 +0000
2295@@ -1,169 +0,0 @@
2296-/*
2297- * Copyright (C) 2012 Canonical Ltd
2298- *
2299- * This program is free software: you can redistribute it and/or modify
2300- * it under the terms of the GNU General Public License version 3 as
2301- * published by the Free Software Foundation.
2302- *
2303- * This program is distributed in the hope that it will be useful,
2304- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2305- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2306- * GNU General Public License for more details.
2307- *
2308- * You should have received a copy of the GNU General Public License
2309- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2310- *
2311- * Authors:
2312- * Lucas Beeler <lucas@yorba.org>
2313- */
2314-
2315-#ifndef GALLERY_UTIL_IMAGING_H_
2316-#define GALLERY_UTIL_IMAGING_H_
2317-
2318-#include <QColor>
2319-#include <QImage>
2320-#include <QVector4D>
2321-
2322-/*!
2323- * \brief clampi
2324- * \param i
2325- * \param min
2326- * \param max
2327- * \return
2328- */
2329-inline int clampi(int i, int min, int max) {
2330- return (i < min) ? min : ((i > max) ? max : i);
2331-}
2332-
2333-/*!
2334- * \brief clampf
2335- * \param x
2336- * \param min
2337- * \param max
2338- * \return
2339- */
2340-inline float clampf(float x, float min, float max) {
2341- return (x < min) ? min : ((x > max) ? max : x);
2342-}
2343-
2344-/*!
2345- * \brief The HSVTransformation class
2346- */
2347-class HSVTransformation
2348-{
2349-public:
2350- HSVTransformation() { }
2351- virtual ~HSVTransformation() { }
2352-
2353- virtual QColor transformPixel(const QColor& pixel_color) const;
2354- virtual bool isIdentity() const = 0;
2355-
2356-protected:
2357- int remap_table_[256];
2358-};
2359-
2360-/*!
2361- * \brief The IntensityHistogram class
2362- */
2363-class IntensityHistogram
2364-{
2365-public:
2366- IntensityHistogram(const QImage& basis_image);
2367- virtual ~IntensityHistogram() { }
2368-
2369- float getCumulativeProbability(int level);
2370-
2371-private:
2372- int m_counts[256];
2373- float m_probabilities[256];
2374- float m_cumulativeProbabilities[256];
2375-};
2376-
2377-/*!
2378- * \brief The ToneExpansionTransformation class
2379- */
2380-class ToneExpansionTransformation : public virtual HSVTransformation
2381-{
2382- static const float DEFAULT_LOW_DISCARD_MASS;
2383- static const float DEFAULT_HIGH_DISCARD_MASS;
2384-
2385-public:
2386- ToneExpansionTransformation(IntensityHistogram h, float lowDiscardMass =
2387- -1.0f, float highDiscardMass = -1.0f);
2388- virtual ~ToneExpansionTransformation() { }
2389-
2390- bool isIdentity() const;
2391-
2392- float lowDiscardMass() const;
2393- float highDiscardMass() const;
2394-
2395-private:
2396- void buildRemapTable();
2397-
2398- int m_lowKink;
2399- int m_highKink;
2400- float m_lowDiscardMass;
2401- float m_highDiscardMass;
2402-};
2403-
2404-/*!
2405- * \brief The HermiteGammaApproximationFunction class
2406- */
2407-class HermiteGammaApproximationFunction
2408-{
2409-public:
2410- HermiteGammaApproximationFunction(float user_interval_upper);
2411- virtual ~HermiteGammaApproximationFunction() { }
2412-
2413- float evaluate(float x);
2414-
2415-private:
2416- float m_xScale;
2417- float m_nonzeroIntervalUpper;
2418-};
2419-
2420-/*!
2421- * \brief The ShadowDetailTransformation class
2422- */
2423-class ShadowDetailTransformation : public virtual HSVTransformation
2424-{
2425- static const float MAX_EFFECT_SHIFT;
2426- static const float MIN_TONAL_WIDTH;
2427- static const float MAX_TONAL_WIDTH;
2428- static const float TONAL_WIDTH;
2429-
2430-public:
2431- ShadowDetailTransformation(float intensity);
2432-
2433- bool isIdentity() const;
2434-
2435-private:
2436- float m_intensity;
2437-};
2438-
2439-/*!
2440- * \brief The AutoEnhanceTransformation class
2441- */
2442-class AutoEnhanceTransformation : public virtual HSVTransformation
2443-{
2444- static const int SHADOW_DETECT_MIN_INTENSITY;
2445- static const int SHADOW_DETECT_MAX_INTENSITY;
2446- static const int SHADOW_DETECT_INTENSITY_RANGE;
2447- static const int EMPIRICAL_DARK;
2448- static const float SHADOW_AGGRESSIVENESS_MUL;
2449-
2450-public:
2451- AutoEnhanceTransformation(const QImage& basis_image);
2452- virtual ~AutoEnhanceTransformation();
2453-
2454- QColor transformPixel(const QColor& pixel_color) const;
2455- bool isIdentity() const;
2456-
2457-private:
2458- ShadowDetailTransformation* m_shadowTransform;
2459- ToneExpansionTransformation* m_toneExpansionTransform;
2460-};
2461-
2462-
2463-#endif // GALLERY_UTIL_IMAGING_H_
2464-
2465
2466=== removed file 'src/photoeditor/orientation.cpp'
2467--- src/photoeditor/orientation.cpp 2015-02-26 20:28:06 +0000
2468+++ src/photoeditor/orientation.cpp 1970-01-01 00:00:00 +0000
2469@@ -1,152 +0,0 @@
2470-/*
2471- * Copyright (C) 2011 Canonical Ltd
2472- *
2473- * This program is free software: you can redistribute it and/or modify
2474- * it under the terms of the GNU General Public License version 3 as
2475- * published by the Free Software Foundation.
2476- *
2477- * This program is distributed in the hope that it will be useful,
2478- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2479- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2480- * GNU General Public License for more details.
2481- *
2482- * You should have received a copy of the GNU General Public License
2483- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2484- *
2485- * Authors:
2486- * Lucas Beeler <lucas@yorba.org>
2487- */
2488-
2489-#include <cstdio>
2490-
2491-#include "orientation.h"
2492-
2493-/*!
2494- * \brief OrientationCorrection::fromOrientation
2495- * \param o
2496- * \return
2497- */
2498-OrientationCorrection OrientationCorrection::fromOrientation(Orientation o)
2499-{
2500- double rotation_angle = 0.0;
2501- double horizontal_scale_factor = 1.0;
2502-
2503- switch (o) {
2504- case TOP_RIGHT_ORIGIN:
2505- horizontal_scale_factor = -1.0;
2506- break;
2507-
2508- case BOTTOM_RIGHT_ORIGIN:
2509- rotation_angle = 180.0;
2510- break;
2511-
2512- case BOTTOM_LEFT_ORIGIN:
2513- horizontal_scale_factor = -1.0;
2514- rotation_angle = 180.0;
2515- break;
2516-
2517- case LEFT_TOP_ORIGIN:
2518- horizontal_scale_factor = -1.0;
2519- rotation_angle = -90.0;
2520- break;
2521-
2522- case RIGHT_TOP_ORIGIN:
2523- rotation_angle = 90.0;
2524- break;
2525-
2526- case RIGHT_BOTTOM_ORIGIN:
2527- horizontal_scale_factor = -1.0;
2528- rotation_angle = 90.0;
2529- break;
2530-
2531- case LEFT_BOTTOM_ORIGIN:
2532- rotation_angle = -90.0;
2533- break;
2534-
2535- default:
2536- ; // do nothing
2537- break;
2538- }
2539-
2540- return OrientationCorrection(rotation_angle, horizontal_scale_factor);
2541-}
2542-
2543-/*!
2544- * \brief OrientationCorrection::identity
2545- * \return
2546- */
2547-OrientationCorrection OrientationCorrection::identity()
2548-{
2549- return OrientationCorrection(0.0, 1.0);
2550-}
2551-
2552-/*!
2553- * \brief OrientationCorrection::rotateOrientation
2554- * \param orientation
2555- * \param left
2556- * \return
2557- */
2558-Orientation OrientationCorrection::rotateOrientation(Orientation orientation, bool left)
2559-{
2560- QVector<Orientation> sequence_a;
2561- QVector<Orientation> sequence_b;
2562- sequence_a <<
2563- TOP_LEFT_ORIGIN << LEFT_BOTTOM_ORIGIN << BOTTOM_RIGHT_ORIGIN << RIGHT_TOP_ORIGIN;
2564- sequence_b <<
2565- TOP_RIGHT_ORIGIN << RIGHT_BOTTOM_ORIGIN << BOTTOM_LEFT_ORIGIN << LEFT_TOP_ORIGIN;
2566-
2567- const QVector<Orientation>& sequence = (
2568- sequence_a.contains(orientation) ? sequence_a : sequence_b);
2569-
2570- int current = sequence.indexOf(orientation);
2571- int jump = (left ? 1 : sequence.count() - 1);
2572- int next = (current + jump) % sequence.count();
2573-
2574- return sequence[next];
2575-}
2576-
2577-/*!
2578- * \brief OrientationCorrection::toTransform
2579- * Returns the correction as a QTransform.
2580- * \return Returns the correction as a QTransform.
2581- */
2582-QTransform OrientationCorrection::toTransform() const
2583-{
2584- QTransform result;
2585- result.scale(m_horizontalScaleFactor, 1.0);
2586- result.rotate(m_rotationAngle);
2587-
2588- return result;
2589-}
2590-
2591-/*!
2592- * \brief OrientationCorrection::isFlippedFrom
2593- * Returns whether the two orientations are flipped relative to each other.
2594- * Ignores rotation_angle; only checks horizontal_scale_factor_.
2595- * \param other
2596- * \return
2597- */
2598-bool OrientationCorrection::isFlippedFrom(
2599- const OrientationCorrection& other) const
2600-{
2601- return (m_horizontalScaleFactor != other.m_horizontalScaleFactor);
2602-}
2603-
2604-/*!
2605- * \brief OrientationCorrection::getNormalizedRotationDifference
2606- * Returns the rotation difference in degrees (this - other), normalized to
2607- * 0, 90, 180, or 270. Ignores the horizontal_scale_factor_.
2608- * \param other
2609- * \return
2610- */
2611-int OrientationCorrection::getNormalizedRotationDifference(
2612- const OrientationCorrection& other) const
2613-{
2614- int degrees_rotation = (int)m_rotationAngle - (int)other.m_rotationAngle;
2615- if (degrees_rotation < 0)
2616- degrees_rotation += 360;
2617-
2618- Q_ASSERT(degrees_rotation == 0 || degrees_rotation == 90 ||
2619- degrees_rotation == 180 || degrees_rotation == 270);
2620- return degrees_rotation;
2621-}
2622
2623=== removed file 'src/photoeditor/orientation.h'
2624--- src/photoeditor/orientation.h 2015-02-26 20:28:06 +0000
2625+++ src/photoeditor/orientation.h 1970-01-01 00:00:00 +0000
2626@@ -1,64 +0,0 @@
2627-/*
2628- * Copyright (C) 2011 Canonical Ltd
2629- *
2630- * This program is free software: you can redistribute it and/or modify
2631- * it under the terms of the GNU General Public License version 3 as
2632- * published by the Free Software Foundation.
2633- *
2634- * This program is distributed in the hope that it will be useful,
2635- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2636- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2637- * GNU General Public License for more details.
2638- *
2639- * You should have received a copy of the GNU General Public License
2640- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2641- *
2642- * Authors:
2643- * Lucas Beeler <lucas@yorba.org>
2644- */
2645-
2646-#ifndef GALLERY_ORIENTATION_H_
2647-#define GALLERY_ORIENTATION_H_
2648-
2649-#include <QTransform>
2650-
2651-enum Orientation {
2652- ORIGINAL_ORIENTATION = 0,
2653- MIN_ORIENTATION = 1,
2654- TOP_LEFT_ORIGIN = 1,
2655- TOP_RIGHT_ORIGIN = 2,
2656- BOTTOM_RIGHT_ORIGIN = 3,
2657- BOTTOM_LEFT_ORIGIN = 4,
2658- LEFT_TOP_ORIGIN = 5,
2659- RIGHT_TOP_ORIGIN = 6,
2660- RIGHT_BOTTOM_ORIGIN = 7,
2661- LEFT_BOTTOM_ORIGIN = 8,
2662- MAX_ORIENTATION = 8
2663-};
2664-
2665-/*!
2666- * \brief The OrientationCorrection struct
2667- */
2668-class OrientationCorrection
2669-{
2670-public:
2671- static OrientationCorrection fromOrientation(Orientation o);
2672- static OrientationCorrection identity();
2673- static Orientation rotateOrientation(Orientation orientation, bool left);
2674-
2675- QTransform toTransform() const;
2676-
2677- bool isFlippedFrom(const OrientationCorrection& other) const;
2678- int getNormalizedRotationDifference(const OrientationCorrection& other) const;
2679-
2680-private:
2681- OrientationCorrection(double rotation_angle, double horizontal_scale_factor)
2682- : m_rotationAngle(rotation_angle),
2683- m_horizontalScaleFactor(horizontal_scale_factor) { }
2684-
2685- const double m_rotationAngle;
2686- const double m_horizontalScaleFactor;
2687-};
2688-
2689-
2690-#endif // GALLERY_ORIENTATION_H_
2691
2692=== removed file 'src/photoeditor/photo-caches.cpp'
2693--- src/photoeditor/photo-caches.cpp 2015-02-26 20:28:06 +0000
2694+++ src/photoeditor/photo-caches.cpp 1970-01-01 00:00:00 +0000
2695@@ -1,183 +0,0 @@
2696-/*
2697- * Copyright (C) 2012 Canonical Ltd
2698- *
2699- * This program is free software: you can redistribute it and/or modify
2700- * it under the terms of the GNU General Public License version 3 as
2701- * published by the Free Software Foundation.
2702- *
2703- * This program is distributed in the hope that it will be useful,
2704- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2705- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2706- * GNU General Public License for more details.
2707- *
2708- * You should have received a copy of the GNU General Public License
2709- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2710- *
2711- * Authors:
2712- * Charles Lindsay <chaz@yorba.org>
2713- */
2714-
2715-#include "photo-caches.h"
2716-
2717-#include <QDir>
2718-#include <utime.h>
2719-
2720-const QString PhotoCaches::ORIGINAL_DIR = ".original";
2721-const QString PhotoCaches::ENHANCED_DIR = ".enhanced";
2722-
2723-/*!
2724- * \brief PhotoCaches::PhotoCaches
2725- * \param file
2726- */
2727-PhotoCaches::PhotoCaches(const QFileInfo& file) : m_file(file),
2728- m_originalFile(file.dir(),
2729- QString("%1/%2").arg(ORIGINAL_DIR).arg(file.fileName())),
2730- m_enhancedFile(file.dir(),
2731- QString("%1/%2").arg(ENHANCED_DIR).arg(file.fileName()))
2732-{
2733- // We always want our file checks to hit the disk.
2734- m_file.setCaching(false);
2735- m_originalFile.setCaching(false);
2736- m_enhancedFile.setCaching(false);
2737-}
2738-
2739-/*!
2740- * \brief PhotoCaches::hasCachedOriginal
2741- * \return
2742- */
2743-bool PhotoCaches::hasCachedOriginal() const
2744-{
2745- return m_originalFile.exists();
2746-}
2747-
2748-/*!
2749- * \brief PhotoCaches::hasCachedEnhanced
2750- * \return
2751- */
2752-bool PhotoCaches::hasCachedEnhanced() const
2753-{
2754- return m_enhancedFile.exists();
2755-}
2756-
2757-/*!
2758- * \brief PhotoCaches::originalFile
2759- * \return
2760- */
2761-const QFileInfo& PhotoCaches::originalFile() const
2762-{
2763- return m_originalFile;
2764-}
2765-
2766-/*!
2767- * \brief PhotoCaches::enhancedFile
2768- * \return
2769- */
2770-const QFileInfo& PhotoCaches::enhancedFile() const
2771-{
2772- return m_enhancedFile;
2773-}
2774-
2775-/*!
2776- * \brief PhotoCaches::pristineFile
2777- * Returns original_file() if it exists; otherwise, returns the file passed
2778- * to the constructor.
2779- * \return
2780- */
2781-const QFileInfo& PhotoCaches::pristineFile() const
2782-{
2783- return (hasCachedOriginal() ? m_originalFile : m_file);
2784-}
2785-
2786-/*!
2787- * \brief PhotoCaches::cacheOriginal
2788- * Moves the pristine file into .original so we don't mess it up. Note that
2789- * this potentially removes the main file, so it must be followed by a copy
2790- * from original (or elsewhere) back to the file.
2791- * \return
2792- */
2793-bool PhotoCaches::cacheOriginal()
2794-{
2795- if (hasCachedOriginal()) {
2796- return true;
2797- }
2798-
2799- m_file.dir().mkdir(ORIGINAL_DIR);
2800-
2801- return rename(m_file, m_originalFile);
2802-}
2803-
2804-/*!
2805- * \brief PhotoCaches::restoreOriginal
2806- * Moves the file out of .original, overwriting the main file. Note that
2807- * this removes the .original file.
2808- * \return
2809- */
2810-bool PhotoCaches::restoreOriginal()
2811-{
2812- if (!hasCachedOriginal()) {
2813- return true;
2814- }
2815-
2816- remove(m_file);
2817- // touch the file so that the thumbnails will correctly regenerate
2818- utime(m_originalFile.absoluteFilePath().toUtf8(), NULL);
2819- return rename(m_originalFile, m_file);
2820-}
2821-
2822-/*!
2823- * \brief PhotoCaches::cacheEnhancedFromOriginal
2824- * Copies the file in .original to .enhanced so it can then be enhanced.
2825- * \return
2826- */
2827-bool PhotoCaches::cacheEnhancedFromOriginal()
2828-{
2829- m_file.dir().mkdir(ENHANCED_DIR);
2830-
2831- // If called subsequently, the previously cached version is replaced.
2832- remove(m_enhancedFile);
2833- return copy(pristineFile(), m_enhancedFile);
2834-}
2835-
2836-/*!
2837- * \brief PhotoCaches::overwriteFromCache
2838- * Tries to overwrite the file from one of its cached versions.
2839- * \param preferEnhanced
2840- * \return
2841- */
2842-bool PhotoCaches::overwriteFromCache(bool preferEnhanced)
2843-{
2844- if (preferEnhanced && hasCachedEnhanced()) {
2845- remove(m_file);
2846- return copy(m_enhancedFile, m_file);
2847- } else if (hasCachedOriginal()) {
2848- remove(m_file);
2849- return copy(m_originalFile, m_file);
2850- } else {
2851- return true;
2852- }
2853-}
2854-
2855-/*!
2856- * \brief PhotoCaches::discardCachedOriginal
2857- */
2858-void PhotoCaches::discardCachedOriginal()
2859-{
2860- remove(m_originalFile);
2861-}
2862-
2863-/*!
2864- * \brief PhotoCaches::discardCachedEnhanced
2865- */
2866-void PhotoCaches::discardCachedEnhanced()
2867-{
2868- remove(m_enhancedFile);
2869-}
2870-
2871-/*!
2872- * \brief PhotoCaches::discardAll
2873- */
2874-void PhotoCaches::discardAll()
2875-{
2876- discardCachedOriginal();
2877- discardCachedEnhanced();
2878-}
2879
2880=== removed file 'src/photoeditor/photo-caches.h'
2881--- src/photoeditor/photo-caches.h 2015-02-26 20:28:06 +0000
2882+++ src/photoeditor/photo-caches.h 1970-01-01 00:00:00 +0000
2883@@ -1,76 +0,0 @@
2884-/*
2885- * Copyright (C) 2012 Canonical Ltd
2886- *
2887- * This program is free software: you can redistribute it and/or modify
2888- * it under the terms of the GNU General Public License version 3 as
2889- * published by the Free Software Foundation.
2890- *
2891- * This program is distributed in the hope that it will be useful,
2892- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2893- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2894- * GNU General Public License for more details.
2895- *
2896- * You should have received a copy of the GNU General Public License
2897- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2898- *
2899- * Authors:
2900- * Charles Lindsay <chaz@yorba.org>
2901- */
2902-
2903-#ifndef GALLERY_PHOTO_CACHES_H_
2904-#define GALLERY_PHOTO_CACHES_H_
2905-
2906-#include <QFile>
2907-#include <QFileInfo>
2908-#include <QString>
2909-
2910-/*!
2911- * \brief The PhotoCaches class
2912- *
2913- * An abstraction around the various files we keep in addition to the photo
2914- * file itself: the original, the pristine version of the file without any
2915- * applied edits; and the enhanced, a version of the original with auto-enhance
2916- * applied to it (necessary because of how slow auto-enhance is).
2917- */
2918-class PhotoCaches
2919-{
2920-public:
2921- static const QString ORIGINAL_DIR;
2922- static const QString ENHANCED_DIR;
2923-
2924- PhotoCaches(); // FIXME: remove this class and only deal with a stack of temporary rollback files
2925- PhotoCaches(const QFileInfo& file);
2926-
2927- bool hasCachedOriginal() const;
2928- bool hasCachedEnhanced() const;
2929-
2930- const QFileInfo& originalFile() const;
2931- const QFileInfo& enhancedFile() const;
2932- const QFileInfo& pristineFile() const;
2933-
2934- bool cacheOriginal();
2935- bool restoreOriginal();
2936- bool cacheEnhancedFromOriginal();
2937- bool overwriteFromCache(bool preferEnhanced);
2938-
2939- void discardCachedOriginal();
2940- void discardCachedEnhanced();
2941- void discardAll();
2942-
2943-private:
2944- static bool remove(const QFileInfo& file) {
2945- return QFile::remove(file.filePath());
2946- }
2947- static bool rename(const QFileInfo& oldName, const QFileInfo& newName) {
2948- return QFile::rename(oldName.filePath(), newName.filePath());
2949- }
2950- static bool copy(const QFileInfo& oldName, const QFileInfo& newName) {
2951- return QFile::copy(oldName.filePath(), newName.filePath());
2952- }
2953-
2954- QFileInfo m_file;
2955- QFileInfo m_originalFile;
2956- QFileInfo m_enhancedFile;
2957-};
2958-
2959-#endif
2960
2961=== removed file 'src/photoeditor/photo-data.cpp'
2962--- src/photoeditor/photo-data.cpp 2015-02-26 20:28:06 +0000
2963+++ src/photoeditor/photo-data.cpp 1970-01-01 00:00:00 +0000
2964@@ -1,275 +0,0 @@
2965-/*
2966- * Copyright (C) 2011-2014 Canonical Ltd
2967- *
2968- * This program is free software: you can redistribute it and/or modify
2969- * it under the terms of the GNU General Public License version 3 as
2970- * published by the Free Software Foundation.
2971- *
2972- * This program is distributed in the hope that it will be useful,
2973- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2974- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2975- * GNU General Public License for more details.
2976- *
2977- * You should have received a copy of the GNU General Public License
2978- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2979- *
2980- * Authors:
2981- * Jim Nelson <jim@yorba.org>
2982- * Lucas Beeler <lucas@yorba.org>
2983- * Charles Lindsay <chaz@yorba.org>
2984- * Eric Gregory <eric@yorba.org>
2985- * Clint Rogers <clinton@yorba.org>
2986- * Ugo Riboni <ugo.riboni@canonical.com>
2987- */
2988-
2989-#include "photo-data.h"
2990-#include "photo-edit-command.h"
2991-#include "photo-edit-thread.h"
2992-
2993-// medialoader
2994-#include "photo-metadata.h"
2995-
2996-// util
2997-#include "imaging.h"
2998-
2999-#include <QApplication>
3000-#include <QDebug>
3001-#include <QDir>
3002-#include <QFileInfo>
3003-#include <QImage>
3004-#include <QImageReader>
3005-#include <QImageWriter>
3006-#include <QStack>
3007-#include <QStandardPaths>
3008-
3009-/*!
3010- * \brief Photo::isValid
3011- * \param file
3012- * \return
3013- */
3014-bool PhotoData::isValid(const QFileInfo& file)
3015-{
3016- QImageReader reader(file.filePath());
3017- QByteArray format = reader.format();
3018-
3019- if (QString(format).toLower() == "tiff") {
3020- // QImageReader.canRead() will detect some raw files as readable TIFFs,
3021- // though QImage will fail to load them.
3022- QString extension = file.suffix().toLower();
3023- if (extension != "tiff" && extension != "tif")
3024- return false;
3025- }
3026-
3027- PhotoMetadata* tmp = PhotoMetadata::fromFile(file);
3028- if (tmp == NULL)
3029- return false;
3030-
3031- delete tmp;
3032- return reader.canRead() &&
3033- QImageWriter::supportedImageFormats().contains(reader.format());
3034-}
3035-
3036-/*!
3037- * \brief Photo::Photo
3038- * \param file
3039- */
3040-PhotoData::PhotoData()
3041- : QObject(),
3042- m_editThread(0),
3043- m_busy(false),
3044- m_orientation(TOP_LEFT_ORIGIN)
3045-{
3046-}
3047-
3048-void PhotoData::setPath(QString path)
3049-{
3050- if (QFileInfo(path).absoluteFilePath() != m_file.absoluteFilePath()) {
3051- QFileInfo newFile(path);
3052- if (newFile.exists() && newFile.isFile()) {
3053- QByteArray format = QImageReader(newFile.absoluteFilePath()).format();
3054- m_fileFormat = QString(format).toLower();
3055- if (m_fileFormat == "jpg") // Why does Qt expose two different names here?
3056- m_fileFormat = "jpeg";
3057-
3058- m_file = newFile;
3059- Q_EMIT pathChanged();
3060-
3061- if (fileFormatHasMetadata()) {
3062- PhotoMetadata* metadata = PhotoMetadata::fromFile(newFile.absoluteFilePath());
3063- m_orientation = metadata->orientation();
3064- delete metadata;
3065- Q_EMIT orientationChanged();
3066- }
3067- }
3068- }
3069-}
3070-
3071-QString PhotoData::path() const
3072-{
3073- return m_file.absoluteFilePath();
3074-}
3075-
3076-QFileInfo PhotoData::file() const
3077-{
3078- return m_file;
3079-}
3080-
3081-/*!
3082- * \brief Photo::~Photo
3083- */
3084-PhotoData::~PhotoData()
3085-{
3086- if (m_editThread) {
3087- m_editThread->wait();
3088- finishEditing();
3089- }
3090-}
3091-
3092-/*!
3093- * \brief Photo::orientation
3094- * \return
3095- */
3096-Orientation PhotoData::orientation() const
3097-{
3098- return m_orientation;
3099-}
3100-
3101-void PhotoData::refreshFromDisk()
3102-{
3103- if (fileFormatHasMetadata()) {
3104- PhotoMetadata* metadata = PhotoMetadata::fromFile(m_file.absoluteFilePath());
3105- qDebug() << "Refreshing orient." << m_orientation << "to" << metadata->orientation();
3106- m_orientation = metadata->orientation();
3107- delete metadata;
3108- Q_EMIT orientationChanged();
3109- }
3110-
3111- Q_EMIT dataChanged();
3112-}
3113-
3114-/*!
3115- * \brief Photo::rotateRight
3116- */
3117-void PhotoData::rotateRight()
3118-{
3119- Orientation current = fileFormatHasOrientation() ? orientation() :
3120- TOP_LEFT_ORIGIN;
3121- Orientation rotated = OrientationCorrection::rotateOrientation(current,
3122- false);
3123- qDebug() << " Rotate from orientation " << current << "to" << rotated;
3124-
3125- PhotoEditCommand command;
3126- command.type = EDIT_ROTATE;
3127- command.orientation = rotated;
3128- asyncEdit(command);
3129-}
3130-
3131-/*!
3132- * \brief Photo::autoEnhance
3133- */
3134-void PhotoData::autoEnhance()
3135-{
3136- PhotoEditCommand command;
3137- command.type = EDIT_ENHANCE;
3138- asyncEdit(command);
3139-}
3140-
3141-/*!
3142- * \brief Photo::exposureCompensation Changes the brightnes of the image
3143- * \param value Value for the compensation. -1.0 moves the image into total black.
3144- * +1.0 to total white. 0.0 leaves it as it is.
3145- */
3146-void PhotoData::exposureCompensation(qreal value)
3147-{
3148- PhotoEditCommand command;
3149- command.type = EDIT_COMPENSATE_EXPOSURE;
3150- command.exposureCompensation = value;
3151- asyncEdit(command);
3152-}
3153-
3154-/*!
3155- * \brief Photo::crop
3156- * Specify all coords in [0.0, 1.0], where 1.0 is the full size of the image.
3157- * They will be clamped to this range if you don't.
3158- * \param vrect the rectangle specifying the region to be cropped
3159- */
3160-void PhotoData::crop(QVariant vrect)
3161-{
3162- PhotoEditCommand command;
3163- command.type = EDIT_CROP;
3164- command.crop_rectangle = vrect.toRectF();
3165- asyncEdit(command);
3166-}
3167-
3168-/*!
3169- * \brief Photo::asyncEdit does edit the photo according to the given command
3170- * in a background thread.
3171- * \param The command defining the edit operation to perform.
3172- */
3173-void PhotoData::asyncEdit(const PhotoEditCommand& command)
3174-{
3175- if (m_busy) {
3176- qWarning() << "Can't start edit operation while another one is running.";
3177- return;
3178- }
3179- m_busy = true;
3180- Q_EMIT busyChanged();
3181- m_editThread = new PhotoEditThread(this, command);
3182- connect(m_editThread, SIGNAL(finished()), this, SLOT(finishEditing()));
3183- m_editThread->start();
3184-}
3185-
3186-/*!
3187- * \brief Photo::finishEditing do all the updates once the editing is done
3188- */
3189-void PhotoData::finishEditing()
3190-{
3191- if (!m_editThread || m_editThread->isRunning())
3192- return;
3193-
3194- m_editThread->deleteLater();
3195- m_editThread = 0;
3196- m_busy = false;
3197-
3198- refreshFromDisk();
3199-
3200- Q_EMIT busyChanged();
3201- Q_EMIT editFinished();
3202-}
3203-
3204-/*!
3205- * \brief Photo::fileFormat returns the file format as QString
3206- * \return
3207- */
3208-const QString &PhotoData::fileFormat() const
3209-{
3210- return m_fileFormat;
3211-}
3212-
3213-/*!
3214- * \brief Photo::fileFormatHasMetadata
3215- * \return
3216- */
3217-bool PhotoData::fileFormatHasMetadata() const
3218-{
3219- return (m_fileFormat == "jpeg" || m_fileFormat == "tiff" ||
3220- m_fileFormat == "png");
3221-}
3222-
3223-/*!
3224- * \brief Photo::fileFormatHasOrientation
3225- * \return
3226- */
3227-bool PhotoData::fileFormatHasOrientation() const
3228-{
3229- return (m_fileFormat == "jpeg");
3230-}
3231-
3232-/*!
3233- * \brief Photo::busy return true if there is an editing operation in progress
3234- * \return
3235- */
3236-bool PhotoData::busy() const
3237-{
3238- return m_busy;
3239-}
3240
3241=== removed file 'src/photoeditor/photo-data.h'
3242--- src/photoeditor/photo-data.h 2015-02-26 20:28:06 +0000
3243+++ src/photoeditor/photo-data.h 1970-01-01 00:00:00 +0000
3244@@ -1,92 +0,0 @@
3245-/*
3246- * Copyright (C) 2011-2014 Canonical Ltd
3247- *
3248- * This program is free software: you can redistribute it and/or modify
3249- * it under the terms of the GNU General Public License version 3 as
3250- * published by the Free Software Foundation.
3251- *
3252- * This program is distributed in the hope that it will be useful,
3253- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3254- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3255- * GNU General Public License for more details.
3256- *
3257- * You should have received a copy of the GNU General Public License
3258- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3259- *
3260- * Authors:
3261- * Jim Nelson <jim@yorba.org>
3262- * Lucas Beeler <lucas@yorba.org>
3263- * Charles Lindsay <chaz@yorba.org>
3264- * Ugo Riboni <ugo.riboni@canonical.com>
3265- */
3266-
3267-#ifndef PHOTO_DATA_H_
3268-#define PHOTO_DATA_H_
3269-
3270-// util
3271-#include "orientation.h"
3272-
3273-// QT
3274-#include <QFileInfo>
3275-#include <QVariant>
3276-
3277-class PhotoEditCommand;
3278-class PhotoEditThread;
3279-
3280-/*!
3281- * \brief The Photo class
3282- */
3283-class PhotoData : public QObject
3284-{
3285- Q_OBJECT
3286-
3287- Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
3288- Q_PROPERTY(int orientation READ orientation NOTIFY orientationChanged)
3289- Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
3290-
3291-public:
3292- explicit PhotoData();
3293- virtual ~PhotoData();
3294-
3295- static bool isValid(const QFileInfo& file);
3296-
3297- QString path() const;
3298- void setPath(QString path);
3299- QFileInfo file() const;
3300- bool busy() const;
3301-
3302- virtual Orientation orientation() const;
3303-
3304- Q_INVOKABLE void refreshFromDisk();
3305- Q_INVOKABLE void rotateRight();
3306- Q_INVOKABLE void autoEnhance();
3307- Q_INVOKABLE void exposureCompensation(qreal value);
3308- Q_INVOKABLE void crop(QVariant vrect);
3309-
3310- const QString &fileFormat() const;
3311- bool fileFormatHasMetadata() const;
3312- bool fileFormatHasOrientation() const;
3313-
3314-Q_SIGNALS:
3315- void pathChanged();
3316- void orientationChanged();
3317- void busyChanged();
3318-
3319- void editFinished();
3320- void dataChanged();
3321-
3322-private Q_SLOTS:
3323- void finishEditing();
3324-
3325-private:
3326- void asyncEdit(const PhotoEditCommand& state);
3327-
3328- QString m_fileFormat;
3329- PhotoEditThread *m_editThread;
3330- QFileInfo m_file;
3331- bool m_busy;
3332-
3333- Orientation m_orientation;
3334-};
3335-
3336-#endif // PHOTO_DATA_H_
3337
3338=== removed file 'src/photoeditor/photo-edit-command.h'
3339--- src/photoeditor/photo-edit-command.h 2015-02-26 20:28:06 +0000
3340+++ src/photoeditor/photo-edit-command.h 1970-01-01 00:00:00 +0000
3341@@ -1,58 +0,0 @@
3342-/*
3343- * Copyright (C) 2014 Canonical Ltd
3344- *
3345- * This program is free software: you can redistribute it and/or modify
3346- * it under the terms of the GNU General Public License version 3 as
3347- * published by the Free Software Foundation.
3348- *
3349- * This program is distributed in the hope that it will be useful,
3350- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3351- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3352- * GNU General Public License for more details.
3353- *
3354- * You should have received a copy of the GNU General Public License
3355- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3356- */
3357-
3358-#ifndef GALLERY_PHOTO_EDIT_STATE_H_
3359-#define GALLERY_PHOTO_EDIT_STATE_H_
3360-
3361-// util
3362-#include "orientation.h"
3363-
3364-#include <QRectF>
3365-#include <QVector4D>
3366-
3367-enum EditType {
3368- EDIT_NONE = 0,
3369- EDIT_ROTATE = 1,
3370- EDIT_CROP = 2,
3371- EDIT_ENHANCE = 3,
3372- EDIT_COMPENSATE_EXPOSURE = 4
3373-};
3374-
3375-/*!
3376- * \brief The PhotoEditCommand class
3377- *
3378- * A single edit that will be applied to a photo.
3379- */
3380-class PhotoEditCommand
3381-{
3382-public:
3383- EditType type;
3384- Orientation orientation;
3385- QRectF crop_rectangle;
3386- qreal exposureCompensation;
3387- /// The color balance parameters are stored here in the order:
3388- /// brightness (x), contrast(y), saturation(z), hue(w)
3389- QVector4D colorBalance_;
3390-
3391- PhotoEditCommand() :
3392- type(EDIT_NONE),
3393- orientation(ORIGINAL_ORIENTATION),
3394- crop_rectangle(),
3395- exposureCompensation(0.0) {
3396- }
3397-};
3398-
3399-#endif
3400
3401=== removed file 'src/photoeditor/photo-edit-thread.cpp'
3402--- src/photoeditor/photo-edit-thread.cpp 2015-02-26 20:28:06 +0000
3403+++ src/photoeditor/photo-edit-thread.cpp 1970-01-01 00:00:00 +0000
3404@@ -1,185 +0,0 @@
3405-/*
3406- * Copyright (C) 2013-2014 Canonical Ltd
3407- *
3408- * This program is free software: you can redistribute it and/or modify
3409- * it under the terms of the GNU General Public License version 3 as
3410- * published by the Free Software Foundation.
3411- *
3412- * This program is distributed in the hope that it will be useful,
3413- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3414- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3415- * GNU General Public License for more details.
3416- *
3417- * You should have received a copy of the GNU General Public License
3418- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3419- */
3420-
3421-#include "photo-edit-thread.h"
3422-#include "photo-data.h"
3423-
3424-// medialoader
3425-#include "photo-metadata.h"
3426-
3427-// util
3428-#include "imaging.h"
3429-
3430-#include <QDebug>
3431-
3432-/*!
3433- * \brief PhotoEditThread::PhotoEditThread
3434- */
3435-PhotoEditThread::PhotoEditThread(PhotoData *photo, const PhotoEditCommand &command)
3436- : QThread(),
3437- m_photo(photo),
3438- m_command(command)
3439-{
3440-}
3441-
3442-/*!
3443- * \brief PhotoEditThread::command resturns the editing command used for this processing
3444- * \return
3445- */
3446-const PhotoEditCommand &PhotoEditThread::command() const
3447-{
3448- return m_command;
3449-}
3450-
3451-/*!
3452- * \brief PhotoEditThread::run \reimp
3453- */
3454-void PhotoEditThread::run()
3455-{
3456- // The only operation in which we don't have to work on the actual image
3457- // pixels is image rotation in the case where we can simply change the
3458- // metadata rotation field.
3459- if (m_command.type == EDIT_ROTATE && m_photo->fileFormatHasOrientation()) {
3460- handleSimpleMetadataRotation(m_command);
3461- return;
3462- }
3463-
3464- // In all other cases we load the image, do the work, and save it back.
3465- QImage image(m_photo->file().filePath(), m_photo->fileFormat().toStdString().c_str());
3466- if (image.isNull()) {
3467- qWarning() << "Error loading" << m_photo->file().filePath() << "for editing";
3468- return;
3469- }
3470-
3471- // Copy all metadata from the original image so that we can save it to the
3472- // new one after modifying the pixels.
3473- PhotoMetadata* original = PhotoMetadata::fromFile(m_photo->file());
3474-
3475- // If the photo was previously rotated through metadata and we are editing
3476- // the actual pixels, first rotate the image to match the orientation so
3477- // that the correct pixels are edited.
3478- // Obviously don't do this in the case we have been asked to do a rotation
3479- // operation on the pixels, as we would do it later as the operation itself.
3480- if (m_photo->fileFormatHasOrientation() && m_command.type != EDIT_ROTATE) {
3481- Orientation orientation = m_photo->orientation();
3482- QTransform transform = OrientationCorrection::fromOrientation(orientation).toTransform();
3483- image = image.transformed(transform);
3484- }
3485-
3486- if (m_command.type == EDIT_ROTATE) {
3487- QTransform transform = OrientationCorrection::fromOrientation(m_command.orientation).toTransform();
3488- image = image.transformed(transform);
3489- } else if (m_command.type == EDIT_CROP) {
3490- QRect rect;
3491- rect.setX(qBound(0.0, m_command.crop_rectangle.x(), 1.0) * image.width());
3492- rect.setY(qBound(0.0, m_command.crop_rectangle.y(), 1.0) * image.height());
3493- rect.setWidth(qBound(0.0, m_command.crop_rectangle.width(), 1.0) * image.width());
3494- rect.setHeight(qBound(0.0, m_command.crop_rectangle.height(), 1.0) * image.height());
3495-
3496- image = image.copy(rect);
3497- } else if (m_command.type == EDIT_ENHANCE) {
3498- image = enhanceImage(image);
3499- } else if (m_command.type == EDIT_COMPENSATE_EXPOSURE) {
3500- image = compensateExposure(image, m_command.exposureCompensation);
3501- } else {
3502- qWarning() << "Edit thread running with unknown or no operation.";
3503- return;
3504- }
3505-
3506- bool saved = image.save(m_photo->file().filePath(),
3507- m_photo->fileFormat().toStdString().c_str(), 90);
3508- if (!saved)
3509- qWarning() << "Error saving edited" << m_photo->file().filePath();
3510-
3511- PhotoMetadata* copy = PhotoMetadata::fromFile(m_photo->file());
3512- original->copyTo(copy);
3513- copy->setOrientation(TOP_LEFT_ORIGIN); // reset previous orientation
3514- copy->updateThumbnail(image);
3515- copy->save();
3516-
3517- delete original;
3518- delete copy;
3519-}
3520-
3521-/*!
3522- * \brief PhotoEditThread::handleSimpleMetadataRotation
3523- * Handler for the case of an image whose only change is to its
3524- * orientation; used to skip re-encoding of JPEGs.
3525- * \param state
3526- */
3527-void PhotoEditThread::handleSimpleMetadataRotation(const PhotoEditCommand& state)
3528-{
3529- PhotoMetadata* metadata = PhotoMetadata::fromFile(m_photo->file());
3530- metadata->setOrientation(state.orientation);
3531- metadata->save();
3532- delete(metadata);
3533-}
3534-
3535-/*!
3536- * \brief PhotoEditThread::enhanceImage
3537- */
3538-QImage PhotoEditThread::enhanceImage(const QImage& image)
3539-{
3540- int width = image.width();
3541- int height = image.height();
3542-
3543- QImage sample_img = (image.width() > 400) ? image.scaledToWidth(400) : image;
3544-
3545- AutoEnhanceTransformation enhance = AutoEnhanceTransformation(sample_img);
3546-
3547- QImage::Format dest_format = image.format();
3548-
3549- // Can't write into indexed images, due to a limitation in Qt.
3550- if (dest_format == QImage::Format_Indexed8)
3551- dest_format = QImage::Format_RGB32;
3552-
3553- QImage enhanced_image(width, height, dest_format);
3554-
3555- for (int j = 0; j < height; j++) {
3556- for (int i = 0; i < width; i++) {
3557- QColor px = enhance.transformPixel(
3558- QColor(image.pixel(i, j)));
3559- enhanced_image.setPixel(i, j, px.rgb());
3560- }
3561- }
3562-
3563- return enhanced_image;
3564-}
3565-
3566-/*!
3567- * \brief PhotoEditThread::compensateExposure Compensates the exposure
3568- * Compensating the exposure is a change in brightnes
3569- * \param image Image to change the brightnes
3570- * \param compansation -1.0 is total dark, +1.0 is total bright
3571- * \return The image with adjusted brightnes
3572- */
3573-QImage PhotoEditThread::compensateExposure(const QImage &image, qreal compensation)
3574-{
3575- int shift = qBound(-255, (int)(255*compensation), 255);
3576- QImage result(image.width(), image.height(), image.format());
3577-
3578- for (int j = 0; j < image.height(); j++) {
3579- for (int i = 0; i <image.width(); i++) {
3580- QColor px = image.pixel(i, j);
3581- int red = qBound(0, px.red() + shift, 255);
3582- int green = qBound(0, px.green() + shift, 255);
3583- int blue = qBound(0, px.blue() + shift, 255);
3584- result.setPixel(i, j, qRgb(red, green, blue));
3585- }
3586- }
3587-
3588- return result;
3589-}
3590
3591=== removed file 'src/photoeditor/photo-edit-thread.h'
3592--- src/photoeditor/photo-edit-thread.h 2015-02-26 20:28:06 +0000
3593+++ src/photoeditor/photo-edit-thread.h 1970-01-01 00:00:00 +0000
3594@@ -1,56 +0,0 @@
3595-/*
3596- * Copyright (C) 2013-2014 Canonical Ltd
3597- *
3598- * This program is free software: you can redistribute it and/or modify
3599- * it under the terms of the GNU General Public License version 3 as
3600- * published by the Free Software Foundation.
3601- *
3602- * This program is distributed in the hope that it will be useful,
3603- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3604- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3605- * GNU General Public License for more details.
3606- *
3607- * You should have received a copy of the GNU General Public License
3608- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3609- */
3610-
3611-#ifndef GALLERY_PHOTO_EDIT_THREAD_H_
3612-#define GALLERY_PHOTO_EDIT_THREAD_H_
3613-
3614-#include "photo-caches.h"
3615-#include "photo-edit-command.h"
3616-
3617-// util
3618-#include "orientation.h"
3619-
3620-#include <QImage>
3621-#include <QThread>
3622-#include <QUrl>
3623-
3624-class PhotoData;
3625-
3626-/*!
3627- * \brief The PhotoEditThread class
3628- */
3629-class PhotoEditThread: public QThread
3630-{
3631- Q_OBJECT
3632-public:
3633- PhotoEditThread(PhotoData *photo, const PhotoEditCommand& command);
3634-
3635- const PhotoEditCommand& command() const;
3636-
3637-protected:
3638- void run() Q_DECL_OVERRIDE;
3639-
3640-private:
3641- QImage enhanceImage(const QImage& image);
3642- QImage compensateExposure(const QImage& image, qreal compansation);
3643- QImage doColorBalance(const QImage& image, qreal brightness, qreal contrast, qreal saturation, qreal hue);
3644- void handleSimpleMetadataRotation(const PhotoEditCommand& state);
3645-
3646- PhotoData *m_photo;
3647- PhotoEditCommand m_command;
3648-};
3649-
3650-#endif

Subscribers

People subscribed via source and target branches