1 | <template>
|
---|
2 | <div class="root">
|
---|
3 | <div class="control-bar">
|
---|
4 | <label for="input-invert">Invert: </label>
|
---|
5 | <input id="input-invert" type="checkbox" v-model="invert" />
|
---|
6 |
|
---|
7 | <label for="input-rotation">Rotation: </label>
|
---|
8 | <input id="input-rotation" type="range" v-model="rotation" min="0" max="360" class="slider-continuous" />
|
---|
9 | </div>
|
---|
10 |
|
---|
11 | <img :src="imageUrl" class="image" :style="{ filter: filterString, transform: transformString }" />
|
---|
12 | </div>
|
---|
13 | </template>
|
---|
14 |
|
---|
15 | <style scoped lang="scss">
|
---|
16 | .image {
|
---|
17 | max-width: 100%;
|
---|
18 | object-fit: contain;
|
---|
19 | }
|
---|
20 |
|
---|
21 | .control-bar {
|
---|
22 | display: flex;
|
---|
23 | align-items: center;
|
---|
24 | gap: 1em;
|
---|
25 | }
|
---|
26 | </style>
|
---|
27 |
|
---|
28 | <script>
|
---|
29 | import { mapState } from "vuex";
|
---|
30 | import Jimp from "jimp/es"
|
---|
31 |
|
---|
32 | export default {
|
---|
33 | name: "ImageDisplay",
|
---|
34 | props: {
|
---|
35 | imageBuffer: ArrayBuffer,
|
---|
36 | type: String
|
---|
37 | },
|
---|
38 | data() {
|
---|
39 | return {
|
---|
40 | invert: false,
|
---|
41 | rotation: 0,
|
---|
42 | internalBuffer: ArrayBuffer,
|
---|
43 | imageUrl: String
|
---|
44 | }
|
---|
45 | },
|
---|
46 | computed: mapState({
|
---|
47 | translations: state => state.translations,
|
---|
48 | filterString() {
|
---|
49 | let filters = "";
|
---|
50 |
|
---|
51 | if (this.invert) {
|
---|
52 | filters += "invert(1) ";
|
---|
53 | }
|
---|
54 |
|
---|
55 | return filters;
|
---|
56 | },
|
---|
57 | transformString() {
|
---|
58 | return `rotate(${this.rotation}deg)`
|
---|
59 | }
|
---|
60 | }),
|
---|
61 | watch: {
|
---|
62 | internalBuffer(newValue) {
|
---|
63 | if (this.imageUrl != null) {
|
---|
64 | URL.revokeObjectURL(this.imageUrl);
|
---|
65 | }
|
---|
66 |
|
---|
67 | if (newValue === null) {
|
---|
68 | return;
|
---|
69 | }
|
---|
70 |
|
---|
71 | const arrayBufferView = new Uint8Array(newValue);
|
---|
72 | const blob = new Blob([ arrayBufferView ], { type: this.type });
|
---|
73 | this.imageUrl = URL.createObjectURL(blob);
|
---|
74 | }
|
---|
75 | },
|
---|
76 | methods: {
|
---|
77 | async getImageBlobAsync() {
|
---|
78 | const buffer = Buffer.from(this.internalBuffer);
|
---|
79 | const that = this;
|
---|
80 |
|
---|
81 | const modifiedBuffer = await Jimp.read(buffer)
|
---|
82 | .then(async image => {
|
---|
83 | if (that.invert) {
|
---|
84 | image.invert();
|
---|
85 | }
|
---|
86 |
|
---|
87 | if (that.rotation !== 0) {
|
---|
88 | image.rotate(that.rotation);
|
---|
89 | }
|
---|
90 |
|
---|
91 | return await image.getBufferAsync(Jimp.MIME_PNG);
|
---|
92 | });
|
---|
93 |
|
---|
94 | return new Blob([ modifiedBuffer ], { type: Jimp.MIME_PNG });
|
---|
95 | }
|
---|
96 | },
|
---|
97 | beforeMount() {
|
---|
98 | this.internalBuffer = this.imageBuffer;
|
---|
99 | },
|
---|
100 | beforeUnmount() {
|
---|
101 | if (this.imageUrl != null) {
|
---|
102 | URL.revokeObjectURL(this.imageUrl);
|
---|
103 | }
|
---|
104 | }
|
---|
105 | }
|
---|
106 | </script>
|
---|