@operato/ocr 0.2.15 → 0.2.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/demo/index.html +699 -25
  3. package/dist/src/index.d.ts +1 -1
  4. package/dist/src/index.js +1 -1
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/{camera-capturer.d.ts → ox-camera-capturer.d.ts} +0 -0
  7. package/dist/src/{camera-capturer.js → ox-camera-capturer.js} +18 -10
  8. package/dist/src/ox-camera-capturer.js.map +1 -0
  9. package/dist/src/{ocr-helper.d.ts → ox-ocr-helper.d.ts} +8 -4
  10. package/dist/src/{ocr-helper.js → ox-ocr-helper.js} +47 -51
  11. package/dist/src/ox-ocr-helper.js.map +1 -0
  12. package/dist/src/ox-ocr-result-image.d.ts +37 -0
  13. package/dist/src/ox-ocr-result-image.js +279 -0
  14. package/dist/src/ox-ocr-result-image.js.map +1 -0
  15. package/dist/src/type.d.ts +15 -0
  16. package/dist/src/type.js +6 -0
  17. package/dist/src/type.js.map +1 -0
  18. package/dist/src/{file-drop-helper.d.ts → utils/file-drop-helper.d.ts} +0 -0
  19. package/dist/src/{file-drop-helper.js → utils/file-drop-helper.js} +0 -0
  20. package/dist/src/utils/file-drop-helper.js.map +1 -0
  21. package/dist/src/utils/touch-to-mouse-event.d.ts +1 -0
  22. package/dist/src/utils/touch-to-mouse-event.js +34 -0
  23. package/dist/src/utils/touch-to-mouse-event.js.map +1 -0
  24. package/dist/stories/index.stories.d.ts +1 -1
  25. package/dist/stories/index.stories.js +10 -14
  26. package/dist/stories/index.stories.js.map +1 -1
  27. package/dist/test/ox-ocr-helper.test.d.ts +1 -0
  28. package/dist/test/{ocr-helper.test.js → ox-ocr-helper.test.js} +7 -7
  29. package/dist/test/ox-ocr-helper.test.js.map +1 -0
  30. package/dist/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +3 -2
  32. package/src/index.ts +1 -1
  33. package/src/{camera-capturer.ts → ox-camera-capturer.ts} +17 -9
  34. package/src/{ocr-helper.ts → ox-ocr-helper.ts} +43 -49
  35. package/src/ox-ocr-result-image.ts +303 -0
  36. package/src/type.ts +13 -0
  37. package/src/{file-drop-helper.ts → utils/file-drop-helper.ts} +0 -0
  38. package/src/utils/touch-to-mouse-event.ts +39 -0
  39. package/stories/index.stories.ts +29 -37
  40. package/test/{ocr-helper.test.ts → ox-ocr-helper.test.ts} +8 -7
  41. package/dist/src/camera-capturer.js.map +0 -1
  42. package/dist/src/file-drop-helper.js.map +0 -1
  43. package/dist/src/ocr-helper.js.map +0 -1
  44. package/dist/test/ocr-helper.test.d.ts +0 -1
  45. package/dist/test/ocr-helper.test.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA","sourcesContent":["export * from './ocr-helper.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA","sourcesContent":["export * from './ox-ocr-helper.js'\n"]}
@@ -1,14 +1,14 @@
1
1
  import { __decorate } from "tslib";
2
2
  import '@material/mwc-icon';
3
- import { LitElement, css, html } from 'lit';
3
+ import { css, html, LitElement } from 'lit';
4
4
  import { customElement, property, query } from 'lit/decorators.js';
