Coder Social home page Coder Social logo

Comments (24)

simioluwatomi avatar simioluwatomi commented on May 21, 2024 2

Hello, @simioluwatomi!

I'm not @zefexdeveloper, so I can't share the code snippets, but this task should be pretty trivial. Do you want to download image on the backend or send the cropped image from the frontend to the backend?

I've actually figured this out. Thank you!

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024 1

I will investigate this possibility. Maybe I should add the prop roundCoordinates, but it's the pretty straightforward solution.

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024 1

Please update to 0.16.0 version.

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024 1

Yes, I thought out and decided that's pretty optimal solution. Nonetheless, there is workaround to disable the rounding coordinates, but I couldn't come out with any situation where it might be needed.

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024 1

@Norserium Just updated here and it saved me a few lines of code rounding numbers 😆 Thank you

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024

Hello, @zefexdeveloper!

I didn't understand your problem clearly. How do you check the size of an image at the backend and frontend?

Could you try to use canvas.toBlob(callback, 'image/jpeg') method to get the blob, instead of using canvas.toDataURL and your custom method?

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024

Hi @Norserium, the file size on the back end depends on what technology you are using, this project I'm using Laravel (PHP) and it's just a matter of calling getSize but as we are talking about validation here, the validation rule itself will check if the file size is bigger than what was specified.

If you select an image, let's say with 500kb and console.log the base64 on Chrome it will show you the file size.

This was a 334kb image selected, turned 3.9mb:
image

I will try this canvas.toBlob, didn't know it existed.

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024

It's better to use Blob.size property to check the size of sending image.

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024

@Norserium Yes, but it doesn't change the problem of having different file size on selecting and when sending. For example, the front end validation is when you select a file right? This way you can check if the file isn't bigger than 5mb, but when you crop, the file size is way bigger. The validation on the back end is when sending the image, so I can't put like 5mb max on the back end as well cause if the user selects an image on the front end that is let's say 4.5mb and crops, it will turn at least 15mb more or less so the backend won't allow it.

I will try this canvas.toBlob cause working with base64 is problematic cause of this, the image size is way bigger.

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024

What's the image type do you use for converting to base64? Default is image/png, so if you upload .jpg image result might be larger.

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024

@Norserium I was using the code above, it's pretty much the same as canvas.toBlob as I was reading and canvas.toBlob doesn't work on Edge and doesn't have the quality argument in most browsers so it will be pretty much the same. (or worse with less support: https://caniuse.com/#search=toblob)

Do you have a project set up where you can call canvas.toBlob and check if the file size is bigger (or a lot bigger) than it should be?

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024

The conceptual problem consists in impossibility to preserve size of the image after drawing one at an canvas and getting one from that canvas.

I can advise two ways:

  1. Use image/jpeg during conversion (toBlob, toDataURL). You won't get the same size, but it should be pretty similar.
  2. Crop the image on your backend by sending full image and coordinates to it.

Do you have a project set up where you can call canvas.toBlob and check if the file size is bigger (or a lot bigger) than it should be?

I've made it now:
https://codesandbox.io/s/vue-avanced-cropper-comparing-file-sizes-1xl7r

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024

@Norserium The second alternative sounds good, this way I can validate the size both on the front and on the back end without the cropping difference.

I will be trying to second alternative and see if it works nice. Thank you very much.

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024

@zefexdeveloper, did you solve your problem?

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024

@Norserium Sorry the delay answering. I refactored the code in order to send the coordinates and crop on the backend but the libraries asks for integer instead of float when cropping so I had to round them. Is it possible to have an option to return the coordinates as integer?

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024

@Norserium Thank you very much, it will help me a lot, right now I have to round each one and it's pretty shitty solution. Most of the others croppers I saw they have the coordinates as integers, having both in float for precision and integer for compatibility would be great.

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024

Anything on this @Norserium ? Thank you

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024

I'm pretty busy on other projects, so I've postponed the implementing of this feature to this weekends. Sorry for the delay.

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024

@Norserium That is ok, wish you luck. Thank you very much.

from vue-advanced-cropper.

theprobugmaker avatar theprobugmaker commented on May 21, 2024

@Norserium You rock, thank you for this. It's rounded by default now right?

from vue-advanced-cropper.

simioluwatomi avatar simioluwatomi commented on May 21, 2024

@Norserium Sorry the delay answering. I refactored the code in order to send the coordinates and crop on the backend but the libraries asks for integer instead of float when cropping so I had to round them. Is it possible to have an option to return the coordinates as integer?

Please how did you do this? Care to share some code snippets? I'm also using Laravel and I'm at my wits end because I don't know how to get the file object. Please help out. Thank you

from vue-advanced-cropper.

Norserium avatar Norserium commented on May 21, 2024

Hello, @simioluwatomi!

