When taking a vertical picture on my iPhone, my Vue component does not function properly

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.

Upside down photo

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.

Right side up photo

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...

Answer №1

After realizing that this code was causing issues, I decided to remove it. Problem solved!

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`;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

A guide to exporting a PDF in A4 size landscape mode with jspdf

As a novice in UI development, I am currently trying to export HTML content to PDF using the JSPDF library. However, I have encountered difficulties in generating the PDF in A4 size landscape mode. The HTML code includes data with charts (canvasjs/chartjs) ...

The chart appears oversized in the vue js. How can I make it smaller in size?

I recently integrated a line chart from Chart JS into my Vue.js project, but the chart is taking up too much space on my webpage. I'm looking for ways to make it appear smaller and more compact. This is my first time working with charts in Vue.js, so ...

The command "actions" in Selenium is not recognized

I am having trouble trying to perform a mouse click based on position. No matter what I try, I keep receiving the same error message. I encountered this issue when attempting a double click on the main search bar of google.com. For assistance, refer to: ...

Is there a way to adjust the transparency of an image without affecting any overlaid text while using Bootstrap's carousel feature?

I am currently working with Bootstrap v4 to build a carousel featuring an image with caption text. My goal is to have the image faded while leaving the text unaffected. Despite trying several non-Bootstrap solutions, I have been unsuccessful in achieving t ...

What is the purpose of "on" and "attrs" in Vuetify tooltips?

While exploring the Vuetify documentation, I came across an example for "Tooltip" that caught my attention: <v-tooltip left> <template v-slot:activator="{ on, attrs }"> <v-btn color="primary" dark ...

embed a hyperlink onto a live video at a designated moment within an HTML document

Can anyone help me figure out how to overlay a link over a video playing at a specific time on an HTML page? I know it's easy to do on Youtube, but I need to accomplish this task without using Youtube. :) Thank you in advance for any assistance! ...

The alternative condition for jQuery Color takes 17 seconds to respond

After extensive testing on all the browsers available on my computer, I implemented error handling and encountered no issues. The script is simple and works, but not as intended. When scrolling down, the bar should change to red, and while scrolling up, ...

Error in jQuery and Canvas Image Crop: The index or size is invalid, exceeding the permissible limit

Recently, I downloaded and installed the Canvas Image Crop plugin from CodeCanyon but encountered a problem specifically on firefox. An error message kept popping up whenever I tried to upload certain images: "Index or size is negative or greater than the ...

Creating an HTML form that submits data to a PHP script, which then saves the

Looking for some assistance with a PHP issue I am having. I know my way around PHP, but I wouldn't say I'm an expert. Here's the problem: I have created an HTML form (form.html) and now I want the output from formular.php to be saved as a u ...

Clicking a button will bring back the component to its assigned ID

How can I dynamically add a component <SaveTask/> to a specific div tag with the id of <div id="saveTask">? When I use this.setState(), it replaces the container and displays only the <SaveTask/> component. However, I want to re ...

Using Ajax to update multiple text field rows with unique values

I have a question regarding utilizing Ajax to update the second text field based on the input from the first text field. I am looking to create multiple rows using a for loop, with each row having its own set of values. HTML <form style="text-align:c ...

unable to assign values to this.props (appears as undefined or an empty array)

Upon setting up react/redux, I encountered a peculiar issue. When my component mounts, it should render the information stored in this.props.heroes.data. However, upon logging this data, I receive an unexpected value of [{id:1,heroname:'Batman',r ...

Trouble with executing two asynchronous AJAX calls simultaneously in ASP.NET using jQuery

When developing a web application in asp.net, I encountered an issue with using jQuery Ajax for some pages. The problem arose when making two asynchronous Ajax calls - instead of receiving the results one by one, they both appeared simultaneously after the ...

If I do not utilize v-model within computed, then computed will not provide a value

I'm fairly new to coding in JS and Vue.js. I've been attempting to create a dynamic search input feature that filters an array of objects fetched from my API based on user input. The strange issue I'm coming across is that the computed metho ...

Bring in a function by its name from the ts-nameof package that is not declared in the d.ts export

Recently, I came across a captivating package that caught my interest and I would love to incorporate it into my TypeScript application: https://github.com/dsherret/ts-nameof However, upon attempting to import the nameof function, I realized it was not be ...

What is the best way to include a pound sign in a cfoutput tag?

My challenge is that I need to display the following HTML tags after receiving data from an AJAX query. The problem arises because in cfml, any string starting with a "#" is considered as an identifier, resulting in an error. <cfoutput> ...

Arrange the keys of a map in ascending order, prioritizing special characters and their precedence

JavaScript ES6 Map Example: const map = new Map(); map.set('first', ['1', '2']); map.set('second', ['abc', 'def']); map.set('_third', []); map.set(')(*', []); map.set('he ...

Steps to develop a log-in API using Node.js

In the process of developing my web application, I have utilized node js exclusively for all functionalities and the web user interface has been successfully implemented. An issue that has come to light is that users are able to access the services API wi ...

Error: The value of 'id' cannot be assigned to an undefined property

Recently, I've been delving into learning JS Express and decided to create a basic solution to handle GET / DELETE / POST / PUT requests. Everything was running smoothly until I encountered an issue with the POST router. Below is the code snippet for ...

Retrieving JSON data with jQuery's Ajax functionality

I'm currently developing a web application to handle the administrative tasks for a restaurant. The main functionalities include creating new orders, adding order items, and managing financial overviews. One of the key features is the ability to view ...