- Timestamp:
- 2021-11-24T10:57:13+13:00 (2 years ago)
- Location:
- main/trunk/model-interfaces-dev/atea/ocr
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/model-interfaces-dev/atea/ocr
- Property svn:ignore
-
old new 1 1 dist 2 node_modules
-
- Property svn:ignore
-
main/trunk/model-interfaces-dev/atea/ocr/src/components/MainPage.vue
r35734 r35743 1 1 <template> 2 <div class="root"> 3 <edit-page v-if="imageToEdit != null" class="image-editor" :image="imageToEdit" @closeRequested="onEditorCloseRequested" /> 4 5 <button class="btn-primary spacing-bottom" @click="uploadFile"> 6 <span class="material-icons">upload</span> 7 <span>{{ translations.get("Main_UploadImages") }}</span> 8 </button> 9 10 <div v-for="[id, imageInfo] in images" :key="id" class="image-list card" 11 :style="{ 'max-height': imageInfo.isExpanded ? 'none' : '12em' }"> 12 <image-display :imageBuffer="imageInfo.buffer" :type="imageInfo.image.type" :ref="id" /> 13 14 <div class="controls"> 15 <button class="btn-primary" @click="doOcr(id)" :disabled="imageInfo.ocr"> 16 <span class="material-icons">play_arrow</span> 17 <span>{{ translations.get("Main_PerformOCR") }}</span> 18 </button> 19 20 <!-- <div v-if="imageInfo.ocr" class="progress-bar-container"> 21 <div class="progress-bar-value progress-bar-indeterminate" /> 22 </div> --> 23 <button class="btn-primary" @click="imageToEdit = imageInfo.image">Edit</button> 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" /> 24 35 25 36 <div class="text-container"> 26 <pre>{{ imageInfo.text }}</pre>37 <pre>{{ ocrResult }}</pre> 27 38 </div> 28 39 </div> 29 30 <div class="expander-spacer" />31 <div v-if="!imageInfo.isExpanded" class="washout" />32 33 <button class="btn-primary theme-flat expander" @click="imageInfo.isExpanded = !imageInfo.isExpanded">34 v Expand35 </button>36 40 </div> 37 41 38 <input ref="fileInput" type="file" @input="onFilesChanged" class="hidden" multiple42 <input ref="fileInput" type="file" @input="onFilesChanged" class="hidden" 39 43 accept="image/png,image/jpeg,image/gif,image/bmp,image/tiff,image/webp,application/pdf" /> 40 44 </div> … … 42 46 </template> 43 47 44 <style scoped lang="scss"> 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 45 86 .hidden { 46 87 display: none; 47 }48 49 .spacing-bottom {50 margin-bottom: 1em;51 88 } 52 89 … … 60 97 } 61 98 62 .image- list{99 .image-area { 63 100 display: grid; 64 101 grid-template-columns: 1fr 1fr; 102 grid-template-rows: auto 1fr; 103 height: 100%; 104 65 105 gap: 1rem; 106 align-items: center; 107 justify-items: center; 66 108 67 109 position: relative; 68 110 overflow: hidden; 69 111 70 margin-bottom: 1rem; 71 72 .expander { 73 position: absolute; 74 bottom: 0; 112 .text-container { 113 height: 100%; 75 114 width: 100%; 76 z-index: 2;77 115 } 78 79 .expander-spacer { 80 height: 1em; 81 } 82 83 .washout { 84 position: absolute; 85 bottom: 0; 86 height: 60%; 87 width: 100%; 88 background: linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgb(247, 247, 247) 95%); 89 } 116 } 117 118 .image-display { 119 border: 1px solid #444; 120 max-width: 100%; 121 max-height: 80vh; 122 object-fit: contain; 90 123 } 91 124 92 125 .controls { 93 126 display: flex; 94 flex-direction: column;95 127 gap: 1em; 128 grid-column-start: span 2; 96 129 } 97 130 </style> … … 100 133 import { mapState } from "vuex"; 101 134 import EditPage from "./EditPage.vue"; 102 import ImageDisplay from "./ImageDisplay.vue"103 135 import OcrService, { OcrOptions } from "../js/OcrService" 104 import Utilfrom "../js/Util";136 import { log } from "../js/Util"; 105 137 106 138 const ocrService = new OcrService(); … … 109 141 name: "MainPage", 110 142 components: { 111 ImageDisplay,112 143 EditPage 113 144 }, 114 145 data() { 115 146 return { 116 /** @type {Map<String, {image: File, buffer: ArrayBuffer, text: String, ocr: Boolean, isExpanded: Boolean}>} */ 117 images: new Map(), 118 imageToEdit: null 147 /** @type {File} */ 148 image: null, 149 imageUrl: null, 150 ocrInProgress: false, 151 ocrResult: null, 152 showEditor: false 119 153 } 120 154 }, … … 131 165 /** @type {File[]} */ 132 166 const files = this.$refs.fileInput.files; 133 if (files === null || files === undefined || files.length <1) {167 if (files === null || files === undefined || files.length !== 1) { 134 168 return; 135 169 } 136 170 137 for (const file of files) { 138 const buffer = await file.arrayBuffer(); 139 140 this.images.set( 141 Util.generateUuid(), 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([ 142 181 { 143 image: file,144 buffer: buffer182 image: imageBlob, 183 options: new OcrOptions(false) 145 184 } 146 ) 147 } 148 }, 149 async doOcr(id) { 150 // TODO: Catch and log error 151 152 const imageInfo = this.images.get(id); 153 imageInfo.ocr = true; 154 155 const imageBlob = await this.$refs[id].getImageBlobAsync(); 156 157 const result = await ocrService.run([ 158 { 159 image: imageBlob, 160 options: new OcrOptions(false) 161 } 162 ]); 163 164 imageInfo.ocr = false; 165 imageInfo.text = result[0].text; 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 } 166 197 }, 167 198 onEditorCloseRequested() { 168 this.imageToEdit = null; 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 = ""; 169 209 } 170 210 }
Note:
See TracChangeset
for help on using the changeset viewer.