Implement image selector
This commit is contained in:
42
src/components/ImageCollection.vue
Normal file
42
src/components/ImageCollection.vue
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
selected: [image: HTMLImageElement]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const images = ref<HTMLImageElement[]>([]);
|
||||||
|
|
||||||
|
function onFileChange(event: Event): void {
|
||||||
|
const files = (event.target as HTMLInputElement).files!;
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function(event) {
|
||||||
|
const image = new Image();
|
||||||
|
image.onload = () => images.value.push(image);
|
||||||
|
image.src = event.target!.result as string;
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(files[0]);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="file-column">
|
||||||
|
<input id="file-upload" type="file" @change="onFileChange">
|
||||||
|
<label for="file-upload"><a class="button" style="display: block">Add</a></label>
|
||||||
|
<div v-for="(img, idx) in images" :key="idx" class="image-file">
|
||||||
|
<img :src="img.src" width="64" height="64" alt="" @click="$emit('selected', img)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#file-upload {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.file-column {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 8px;
|
||||||
|
border-right: 1px solid black;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { grayScale } from "../processing/gray-scale.ts";
|
import { grayScale } from "../processing/gray-scale.ts";
|
||||||
|
import ImageCollection from "./ImageCollection.vue";
|
||||||
|
|
||||||
const canvas = ref<HTMLCanvasElement | null>(null)
|
const canvas = ref<HTMLCanvasElement | null>(null)
|
||||||
let ctx: CanvasRenderingContext2D;
|
let ctx: CanvasRenderingContext2D;
|
||||||
@@ -8,25 +9,28 @@ onMounted(() => {
|
|||||||
ctx = canvas.value!.getContext('2d')!;
|
ctx = canvas.value!.getContext('2d')!;
|
||||||
})
|
})
|
||||||
|
|
||||||
function onFileChange(event: Event) {
|
function onSelected(img: HTMLImageElement): void {
|
||||||
const files = (event.target as HTMLInputElement).files!;
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = function(event) {
|
|
||||||
const img = new Image();
|
|
||||||
img.onload = () => {
|
|
||||||
ctx.drawImage(img, 0, 0);
|
ctx.drawImage(img, 0, 0);
|
||||||
const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
||||||
const pixels = imageData.data;
|
const pixels = imageData.data;
|
||||||
grayScale(pixels);
|
grayScale(pixels);
|
||||||
ctx.putImageData(imageData, 0, 0);
|
ctx.putImageData(imageData, 0, 0);
|
||||||
}
|
|
||||||
img.src = event.target!.result as string;
|
|
||||||
}
|
|
||||||
reader.readAsDataURL(files[0]);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<input type="file" @change="onFileChange">
|
<div class="editor">
|
||||||
|
<ImageCollection @selected="onSelected" />
|
||||||
<canvas ref="canvas" width="500" height="500"></canvas>
|
<canvas ref="canvas" width="500" height="500"></canvas>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.editor {
|
||||||
|
display: flex;
|
||||||
|
box-shadow: 0 0 2px 2px #1a1a1a;
|
||||||
|
}
|
||||||
|
canvas {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@@ -35,22 +35,27 @@ h1 {
|
|||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button, .button {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
padding: 0.6em 1.2em;
|
padding: 0.6em 1.2em;
|
||||||
|
margin-bottom: 8px;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
background-color: #1a1a1a;
|
background-color: #1a1a1a;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color 0.25s;
|
transition: border-color 0.25s;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
button:hover {
|
button:hover, .button:hover {
|
||||||
border-color: #646cff;
|
border-color: #646cff;
|
||||||
}
|
}
|
||||||
button:focus,
|
button:focus,
|
||||||
button:focus-visible {
|
button:focus-visible,
|
||||||
|
.button:focus,
|
||||||
|
.button:focus-visible {
|
||||||
outline: 4px auto -webkit-focus-ring-color;
|
outline: 4px auto -webkit-focus-ring-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user