how to resize image and reorient it if it rotates when uploaded through IOS devices using image intervention package?
Asked Answered
D

3

-2

I have developed a Laravel web application with the help of some tutorial videos and codes given by other developers on stackoverflow .The app is working pretty good except for the image upload feature. I am facing an issue related to the uploaded image being cut either on the sides or on the bottom as well as the image when uploaded through any IOS device then the image under goes rotation. I have installed image intervention but i don't know where to put the code inside my files i am sharing my controller code as well as the image displaying code here controller code

namespace App\Http\Controllers;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\MessageBag;
use App\comment;
use App\User;
use App\post;
use View;
use Lang;
use image;
class usersController extends Controller
{
    private $u;

    public function __construct(){
        $this->u = new User();
    }
    public function search(Request $request){
        $search_input = $request["input"];
        $path = $request["path"];
        $users = User::where("name","like","%$search_input%")->orWhere("username","like","%$search_input%")->get();

        if ($users->isEmpty()) {
            return "<p style='text-align: center;width: 100%;color: gray;font-size: 12px;margin: 3px'>".Lang::get('trans.nothingToShow')."</p>";
        }else{
            foreach ($users as $user) {
                if ($user->verify == 1) {
                    $ifVerify = '<span class="verify-badge" style="width: 420px; height: 700px; background:  url(\''.$path.'/imgs/verify.png\') no-repeat; background-size: cover; margin: 0px 2px;"></span>';
                }else{
                    $ifVerify = '';
                }
                if($user->avatar == "avatar.png"){
                    $avatar_path = '/imgs/avatar.png';
                }else{
                    $avatar_path = '/storage/avatar/'.$user->avatar;
                }
                echo '<div class="navbar-search-item">
                    <a href="'.$path.'/'.$user->username.'">
                        <div>
                            <div style="background-image:url(\''.$path.$avatar_path.'\');">
                            </div>
                            <p>
                                '.$user->name.$ifVerify.'<br>
                                <span>@'.$user->username.'</span>
                            </p>
                        </div>
                    </a>
                </div>';
            }
        }
    }
    public function profile($username){
        $user_info = User::where("username",$username)->get();
        foreach ($user_info as $uinfo) {
            $user_id = $uinfo->uid;
        }
        if (isset($user_id)) {
            $feedbacks = post::where("to_id",$user_id)->where("privacy",1)->orderBy('time', 'desc')->get();
            $feedbacks_count = post::where("to_id",$user_id)->get()->count();
            $new_count = post::where("to_id",$user_id)->where('read',0)->get()->count();
            // check comments on post (count)
            $commentsCount = array();
            foreach ($feedbacks as $fb) {
                $pid = $fb->pid;
                $countComments = comment::where("c_pid",$pid)->get()->count();
                array_push($commentsCount,$countComments);
            }
            return view("pages.profile")->with(["user_info" => $user_info,"feedbacks" => $feedbacks,'feedbacks_count' => $feedbacks_count,'new_count' => $new_count,'commentsCount' => $commentsCount]);
        }else{
            return view("pages.profile")->with(["user_info" => $user_info]);
        }
    }
    public function settings($username){
        $user_info = User::where("username",$username)->get();
        if (Auth::user()->username == $username) {
            return view("pages.settings")->with("user_info",$user_info);
        }else{
            return redirect()->back();
        }

    }
    public function s_general(Request $request){
        $this->validate($request,[
            'avatar' => 'nullable|image|mimes:jpeg,png,jpg|max:3072',
            'fullname' => 'required',
            'email' => 'required|email'
        ]);
        if ($request['fullname'] == Auth::user()->name && $request['email'] == Auth::user()->email && !$request->hasFile('avatar')) {
            return redirect()->back()->with('general_msg', Lang::get('trans.noChanges_MSG'));
        }else{
            $avatar = $request->file('avatar');
            if ($request->hasFile('avatar')) {
                $avatar_ext = $avatar->getClientOriginalExtension();
                $avatar_name = rand(9,999999999)+time().".".$avatar_ext;
                $avatar_new = $avatar->storeAs("avatar",$avatar_name);
            }else{
                $avatar_name = Auth::user()->avatar;
            }
            $update_general = User::where('uid',Auth::user()->uid)->update(['name' => $request['fullname'],'email' => $request['email'],'avatar' => $avatar_name]);
            return redirect()->back()->with('general_msg', Lang::get('trans.changes_saved'));
        }

    }

and this is how i display the image <div class="profile-avatar" style="width: 300px;height:400px; border-radius: 0%;background-image: url('@if(Auth::user()->avatar == "avatar.png") {{ url("/imgs/".Auth::user()->avatar) }} @else {{ url("/storage/avatar/".Auth::user()->avatar) }} @endif');">

please help me with code should i put and where i should put that in order to resolve this issue

this code is for preview of the image

