|
@ -13,7 +13,7 @@ |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- Heading --> |
|
|
<!-- Heading --> |
|
|
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4"> |
|
|
<h1 id="ViewHeading" class="text-center font-bold"> |
|
|
<span v-if="uploading"> Uploading... </span> |
|
|
<span v-if="uploading"> Uploading... </span> |
|
|
<span v-else-if="blob"> Look Good? </span> |
|
|
<span v-else-if="blob"> Look Good? </span> |
|
|
<span v-else> Say "Cheese"! </span> |
|
|
<span v-else> Say "Cheese"! </span> |
|
@ -30,6 +30,7 @@ |
|
|
> |
|
|
> |
|
|
<span>Upload</span> |
|
|
<span>Upload</span> |
|
|
</button> |
|
|
</button> |
|
|
|
|
|
<!--{{ imageHeight }} {{ imageWidth }} {{ imageWarning }}--> |
|
|
<button |
|
|
<button |
|
|
@click="retryImage" |
|
|
@click="retryImage" |
|
|
class="bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-2 rounded-full" |
|
|
class="bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-2 rounded-full" |
|
@ -37,16 +38,20 @@ |
|
|
<span>Retry</span> |
|
|
<span>Retry</span> |
|
|
</button> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
<img :src="URL.createObjectURL(blob)" class="mt-2 w-full" /> |
|
|
<div |
|
|
|
|
|
:style="'height: ' + imageHeight + 'px; width: ' + imageWidth + 'px;'" |
|
|
|
|
|
> |
|
|
|
|
|
<img :src="URL.createObjectURL(blob)" class="mt-2" /> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div v-else> |
|
|
<div v-else> |
|
|
<!-- |
|
|
<!-- |
|
|
Camera "resolution" doesn't change how it shows on screen but rather stretches the result, eg the following which just stretches it vertically: |
|
|
Camera "resolution" doesn't change how it shows on screen but rather stretches the result, eg the following which just stretches it vertically: |
|
|
:resolution="{ width: 375, height: 812 }" |
|
|
:resolution="{ width: 375, height: 812 }" |
|
|
|
|
|
It even messes up when trying to match the ratio with imageHeight and imageWidth. |
|
|
--> |
|
|
--> |
|
|
<camera facingMode="environment" autoplay ref="camera"> |
|
|
<camera facingMode="environment" autoplay ref="camera"> |
|
|
<div class="absolute bottom-0 w-full flex justify-center pb-4"> |
|
|
<div class="absolute top-0 w-full flex justify-center pb-4"> |
|
|
<!-- Button --> |
|
|
|
|
|
<button |
|
|
<button |
|
|
@click="takeImage" |
|
|
@click="takeImage" |
|
|
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-2 rounded-full" |
|
|
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-2 rounded-full" |
|
@ -78,6 +83,9 @@ export default class GiftedPhotoDialog extends Vue { |
|
|
activeDid = ""; |
|
|
activeDid = ""; |
|
|
blob: Blob | null = null; |
|
|
blob: Blob | null = null; |
|
|
setImage: (arg: string) => void = () => {}; |
|
|
setImage: (arg: string) => void = () => {}; |
|
|
|
|
|
imageHeight?: number = window.innerHeight / 2; |
|
|
|
|
|
imageWidth?: number = window.innerWidth / 2; |
|
|
|
|
|
imageWarning = "."; |
|
|
uploading = false; |
|
|
uploading = false; |
|
|
visible = false; |
|
|
visible = false; |
|
|
|
|
|
|
|
@ -115,7 +123,55 @@ export default class GiftedPhotoDialog extends Vue { |
|
|
|
|
|
|
|
|
async takeImage(/* payload: MouseEvent */) { |
|
|
async takeImage(/* payload: MouseEvent */) { |
|
|
const cameraComponent = this.$refs.camera as InstanceType<typeof Camera>; |
|
|
const cameraComponent = this.$refs.camera as InstanceType<typeof Camera>; |
|
|
this.blob = await cameraComponent?.snapshot(); // png is default; if that changes, change extension in formData.append |
|
|
console.log("cameraComponent", cameraComponent, cameraComponent.resolution); |
|
|
|
|
|
this.imageHeight = cameraComponent?.resolution?.height; |
|
|
|
|
|
this.imageWidth = cameraComponent?.resolution?.width; |
|
|
|
|
|
const initialImageRatio = this.imageWidth / this.imageHeight; |
|
|
|
|
|
console.log( |
|
|
|
|
|
"initialImageRatio", |
|
|
|
|
|
initialImageRatio, |
|
|
|
|
|
this.imageWidth, |
|
|
|
|
|
this.imageHeight, |
|
|
|
|
|
); |
|
|
|
|
|
const windowRatio = window.innerWidth / window.innerHeight; |
|
|
|
|
|
console.log( |
|
|
|
|
|
"windowRatio", |
|
|
|
|
|
windowRatio, |
|
|
|
|
|
window.innerWidth, |
|
|
|
|
|
window.innerHeight, |
|
|
|
|
|
); |
|
|
|
|
|
if (initialImageRatio > 1 && windowRatio < 1) { |
|
|
|
|
|
this.imageWarning = "?"; |
|
|
|
|
|
// For some reason, mobile in portrait orientation renders a horizontally-stretched image. |
|
|
|
|
|
// We're gonna force it opposite. |
|
|
|
|
|
this.imageHeight = cameraComponent?.resolution?.width; |
|
|
|
|
|
this.imageWidth = cameraComponent?.resolution?.height; |
|
|
|
|
|
} else if (initialImageRatio < 1 && windowRatio > 1) { |
|
|
|
|
|
// Haven't seen this happen, but just in case. |
|
|
|
|
|
this.imageWarning = "??"; |
|
|
|
|
|
this.imageHeight = cameraComponent?.resolution?.width; |
|
|
|
|
|
this.imageWidth = cameraComponent?.resolution?.height; |
|
|
|
|
|
} |
|
|
|
|
|
const newImageRatio = this.imageWidth / this.imageHeight; |
|
|
|
|
|
console.log( |
|
|
|
|
|
"newImageRatio", |
|
|
|
|
|
newImageRatio, |
|
|
|
|
|
this.imageWidth, |
|
|
|
|
|
this.imageHeight, |
|
|
|
|
|
); |
|
|
|
|
|
if (newImageRatio < windowRatio) { |
|
|
|
|
|
this.imageHeight = window.innerHeight / 2; |
|
|
|
|
|
this.imageWidth = this.imageHeight * newImageRatio; |
|
|
|
|
|
} else { |
|
|
|
|
|
this.imageWidth = window.innerWidth / 2; |
|
|
|
|
|
this.imageHeight = this.imageWidth / newImageRatio; |
|
|
|
|
|
} |
|
|
|
|
|
// The resolution is only necessary because of that mobile portrait-orientation case. |
|
|
|
|
|
// But setting this screws up desktop the mobile emulation. |
|
|
|
|
|
this.blob = await cameraComponent?.snapshot({ |
|
|
|
|
|
height: this.imageHeight, |
|
|
|
|
|
width: this.imageWidth, |
|
|
|
|
|
}); // png is default; if that changes, change extension in formData.append |
|
|
if (!this.blob) { |
|
|
if (!this.blob) { |
|
|
this.$notify( |
|
|
this.$notify( |
|
|
{ |
|
|
{ |
|
@ -134,6 +190,45 @@ export default class GiftedPhotoDialog extends Vue { |
|
|
this.blob = null; |
|
|
this.blob = null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**** |
|
|
|
|
|
|
|
|
|
|
|
Here's an approach without a library, which works similarly and looks ugly. |
|
|
|
|
|
|
|
|
|
|
|
<button id="start-camera" @click="cameraClicked">Start Camera</button> |
|
|
|
|
|
<video id="video" width="320" height="240" autoplay></video> |
|
|
|
|
|
<button id="snap-photo" @click="photoSnapped">Snap Photo</button> |
|
|
|
|
|
<canvas id="canvas" width="320" height="240"></canvas> |
|
|
|
|
|
|
|
|
|
|
|
async cameraClicked() { |
|
|
|
|
|
console.log("camera_button clicked"); |
|
|
|
|
|
const video = document.querySelector("#video"); |
|
|
|
|
|
const stream = await navigator.mediaDevices.getUserMedia({ |
|
|
|
|
|
video: true, |
|
|
|
|
|
audio: false, |
|
|
|
|
|
}); |
|
|
|
|
|
if (video instanceof HTMLVideoElement) { |
|
|
|
|
|
video.srcObject = stream; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
photoSnapped() { |
|
|
|
|
|
const video = document.querySelector("#video"); |
|
|
|
|
|
const canvas = document.querySelector("#canvas"); |
|
|
|
|
|
console.log("snap_photo clicked"); |
|
|
|
|
|
if ( |
|
|
|
|
|
canvas instanceof HTMLCanvasElement && |
|
|
|
|
|
video instanceof HTMLVideoElement |
|
|
|
|
|
) { |
|
|
|
|
|
canvas |
|
|
|
|
|
?.getContext("2d") |
|
|
|
|
|
?.drawImage(video, 0, 0, canvas.width, canvas.height); |
|
|
|
|
|
const image_data_url = canvas?.toDataURL("image/jpeg"); |
|
|
|
|
|
|
|
|
|
|
|
// data url of the image |
|
|
|
|
|
console.log(image_data_url); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
****/ |
|
|
|
|
|
|
|
|
async uploadImage() { |
|
|
async uploadImage() { |
|
|
this.uploading = true; |
|
|
this.uploading = true; |
|
|
const identifier = await getIdentity(this.activeDid); |
|
|
const identifier = await getIdentity(this.activeDid); |
|
|