5
- import { FileDropHelper } from './file-drop-helper';
5
+ import { FileDropHelper } from './utils/file-drop-helper';
6
6
  let CameraCapturer = class CameraCapturer extends LitElement {
7
7
  render() {
8
8
  var files = this._files || [];
9
9
  return html `
10
10
  <mwc-icon>camera</mwc-icon>
11
- <span>Capture image<br />or drop files here!</span>
11
+ <span>Capture image or drop files here!</span>
12
12
  <input
13
13
  id="input-file"
14
14
  type="file"
@@ -39,7 +39,8 @@ let CameraCapturer = class CameraCapturer extends LitElement {
39
39
  - ${file.name}
40
40
  <mwc-icon
41
41
  @click=${(e) => {
42
- this._files = [...files.splice(files.indexOf(file), 1)];
42
+ files.splice(files.indexOf(file), 1);
43
+ this._files = [...files];
43
44
  this.dispatchEvent(new CustomEvent('files-change', {
44
45
  bubbles: true,
45
46
  composed: true,
@@ -91,8 +92,10 @@ CameraCapturer.styles = [
91
92
  display: flex;
92
93
  flex-direction: column;
93
94
  border-radius: var(--border-radius);
94
- text-align: center;
95
- padding-bottom: 5px !important;
95
+ align-items: center;
96
+ justify-content: center;
97
+ padding: var(--padding-default, 9px);
98
+ min-height: 100px;
96
99
  text-transform: capitalize;
97
100
 
98
101
  border: var(--file-uploader-border);
@@ -128,19 +131,24 @@ CameraCapturer.styles = [
128
131
  ul {
129
132
  max-width: 500px;
130
133
  list-style: none;
134
+ margin: 5px 0 0 0;
131
135
  padding: 0;
136
+ max-height: 46px;
137
+ overflow: auto;
138
+ background-color: rgba(var(--primary-color-rgb), 0.1);
132
139
  }
133
140
  li {
134
141
  text-align: left;
135
142
 
136
- padding: var(--file-uploader-li-padding);
143
+ padding: 3px 5px 2px 5px;
137
144
  border-bottom: var(--file-uploader-li-border-bottom);
145
+ font: normal 14px var(--theme-font);
138
146
  }
139
147
  li mwc-icon {
140
148
  float: right;
141
149
  cursor: pointer;
142
- font: var(--file-uploader-li-icon-font);
143
150
  margin: var(--file-uploader-li-icon-margin);
151
+ font-size: 1em;
144
152
  }
145
153
  li mwc-icon:hover,
146
154
  li mwc-icon:active {
@@ -164,7 +172,7 @@ __decorate([
164
172
  query('#input-file')
165
173
  ], CameraCapturer.prototype, "fileInput", void 0);
166
174
  CameraCapturer = __decorate([
167
- customElement('camera-capturer')
175
+ customElement('ox-camera-capturer')
168
176
  ], CameraCapturer);
169
177
  export { CameraCapturer };
170
- //# sourceMappingURL=camera-capturer.js.map
178
+ //# sourceMappingURL=ox-camera-capturer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-camera-capturer.js","sourceRoot":"","sources":["../../src/ox-camera-capturer.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/mwc-icon'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { FileDropHelper } from './utils/file-drop-helper'\n\n@customElement('ox-camera-capturer')\nexport class CameraCapturer extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n border-radius: var(--border-radius);\n align-items: center;\n justify-content: center;\n padding: var(--padding-default, 9px);\n min-height: 100px;\n text-transform: capitalize;\n\n border: var(--file-uploader-border);\n background-color: var(--main-section-background-color);\n font: var(--file-uploader-font) !important;\n color: var(--file-uploader-color);\n }\n :host > mwc-icon {\n color: var(--file-uploader-icon-color);\n }\n\n :host(.candrop) {\n background-color: var(--file-uploader-candrop-background-color);\n }\n\n #input-file {\n display: none;\n }\n\n label {\n position: relative;\n width: auto;\n border: none;\n text-transform: capitalize;\n\n padding: var(--file-uploader-label-padding);\n border-radius: var(--file-uploader-label-border-radius);\n background-color: var(--file-uploader-label-background-color);\n color: var(--file-uploader-label-color);\n font: var(--file-uploader-label-font) !important;\n }\n\n ul {\n max-width: 500px;\n list-style: none;\n margin: 5px 0 0 0;\n padding: 0;\n max-height: 46px;\n overflow: auto;\n background-color: rgba(var(--primary-color-rgb), 0.1);\n }\n li {\n text-align: left;\n\n padding: 3px 5px 2px 5px;\n border-bottom: var(--file-uploader-li-border-bottom);\n font: normal 14px var(--theme-font);\n }\n li mwc-icon {\n float: right;\n cursor: pointer;\n margin: var(--file-uploader-li-icon-margin);\n font-size: 1em;\n }\n li mwc-icon:hover,\n li mwc-icon:active {\n color: var(--file-uploader-li-icon-focus-color);\n }\n `\n ]\n\n @property({ type: Boolean }) multiple?: boolean\n @property({ type: String }) accept?: string\n @property({ type: String }) label?: string\n @property({ type: Array }) _files?: File[]\n\n render() {\n var files = this._files || []\n\n return html`\n <mwc-icon>camera</mwc-icon>\n <span>Capture image or drop files here!</span>\n <input\n id=\"input-file\"\n type=\"file\"\n accept=${this.accept}\n ?multiple=${this.multiple}\n hidden\n capture=\"environment\"\n @change=${(e: Event) => {\n const fileInput = e.currentTarget as HTMLInputElement\n\n this._files = [...files, ...Array.from(fileInput.files as FileList)]\n\n this.dispatchEvent(\n new CustomEvent('files-change', {\n bubbles: true,\n composed: true,\n detail: {\n files: files\n }\n })\n )\n\n // fileInput.value = null\n fileInput.files = null\n }}\n />\n <label for=\"input-file\">${this.label || 'capture image'}</label>\n\n ${files?.length\n ? html` <ul>\n ${files.map(\n file => html`\n <li>\n - ${file.name}\n <mwc-icon\n @click=${(e: Event) => {\n files.splice(files.indexOf(file), 1)\n this._files = [...files]\n this.dispatchEvent(\n new CustomEvent('files-change', {\n bubbles: true,\n composed: true,\n detail: {\n files: this._files\n }\n })\n )\n }}\n >delete_outline</mwc-icon\n >\n </li>\n `\n )}\n </ul>`\n : ''}\n `\n }\n\n firstUpdated() {\n FileDropHelper.set(this)\n\n this.addEventListener('file-drop', (e: Event) => {\n const detail = (e as CustomEvent).detail\n this._files = this.multiple ? detail : detail[0] ? [detail[0]] : []\n\n this.dispatchEvent(\n new CustomEvent('files-change', {\n bubbles: true,\n composed: true,\n detail: {\n files: this._files\n }\n })\n )\n })\n }\n\n @query('#input-file') fileInput!: HTMLInputElement\n\n get files() {\n return this._files\n }\n\n reset() {\n this.fileInput.value = ''\n this._files = []\n\n this.dispatchEvent(\n new CustomEvent('files-change', {\n bubbles: true,\n composed: true,\n detail: {\n files: this._files\n }\n })\n )\n }\n}\n"]}
@@ -1,14 +1,18 @@
1
- import './camera-capturer';
2
1
  import '@material/mwc-button';
