আপলোড করার আগে একটি চিত্রের আকার পরিবর্তন করতে এইচটিএমএল 5 ব্যবহার করুন


105

এই প্রশ্নের উত্তর দেওয়ার জন্য আমি স্ট্যাকওভারফ্লোতে কয়েকটি আলাদা পোস্ট এবং এমনকী প্রশ্ন পেয়েছি। আমি মূলত এই পোস্ট হিসাবে একই জিনিস বাস্তবায়ন করছি ।

সুতরাং এখানে আমার সমস্যা। আমি যখন ছবিটি আপলোড করি তখন আমারও বাকি ফর্মটি জমা দিতে হবে। এখানে আমার এইচটিএমএল:

<form id="uploadImageForm" enctype="multipart/form-data">
  <input name="imagefile[]" type="file" id="takePictureField" accept="image/*" onchange="uploadPhotos(\'#{imageUploadUrl}\')" />
  <input id="name" value="#{name}" />
  ... a few more inputs ... 
</form>

পূর্বে, আমার ইমেজটিকে পুনরায় আকার দেওয়ার দরকার ছিল না, তাই আমার জাভাস্ক্রিপ্টটি দেখতে এ জাতীয় দেখাচ্ছে:

window.uploadPhotos = function(url){
    var data = new FormData($("form[id*='uploadImageForm']")[0]);

    $.ajax({
        url: url,
        data: data,
        cache: false,
        contentType: false,
        processData: false,
        type: 'POST',
        success: function(data){
            ... handle error...
            }
        }
    });
};

এটি সবই দুর্দান্ত কাজ করেছে ... এখন যেহেতু আমাকে চিত্রগুলি পুনরায় আকার দেওয়া দরকার ... আমি কীভাবে ফর্মটিতে চিত্রটি প্রতিস্থাপন করতে পারি যাতে পুনরায় আকারিত ছবিটি পোস্ট করা হয় এবং আপলোড করা চিত্রটি নয়?

window.uploadPhotos = function(url){

    var resizedImage;

    // Read in file
    var file = event.target.files[0];

    // Ensure it's an image
    if(file.type.match(/image.*/)) {
        console.log('An image has been loaded');

        // Load the image
        var reader = new FileReader();
        reader.onload = function (readerEvent) {
            var image = new Image();
            image.onload = function (imageEvent) {

                // Resize the image
                var canvas = document.createElement('canvas'),
                    max_size = 1200,
                    width = image.width,
                    height = image.height;
                if (width > height) {
                    if (width > max_size) {
                        height *= max_size / width;
                        width = max_size;
                    }
                } else {
                    if (height > max_size) {
                        width *= max_size / height;
                        height = max_size;
                    }
                }
                canvas.width = width;
                canvas.height = height;
                canvas.getContext('2d').drawImage(image, 0, 0, width, height);
                resizedImage = canvas.toDataURL('image/jpeg');
            }
            image.src = readerEvent.target.result;
        }
        reader.readAsDataURL(file);
    }


   // TODO: Need some logic here to switch out which photo is being posted...

    var data = new FormData($("form[id*='uploadImageForm']")[0]);

    $.ajax({
        url: url,
        data: data,
        cache: false,
        contentType: false,
        processData: false,
        type: 'POST',
        success: function(data){
            ... handle error...
            }
        }
    });
};

আমি ফর্মটি ফাইলের ইনপুটটি সরিয়ে নিয়ে যাওয়া এবং ফর্মের মধ্যে একটি লুকানো ইনপুট থাকার বিষয়ে ভেবেছি যা আমি পুনরায় আকারিত চিত্রটির মানকে সেট করে দিয়েছি ... তবে আমি ভাবছি যে আমি কেবল সেই চিত্রটি প্রতিস্থাপন করতে পারি কিনা? ইতিমধ্যে ফর্ম আছে।


আপনি কি কোনও সার্ভার সাইড ল্যাঙ্গুয়েজ বা কেবল এইচটিএমএল 5 এবং জাভাস্ক্রিপ্ট নিয়ে কাজ করছেন?
luke2012

4
@ luke2012 জাভা সার্ভার সাইড
ফেরিক্স 2

জেসিক্রপের মতো কিছু ব্যবহার করে ক্লায়েন্ট সাইডে চিত্রটি ক্রপ করুন তারপরে স্থানাঙ্কগুলি সার্ভারের দিকে প্রেরণ করুন এবং এটি ক্রপ করুন। যেমনBufferedImage dest = src.getSubimage(rect.x, rect.y, rect.width, rect.height);
luke2012

4
@ luke2012 বিন্দুটি হ'ল এটি সার্ভারে প্রেরণের আগে চিত্রের আকার হ্রাস করা।
ferics2

পান্ডাম্যাটাক . com / জনের / জেনারড / টেস্ট / ক্রপ এর জেএস উত্সটি একবার দেখে নিন ...
luke2012

উত্তর:


169

এখানে আমি শেষ করে যা করেছি এবং এটি দুর্দান্ত কাজ করেছে।

প্রথমে আমি ফাইলের ইনপুটটি ফর্মের বাইরে সরিয়ে নিয়েছি যাতে এটি জমা না দেওয়া হয়:

<input name="imagefile[]" type="file" id="takePictureField" accept="image/*" onchange="uploadPhotos(\'#{imageUploadUrl}\')" />
<form id="uploadImageForm" enctype="multipart/form-data">
    <input id="name" value="#{name}" />
    ... a few more inputs ... 
</form>

তারপরে আমি uploadPhotosফাংশনটি পরিবর্তন করে কেবল আকার পরিবর্তন করতেই হ্যান্ডেল করতে পারি:

window.uploadPhotos = function(url){
    // Read in file
    var file = event.target.files[0];

    // Ensure it's an image
    if(file.type.match(/image.*/)) {
        console.log('An image has been loaded');

        // Load the image
        var reader = new FileReader();
        reader.onload = function (readerEvent) {
            var image = new Image();
            image.onload = function (imageEvent) {

                // Resize the image
                var canvas = document.createElement('canvas'),
                    max_size = 544,// TODO : pull max size from a site config
                    width = image.width,
                    height = image.height;
                if (width > height) {
                    if (width > max_size) {
                        height *= max_size / width;
                        width = max_size;
                    }
                } else {
                    if (height > max_size) {
                        width *= max_size / height;
                        height = max_size;
                    }
                }
                canvas.width = width;
                canvas.height = height;
                canvas.getContext('2d').drawImage(image, 0, 0, width, height);
                var dataUrl = canvas.toDataURL('image/jpeg');
                var resizedImage = dataURLToBlob(dataUrl);
                $.event.trigger({
                    type: "imageResized",
                    blob: resizedImage,
                    url: dataUrl
                });
            }
            image.src = readerEvent.target.result;
        }
        reader.readAsDataURL(file);
    }
};

আপনি দেখতে পাচ্ছেন যে আমি canvas.toDataURL('image/jpeg');পুনরায় আকারিত চিত্রটি একটি ডেটাআরএল অ্যাডনে রূপান্তর করতে ব্যবহার করছি তখন আমি ফাংশনটি কল dataURLToBlob(dataUrl);করে ডেটাআরআলকে একটি ফোটাতে পরিণত করব যা আমি ফর্মটিতে যুক্ত করতে পারি। যখন ব্লবটি তৈরি হবে, আমি একটি কাস্টম ইভেন্ট ট্রিগার করব। ব্লব তৈরির জন্য এখানে ফাংশনটি দেওয়া হয়েছে:

/* Utility function to convert a canvas to a BLOB */
var dataURLToBlob = function(dataURL) {
    var BASE64_MARKER = ';base64,';
    if (dataURL.indexOf(BASE64_MARKER) == -1) {
        var parts = dataURL.split(',');
        var contentType = parts[0].split(':')[1];
        var raw = parts[1];

        return new Blob([raw], {type: contentType});
    }

    var parts = dataURL.split(BASE64_MARKER);
    var contentType = parts[0].split(':')[1];
    var raw = window.atob(parts[1]);
    var rawLength = raw.length;

    var uInt8Array = new Uint8Array(rawLength);

    for (var i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
    }

    return new Blob([uInt8Array], {type: contentType});
}
/* End Utility function to convert a canvas to a BLOB      */

অবশেষে, এখানে আমার ইভেন্ট হ্যান্ডলারটি কাস্টম ইভেন্ট থেকে ব্লব নেয়, ফর্মটি সংযোজন করে এবং পরে এটি জমা দেয়।

/* Handle image resized events */
$(document).on("imageResized", function (event) {
    var data = new FormData($("form[id*='uploadImageForm']")[0]);
    if (event.blob && event.url) {
        data.append('image_data', event.blob);

        $.ajax({
            url: event.url,
            data: data,
            cache: false,
            contentType: false,
            processData: false,
            type: 'POST',
            success: function(data){
               //handle errors...
            }
        });
    }
});

4
আশ্চর্যজনক কোড, কিছু টুইট করার পরে এবং কিছু ত্রুটি ঠিক করার পরে (আমি ঠিক কী এবং কোনটি মনে করি না) এটি কাজ করতে পেরেছি। যাইহোক, আমি মনে করি আপনি যখন লিখেছিলেন width *= max_size / width;আসলে আপনি বোঝাতে চেয়েছিলেন width *= max_size / height;
ব্যবহারকারী 1111929

4
এই কোডটি কি মোবাইল ডিভাইসে কাজ করে? আইওএস এবং অ্যান্ড্রয়েডের অধীনে?
বিমানওয়ালা

4
@ প্লেনওয়াকার আমি আসলে মোবাইল ডিভাইসের জন্য কোডটি লিখেছিলাম। ডেটা ব্যবহার কমাতে।
ferics2

4
@ প্লেনওয়াকার, আমি এটি লেখার সময় আইওএস-তে পরীক্ষা করছিলাম। আশা করি এটা তোমার জন্য কাজ করবে।
ferics2

