source: main/trunk/model-interfaces-dev/atea/ocr/src/components/MainPage.vue@ 35743

Last change on this file since 35743 was 35743, checked in by cstephen, 13 months ago

Rework for single image content.
Implement rotation and inversion editing.

File size: 5.3 KB
Line 
1<template>
2<div class="main-page-root">
3 <edit-page v-if="showEditor" class="image-editor" :image="image" @closeRequested="onEditorCloseRequested" />
4
5 <div class="paper root-container" :class="{ 'root-container-image-state': image !== null }">
6 <div v-if="image === null" class="upload-area" @click="uploadFile">
7 <span class="heading1">{{ translations.get("Title") }}</span>
8 <span class="material-icons mdi-xl">upload_file</span>
9 <span>Upload an image/PDF</span>
10 </div>
11
12 <div v-if="image !== null" class="image-area">
13 <div class="controls">
14 <button class="btn-primary" @click="doOcr" :disabled="ocrInProgress">
15 <span class="material-icons">play_arrow</span>
16 <span>{{ translations.get("Main_PerformOCR") }}</span>
17 </button>
18
19 <button class="btn-primary" @click="showEditor = true">
20 <span class="material-icons">edit</span>
21 <span>Edit Image</span>
22 </button>
23
24 <button class="btn-primary" @click="reset" :disabled="ocrInProgress">
25 <span class="material-icons">restart_alt</span>
26 <span>New</span>
27 </button>
28
29 <div v-if="ocrInProgress" class="progress-bar-container">
30 <div class="progress-bar-value progress-bar-indeterminate" />
31 </div>
32 </div>
33
34 <img class="image-display" :src="imageUrl" />
35
36 <div class="text-container">
37 <pre>{{ ocrResult }}</pre>
38 </div>
39 </div>
40 </div>
41
42 <input ref="fileInput" type="file" @input="onFilesChanged" class="hidden"
43 accept="image/png,image/jpeg,image/gif,image/bmp,image/tiff,image/webp,application/pdf" />
44</div>
45
46</template>
47
48<style lang="scss" scoped>
49.main-page-root {
50 display: flex;
51 align-items: center;
52 justify-content: center;
53}
54
55.root-container {
56 padding: 1em;
57 transition-duration: var(--transition-duration);
58}
59
60.root-container-image-state {
61 width: calc(100% - 3em);
62 height: calc(100% - 3em);
63}
64
65.upload-area {
66 display: grid;
67 grid-template-columns: auto auto;
68 grid-template-rows: auto 1fr;
69 align-items: center;
70 justify-items: center;
71
72 padding: 2em;
73 gap: 1em;
74
75 font-size: 2rem;
76 cursor: pointer;
77 border: 3px dashed var(--bg-color);
78 border-radius: var(--border-radius);
79
80 .heading1 {
81 grid-column-start: span 2;
82 color: #666;
83 }
84}
85
86.hidden {
87 display: none;
88}
89
90.image-editor {
91 position: absolute;
92 height: 100%;
93 width: 100%;
94 top: 0;
95 left: 0;
96 z-index: 9;
97}
98
99.image-area {
100 display: grid;
101 grid-template-columns: 1fr 1fr;
102 grid-template-rows: auto 1fr;
103 height: 100%;
104
105 gap: 1rem;
106 align-items: center;
107 justify-items: center;
108
109 position: relative;
110 overflow: hidden;
111
112 .text-container {
113 height: 100%;
114 width: 100%;
115 }
116}
117
118.image-display {
119 border: 1px solid #444;
120 max-width: 100%;
121 max-height: 80vh;
122 object-fit: contain;
123}
124
125.controls {
126 display: flex;
127 gap: 1em;
128 grid-column-start: span 2;
129}
130</style>
131
132<script>
133import { mapState } from "vuex";
134import EditPage from "./EditPage.vue";
135import OcrService, { OcrOptions } from "../js/OcrService"
136import { log } from "../js/Util";
137
138const ocrService = new OcrService();
139
140export default {
141 name: "MainPage",
142 components: {
143 EditPage
144 },
145 data() {
146 return {
147 /** @type {File} */
148 image: null,
149 imageUrl: null,
150 ocrInProgress: false,
151 ocrResult: null,
152 showEditor: false
153 }
154 },
155 computed: {
156 ...mapState({
157 translations: state => state.translations
158 })
159 },
160 methods: {
161 uploadFile() {
162 this.$refs.fileInput.click();
163 },
164 async onFilesChanged() {
165 /** @type {File[]} */
166 const files = this.$refs.fileInput.files;
167 if (files === null || files === undefined || files.length !== 1) {
168 return;
169 }
170
171 this.image = files[0];
172 this.imageUrl = URL.createObjectURL(this.image);
173 },
174 async doOcr() {
175 try {
176 this.ocrInProgress = true;
177
178 const imageBlob = await this.$refs.imageEditor.getImageBlobAsync();
179
180 const result = await ocrService.run([
181 {
182 image: imageBlob,
183 options: new OcrOptions(false)
184 }
185 ]);
186
187 this.ocrResult = result[0].text;
188 }
189 catch (ex) {
190 // TODO: Display error
191 log("Failed to perform OCR", "error");
192 log(ex, "error");
193 }
194 finally {
195 this.ocrInProgress = false;
196 }
197 },
198 onEditorCloseRequested() {
199 this.showEditor = false;
200 },
201 reset() {
202 this.image = null;
203 URL.revokeObjectURL(this.imageUrl);
204 this.imageUrl = null;
205 this.ocrInProgress = false;
206 this.ocrResult = null;
207 this.showEditor = false;
208 this.$refs.fileInput.value = "";
209 }
210 }
211}
212</script>
Note: See TracBrowser for help on using the repository browser.