জাভাস্ক্রিপ্ট ক্যানভাসের মাধ্যমে চিত্রের আকার পরিবর্তন করুন (সাবলীলভাবে)


90

আমি ক্যানভাসের সাহায্যে কয়েকটি চিত্রের আকার বদলে দেওয়ার চেষ্টা করছি তবে কীভাবে এগুলিকে কীভাবে হালকা করা যায় সে সম্পর্কে আমি নির্বোধ। ফটোশপ, ব্রাউজার ইত্যাদিতে ... তারা কয়েকটি অ্যালগরিদম ব্যবহার করেন (যেমন: বিউকিউবিক, বিলিনিয়ার) তবে আমি জানি না যে এগুলি ক্যানভাসে নির্মিত বা না।

এখানে আমার কোলাহলটি: http://jsfiddle.net/EWupT/

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width=300
canvas.height=234
ctx.drawImage(img, 0, 0, 300, 234);
document.body.appendChild(canvas);

প্রথমটি হ'ল একটি সাধারণ আকার পরিবর্তনকৃত চিত্র ট্যাগ এবং দ্বিতীয়টি ক্যানভাস। খেয়াল করুন কীভাবে ক্যানভাসটি এতটা মসৃণ নয়। আমি কীভাবে 'মসৃণতা' অর্জন করতে পারি?

উত্তর:


136

আরও ভাল ফলাফল অর্জন করতে আপনি ডাউন-স্টেপিং ব্যবহার করতে পারেন। বেশিরভাগ ব্রাউজারগুলি চিত্রগুলি পুনরায় আকার দেওয়ার সময় দ্বি-ঘনক না করে লিনিয়ার ইন্টারপোলেশন ব্যবহার করে।

( আপডেট সেখানে চশমাগুলিতে একটি মানের সম্পত্তি যুক্ত করা হয়েছে, imageSmoothingQualityযা বর্তমানে কেবল ক্রোমে উপলব্ধ)

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

দ্বি-লিনিয়ার ইন্টারপোলেশনটি করতে 2x2 পিক্সেল ব্যবহার করে যখন দ্বি-ঘনক 4x4 ব্যবহার করে যাতে পদক্ষেপে আপনি দ্বি-ঘনক ফলাফলের কাছাকাছি যেতে পারেন যখন ফলক চিত্রগুলিতে দেখা যায় দ্বি-লিনিয়ার অন্তরঙ্গকরণ ব্যবহার করে।

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = new Image();

img.onload = function () {

    // set size proportional to image
    canvas.height = canvas.width * (img.height / img.width);

    // step 1 - resize to 50%
    var oc = document.createElement('canvas'),
        octx = oc.getContext('2d');

    oc.width = img.width * 0.5;
    oc.height = img.height * 0.5;
    octx.drawImage(img, 0, 0, oc.width, oc.height);

    // step 2
    octx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5);

    // step 3, resize to final size
    ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5,
    0, 0, canvas.width, canvas.height);
}
img.src = "//i.imgur.com/SHo6Fub.jpg";
<img src="//i.imgur.com/SHo6Fub.jpg" width="300" height="234">
<canvas id="canvas" width=300></canvas>

আপনার আকার পরিবর্তনটি কতটা কঠোর তার উপর নির্ভর করে পার্থক্য কম হলে আপনি পদক্ষেপ 2 এড়িয়ে যেতে পারেন।

ডেমোতে আপনি দেখতে পারেন নতুন ফলাফলটি এখন চিত্রের উপাদানগুলির সাথে অনেক মিল।


4
@ ধীরে ধীরে, কখনও কখনও এই জিনিসগুলি ঘটে :) চিত্রগুলির জন্য আপনি সাধারণত একটি CSS বিটিডাব্লু সেট করে এটিকে ওভাররাইড করতে পারেন।

কেন, প্রথম ফলাফলটি দুর্দান্ত কাজ করেছে তবে আমি যখন চিত্রগুলি পরিবর্তন করি আপনি দেখতে পাচ্ছেন এটি খুব ঝাপসা হয়ে আসছে jsfiddle.net/kcHLG এই ক্ষেত্রে এবং অন্যদের মধ্যে কী করা যেতে পারে?
স্টিভ