I'm not @zefexdeveloper, so I can't share the code snippets, but this task should be pretty trivial. Do you want to download image on the backend or send the cropped image from the frontend to the backend?

from vue-advanced-cropper.

powolnymarcel avatar powolnymarcel commented on May 21, 2024

@simioluwatomi
Usually when you figure things out, you share it for others..

from vue-advanced-cropper.

simioluwatomi avatar simioluwatomi commented on May 21, 2024

@powolnymarcel

Here you go

Vue component

<template>
    <div>
        <cropper
            :src="image"
            :stencil-props="{ aspectRatio: 1 }"
            ref="cropper"
            class="border border-dashed w-100"
            style="min-height: 300px; max-height: 600px"
        ></cropper>

        <p class="mt-3 text-center text-danger">{{ errorMessages[0] }}</p>

        <div class="btn-options justify-content-around my-3">

            <ValidationProvider rules="required|ext:jpg,png,jpeg|size:1024" ref="provider">

                <b-button variant="outline-primary" @click="$refs.file.click()">

                    <input type="file"
                           ref="file"
                           v-show="false"
                           accept="image/png,image/jpeg,image/jpg"
                           @change="loadImage($event)">

                    Select image

                </b-button>

            </ValidationProvider>

            <b-button variant="secondary" @click="rotate" :disabled="invalid">Rotate</b-button>

            <b-button variant="primary" type="submit" @click="upload" :disabled="invalid">Upload</b-button>

        </div>

    </div>

</template>

<script>
    import {Cropper} from "vue-advanced-cropper";
    import iziToast from "izitoast";
    import {ValidationProvider, ValidationObserver, extend} from 'vee-validate';
    import {required, ext, size} from 'vee-validate/dist/rules';

    extend('required', {
        ...required,
        message: 'This field is required.'
    });

    extend('ext', {
        ...ext,
        message: 'The selected file must be an image.'
    });

    extend('size', {
        ...size,
        message: "The selected image should not be greater than 1 megabyte."
    });


    export default {
        name: "ImageUploadComponent",
        components: {
            Cropper,
            ValidationProvider,
            ValidationObserver
        },
        props: {
            'user': {
                type: Object,
                required: true
            },
        },
        data() {
            return {
                image: null,
                avatar: null,
                invalid: true,
                errorMessages: '',
            };
        },
        methods: {
            async loadImage(event) {
                const {errors, valid} = await this.$refs.provider.validate(event);

                if (errors) {
                    this.errorMessages = errors;
                }

                if (valid) {
                    // Reference to the DOM input element
                    let input = event.target;
                    // Ensure that you have a file before attempting to read it
                    if (input.files && input.files[0]) {
                        // create a new FileReader to read this image and convert to base64 format
                        let reader = new FileReader();
                        // Define a callback function to run, when FileReader finishes its job
                        reader.onload = (event) => {
                            // Note: arrow function used here, so that "this.imageData" refers to the imageData of Vue component
                            // Read image as base64 and set to imageData
                            this.image = event.target.result;
                        };
                        this.avatar = input.files[0];
                        // Start the reader job - read file as a data url (base64 format)
                        reader.readAsDataURL(this.avatar);
                    }
                    this.invalid = false;
                }
            },
            rotate() {
                let image = document.createElement("img");
                image.crossOrigin = "anonymous";
                image.src = this.image;
                image.onload = () => {
                    let canvas = document.createElement("canvas");
                    let ctx = canvas.getContext("2d");

                    if (image.width > image.height) {
                        canvas.width = image.height;
                        canvas.height = image.width;
                        ctx.translate(image.height, image.width / image.height);
                    } else {
                        canvas.height = image.width;
                        canvas.width = image.height;
                        ctx.translate(image.height, image.width / image.height);
                    }
                    ctx.rotate(Math.PI / 2);
                    ctx.drawImage(image, 0, 0);
                    this.image = canvas.toDataURL();
                };
            },
            upload(blob) {
                const {canvas} = this.$refs.cropper.getResult();
                canvas.toBlob(result => {
                    let formData = new FormData();
                    formData.append('avatar', result, this.avatar.name);
                    axios.post(`/${this.user.username}/avatar`, formData)
                        .then(function (response) {                            
                            // handle success response here
                        }.bind(this))
                        .catch(function (error) {
                            // handle error response here
                        }.bind(this));
                }, 'image/jpeg')
            },
        },
    };
</script>

Controller method

public function __invoke(Request $request, User $user)
    {
        $request->validate(['avatar' => ['required', 'image', 'max:1024']], [
            'max' => 'The uploaded image should not be greater than 1 megabyte.',
        ]);

        $path = $request->file('avatar')->storeAs(
            "{$user->id}",
            sha1($user->id).'.jpeg',
            'uploads'
        );

        $user->update(['avatar' => $path]);

        return response()->json($user);
    }

from vue-advanced-cropper.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.