Having trouble with displaying recently uploaded images on a form. If the image is taken from a phone, it may have an exif property that browsers do not handle correctly, causing the picture to appear flipped or sideways.
To fix this issue, I used the exif-js library and implemented a component to ensure that the image loads and displays in the correct orientation.
However, during testing, we discovered that on iPhones, photos taken manually in vertical mode cause the image to be displayed incorrectly outside the div container in the lower left corner.
Incorrectly displayed iPhone image
This error affects all subsequent images as well, but everything looks fine on Android devices.
The 'src' attribute in the img tag changes dynamically, so I also need the 'transform' property to change dynamically using the updated() method. It's not ideal code, but...
Usage:
<div class="form-group">
<div class="row">
<div class="col-md-6 edit-activity-images">
<auto-rotate><img class="edit-activity-images-inner" alt="activity"
:src="getUploadedImageBackground()||staticFile('images/img-place-holder.png')"
></auto-rotate>
Style
.edit-activity-images-inner{
object-fit: cover;
width: 100%;
height: 100%;
}
Component
<template>
<div class="holder">
<slot></slot>
</div>
</template>
<script>
import imagesLoaded from 'imagesloaded'
import EXIF from 'exif-js'
const rotateAngles = [
{},
{y: 0, z: 0},
{y: 180, z: 0},
{y: 0, z: 180},
{y: 180, z: 180},
{y: 180, z: -90},
{y: 0, z: -90},
{y: 180, z: 90},
{y: 0, z: 90}
];
function getOrientation(el) {
return new Promise(function (resolve) {
imagesLoaded(el, function () {
EXIF.getData(el, function () {
const orientation = EXIF.getTag(this, 'Orientation');
resolve(orientation);
})
})
})
}
function getRotationAngle(newOrientation, oldOrientation) {
const y = rotateAngles[newOrientation].y - rotateAngles[oldOrientation].y;
let z = rotateAngles[newOrientation].z - rotateAngles[oldOrientation].z;
if (y)
z = z * -1;
return { y, z }
}
const recently_added = {};
const havent_exif = {};
export default {
name: "AutoRotate",
updated() {
const slot = this.$slots.default[0];
if (slot.tag !== 'img') {
console.error('Warning: slot should be an img tag.');
return;
}
const holder = this.$el;
const img = holder.childNodes[0];
img.exifdata = undefined;
if (recently_added[img.src]) {
img.style['transform'] = recently_added[img.src];
return
} else if (havent_exif[img.src]) {
img.style['transform'] = "translate(0px, 0px) rotateY(0deg) rotateZ(0deg)";
return;
}
getOrientation(img).then(function (currentOrientation) {
if (currentOrientation !== undefined) {
const angle = getRotationAngle(1, currentOrientation);
const transform = `rotateY(${angle.y}deg) rotateZ(${angle.z}deg)`;
let translate = '';
if (angle.z % 180 !== 0) {
const height = img.clientHeight;
const width = img.clientWidth;
translate = `translate(${(height - width) / 2}px, ${(width - height) / 2}px)`;
holder.style['width'] = `${height}px`;
holder.style['height'] = `${width}px`;
}
img.style['vertical-align'] = 'bottom';
img.style['transform'] = translate + ' ' + transform;
recently_added[img.src] = translate + ' ' + transform;
} else {
havent_exif[img.src] = true;
if (!recently_added[img.src]) {
img.style['transform'] = "translate(0px, 0px) rotateY(0deg) rotateZ(0deg)";
}
}
})
}
}
<style scoped>
.holder {
object-fit: cover;
width: 100%;
height: 100%;
}
</style>
I'm hoping someone can provide some guidance on how to improve this code...