2
+ import './ox-camera-capturer';
3
+ import './ox-ocr-result-image';
3
4
  import { LitElement } from 'lit';
5
+ import { ScanResult } from './type';
4
6
  export declare class OcrHelper extends LitElement {
5
7
  static styles: import("lit").CSSResult[];
8
+ result: ScanResult[];
6
9
  _files: any;
7
- index: number;
10
+ _index: number;
8
11
  fileUploader: any;
9
- result: any;
12
+ copied: HTMLElement;
10
13
  render(): import("lit-html").TemplateResult<1>;
11
14
  fileschange(e: Event): void;
12
15
  reset(): void;
13
- upload(): Promise<void>;
16
+ onSelected(e: CustomEvent): void;
17
+ submit(): Promise<void>;
14
18
  }
@@ -1,24 +1,25 @@
1
1
  import { __decorate } from "tslib";
2
- import './camera-capturer';
3
2
  import '@material/mwc-button';
4
- import { LitElement, css, html } from 'lit';
5
- import { customElement, property, query } from 'lit/decorators.js';
3
+ import './ox-camera-capturer';
4
+ import './ox-ocr-result-image';
5
+ import { css, html, LitElement } from 'lit';
6
+ import { customElement, property, query, state } from 'lit/decorators.js';
7
+ import { NOTHING_RESULT } from './type';
6
8
  let OcrHelper = class OcrHelper extends LitElement {
7
9
  constructor() {
8
10
  super(...arguments);
9
- this.index = 0;
11
+ this.result = [];
12
+ this._index = 0;
10
13
  }
11
14
  render() {
15
+ var _a;
12
16
  const files = this._files || [];
13
- const index = this.index || 0;
17
+ const index = this._index || 0;
14
18
  const file = files[index];
15
- const image = file && URL.createObjectURL(file);
16
- if (image) {
17
- requestAnimationFrame(() => URL.revokeObjectURL(image));
18
- }
19
+ const result = ((_a = this.result) === null || _a === void 0 ? void 0 : _a[index]) || NOTHING_RESULT;
19
20
  return html `
20
21
  <div attachment-wrap>
21
- <camera-capturer
22
+ <ox-camera-capturer
22
23
  name="scanner"
23
24
  id="capturer"
24
25
  label="Capture Images"
@@ -27,10 +28,10 @@ let OcrHelper = class OcrHelper extends LitElement {
27
28
  ?hidden=${false}
28
29
  custom-input
29
30
  @files-change=${(e) => this.fileschange(e)}
30
- ></camera-capturer>
31
+ ></ox-camera-capturer>
31
32
  </div>
32
33
  <div buttons>
33
- <mwc-button @click=${(e) => this.upload()}>submit</mwc-button>
34
+ <mwc-button @click=${(e) => this.submit()}>submit</mwc-button>
34
35
  <mwc-button @click=${(e) => this.reset()}>reset</mwc-button>
35
36
  </div>
36
37
  <div id="images">
@@ -41,15 +42,20 @@ let OcrHelper = class OcrHelper extends LitElement {
41
42
  const item = (_a = e.target) === null || _a === void 0 ? void 0 : _a.closest('[i]');
42
43
  const children = (_b = e.currentTarget) === null || _b === void 0 ? void 0 : _b.querySelectorAll('[i]');
43
44
  if (item) {
44
- this.index = Array.from(children).indexOf(item);
45
+ this._index = Array.from(children).indexOf(item);
45
46
  }
46
47
  }}
47
48
  >
48
49
  ${files.map((file, idx) => html `<div i ?active=${idx === index}>${idx}</div>`)}
49
50
  </div>
50
- <div image>${file ? html ` <img src=${URL.createObjectURL(file)} /> ` : html ``}</div>
51
+ <ox-ocr-result-image
52
+ .file=${file}
53
+ @selected=${(e) => this.onSelected(e)}
54
+ .result=${result}
55
+ ></ox-ocr-result-image>
51
56
  </div>
52
- <div id="result"></div>
57
+
58
+ <div id="copied"></div>
53
59
  `;
54
60
  }
55
61
  fileschange(e) {
@@ -57,25 +63,16 @@ let OcrHelper = class OcrHelper extends LitElement {
57
63
  }
58
64
  reset() {
59
65
  this.fileUploader.reset();
60
- this.result.textContent = '';
66
+ this.copied.textContent = '';
67
+ }
68
+ onSelected(e) {
69
+ navigator.clipboard.writeText(e.detail);
61
70
  }
62
- async upload() {
63
- // const response = await client.query({
64
- // query: gql`
65
- // query ocrRequest($images: [Upload!]!) {
66
- // ocrRequest(images: $images)
67
- // }
68
- // `,
69
- // variables: {
70
- // images: this.fileUploader?.files
71
- // },
72
- // context: { hasUpload: true }
73
- // })
74
- // if (!response.errors) {
75
- // this.result.textContent = response.data.ocrRequest
76
- // } else {
77
- // this.result.textContent = 'error'
78
- // }
71
+ async submit() {
72
+ var _a;
73
+ this.dispatchEvent(new CustomEvent('attached', {
74
+ detail: (_a = this.fileUploader) === null || _a === void 0 ? void 0 : _a.files
75
+ }));
79
76
  }
80
77
  };
81
78
  OcrHelper.styles = [
@@ -93,7 +90,7 @@ OcrHelper.styles = [
93
90
 
94
91
  #images {
95
92
  flex: 1;
96
- background-color: black;
93
+ background-color: var(--main-section-background-color, #f4f7fb);
97
94
  color: white;
98
95
 
99
96
  display: flex;
@@ -107,41 +104,40 @@ OcrHelper.styles = [
107
104
 
108
105
  [i] {
109
106
  min-width: 50px;
110
- background-color: black;
107
+ background-color: var(--secondary-color, #394e64);
108
+ border-right: 1px solid rgba(0, 0, 0, 0.2);
109
+ padding: var(--padding-narrow, 4px);
111
110
  text-align: center;
111
+ height: 1.4em;
112
112
  }
113
113
 
114
114
  [i][active] {
115
- background-color: red;
115
+ background-color: var(--primary-color, #22a6a7);
116
+ font-weight: bold;
116
117
  }
117
118
 
118
- [image] {
119
+ ox-ocr-result-image {
119
120
  flex: 1;
120
-
121
- display: flex;
122
- flex-direction: column;
123
- justify-content: center;
124
- }
125
-
126
- img {
127
- style=width: 100%;
128
121
  }
129
122
  `
130
123
  ];
131
124
  __decorate([
132
125
  property({ type: Array })
126
+ ], OcrHelper.prototype, "result", void 0);
127
+ __decorate([
128
+ state()
133
129
  ], OcrHelper.prototype, "_files", void 0);
134
130
  __decorate([
135
- property({ type: Number })
136
- ], OcrHelper.prototype, "index", void 0);
131
+ state()
132
+ ], OcrHelper.prototype, "_index", void 0);
137
133
  __decorate([
138
134
  query('#capturer')
139
135
  ], OcrHelper.prototype, "fileUploader", void 0);
140
136
  __decorate([
141
- query('#result')
142
- ], OcrHelper.prototype, "result", void 0);
137
+ query('#copied')
138
+ ], OcrHelper.prototype, "copied", void 0);
143
139
  OcrHelper = __decorate([
144
- customElement('ocr-helper')
140
+ customElement('ox-ocr-helper')
145
141
  ], OcrHelper);
146
142
  export { OcrHelper };
147
- //# sourceMappingURL=ocr-helper.js.map
143
+ //# sourceMappingURL=ox-ocr-helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-ocr-helper.js","sourceRoot":"","sources":["../../src/ox-ocr-helper.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/mwc-button'\nimport './ox-camera-capturer'\nimport './ox-ocr-result-image'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { NOTHING_RESULT, ScanResult } from './type'\n\n@customElement('ox-ocr-helper')\nexport class OcrHelper extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-width: 240px;\n }\n\n [buttons] {\n display: flex;\n flex-direction: row-reverse;\n }\n\n #images {\n flex: 1;\n background-color: var(--main-section-background-color, #f4f7fb);\n color: white;\n\n display: flex;\n flex-direction: column;\n }\n\n [tab] {\n display: flex;\n flex-direction: row;\n }\n\n [i] {\n min-width: 50px;\n background-color: var(--secondary-color, #394e64);\n border-right: 1px solid rgba(0, 0, 0, 0.2);\n padding: var(--padding-narrow, 4px);\n text-align: center;\n height: 1.4em;\n }\n\n [i][active] {\n background-color: var(--primary-color, #22a6a7);\n font-weight: bold;\n }\n\n ox-ocr-result-image {\n flex: 1;\n }\n `\n ]\n\n @property({ type: Array }) result: ScanResult[] = []\n\n @state() _files: any\n @state() _index: number = 0\n\n @query('#capturer') fileUploader!: any\n @query('#copied') copied!: HTMLElement\n\n render() {\n const files = this._files || []\n const index = this._index || 0\n const file = files[index]\n const result = this.result?.[index] || NOTHING_RESULT\n\n return html`\n <div attachment-wrap>\n <ox-camera-capturer\n name=\"scanner\"\n id=\"capturer\"\n label=\"Capture Images\"\n accept=\"image/*\"\n multiple=\"true\"\n ?hidden=${false}\n custom-input\n @files-change=${(e: Event) => this.fileschange(e)}\n ></ox-camera-capturer>\n </div>\n <div buttons>\n <mwc-button @click=${(e: Event) => this.submit()}>submit</mwc-button>\n <mwc-button @click=${(e: Event) => this.reset()}>reset</mwc-button>\n </div>\n <div id=\"images\">\n <div\n tab\n @click=${(e: MouseEvent) => {\n const item = (e.target as HTMLElement)?.closest('[i]')\n const children = (e.currentTarget as HTMLElement)?.querySelectorAll('[i]')\n if (item) {\n this._index = Array.from(children).indexOf(item)\n }\n }}\n >\n ${files.map((file: any, idx: number) => html`<div i ?active=${idx === index}>${idx}</div>`)}\n </div>\n <ox-ocr-result-image\n .file=${file}\n @selected=${(e: CustomEvent) => this.onSelected(e)}\n .result=${result}\n ></ox-ocr-result-image>\n </div>\n\n <div id=\"copied\"></div>\n `\n }\n\n fileschange(e: Event) {\n this._files = this.fileUploader.files\n }\n\n reset() {\n this.fileUploader.reset()\n this.copied.textContent = ''\n }\n\n onSelected(e: CustomEvent) {\n navigator.clipboard.writeText(e.detail)\n }\n\n async submit() {\n this.dispatchEvent(\n new CustomEvent('attached', {\n detail: this.fileUploader?.files\n })\n )\n }\n}\n"]}
@@ -0,0 +1,37 @@
1
+ import { LitElement, PropertyValues } from 'lit';
2
+ import { ScanResult } from './type';
3
+ export declare class OcrResultImage extends LitElement {
4
+ static styles: import("lit").CSSResult[];
5
+ file: any;
6
+ result: ScanResult;
7
+ _ratio: {
8
+ x: number;
9
+ y: number;
10
+ };
11
+ _image: string;
12
+ _resizeObserver: ResizeObserver;
13
+ _trails: Array<Array<{
14
+ x: number;
15
+ y: number;
16
+ }>>;
17
+ _tracking: boolean;
18
+ _selections: Array<number>;
19
+ _text: string;
20
+ _img: HTMLImageElement;
21
+ _overlay: HTMLCanvasElement;
22
+ render(): import("lit-html").TemplateResult<1>;
23
+ renderOverlay(): void;
24
+ calculateRatio(): Promise<void>;
25
+ connectedCallback(): Promise<void>;
26
+ disconnectedCallback(): void;
27
+ reset(): void;
28
+ updated(changes: PropertyValues<this>): Promise<void>;
29
+ findIndex(x: number, y: number): number;
30
+ updateTrails(point: {
31
+ x: number;
32
+ y: number;
33
+ }, started: boolean, attached?: boolean): void;
34
+ onTrailStart(e: MouseEvent): void;
35
+ onTrailEnd(e: MouseEvent): void;
36
+ onTrail(e: MouseEvent): void;
37
+ }
@@ -0,0 +1,279 @@
1
+ import { __decorate } from "tslib";
2
+ import { css, html, LitElement } from 'lit';
3
+ import { customElement, property, query, state } from 'lit/decorators.js';
4
+ import { NOTHING_RESULT } from './type';
5
+ import { touch2mouse } from './utils/touch-to-mouse-event';
6
+ let OcrResultImage = class OcrResultImage extends LitElement {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.result = NOTHING_RESULT;
10
+ this._ratio = { x: 1, y: 1 };
11
+ this._trails = [];
12
+ this._tracking = false;
13
+ this._selections = [];
14
+ this._text = '';
15
+ }
16
+ render() {
17
+ return html `
18
+ <img src=${this._image} @load=${() => this.calculateRatio()} />
19
+ <canvas overlay></canvas>
20
+
21
+ ${this._text ? html ` <div notice>${this._text} copied!</div> ` : html ``}
22
+ `;
23
+ }
24
+ renderOverlay() {
25
+ const { boundaries } = this.result;
26
+ const context = this._overlay.getContext('2d');
27
+ if (!context) {
28
+ return;
29
+ }
30
+ context.save();
31
+ context.clearRect(0, 0, this._overlay.width, this._overlay.height);
32
+ context.lineWidth = 5;
33
+ context.strokeStyle = 'red';
34
+ context.fillStyle = 'red';
35
+ context.lineJoin = 'round';
36
+ context.lineCap = 'round';
37
+ this._image &&
38
+ boundaries
39
+ .map((bounds) => {
40
+ return bounds.map(bound => {
41
+ return {
42
+ x: bound.x,
43
+ y: bound.y // * this._ratio.y
44
+ };
45
+ });
46
+ })
47
+ .forEach((bounds, idx) => {
48
+ context.beginPath();
49
+ context.moveTo(bounds[0].x, bounds[0].y);
50
+ context.lineTo(bounds[1].x, bounds[1].y);
51
+ context.lineTo(bounds[2].x, bounds[2].y);
52
+ context.lineTo(bounds[3].x, bounds[3].y);
53
+ context.closePath();
54
+ if (this._selections.includes(idx)) {
55
+ context.fill();
56
+ }
57
+ context.stroke();
58
+ });
59
+ /* draw trails */
60
+ if (this._trails && this._trails.length > 0) {
61
+ context.lineWidth = 10;
62
+ context.strokeStyle = 'blue';
63
+ context.beginPath();
64
+ this._trails.forEach(trail => {
65
+ if (trail && trail.length > 0) {
66
+ const { x, y } = trail[0];
67
+ context.moveTo(x, y);
68
+ trail.slice(1).forEach(point => {
69
+ const { x, y } = point;
70
+ context.lineTo(x, y);
71
+ });
72
+ }
73
+ });
74
+ context.stroke();
75
+ }
76
+ context.restore();
77
+ }
78
+ async calculateRatio() {
79
+ const { naturalWidth, naturalHeight, offsetWidth, offsetHeight } = this._img;
80
+ const { offsetWidth: overlayWidth, offsetHeight: overlayHeight } = this._overlay;
81
+ if (!naturalWidth || !naturalHeight) {
82
+ return;
83
+ }
84
+ this._ratio = {
85
+ x: offsetWidth / naturalWidth,
86
+ y: offsetHeight / naturalHeight
87
+ };
88
+ this._overlay.setAttribute('width', String(overlayWidth / this._ratio.x));
89
+ this._overlay.setAttribute('height', String(overlayHeight / this._ratio.y));
90
+ }
91
+ async connectedCallback() {
92
+ await super.connectedCallback();
93
+ this._resizeObserver = new ResizeObserver(entries => {
94
+ this.calculateRatio();
95
+ this.renderOverlay();
96
+ });
97
+ await this.updateComplete;
98
+ this._resizeObserver.observe(this._overlay);
99
+ this.calculateRatio();
100
+ this.addEventListener('mousedown', this.onTrailStart.bind(this));
101
+ this.addEventListener('mouseup', this.onTrailEnd.bind(this));
102
+ this.addEventListener('mousemove', this.onTrail.bind(this));
103
+ this.addEventListener('touchstart', touch2mouse);
104
+ this.addEventListener('touchend', touch2mouse);
105
+ this.addEventListener('touchmove', touch2mouse);
106
+ }
107
+ disconnectedCallback() {
108
+ super.disconnectedCallback();
109
+ this._resizeObserver.disconnect();
110
+ }
111
+ reset() {
112
+ this._selections = [];
113
+ this._trails = [];
114
+ this._text = '';
115
+ }
116
+ async updated(changes) {
117
+ if (changes.has('file') || changes.has('result')) {
118
+ this.reset();
119
+ }
120
+ if (changes.has('file')) {
121
+ this._image = this.file && URL.createObjectURL(this.file);
122
+ if (this._image) {
123
+ requestAnimationFrame(() => {
124
+ URL.revokeObjectURL(this._image);
125
+ });
126
+ await this.updateComplete;
127
+ this.calculateRatio();
128
+ }
129
+ }
130
+ this.renderOverlay();
131
+ }
132
+ findIndex(x, y) {
133
+ const { boundaries } = this.result;
134
+ return boundaries.findIndex(path => {
135
+ var result = false;
136
+ path.forEach((p, idx) => {
137
+ let j = (idx + path.length + 1) % path.length;
138
+ let x1 = p.x;
139
+ let y1 = p.y;
140
+ let x2 = path[j].x;
141
+ let y2 = path[j].y;
142
+ if (y1 > y != y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1) {
143
+ result = !result;
144
+ }
145
+ });
146
+ return result;
147
+ });
148
+ }
149
+ updateTrails(point, started, attached) {
150
+ if (started && !attached) {
151
+ this.reset();
152
+ }
153
+ if (started) {
154
+ this._trails.push([]);
155
+ }
156
+ var trail = this._trails[this._trails.length - 1];
157
+ if (!trail) {
158
+ return;
159
+ }
160
+ trail.push(point);
161
+ this._trails.flat().forEach(({ x, y }) => {
162
+ const idx = this.findIndex(x, y);
163
+ if (idx === -1) {
164
+ return;
165
+ }
166
+ if (!this._selections.includes(idx)) {
167
+ this._selections.push(idx);
168
+ }
169
+ });
170
+ this.requestUpdate();
171
+ }
172
+ onTrailStart(e) {
173
+ const { offsetX: x, offsetY: y, button, shiftKey } = e;
174
+ if (button !== 0) {
175
+ return;
176
+ }
177
+ this._tracking = true;
178
+ this.updateTrails({ x: x / this._ratio.x, y: y / this._ratio.y }, true, shiftKey);
179
+ }
180
+ onTrailEnd(e) {
181
+ if (!this._tracking) {
182
+ return;
183
+ }
184
+ this._text = this._selections.map(idx => this.result.texts[idx]).join('');
185
+ this.dispatchEvent(new CustomEvent('selected', {
186
+ detail: this._text
187
+ }));
188
+ this._tracking = false;
189
+ }
190
+ onTrail(e) {
191
+ const { offsetX: x, offsetY: y } = e;
192
+ if (!this._tracking) {
193
+ return;
194
+ }
195
+ this.updateTrails({ x: x / this._ratio.x, y: y / this._ratio.y }, false);
196
+ }
197
+ };
198
+ OcrResultImage.styles = [
199
+ css `
200
+ :host {
201
+ display: block;
202
+ position: relative;
203
+ }
204
+
205
+ img {
206
+ display: block;
207
+ flex: 1;
208
+ border: 0;
209
+ padding: 0;
210
+ margin: 0;
211
+ max-width: 100%;
212
+ max-height: 100%;
213
+ }
214
+
215
+ [overlay] {
216
+ position: absolute;
217
+ top: 0;
218
+ left: 0;
219
+ width: 100%;
220
+ height: 100%;
221
+
222
+ border: 0;
223
+ padding: 0;
224
+ margin: 0;
225
+ opacity: 50%;
226
+ }
227
+
228
+ [notice] {
229
+ position: absolute;
230
+ bottom: 0;
231
+ background-color: var(--primary-color, #38a25b);
232
+ padding: var(--padding-default, 9px) var(--padding-wide, 15px);
233
+ opacity: 0.95;
234
+
235
+ overflow-wrap: anywhere;
236
+
237
+ color: #fff;
238
+ font-size: 1.5em;
239
+ }
240
+ `
241
+ ];
242
+ __decorate([
243
+ property({ type: Array })
244
+ ], OcrResultImage.prototype, "file", void 0);
245
+ __decorate([
246
+ property({ type: Array })
247
+ ], OcrResultImage.prototype, "result", void 0);
248
+ __decorate([
249
+ state()
250
+ ], OcrResultImage.prototype, "_ratio", void 0);
251
+ __decorate([
252
+ state()
253
+ ], OcrResultImage.prototype, "_image", void 0);
254
+ __decorate([
255
+ state()
256
+ ], OcrResultImage.prototype, "_resizeObserver", void 0);
257
+ __decorate([
258
+ state()
259
+ ], OcrResultImage.prototype, "_trails", void 0);
260
+ __decorate([
261
+ state()
262
+ ], OcrResultImage.prototype, "_tracking", void 0);
263
+ __decorate([
264
+ state()
265
+ ], OcrResultImage.prototype, "_selections", void 0);
266
+ __decorate([
267
+ state()
268
+ ], OcrResultImage.prototype, "_text", void 0);
269
+ __decorate([
270
+ query('img')
271
+ ], OcrResultImage.prototype, "_img", void 0);
272
+ __decorate([
273
+ query('[overlay]')
274
+ ], OcrResultImage.prototype, "_overlay", void 0);
275
+ OcrResultImage = __decorate([
276
+ customElement('ox-ocr-result-image')
277
+ ], OcrResultImage);
278
+ export { OcrResultImage };
279
+ //# sourceMappingURL=ox-ocr-result-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-ocr-result-image.js","sourceRoot":"","sources":["../../src/ox-ocr-result-image.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { NOTHING_RESULT, ScanResult } from './type'\nimport { touch2mouse } from './utils/touch-to-mouse-event'\n\n@customElement('ox-ocr-result-image')\nexport class OcrResultImage extends LitElement {\n static styles = [\n css`\n :host {\n display: block;\n position: relative;\n }\n\n img {\n display: block;\n flex: 1;\n border: 0;\n padding: 0;\n margin: 0;\n max-width: 100%;\n max-height: 100%;\n }\n\n [overlay] {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n border: 0;\n padding: 0;\n margin: 0;\n opacity: 50%;\n }\n\n [notice] {\n position: absolute;\n bottom: 0;\n background-color: var(--primary-color, #38a25b);\n padding: var(--padding-default, 9px) var(--padding-wide, 15px);\n opacity: 0.95;\n\n overflow-wrap: anywhere;\n\n color: #fff;\n font-size: 1.5em;\n }\n `\n ]\n\n @property({ type: Array }) file: any\n @property({ type: Array }) result: ScanResult = NOTHING_RESULT\n\n @state() _ratio: { x: number; y: number } = { x: 1, y: 1 }\n @state() _image!: string\n @state() _resizeObserver!: ResizeObserver\n @state() _trails: Array<Array<{ x: number; y: number }>> = []\n @state() _tracking: boolean = false\n @state() _selections: Array<number> = []\n @state() _text: string = ''\n\n @query('img') _img!: HTMLImageElement\n @query('[overlay]') _overlay!: HTMLCanvasElement\n\n render() {\n return html`\n <img src=${this._image} @load=${() => this.calculateRatio()} />\n <canvas overlay></canvas>\n\n ${this._text ? html` <div notice>${this._text} copied!</div> ` : html``}\n `\n }\n\n renderOverlay() {\n const { boundaries } = this.result\n\n const context = this._overlay.getContext('2d')\n if (!context) {\n return\n }\n\n context.save()\n\n context.clearRect(0, 0, this._overlay.width, this._overlay.height)\n\n context.lineWidth = 5\n context.strokeStyle = 'red'\n context.fillStyle = 'red'\n context.lineJoin = 'round'\n context.lineCap = 'round'\n\n this._image &&\n boundaries\n .map((bounds): Array<{ x: number; y: number }> => {\n return bounds.map(bound => {\n return {\n x: bound.x, //* this._ratio.x,\n y: bound.y // * this._ratio.y\n }\n })\n })\n .forEach((bounds, idx) => {\n context.beginPath()\n context.moveTo(bounds[0].x, bounds[0].y)\n context.lineTo(bounds[1].x, bounds[1].y)\n context.lineTo(bounds[2].x, bounds[2].y)\n context.lineTo(bounds[3].x, bounds[3].y)\n context.closePath()\n\n if (this._selections.includes(idx)) {\n context.fill()\n }\n context.stroke()\n })\n\n /* draw trails */\n if (this._trails && this._trails.length > 0) {\n context.lineWidth = 10\n context.strokeStyle = 'blue'\n\n context.beginPath()\n\n this._trails.forEach(trail => {\n if (trail && trail.length > 0) {\n const { x, y } = trail[0]\n context.moveTo(x, y)\n\n trail.slice(1).forEach(point => {\n const { x, y } = point\n context.lineTo(x, y)\n })\n }\n })\n\n context.stroke()\n }\n\n context.restore()\n }\n\n async calculateRatio() {\n const { naturalWidth, naturalHeight, offsetWidth, offsetHeight } = this._img\n const { offsetWidth: overlayWidth, offsetHeight: overlayHeight } = this._overlay\n\n if (!naturalWidth || !naturalHeight) {\n return\n }\n\n this._ratio = {\n x: offsetWidth / naturalWidth,\n y: offsetHeight / naturalHeight\n }\n\n this._overlay.setAttribute('width', String(overlayWidth / this._ratio.x))\n this._overlay.setAttribute('height', String(overlayHeight / this._ratio.y))\n }\n\n async connectedCallback() {\n await super.connectedCallback()\n\n this._resizeObserver = new ResizeObserver(entries => {\n this.calculateRatio()\n this.renderOverlay()\n })\n\n await this.updateComplete\n this._resizeObserver.observe(this._overlay)\n\n this.calculateRatio()\n\n this.addEventListener('mousedown', this.onTrailStart.bind(this) as EventListener)\n this.addEventListener('mouseup', this.onTrailEnd.bind(this) as EventListener)\n this.addEventListener('mousemove', this.onTrail.bind(this) as EventListener)\n this.addEventListener('touchstart', touch2mouse as EventListener)\n this.addEventListener('touchend', touch2mouse as EventListener)\n this.addEventListener('touchmove', touch2mouse as EventListener)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n\n this._resizeObserver.disconnect()\n }\n\n reset() {\n this._selections = []\n this._trails = []\n this._text = ''\n }\n\n async updated(changes: PropertyValues<this>) {\n if (changes.has('file') || changes.has('result')) {\n this.reset()\n }\n\n if (changes.has('file')) {\n this._image = this.file && URL.createObjectURL(this.file)\n if (this._image) {\n requestAnimationFrame(() => {\n URL.revokeObjectURL(this._image)\n })\n\n await this.updateComplete\n this.calculateRatio()\n }\n }\n\n this.renderOverlay()\n }\n\n findIndex(x: number, y: number): number {\n const { boundaries } = this.result\n\n return boundaries.findIndex(path => {\n var result = false\n\n path.forEach((p, idx) => {\n let j = (idx + path.length + 1) % path.length\n\n let x1 = p.x\n let y1 = p.y\n let x2 = path[j].x\n let y2 = path[j].y\n\n if (y1 > y != y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1) {\n result = !result\n }\n })\n\n return result\n })\n }\n\n updateTrails(point: { x: number; y: number }, started: boolean, attached?: boolean) {\n if (started && !attached) {\n this.reset()\n }\n\n if (started) {\n this._trails.push([])\n }\n\n var trail = this._trails[this._trails.length - 1]\n if (!trail) {\n return\n }\n\n trail.push(point)\n\n this._trails.flat().forEach(({ x, y }) => {\n const idx = this.findIndex(x, y)\n if (idx === -1) {\n return\n }\n\n if (!this._selections.includes(idx)) {\n this._selections.push(idx)\n }\n })\n\n this.requestUpdate()\n }\n\n onTrailStart(e: MouseEvent) {\n const { offsetX: x, offsetY: y, button, shiftKey } = e\n\n if (button !== 0) {\n return\n }\n\n this._tracking = true\n this.updateTrails({ x: x / this._ratio.x, y: y / this._ratio.y }, true, shiftKey)\n }\n\n onTrailEnd(e: MouseEvent) {\n if (!this._tracking) {\n return\n }\n\n this._text = this._selections.map(idx => this.result.texts[idx]).join('')\n\n this.dispatchEvent(\n new CustomEvent('selected', {\n detail: this._text\n })\n )\n\n this._tracking = false\n }\n\n onTrail(e: MouseEvent) {\n const { offsetX: x, offsetY: y } = e\n\n if (!this._tracking) {\n return\n }\n\n this.updateTrails({ x: x / this._ratio.x, y: y / this._ratio.y }, false)\n }\n}\n"]}