  <div style="display: inline-flex;">
    <div class="profile-avatar" id="settings_img_elm" style="margin: 10px; width:350px;margin-top: 0; margin-bottom: 0;border-color: #fff; text-align: center;background-image: url('@if(Auth::user()->avatar == "avatar.png") {{ url("/imgs/".Auth::user()->avatar) }} @else {{ url("/storage/avatar/".Auth::user()->avatar) }} @endif');">
  </div>
  <p style="color: #a7aab5; font-size: 9px;padding: 25px 10px 25px 10px; margin: 0;">@lang("trans.preview")<br>@lang("trans.maxSize")<br>upload vertical <br>images.<br>Save the<br>image first<br> and then<br> check the<br> preview</p>
  </div>
  <p style="border-bottom: 1px solid #dfe2e6;margin: 0; margin-top: 12px; margin-bottom: 12px;">
    <input type="file" name="avatar" style="display: none;" id="settings_img">
    <label for="settings_img" class="btn btn-success">@lang("trans.selectImage")</label>

the javascript for the preview image is

function imagePreview(input,elm) {
        if (input.files && input.files[0]) {
            var reader = new FileReader();
            reader.onload = function (e) {
                $(elm).css("background-image","url('"+e.target.result+"')");
            }
            reader.readAsDataURL(input.files[0]);
        }
    }
    $("#settings_img").on("change",function(){
        imagePreview(this,"#settings_img_elm");
    });
    $("#feedback_hFile").on("change",function(){
        $(".send_feedback_image").show();
        imagePreview(this,"#sfb_image_preview");
    });
Devilish answered 15/12, 2019 at 15:59 Comment(0)
P
1

The code below should get you started. The two key things you are looking for here are Interventions orientate and resize methods which should take care of the two issues you mention. Orientation will rotate the image based on EXIF data, and resize can resize your image to whatever specifications you need.

Import the facade

use Intervention\Image\Facades\Image;

Suggestions

Remove use image; from your imports as it is probably causing or going to cause you issues. It is invalid.

s_general method adjustments

public function s_general(Request $request){
    $this->validate($request,[
        'avatar' => 'nullable|image|mimes:jpeg,png,jpg|max:3072',
        'fullname' => 'required',
        'email' => 'required|email'
    ]);

    if ($request['fullname'] === Auth::user()->name && $request['email'] === Auth::user()->email && !$request->hasFile('avatar')) {
        return redirect()->back()->with('general_msg', Lang::get('trans.noChanges_MSG'));
    }

    if ($request->hasFile('avatar')) {
        // Grab the original image from the request
        $originalImage = $request->file('avatar');

        // Grab the original image extension
        $originalExtension = $originalImage->getClientOriginalExtension();

        // Instantiate a new Intervention Image using our original image,
        // read the EXIF 'Orientation' data of the image and rotate the image if needed
        $newImage = Image::make($originalImage)->orientate();

        // Resize the new image to a width of 300 and a height of null (auto)
        // we also use a callback to constrain the aspect ratio so we don't distort the image on resize
        $newImage->resize(300, null, function ($constraint) {
            $constraint->aspectRatio();
        });

        // Generate a randomized filename and append the original image extension
        $filename = random_int(9, 999999999) + time() . '.' . $originalExtension;

        // Save the new image to disk
        $newImage->save(storage_path('app/public/avatar/' . $filename));
    } else {
        $filename = Auth::user()->avatar;
    }

    User::where('uid', Auth::user()->uid)->update(
        [
            'name' => $request['fullname'],
            'email' => $request['email'],
            'avatar' => $filename
        ]);

    return redirect()->back()->with('general_msg', Lang::get('trans.changes_saved'));
}

More suggestions

I know this isn't a code review, but Use PascalCase for your class names. I see you have a few imports such as App\comment and App\post

Your constructor doesn't seem to be needed. I'd ditch it. If you are keeping it, i would get use to more descriptive variable names. Short names like $u are generally considered bad practice.

You have a few unused imports, Validator, Hash and MessageBag could be removed to clean this up.

Your controller is doing a lot of stuff that most would consider bad practice. Fumbling around with html for example. 9.9 times out of 10 you should probably be leveraging blade for these things as it's one of its main purposes.

Stick to one naming convention or another. You are using a mixture of camelCase and snake_case for your variables. I prefer camelCase but whichever you choose it's best to stick with it and not mix them.

Sorry, i know this isn't suppose to be a code review, i just thought that a few little suggestions might help you in the future.

Peculate answered 24/12, 2019 at 22:12 Comment(7)
thank you for your suggestions and your code, the code is working perfectly fine but i actually show preview of the image before saving it and while showing the preview the the image is coming rotated but after saving it becomes proper, is there any solution for this issueDevilish
what are you using to upload/preview the image before submitting it to the server?Peculate
and @Glovanni S the quality of the image is lowDevilish
i am not the developer of this app it was given to me by someone else to work on an i am new to laravel in the settings there is id=img_setting to preview the imageDevilish
the preview code is given in the question please checkDevilish
@Glovanni S i have included the javascript code tooDevilish
to be honest i would probably use a package for this. it gets a bit tricky on the frontend, usually due to devices and different compatibilities between them. something like pqina.nl/filepond or dropzonejs.com to handle the frontend stuff. Someone else might be able to chime in as I came across this because of the laravel tag not so much javascript/jquery workPeculate
J
1

You can check Intervation docs on how to resize image, I've also created an example for you for s_general function:

$avatar = $request->file('avatar');

if ($request->hasFile('avatar')) {

    //pass uploaded avatar to Intervention Image instance
    $image = \Image::make($avatar);

    //resize image to 300 width, keep height automated adjusted, or any other width you need
    $image->resize(300, null, function ($constraint) {
        $constraint->aspectRatio();
    });

    //Or you can set specific width and height
    //$image->resize(300, 200);

    $avatar_ext = $avatar->getClientOriginalExtension();
    $avatar_name = rand(9,999999999) + time().".".$avatar_ext;


    //I used public path to store the image you can change it based on your needs
    $image->save(public_path('/avatar/'.$avatar_name));

}else{

    $avatar_name = Auth::user()->avatar;
}
Jehoash answered 22/12, 2019 at 17:31 Comment(6)
@JeffrinJose did you installed and followed the instuctions of Intervation? image.intervention.io/getting_started/installationJehoash
yeaah i did everything according to the guideDevilish
@JeffrinJose try changing Image::make to \Image::make or add use Image; on top of the controllerJehoash
@Forxz can u please edit the above given code in the question the use of \image is working but i am getting other errors please edit the above given code for meDevilish
Updated with requestJehoash
i actually wanted you to change my code given in the question@FroxzDevilish
P
1

The code below should get you started. The two key things you are looking for here are Interventions orientate and resize methods which should take care of the two issues you mention. Orientation will rotate the image based on EXIF data, and resize can resize your image to whatever specifications you need.

Import the facade

use Intervention\Image\Facades\Image;

Suggestions

Remove use image; from your imports as it is probably causing or going to cause you issues. It is invalid.

s_general method adjustments

public function s_general(Request $request){
    $this->validate($request,[
        'avatar' => 'nullable|image|mimes:jpeg,png,jpg|max:3072',
        'fullname' => 'required',
        'email' => 'required|email'
    ]);

    if ($request['fullname'] === Auth::user()->name && $request['email'] === Auth::user()->email && !$request->hasFile('avatar')) {
        return redirect()->back()->with('general_msg', Lang::get('trans.noChanges_MSG'));
    }

    if ($request->hasFile('avatar')) {
        // Grab the original image from the request
        $originalImage = $request->file('avatar');

        // Grab the original image extension
        $originalExtension = $originalImage->getClientOriginalExtension();

        // Instantiate a new Intervention Image using our original image,
        // read the EXIF 'Orientation' data of the image and rotate the image if needed
        $newImage = Image::make($originalImage)->orientate();

        // Resize the new image to a width of 300 and a height of null (auto)
        // we also use a callback to constrain the aspect ratio so we don't distort the image on resize
        $newImage->resize(300, null, function ($constraint) {
            $constraint->aspectRatio();
        });

        // Generate a randomized filename and append the original image extension
        $filename = random_int(9, 999999999) + time() . '.' . $originalExtension;

        // Save the new image to disk
        $newImage->save(storage_path('app/public/avatar/' . $filename));
    } else {
        $filename = Auth::user()->avatar;
    }

    User::where('uid', Auth::user()->uid)->update(
        [
            'name' => $request['fullname'],
            'email' => $request['email'],
            'avatar' => $filename
        ]);

    return redirect()->back()->with('general_msg', Lang::get('trans.changes_saved'));
}

More suggestions

I know this isn't a code review, but Use PascalCase for your class names. I see you have a few imports such as App\comment and App\post

Your constructor doesn't seem to be needed. I'd ditch it. If you are keeping it, i would get use to more descriptive variable names. Short names like $u are generally considered bad practice.

You have a few unused imports, Validator, Hash and MessageBag could be removed to clean this up.

Your controller is doing a lot of stuff that most would consider bad practice. Fumbling around with html for example. 9.9 times out of 10 you should probably be leveraging blade for these things as it's one of its main purposes.

Stick to one naming convention or another. You are using a mixture of camelCase and snake_case for your variables. I prefer camelCase but whichever you choose it's best to stick with it and not mix them.

Sorry, i know this isn't suppose to be a code review, i just thought that a few little suggestions might help you in the future.

Peculate answered 24/12, 2019 at 22:12 Comment(7)
thank you for your suggestions and your code, the code is working perfectly fine but i actually show preview of the image before saving it and while showing the preview the the image is coming rotated but after saving it becomes proper, is there any solution for this issueDevilish
what are you using to upload/preview the image before submitting it to the server?Peculate
and @Glovanni S the quality of the image is lowDevilish
i am not the developer of this app it was given to me by someone else to work on an i am new to laravel in the settings there is id=img_setting to preview the imageDevilish
the preview code is given in the question please checkDevilish
@Glovanni S i have included the javascript code tooDevilish
to be honest i would probably use a package for this. it gets a bit tricky on the frontend, usually due to devices and different compatibilities between them. something like pqina.nl/filepond or dropzonejs.com to handle the frontend stuff. Someone else might be able to chime in as I came across this because of the laravel tag not so much javascript/jquery workPeculate
D
0

use image intervention for resizing and for correcting the orientation of the image uploaded from a mobile phone. IF you are showing the preview of this image using simple javascript something like

reader.onload = function (e) {
                $(elm).css("background-image","url('"+e.target.result+"')"); 

then there is a chance that the preview of the image won't be oriented as we want but once you save the image the orientation will be proper. this problem of orientation is encountered mostly on iphone. The code for orientation correction and resizing is

  $newImage = Image::make($originalImage)->orientate();


        $newImage->resize(300, null, function ($constraint) {
            $constraint->aspectRatio();
        });
///or for resizing use

 $newImage->resize(width,height);
Devilish answered 26/12, 2019 at 4:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.