4
ভাল কাজ করেছেন এবং ভাগ করে নেওয়ার জন্য ধন্যবাদ! (অন্যরা উল্লেখ করেছেন তবে চিহ্নিত না করা ছোট্ট ত্রুটিটি চিত্রের আকার পরিবর্তনকারী ইভেন্ট ট্রিগারে রয়েছে "" ইউআরএল: ইউআরএল "হওয়া উচিত" ইউআরএল: ডেটা ইউআরএল ")
সিয়োরাস

49

যদি কোন আগ্রহী আমি একটি টাইপ স্ক্রিপ্ট সংস্করণ তৈরি করেছি:

interface IResizeImageOptions {
  maxSize: number;
  file: File;
}
const resizeImage = (settings: IResizeImageOptions) => {
  const file = settings.file;
  const maxSize = settings.maxSize;
  const reader = new FileReader();
  const image = new Image();
  const canvas = document.createElement('canvas');
  const dataURItoBlob = (dataURI: string) => {
    const bytes = dataURI.split(',')[0].indexOf('base64') >= 0 ?
        atob(dataURI.split(',')[1]) :
        unescape(dataURI.split(',')[1]);
    const mime = dataURI.split(',')[0].split(':')[1].split(';')[0];
    const max = bytes.length;
    const ia = new Uint8Array(max);
    for (var i = 0; i < max; i++) ia[i] = bytes.charCodeAt(i);
    return new Blob([ia], {type:mime});
  };
  const resize = () => {
    let width = image.width;
    let height = image.height;

    if (width > height) {
        if (width > maxSize) {
            height *= maxSize / width;
            width = maxSize;
        }
    } else {
        if (height > maxSize) {
            width *= maxSize / height;
            height = maxSize;
        }
    }

    canvas.width = width;
    canvas.height = height;
    canvas.getContext('2d').drawImage(image, 0, 0, width, height);
    let dataUrl = canvas.toDataURL('image/jpeg');
    return dataURItoBlob(dataUrl);
  };

  return new Promise((ok, no) => {
      if (!file.type.match(/image.*/)) {
        no(new Error("Not an image"));
        return;
      }

      reader.onload = (readerEvent: any) => {
        image.onload = () => ok(resize());
        image.src = readerEvent.target.result;
      };
      reader.readAsDataURL(file);
  })    
};

এবং এখানে জাভাস্ক্রিপ্ট ফলাফল:

var resizeImage = function (settings) {
    var file = settings.file;
    var maxSize = settings.maxSize;
    var reader = new FileReader();
    var image = new Image();
    var canvas = document.createElement('canvas');
    var dataURItoBlob = function (dataURI) {
        var bytes = dataURI.split(',')[0].indexOf('base64') >= 0 ?
            atob(dataURI.split(',')[1]) :
            unescape(dataURI.split(',')[1]);
        var mime = dataURI.split(',')[0].split(':')[1].split(';')[0];
        var max = bytes.length;
        var ia = new Uint8Array(max);
        for (var i = 0; i < max; i++)
            ia[i] = bytes.charCodeAt(i);
        return new Blob([ia], { type: mime });
    };
    var resize = function () {
        var width = image.width;
        var height = image.height;
        if (width > height) {
            if (width > maxSize) {
                height *= maxSize / width;
                width = maxSize;
            }
        } else {
            if (height > maxSize) {
                width *= maxSize / height;
                height = maxSize;
            }
        }
        canvas.width = width;
        canvas.height = height;
        canvas.getContext('2d').drawImage(image, 0, 0, width, height);
        var dataUrl = canvas.toDataURL('image/jpeg');
        return dataURItoBlob(dataUrl);
    };
    return new Promise(function (ok, no) {
        if (!file.type.match(/image.*/)) {
            no(new Error("Not an image"));
            return;
        }
        reader.onload = function (readerEvent) {
            image.onload = function () { return ok(resize()); };
            image.src = readerEvent.target.result;
        };
        reader.readAsDataURL(file);
    });
};

ব্যবহারের মত:

resizeImage({
    file: $image.files[0],
    maxSize: 500
}).then(function (resizedImage) {
    console.log("upload resized image")
}).catch(function (err) {
    console.error(err);
});

বা ( async/ await):

const config = {
    file: $image.files[0],
    maxSize: 500
};
const resizedImage = await resizeImage(config)
console.log("upload resized image")

সত্যিই দুর্দান্ত সমাধান, বেস 64 হিসাবে ফলাফলটি ফেরত দেওয়ার জন্য অতিরিক্ত সেটিং যুক্ত করা যেতে পারে (শেষে ইউআরআইটি ব্লব কলটি উপেক্ষা করুন)।
চেন

আমি এই ত্রুটিটি পেয়েছি:Uncaught (in promise) TypeError: Cannot read property 'type' of undefined
ওভেন এম

4
ভাল লাগল আমাকে ইউনেস্কেপ পরিবর্তন করতে হয়েছিল (<নতুন> উইন্ডো)। ইউনেস্কেপ আমি মিনিসাইজও যুক্ত করেছি।
রবার্ট রাজা

maxSizeবাইট বা কেবিতে হয়?
জাগ্রতী

4
আপনার উত্তর আমাকে এই প্রশ্নের উত্তর দিতে সহায়তা করেছে , ধন্যবাদ।
সৈয়দ

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.