@ ধাপে আপনি পদক্ষেপের সংখ্যা হ্রাস করতে পারবেন মাত্র 1 বা কোনও নয় (কিছু চিত্রের জন্য এটি ভাল কাজ করে)। আরও দেখুন এই উত্তরটি যা এই অনুরূপ কিন্তু এখানে যাতে আপনি ফলে ইমেজ জোচ্চোর পরে এটি লাগে হয়েছে তুলতে পারে আমি এটা করার জন্য একটি তীক্ষ্ণ করুন সংবর্তন এখনো যোগ করেনি।

4
@ ধীরে ধীরে এখানে মাত্র একটি অতিরিক্ত পদক্ষেপ ব্যবহার করে বিলের একটি সংশোধিত ফিডল রয়েছে: jsfiddle.net/AbdiasSoftware/kcHLG/1

4
@ নিউমিউজিক কোডটি ওপিএস কোডের ধারাবাহিকতা। আপনি যদি ফিডলটি খোলেন তবে দেখতে পাবেন ctx সংজ্ঞায়িত হচ্ছে। ভুল বোঝাবুঝি এড়াতে আমি এটি এখানে linedুকেছি।

27

যেহেতু ট্রুং লে এনগুইন নাহটের ফিডাল মোটেও সঠিক নয় (এটি কেবলমাত্র শেষ ধাপে মূল চিত্রটি ব্যবহার করে)
আমি পারফরম্যান্সের তুলনায় আমার নিজস্ব সাধারণ ফিডল লিখেছিলাম:

ছোট ছোট

মূলত এটি:

img.onload = function() {
   var canvas = document.createElement('canvas'),
       ctx = canvas.getContext("2d"),
       oc = document.createElement('canvas'),
       octx = oc.getContext('2d');

   canvas.width = width; // destination canvas size
   canvas.height = canvas.width * img.height / img.width;

   var cur = {
     width: Math.floor(img.width * 0.5),
     height: Math.floor(img.height * 0.5)
   }

   oc.width = cur.width;
   oc.height = cur.height;

   octx.drawImage(img, 0, 0, cur.width, cur.height);

   while (cur.width * 0.5 > width) {
     cur = {
       width: Math.floor(cur.width * 0.5),
       height: Math.floor(cur.height * 0.5)
     };
     octx.drawImage(oc, 0, 0, cur.width * 2, cur.height * 2, 0, 0, cur.width, cur.height);
   }

   ctx.drawImage(oc, 0, 0, cur.width, cur.height, 0, 0, canvas.width, canvas.height);
}

সর্বাধিক আন্ডাররেটেড উত্তর দেখা গেছে।
আমসাকান্না

17

আমি আগ্রহী এমন ব্যক্তির জন্য চিত্র / ক্যানভ্যাসগুলির উচ্চমানের পুনরায় আকার দেওয়ার জন্য হ'ল পুনরায় ব্যবহারযোগ্য কৌণিক পরিষেবাটি তৈরি করেছি: https://gist.github.com/transitive-bullshit/37bac5e741eaec60e983

পরিষেবাটিতে দুটি সমাধান অন্তর্ভুক্ত রয়েছে কারণ তাদের উভয়েরই নিজস্ব উপকার / কনস রয়েছে। ধীরে ধীরে ধীরে ধীরে ল্যানকোস কনভ্যুলশন পদ্ধতির উচ্চমানের হয়, তবে ধাপে ধাপে ধাপে ধাপে ছাপিয়ে যাওয়া পদ্ধতির পক্ষ থেকে যুক্তিযুক্ত ফলস্বরূপ ফলাফল পাওয়া যায় এবং তা দ্রুততর হয়।

ব্যবহারের উদাহরণ:

angular.module('demo').controller('ExampleCtrl', function (imageService) {
  // EXAMPLE USAGE
  // NOTE: it's bad practice to access the DOM inside a controller, 
  // but this is just to show the example usage.

  // resize by lanczos-sinc filter
  imageService.resize($('#myimg')[0], 256, 256)
    .then(function (resizedImage) {
      // do something with resized image
    })

  // resize by stepping down image size in increments of 2x
  imageService.resizeStep($('#myimg')[0], 256, 256)
    .then(function (resizedImage) {
      // do something with resized image
    })
})

