Index: main/trunk/model-interfaces-dev/atea/ocr/src/components/EditPage.vue
===================================================================
--- main/trunk/model-interfaces-dev/atea/ocr/src/components/EditPage.vue	(revision 35734)
+++ main/trunk/model-interfaces-dev/atea/ocr/src/components/EditPage.vue	(revision 35743)
@@ -1,28 +1,27 @@
 <template>
-<div class="root">
+<div class="edit-page-root">
     <div class="image-panel">
-        <table v-if="rotateMode" class="rotate-guide">
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-            <tr><hr /></tr>
-        </table>
-
-        <!-- <img :src="imageUrl" class="image" :style="{ filter: filterString, transform: transformString }" /> -->
-        <div class="image-container">
-            <img v-if="rotateMode" src="images/rotate_arrow_64.png" class="rotate-handle rotate-tl" />
-            <img v-if="rotateMode" src="images/rotate_arrow_64.png" class="rotate-handle rotate-tr" />
-            <img v-if="rotateMode" src="images/rotate_arrow_64.png" class="rotate-handle rotate-bl" />
-            <img v-if="rotateMode" src="images/rotate_arrow_64.png" class="rotate-handle rotate-br" />
-
-            <img :src="imageUrl" class="image" :style="{ filter: filterString, transform: transformString }" />
+        <div class="image-container" :style="{ transform: transformString }">
+            <img v-if="rotateMode" src="images/rotate-arrow.svg" class="rotate-handle rotate-tl" @mousedown="allowRotation = true" draggable="false" />
+            <img v-if="rotateMode" src="images/rotate-arrow.svg" class="rotate-handle rotate-tr" @mousedown="allowRotation = true" draggable="false" />
+            <img v-if="rotateMode" src="images/rotate-arrow.svg" class="rotate-handle rotate-bl" @mousedown="allowRotation = true" draggable="false" />
+            <img v-if="rotateMode" src="images/rotate-arrow.svg" class="rotate-handle rotate-br" @mousedown="allowRotation = true" draggable="false" />
+
+            <table v-if="rotateMode" class="rotate-guide" :style="{ transform: transformStringInverted }">
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+                <tr><td><hr /></td></tr>
+            </table>
+
+            <img ref="image" :src="imageUrl" class="image" :style="{ filter: filterString }" />
         </div>
     </div>
@@ -45,8 +44,7 @@
 
 <style lang="scss" scoped>
-.root {
+.edit-page-root {
     display: grid;
     grid-template-columns: 1fr auto;
-    grid-template-rows: 100%;
     align-items: center;
     justify-items: center;
@@ -65,21 +63,21 @@
 
 .image {
-    max-width: 100%;
-    height: auto;
+    max-width: 70vw;
+    max-height: 70vh;
 }
 
 .image-container {
-    max-width: 70%;
-    max-height: 70%;
     position: relative;
     margin: auto;
-    padding: 1em;
+    padding: 1.5em;
+    user-select: none;
 
     .rotate-handle {
         height: 2em;
         position: absolute;
+        z-index: 5;
 
         // Generated with https://codepen.io/sosuke/pen/Pjoqqp using var(--primary-bg-color)
-        filter: invert(16%) sepia(100%) saturate(3091%) hue-rotate(347deg) brightness(75%) contrast(90%);
+        // filter: invert(16%) sepia(100%) saturate(3091%) hue-rotate(347deg) brightness(75%) contrast(90%);
     }
 
@@ -116,6 +114,13 @@
     z-index: 3;
 
-    tr hr {
-        background-color: rgba(var(--bg-color-raw), 0.5);
+    tr {
+        td {
+            vertical-align: center;
+        }
+
+        hr {
+            background-color: rgba(var(--bg-color-raw), 0.5);
+            height: 2px;
+        }
     }
 }
@@ -137,4 +142,5 @@
 <script>
 import { mapState } from "vuex";
+import Jimp from "jimp/es";
 import ToggleButton from "./ToggleButton.vue"
 
@@ -151,5 +157,7 @@
             imageUrl: URL.createObjectURL(this.image),
             invert: false,
-            rotateMode: false
+            rotation: 0,
+            rotateMode: false,
+            allowRotation: false
         }
     },
@@ -167,9 +175,80 @@
             },
             transformString() {
-                return `rotate(${this.rotation}deg)`
+                return `rotate(${this.rotation}deg)`;
+            },
+            transformStringInverted() {
+                return `rotate(-${this.rotation}deg)`;
             }
         })
     },
     methods: {
+        async getImageBlobAsync() {
+            const buffer = Buffer.from(this.image.arrayBuffer());
+            const that = this;
+
+            const modifiedBuffer = await Jimp.read(buffer)
+                .then(async image => {
+                    if (that.invert) {
+                        image.invert();
+                    }
+
+                    // if (that.rotation !== 0) {
+                    //     image.rotate(that.rotation);
+                    // }
+
+                    return await image.getBufferAsync(Jimp.MIME_PNG);
+                });
+
+            return new Blob([ modifiedBuffer ], { type: Jimp.MIME_PNG });
+        },
+
+        onRotateHandleMouseDown(point) {
+            console.log(point);
+            this.rotatePoint = point;
+        },
+        /**
+         * @param {MouseEvent} e The mouse movement event.
+         */
+        onDocumentMouseMove(e) {
+            if (!this.allowRotation) {
+                return;
+            }
+
+            const imageRectangle = this.$refs.image.getBoundingClientRect();
+            const imageCenterX = (imageRectangle.width / 2) + imageRectangle.left;
+            const imageCenterY = (imageRectangle.height / 2) + imageRectangle.top;
+
+            if (e.clientX > imageCenterX) {
+                this.rotation += e.movementY / 8;
+            }
+            else {
+                this.rotation -= e.movementY / 8;
+            }
+
+            if (e.clientY > imageCenterY) {
+                this.rotation -= e.movementX / 8;
+            }
+            else {
+                this.rotation += e.movementX / 8;
+            }
+
+            if (this.rotation < 0) {
+                this.rotation = 360 + this.rotation;
+            }
+            else if (this.rotation > 360) {
+                this.rotation -= 360;
+            }
+        },
+        onDocumentMouseUp() {
+            this.allowRotation = false;
+        }
+    },
+    beforeMount() {
+        document.addEventListener("mousemove", this.onDocumentMouseMove);
+        document.addEventListener("mouseup", this.onDocumentMouseUp);
+    },
+    beforeUnmount() {
+        document.removeEventListener("mousemove", this.onDocumentMouseMove);
+        document.removeEventListener("mouseup", this.onDocumentMouseUp);
     }
 }