সে সম্পর্কে দুঃখিত - আমি আমার গিথুব ব্যবহারকারীর নামটি পরিবর্তন করেছি। সবেমাত্র
fisch2

4
আমি কৌনিক শব্দটি দেখেছি, আমি সেই মজাদার অনুভূতি পেয়েছি
সুপারউবারডুপার

8

এই কয়েকটি কোড-স্নিপেটগুলি সংক্ষিপ্ত এবং কর্মক্ষম থাকা অবস্থায়, তারা অনুসরণ এবং বুঝতে তুচ্ছ নয়।

যেহেতু আমি স্ট্যাক-ওভারফ্লো থেকে "কপি-পেস্ট" এর অনুরাগী নই, আমি বিকাশকারীরা তাদের সফ্টওয়্যারটিতে যে কোডটি চাপছে তা বোঝার জন্য চাই, আশা করি আপনি নীচের দরকারী হবেন।

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

এই আকার পরিবর্তন করতে আপনি 3 টি ভিন্ন পদ্ধতি খুঁজে পেতে পারেন যা কোডটি কীভাবে কাজ করছে এবং কেন তা আপনাকে বুঝতে সহায়তা করবে।

https://jsfiddle.net/1b68eLdr/93089/

উভয় ডেমো, এবং টাইপস্ক্রিপ্ট পদ্ধতির সম্পূর্ণ কোড যা আপনি আপনার কোডে ব্যবহার করতে চাইতে পারেন, গিটহাব প্রকল্পে পাওয়া যাবে।

https://github.com/eyalc4/ts-image-resizer

এটিই চূড়ান্ত কোড:

export class ImageTools {
base64ResizedImage: string = null;

constructor() {
}

ResizeImage(base64image: string, width: number = 1080, height: number = 1080) {
    let img = new Image();
    img.src = base64image;

    img.onload = () => {

        // Check if the image require resize at all
        if(img.height <= height && img.width <= width) {
            this.base64ResizedImage = base64image;

            // TODO: Call method to do something with the resize image
        }
        else {
            // Make sure the width and height preserve the original aspect ratio and adjust if needed
            if(img.height > img.width) {
                width = Math.floor(height * (img.width / img.height));
            }
            else {
                height = Math.floor(width * (img.height / img.width));
            }

            let resizingCanvas: HTMLCanvasElement = document.createElement('canvas');
            let resizingCanvasContext = resizingCanvas.getContext("2d");

            // Start with original image size
            resizingCanvas.width = img.width;
            resizingCanvas.height = img.height;


            // Draw the original image on the (temp) resizing canvas
            resizingCanvasContext.drawImage(img, 0, 0, resizingCanvas.width, resizingCanvas.height);

            let curImageDimensions = {
                width: Math.floor(img.width),
                height: Math.floor(img.height)
            };

            let halfImageDimensions = {
                width: null,
                height: null
            };

            // Quickly reduce the dize by 50% each time in few iterations until the size is less then
            // 2x time the target size - the motivation for it, is to reduce the aliasing that would have been
            // created with direct reduction of very big image to small image
            while (curImageDimensions.width * 0.5 > width) {
                // Reduce the resizing canvas by half and refresh the image
                halfImageDimensions.width = Math.floor(curImageDimensions.width * 0.5);
                halfImageDimensions.height = Math.floor(curImageDimensions.height * 0.5);

                resizingCanvasContext.drawImage(resizingCanvas, 0, 0, curImageDimensions.width, curImageDimensions.height,
                    0, 0, halfImageDimensions.width, halfImageDimensions.height);

                curImageDimensions.width = halfImageDimensions.width;
                curImageDimensions.height = halfImageDimensions.height;
            }

            // Now do final resize for the resizingCanvas to meet the dimension requirments
            // directly to the output canvas, that will output the final image
            let outputCanvas: HTMLCanvasElement = document.createElement('canvas');
            let outputCanvasContext = outputCanvas.getContext("2d");

            outputCanvas.width = width;
            outputCanvas.height = height;

            outputCanvasContext.drawImage(resizingCanvas, 0, 0, curImageDimensions.width, curImageDimensions.height,
                0, 0, width, height);

            // output the canvas pixels as an image. params: format, quality
            this.base64ResizedImage = outputCanvas.toDataURL('image/jpeg', 0.85);

            // TODO: Call method to do something with the resize image
        }
    };
}}

4

আমি একটি লাইব্রেরি তৈরি করেছি যা সমস্ত রঙের ডেটা রাখার সময় আপনাকে যে কোনও শতাংশ হ্রাস করতে দেয়।

https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js

সেই ফাইলটি আপনি ব্রাউজারে অন্তর্ভুক্ত করতে পারেন। ফলাফলগুলি ফটোশপ বা চিত্রের ম্যাজিকের মতো দেখাবে, কাছাকাছি থাকাগুলি এবং অন্যকে বাদ দেওয়ার পরিবর্তে সমস্ত রঙের ডেটা সংরক্ষণ করে, পিক্সেল গড় করে। গড় অনুমান করার জন্য এটি কোনও সূত্র ব্যবহার করে না, এটি সঠিক গড় নেয়।


4
আমি সম্ভবত এখনই আকার পরিবর্তন করতে ওয়েবগেল ব্যবহার করব
ফানকোডাব্যাট

4

কে 3 এন উত্তরের উপর ভিত্তি করে, আমি সাধারণত যে কেউ চায় তার জন্য কোডটি পুনরায় লিখি

var oc = document.createElement('canvas'), octx = oc.getContext('2d');
    oc.width = img.width;
    oc.height = img.height;
    octx.drawImage(img, 0, 0);
    while (oc.width * 0.5 > width) {
       oc.width *= 0.5;
       oc.height *= 0.5;
       octx.drawImage(oc, 0, 0, oc.width, oc.height);
    }
    oc.width = width;
    oc.height = oc.width * img.height / img.width;
    octx.drawImage(img, 0, 0, oc.width, oc.height);

JSFIDDLE ডেমো আপডেট করুন

এখানে আমার অনলাইন ডেমো


4
এটি কাজ করবে না: প্রতিবার আপনি ক্যানভাসকে আকার দিন, এটি এর প্রসঙ্গটি সাফ করবে। আপনার 2 টি ক্যানভাস দরকার। এখানে এটি চূড়ান্ত মাত্রাগুলির সাথে সরাসরি কল অঙ্কন চিত্রের সমান।
কাইদো

2

আমি বুঝতে পারছি না কেন কেউ পরামর্শ দিচ্ছে না createImageBitmap

createImageBitmap(
    document.getElementById('image'), 
    { resizeWidth: 300, resizeHeight: 234, resizeQuality: 'high' }
)
.then(imageBitmap => 
    document.getElementById('canvas').getContext('2d').drawImage(imageBitmap, 0, 0)
);

সুন্দরভাবে কাজ করে (ধরে নিচ্ছেন আপনি চিত্র এবং ক্যানভাসের জন্য আইডির সেট করেন)।


কারণ এটি ব্যাপকভাবে সমর্থিত নয় caniuse.com/#search=createImageBitmap
ম্যাট

createImageBitmap সমস্ত ব্যবহারকারীর 73% জন্য সমর্থিত। আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে এটি যথেষ্ট ভাল হতে পারে। এটি কেবল সাফারি যা এর জন্য সমর্থন যুক্ত করতে অস্বীকার করে। আমি মনে করি এটি একটি সম্ভাব্য সমাধান হিসাবে উল্লেখযোগ্য।
cagdas_ucar

দুর্দান্ত সমাধান, তবে দুর্ভাগ্যক্রমে এটি ফায়ারফক্সে কাজ করে না
ভেকেরেল

1

আমি সামনের প্রান্তে চিত্রটি ক্রপ এবং আকার পরিবর্তন করতে ছোট js- ইউটিলিটি লিখেছি। এখানে গিটহাব প্রকল্পের লিঙ্ক । এটি প্রেরণে আপনি চূড়ান্ত চিত্র থেকে ব্লব পেতে পারেন।

import imageSqResizer from './image-square-resizer.js'

let resizer = new imageSqResizer(
    'image-input',
    300,
    (dataUrl) => 
        document.getElementById('image-output').src = dataUrl;
);
//Get blob
let formData = new FormData();
formData.append('files[0]', resizer.blob);

//get dataUrl
document.getElementById('image-output').src = resizer.dataUrl;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.