এইচটিএমএল 5 ক্যানভাস আকার পরিবর্তন (ডাউনস্কেল) চিত্র উচ্চ গুণমান?


149

আমি আমার ব্রাউজারে চিত্রগুলির আকার পরিবর্তন করতে এইচটিএমএল 5 ক্যানভাস উপাদান ব্যবহার করি। দেখা যাচ্ছে যে মানটি খুব কম। আমি এটি পেয়েছি: <স্ক্যানভ্যাস> স্কেল করার সময় ইন্টারপোলেশন অক্ষম করুন তবে এটি গুণমান বাড়াতে সহায়তা করে না।

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

ব্রাউজারে কোনও চিত্র স্কেল করার সময় অনুকূল মানের পেতে আমার কী করতে হবে?

দ্রষ্টব্য: আমি একটি বৃহত চিত্রকে একটি ছোট করে স্কেল করতে চাই, একটি ক্যানভাসে রঙ পরিবর্তন করতে এবং ক্যানভাস থেকে ফলাফলটি সার্ভারে প্রেরণ করতে চাই।

সিএসএস:

canvas, img {
    image-rendering: optimizeQuality;
    image-rendering: -moz-crisp-edges;
    image-rendering: -webkit-optimize-contrast;
    image-rendering: optimize-contrast;
    -ms-interpolation-mode: nearest-neighbor;
}

জাতীয়:

var $img = $('<img>');
var $originalCanvas = $('<canvas>');
$img.load(function() {


   var originalContext = $originalCanvas[0].getContext('2d');   
   originalContext.imageSmoothingEnabled = false;
   originalContext.webkitImageSmoothingEnabled = false;
   originalContext.mozImageSmoothingEnabled = false;
   originalContext.drawImage(this, 0, 0, 379, 500);
});

ছবিটি ফটোশপের সাথে পুনরায় আকার দিয়েছে:

এখানে চিত্র বর্ণনা লিখুন

চিত্রটি ক্যানভাসে পুনরায় আকার দিয়েছে:

এখানে চিত্র বর্ণনা লিখুন

সম্পাদনা:

প্রস্তাবিত হিসাবে আমি একাধিক পদক্ষেপে ডাউনস্কলিং করার চেষ্টা করেছি:

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

এটি আমি ব্যবহৃত ফাংশন:

function resizeCanvasImage(img, canvas, maxWidth, maxHeight) {
    var imgWidth = img.width, 
        imgHeight = img.height;

    var ratio = 1, ratio1 = 1, ratio2 = 1;
    ratio1 = maxWidth / imgWidth;
    ratio2 = maxHeight / imgHeight;

    // Use the smallest ratio that the image best fit into the maxWidth x maxHeight box.
    if (ratio1 < ratio2) {
        ratio = ratio1;
    }
    else {
        ratio = ratio2;
    }

    var canvasContext = canvas.getContext("2d");
    var canvasCopy = document.createElement("canvas");
    var copyContext = canvasCopy.getContext("2d");
    var canvasCopy2 = document.createElement("canvas");
    var copyContext2 = canvasCopy2.getContext("2d");
    canvasCopy.width = imgWidth;
    canvasCopy.height = imgHeight;  
    copyContext.drawImage(img, 0, 0);

    // init
    canvasCopy2.width = imgWidth;
    canvasCopy2.height = imgHeight;        
    copyContext2.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvasCopy2.width, canvasCopy2.height);


    var rounds = 2;
    var roundRatio = ratio * rounds;
    for (var i = 1; i <= rounds; i++) {
        console.log("Step: "+i);

        // tmp
        canvasCopy.width = imgWidth * roundRatio / i;
        canvasCopy.height = imgHeight * roundRatio / i;

        copyContext.drawImage(canvasCopy2, 0, 0, canvasCopy2.width, canvasCopy2.height, 0, 0, canvasCopy.width, canvasCopy.height);

        // copy back
        canvasCopy2.width = imgWidth * roundRatio / i;
        canvasCopy2.height = imgHeight * roundRatio / i;
        copyContext2.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvasCopy2.width, canvasCopy2.height);

    } // end for


    // copy back to canvas
    canvas.width = imgWidth * roundRatio / rounds;
    canvas.height = imgHeight * roundRatio / rounds;
    canvasContext.drawImage(canvasCopy2, 0, 0, canvasCopy2.width, canvasCopy2.height, 0, 0, canvas.width, canvas.height);


}

যদি আমি 2 ধাপ নীচে সাইজিং ব্যবহার করি তবে ফলাফলটি এখানে:

এখানে চিত্র বর্ণনা লিখুন

আমি যদি 3 ধাপ নীচে সাইজিং ব্যবহার করি তবে ফলাফলটি এখানে:

এখানে চিত্র বর্ণনা লিখুন

আমি যদি 4 টি ধাপ নীচে সাইজিং ব্যবহার করি তবে ফলাফল এখানে:

এখানে চিত্র বর্ণনা লিখুন

যদি আমি 20 ধাপ নীচে সাইজিং ব্যবহার করি তবে ফলাফলটি এখানে:

এখানে চিত্র বর্ণনা লিখুন

দ্রষ্টব্য: এটি প্রমাণিত হয়েছে যে 1 ধাপ থেকে 2 ধাপে চিত্রের গুণমানের একটি বৃহত্তর উন্নতি হয়েছে তবে আপনি প্রক্রিয়াটিতে আরও পদক্ষেপ যুক্ত করলে চিত্রটি ততই অস্পষ্ট হয়ে যায়।

সমস্যাটি সমাধানের জন্য কি এমন কোনও উপায় আছে যা আপনি আরও বেশি পদক্ষেপ যুক্ত করবেন তা চিত্র আরও अस्पष्ट হয়ে যায়?

2013-10-04 সম্পাদনা করুন: আমি গেমএলকেমিস্টের অ্যালগরিদম চেষ্টা করেছি। এখানে ফটোশপের তুলনায় ফলাফল।

ফটোশপের চিত্র:

ফটোশপের চিত্র

গেমএলকেমিস্টের অ্যালগোরিদম:

খেলাআলেকেমিস্টের অ্যালগরিদম


2
: আপনি বৃদ্ধিলাভ আপনার ইমেজ স্কেলিং চেষ্টা করতে পারে stackoverflow.com/questions/18761404/...
Marke

1
এইচটিএমএল 5 ক্যানভাস অঙ্কনের সম্ভাব্য সদৃশ : চিত্র কীভাবে প্রয়োগ করা যায় । কাজ করে না দেখুন। যদি চিত্রগুলি বড় হয় এবং ছোট আকারে হ্রাস পায় তবে আপনাকে পদক্ষেপে এটি করতে হবে (লিঙ্কে চিত্রগুলি দেখুন)

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

1
@ কেন-আবদিয়াসফটওয়্যার আপনাকে চেষ্টা করার চেষ্টা করেছি তবে সমস্যাটি হ'ল ধাপ অনুসারে স্কেলিংয়ের জন্য আমি যত বেশি রাউন্ড ব্যবহার করি তা আরও খারাপ হবে। কোন ধারণা কিভাবে যে ঠিক কিভাবে?
confile

3
এইচটিএমএল 5 ব্যবহার করে কোনও ব্যয়বহুল পেশাদার ফটো এডিটিং সফ্টওয়্যারটির কার্যকারিতাটির অনুলিপি করার সম্ভাবনাগুলি বেশ পাতলা? আপনি সম্ভবত (ইশ) কাছাকাছি যেতে পারেন, তবে এটি ফটোশপে ঠিক যেমন কাজ করে আমি কল্পনা করতাম অসম্ভব!
লিয়াম

উত্তর:


171

যেহেতু আপনার সমস্যাটি আপনার ইমেজটি ডাউনস্কেল করার জন্য, তাই ইন্টারপোলেশন সম্পর্কে কথা বলার কোনও মানে নেই - যা পিক্সেল তৈরি করার বিষয়ে। বিষয়টি এখানে নিম্নচাপের।

কোনও চিত্রকে নিখরনের জন্য, আমাদের মূল চিত্রের প্রতিটি বর্গ p * পি পিক্সেলকে গন্তব্য চিত্রের একক পিক্সেলে রূপান্তর করতে হবে।

পারফরম্যান্সের কারণে ব্রাউজারগুলি খুব সাধারণ ডাউনস্যাম্পলিং করে: ছোট চিত্রটি তৈরি করতে তারা উত্সটিতে কেবল একটি পিক্সেল বেছে নেবে এবং গন্তব্যের জন্য এর মানটি ব্যবহার করবে। যা কিছু বিবরণ 'ভুলে যায়' এবং শব্দ যোগ করে adds

তবুও এটির ব্যতিক্রম রয়েছে: যেহেতু 2 এক্স চিত্রটি ডাউনসাম্পলিং গণনা করা খুব সহজ (একটি গড়তে গড় 4 পিক্সেল) এবং রেটিনা / হাইডিপিআই পিক্সেলের জন্য ব্যবহৃত হয়, তাই এই কেসটি সঠিকভাবে পরিচালনা করা হয় - ব্রাউজারটি 4 পিক্সেল তৈরি করতে ব্যবহার করে না এক-.

তবে ... আপনি যদি 2X ডাউন স্যাম্পলিংয়ের জন্য বেশ কয়েকটি সময় ব্যবহার করেন তবে আপনি এই সমস্যার মুখোমুখি হবেন যে ক্রমবর্ধমান গোলাকৃতি ত্রুটিগুলি খুব বেশি শব্দ যোগ করবে।
সবচেয়ে খারাপ, আপনি সর্বদা দুজনের শক্তির দ্বারা পুনরায় আকার পরিবর্তন করবেন না এবং নিকটতম পাওয়ারকে + আকার পরিবর্তন করা খুব শেষ গোলমাল।

আপনি যা খুঁজছেন তা পিক্সেল-নিখুঁত ডাউনস্যাম্পলিং, এটি: চিত্রটির পুনরায় স্যাম্পলিং যা সমস্ত ইনপুট পিক্সেলকে অ্যাকাউন্টে-স্কেল- যাই হোক না কেন গ্রহণ করবে।
এটি করতে আমাদের প্রতিটি ইনপুট পিক্সেলের জন্য গণনা করতে হবে, ইনপুট পিক্সেলের স্কেলড প্রজেকশনটি নির্ভর করে এক, দুটি, বা চারটি গন্তব্য পিক্সেলের ক্ষেত্রে এর অবদানটি গন্তব্য পিক্সেলের ঠিক ভিতরে, একটি এক্স বর্ডার, একটি ওয়াই বর্ডার বা উভয়কে ওভারল্যাপ করে ।
(এখানে একটি পরিকল্পনা ভাল লাগবে তবে আমার কাছে এটি নেই don't)

এখানে একটি জম্বাটের 1/3 স্কেলে বনাম আমার পিক্সেল নিখুঁত স্কেল এর ক্যানভাস স্কেলের একটি উদাহরণ।

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

এখানে চিত্র বর্ণনা লিখুন

পিক্সেল নিখুঁত ডাউনস্কেলিং করার কোড এখানে:

বেহালার ফলাফল: http://jsfiddle.net/gamealchemist/r6aVp/ebded/result/
নিজেই ফিডাল : http://jsfiddle.net/gamealchemist/r6aVp/

// scales the image by (float) scale < 1
// returns a canvas containing the scaled image.
function downScaleImage(img, scale) {
    var imgCV = document.createElement('canvas');
    imgCV.width = img.width;
    imgCV.height = img.height;
    var imgCtx = imgCV.getContext('2d');
    imgCtx.drawImage(img, 0, 0);
    return downScaleCanvas(imgCV, scale);
}

// scales the canvas by (float) scale < 1
// returns a new canvas containing the scaled image.
function downScaleCanvas(cv, scale) {
    if (!(scale < 1) || !(scale > 0)) throw ('scale must be a positive number <1 ');
    var sqScale = scale * scale; // square scale = area of source pixel within target
    var sw = cv.width; // source image width
    var sh = cv.height; // source image height
    var tw = Math.floor(sw * scale); // target image width
    var th = Math.floor(sh * scale); // target image height
    var sx = 0, sy = 0, sIndex = 0; // source x,y, index within source array
    var tx = 0, ty = 0, yIndex = 0, tIndex = 0; // target x,y, x,y index within target array
    var tX = 0, tY = 0; // rounded tx, ty
    var w = 0, nw = 0, wx = 0, nwx = 0, wy = 0, nwy = 0; // weight / next weight x / y
    // weight is weight of current source point within target.
    // next weight is weight of current source point within next target's point.
    var crossX = false; // does scaled px cross its current px right border ?
    var crossY = false; // does scaled px cross its current px bottom border ?
    var sBuffer = cv.getContext('2d').
    getImageData(0, 0, sw, sh).data; // source buffer 8 bit rgba
    var tBuffer = new Float32Array(3 * tw * th); // target buffer Float32 rgb
    var sR = 0, sG = 0,  sB = 0; // source's current point r,g,b
    /* untested !
    var sA = 0;  //source alpha  */    

    for (sy = 0; sy < sh; sy++) {
        ty = sy * scale; // y src position within target
        tY = 0 | ty;     // rounded : target pixel's y
        yIndex = 3 * tY * tw;  // line index within target array
        crossY = (tY != (0 | ty + scale)); 
        if (crossY) { // if pixel is crossing botton target pixel
            wy = (tY + 1 - ty); // weight of point within target pixel
            nwy = (ty + scale - tY - 1); // ... within y+1 target pixel
        }
        for (sx = 0; sx < sw; sx++, sIndex += 4) {
            tx = sx * scale; // x src position within target
            tX = 0 |  tx;    // rounded : target pixel's x
            tIndex = yIndex + tX * 3; // target pixel index within target array
            crossX = (tX != (0 | tx + scale));
            if (crossX) { // if pixel is crossing target pixel's right
                wx = (tX + 1 - tx); // weight of point within target pixel
                nwx = (tx + scale - tX - 1); // ... within x+1 target pixel
            }
            sR = sBuffer[sIndex    ];   // retrieving r,g,b for curr src px.
            sG = sBuffer[sIndex + 1];
            sB = sBuffer[sIndex + 2];

            /* !! untested : handling alpha !!
               sA = sBuffer[sIndex + 3];
               if (!sA) continue;
               if (sA != 0xFF) {
                   sR = (sR * sA) >> 8;  // or use /256 instead ??
                   sG = (sG * sA) >> 8;
                   sB = (sB * sA) >> 8;
               }
            */
            if (!crossX && !crossY) { // pixel does not cross
                // just add components weighted by squared scale.
                tBuffer[tIndex    ] += sR * sqScale;
                tBuffer[tIndex + 1] += sG * sqScale;
                tBuffer[tIndex + 2] += sB * sqScale;
            } else if (crossX && !crossY) { // cross on X only
                w = wx * scale;
                // add weighted component for current px
                tBuffer[tIndex    ] += sR * w;
                tBuffer[tIndex + 1] += sG * w;
                tBuffer[tIndex + 2] += sB * w;
                // add weighted component for next (tX+1) px                
                nw = nwx * scale
                tBuffer[tIndex + 3] += sR * nw;
                tBuffer[tIndex + 4] += sG * nw;
                tBuffer[tIndex + 5] += sB * nw;
            } else if (crossY && !crossX) { // cross on Y only
                w = wy * scale;
                // add weighted component for current px
                tBuffer[tIndex    ] += sR * w;
                tBuffer[tIndex + 1] += sG * w;
                tBuffer[tIndex + 2] += sB * w;
                // add weighted component for next (tY+1) px                
                nw = nwy * scale
                tBuffer[tIndex + 3 * tw    ] += sR * nw;
                tBuffer[tIndex + 3 * tw + 1] += sG * nw;
                tBuffer[tIndex + 3 * tw + 2] += sB * nw;
            } else { // crosses both x and y : four target points involved
                // add weighted component for current px
                w = wx * wy;
                tBuffer[tIndex    ] += sR * w;
                tBuffer[tIndex + 1] += sG * w;
                tBuffer[tIndex + 2] += sB * w;
                // for tX + 1; tY px
                nw = nwx * wy;
                tBuffer[tIndex + 3] += sR * nw;
                tBuffer[tIndex + 4] += sG * nw;
                tBuffer[tIndex + 5] += sB * nw;
                // for tX ; tY + 1 px
                nw = wx * nwy;
                tBuffer[tIndex + 3 * tw    ] += sR * nw;
                tBuffer[tIndex + 3 * tw + 1] += sG * nw;
                tBuffer[tIndex + 3 * tw + 2] += sB * nw;
                // for tX + 1 ; tY +1 px
                nw = nwx * nwy;
                tBuffer[tIndex + 3 * tw + 3] += sR * nw;
                tBuffer[tIndex + 3 * tw + 4] += sG * nw;
                tBuffer[tIndex + 3 * tw + 5] += sB * nw;
            }
        } // end for sx 
    } // end for sy

    // create result canvas
    var resCV = document.createElement('canvas');
    resCV.width = tw;
    resCV.height = th;
    var resCtx = resCV.getContext('2d');
    var imgRes = resCtx.getImageData(0, 0, tw, th);
    var tByteBuffer = imgRes.data;
    // convert float32 array into a UInt8Clamped Array
    var pxIndex = 0; //  
    for (sIndex = 0, tIndex = 0; pxIndex < tw * th; sIndex += 3, tIndex += 4, pxIndex++) {
        tByteBuffer[tIndex] = Math.ceil(tBuffer[sIndex]);
        tByteBuffer[tIndex + 1] = Math.ceil(tBuffer[sIndex + 1]);
        tByteBuffer[tIndex + 2] = Math.ceil(tBuffer[sIndex + 2]);
        tByteBuffer[tIndex + 3] = 255;
    }
    // writing result to canvas.
    resCtx.putImageData(imgRes, 0, 0);
    return resCV;
}

এটি বেশ স্মৃতি লোভী, যেহেতু একটি ফ্লোট বাফারকে গন্তব্য চিত্রের মধ্যবর্তী মানগুলি সংরক্ষণ করতে হয় (-> যদি আমরা ফলাফলের ক্যানভাস গণনা করি, তবে আমরা এই অ্যালগরিদমে উত্স চিত্রটির স্মৃতি থেকে 6 গুণ ব্যবহার করি)।
এটিও বেশ ব্যয়বহুল, যেহেতু প্রতিটি উত্স পিক্সেল গন্তব্যের আকার যাই হোক না কেন ব্যবহৃত হয়, এবং আমাদের getImageData / putImageDate এর জন্য অর্থ প্রদান করতে হবে, বেশ ধীর গতিতেও।
তবে এক্ষেত্রে প্রতিটি উত্সের মান প্রক্রিয়া করার চেয়ে দ্রুত হওয়ার কোনও উপায় নেই এবং পরিস্থিতিটি খুব খারাপ নয়: আমার গর্ভের 740 * 556 চিত্রের জন্য প্রসেসিং 30 থেকে 40 এমএসের মধ্যে লাগে।


ক্যানভাসে রাখার আগে আপনি যদি চিত্রটি স্কেল করেন তবে এটি আরও দ্রুত হতে পারে?
বিভক্ত

আমি এটি পাই না ... মনে হচ্ছে এটি আমিই করি। বাফারের পাশাপাশি আমি তৈরি ক্যানভাসের (রেজিসিভি) আকারযুক্ত চিত্রটির আকার। আমি মনে করি এটি দ্রুত পাওয়ার একমাত্র উপায় হ'ল ব্রেশেনসাম-এর মতো পূর্ণসংখ্যা গণনা ব্যবহার করা। তবে 40 মিমি কেবল একটি ভিডিও গেমের জন্য ধীরে ধীরে (25 fps), কোনও ড্র অ্যাপ্লিকেশনটির জন্য নয়।
গেমএলচেমিস্ট

গুণমান বজায় রেখে আপনি কি আপনার অ্যালগোরিদমকে দ্রুত তৈরি করার কোনও সুযোগ দেখতে পাচ্ছেন?
5:19 '

1
আমি 0 | ব্যবহার করে বাফারকে (অ্যালগোরিদমের সর্বশেষ অংশ) গোল করার চেষ্টা করেছি ম্যাট এসিলের পরিবর্তে। এটি কিছুটা দ্রুত। তবে যাইহোক / পুটআইমেজডেটা এবং আবার কিছুটা ওভারহেড রয়েছে, আমরা প্রতিটি পিক্সেল প্রক্রিয়া করতে এড়াতে পারি না।
গেমএলচেমিস্ট

4
ঠিক আছে, তাই আমি কোডটি দেখেছি: আপনি সমাধানের খুব কাছে এসেছিলেন। দুটি ভুল: আপনার সূচকগুলি টিএক্স + 1 এর জন্য এক দ্বারা বন্ধ ছিল (সেগুলি +4, +5, +6, +7 এর পরিবর্তে + 3, + 4, + 5, + 6 ছিল) এবং আরগাবায় লাইন পরিবর্তন করা একটি মুল 4 দ্বারা, 3 নয়। আমি 4 টি এলোমেলো মান পরীক্ষা করে দেখেছি (0.1, 0.15, 0.33, 0.8) এটি ঠিক আছে বলে মনে হয়েছে seemed আপনার আপডেট হওয়া ফ্রিডলটি
গেমএলচেমিস্ট

51

ভাল মানের সহ দ্রুত ক্যানভাসের পুনরায় নমুনা: http://jsfiddle.net/9g9Nv/442/

আপডেট: সংস্করণ 2.0 (দ্রুত, ওয়েব কর্মী + স্থানান্তরযোগ্য বস্তু) - https://github.com/viliusle/Hermite-resize

/**
 * Hermite resize - fast image resize/resample using Hermite filter. 1 cpu version!
 * 
 * @param {HtmlElement} canvas
 * @param {int} width
 * @param {int} height
 * @param {boolean} resize_canvas if true, canvas will be resized. Optional.
 */
function resample_single(canvas, width, height, resize_canvas) {
    var width_source = canvas.width;
    var height_source = canvas.height;
    width = Math.round(width);
    height = Math.round(height);

    var ratio_w = width_source / width;
    var ratio_h = height_source / height;
    var ratio_w_half = Math.ceil(ratio_w / 2);
    var ratio_h_half = Math.ceil(ratio_h / 2);

    var ctx = canvas.getContext("2d");
    var img = ctx.getImageData(0, 0, width_source, height_source);
    var img2 = ctx.createImageData(width, height);
    var data = img.data;
    var data2 = img2.data;

    for (var j = 0; j < height; j++) {
        for (var i = 0; i < width; i++) {
            var x2 = (i + j * width) * 4;
            var weight = 0;
            var weights = 0;
            var weights_alpha = 0;
            var gx_r = 0;
            var gx_g = 0;
            var gx_b = 0;
            var gx_a = 0;
            var center_y = (j + 0.5) * ratio_h;
            var yy_start = Math.floor(j * ratio_h);
            var yy_stop = Math.ceil((j + 1) * ratio_h);
            for (var yy = yy_start; yy < yy_stop; yy++) {
                var dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
                var center_x = (i + 0.5) * ratio_w;
                var w0 = dy * dy; //pre-calc part of w
                var xx_start = Math.floor(i * ratio_w);
                var xx_stop = Math.ceil((i + 1) * ratio_w);
                for (var xx = xx_start; xx < xx_stop; xx++) {
                    var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
                    var w = Math.sqrt(w0 + dx * dx);
                    if (w >= 1) {
                        //pixel too far
                        continue;
                    }
                    //hermite filter
                    weight = 2 * w * w * w - 3 * w * w + 1;
                    var pos_x = 4 * (xx + yy * width_source);
                    //alpha
                    gx_a += weight * data[pos_x + 3];
                    weights_alpha += weight;
                    //colors
                    if (data[pos_x + 3] < 255)
                        weight = weight * data[pos_x + 3] / 250;
                    gx_r += weight * data[pos_x];
                    gx_g += weight * data[pos_x + 1];
                    gx_b += weight * data[pos_x + 2];
                    weights += weight;
                }
            }
            data2[x2] = gx_r / weights;
            data2[x2 + 1] = gx_g / weights;
            data2[x2 + 2] = gx_b / weights;
            data2[x2 + 3] = gx_a / weights_alpha;
        }
    }
    //clear and resize canvas
    if (resize_canvas === true) {
        canvas.width = width;
        canvas.height = height;
    } else {
        ctx.clearRect(0, 0, width_source, height_source);
    }

    //draw
    ctx.putImageData(img2, 0, 0);
}

আমার সেরা মানের দরকার
1313

18
স্থির, আমি "ভাল" কে "সেরা" হিসাবে পরিবর্তন করেছি, এখন কি ঠিক আছে? : ডি। অন্যদিকে আপনি যদি সর্বোত্তম সম্ভাব্য পুনরায় নমুনা চান - ইমেজম্যাগিক ব্যবহার করুন।
ভিলিয়াসল

@ কনফিলে ইমগুর ডট কম ব্যবহার করা নিরাপদে ছিল, তবে প্রশাসকরা কিছু ভুল করেছিলেন? আপনি ভাল মানের দেখতে পাচ্ছেন না, আপনার ব্রাউজারটি সিওআরএসকে মারাত্মক ত্রুটি দেয়। (দূরবর্তী সাইটগুলি থেকে চিত্র ব্যবহার করতে পারে না)
ভিলিউসএল

ঠিক আছে আপনি স্বচ্ছ অঞ্চল সহ অন্য কোনও পিএনজি চিত্র ব্যবহার করতে পারেন। এই সম্পর্কে কোন ধারণা?
বিভক্ত

4
@ কনফিলে আপনি ঠিক বলেছেন, কিছু ক্ষেত্রে স্বচ্ছ চিত্রগুলির তীক্ষ্ণ অঞ্চলে সমস্যা ছিল। আমি আমার পরীক্ষা দিয়ে এই মামলাগুলি মিস করেছি। ফিক্সড রিসাইজ এছাড়াও ফিডলে
ViliusL

28

পরামর্শ 1 - প্রক্রিয়া পাইপ-লাইন প্রসারিত করুন

আপনার উল্লেখ করা লিঙ্কগুলিতে আমি বর্ণনা করার সাথে সাথে আপনি স্টেপ-ডাউন ব্যবহার করতে পারেন তবে আপনি এগুলি কোনও ভুল উপায়ে ব্যবহার করার জন্য উপস্থিত হন।

1: 2 এর উপরে অনুপাতগুলিতে চিত্রগুলি স্কেল করার জন্য পদক্ষেপ নেওয়ার দরকার নেই (সাধারণত, তবে সীমাবদ্ধ নয়)। এটি যেখানে আপনাকে কঠোর ডাউন-স্কেলিং করতে হবে আপনাকে এটিকে চিত্রের সামগ্রীর উপর নির্ভর করে (এবং খুব কমই আরও বেশি) ধাপে বিভক্ত করতে হবে (বিশেষত যেখানে পাতলা রেখার মতো উচ্চ-ফ্রিকোয়েন্সি ঘটে)।

প্রতিবার আপনি কোনও চিত্রের নমুনা নেওয়ার সময় আপনি বিশদ এবং তথ্য শিথিল করবেন। আপনি আশা করতে পারবেন না যে ফলস্বরূপ চিত্রটি আসলটির মতো পরিষ্কার হবে।

এরপরে আপনি যদি অনেকগুলি পদক্ষেপে চিত্রগুলি কমিয়ে দিচ্ছেন তবে আপনি মোট তথ্য প্রচুর আলগা করে ফেলবেন এবং ইতিমধ্যে আপনি লক্ষ্য করেছেন ফলাফল খারাপ হবে।

মাত্র একটি অতিরিক্ত পদক্ষেপ, বা শীর্ষে দুটি দিয়ে চেষ্টা করুন।

Convolutions

ফটোশপের ক্ষেত্রে খেয়াল করুন যে চিত্রটি পুনরায় নমুনা দেওয়ার পরে যেমন ধারালো করা হয়েছে তখন এটি কনভোলশনটি প্রয়োগ করে। এটি কেবল দ্বি-ঘনক বিভাজন নয় যা ফটোশপকে সম্পূর্ণরূপে অনুকরণ করার জন্য আমাদের ফটোশপটি যে পদক্ষেপগুলি করছে তা যুক্ত করতে হবে (ডিফল্ট সেটআপ সহ)।

এই উদাহরণের জন্য আমি আমার আসল উত্তরটি ব্যবহার করব যা আপনি আপনার পোস্টে উল্লেখ করেছেন, তবে পোস্টের প্রক্রিয়া হিসাবে মান উন্নত করতে আমি এটিতে একটি তীক্ষ্ণ সমাবর্তন যুক্ত করেছি (নীচে ডেমো দেখুন)।

তীক্ষ্ণ ফিল্টার যুক্ত করার কোড এখানে রয়েছে (এটি একটি জেনেরিক কনভোলিউশন ফিল্টারের উপর ভিত্তি করে - আমি এর ভিতরে তীক্ষ্ণ হওয়ার জন্য ওজন ম্যাট্রিক্স পাশাপাশি প্রভাবটির উচ্চারণ সামঞ্জস্য করার জন্য একটি মিশ্রণ ফ্যাক্টর রেখেছি):

ব্যবহার:

sharpen(context, width, height, mixFactor);

mixFactorএর মধ্যে একটি মান হয় [0.0, 1.0] এবং আপনি তীক্ষ্ণ করুন প্রভাব দূরে রেখে অনুমতি - নিয়ম অফ থাম্ব: কম আকার প্রভাব কম প্রয়োজন হয়।

ফাংশন ( এই স্নিপেটের উপর ভিত্তি করে ):

function sharpen(ctx, w, h, mix) {

    var weights =  [0, -1, 0,  -1, 5, -1,  0, -1, 0],
        katet = Math.round(Math.sqrt(weights.length)),
        half = (katet * 0.5) |0,
        dstData = ctx.createImageData(w, h),
        dstBuff = dstData.data,
        srcBuff = ctx.getImageData(0, 0, w, h).data,
        y = h;
        
    while(y--) {

        x = w;

        while(x--) {

            var sy = y,
                sx = x,
                dstOff = (y * w + x) * 4,
                r = 0, g = 0, b = 0, a = 0;

            for (var cy = 0; cy < katet; cy++) {
                for (var cx = 0; cx < katet; cx++) {

                    var scy = sy + cy - half;
                    var scx = sx + cx - half;

                    if (scy >= 0 && scy < h && scx >= 0 && scx < w) {

                        var srcOff = (scy * w + scx) * 4;
                        var wt = weights[cy * katet + cx];

                        r += srcBuff[srcOff] * wt;
                        g += srcBuff[srcOff + 1] * wt;
                        b += srcBuff[srcOff + 2] * wt;
                        a += srcBuff[srcOff + 3] * wt;
                    }
                }
            }

            dstBuff[dstOff] = r * mix + srcBuff[dstOff] * (1 - mix);
            dstBuff[dstOff + 1] = g * mix + srcBuff[dstOff + 1] * (1 - mix);
            dstBuff[dstOff + 2] = b * mix + srcBuff[dstOff + 2] * (1 - mix)
            dstBuff[dstOff + 3] = srcBuff[dstOff + 3];
        }
    }

    ctx.putImageData(dstData, 0, 0);
}

এই সংমিশ্রণটি ব্যবহারের ফলাফলটি হবে:

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

ফলাফলকে ডাউনস্যাম্পল করুন এবং সমঝোতার তীক্ষ্ণ করুন

ডিফল্ট "অস্পষ্ট" থেকে খুব তীক্ষ্ণ হয়ে আপনি ফলাফলটি পেতে মিশ্রণটিতে কতটা তীক্ষ্ণতর যুক্ত করতে চান তার উপর নির্ভর করে:

ধারালো বিভিন্ন

পরামর্শ 2 - নিম্ন স্তরের অ্যালগরিদম বাস্তবায়ন

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

দেখুন ক্ষেপক নির্ভর ভাবমূর্তি Downsampling আইইইই থেকে (2011)।
পুরো কাগজের লিঙ্কটি এখানে (পিডিএফ) রয়েছে

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

সারমর্মটি হ'ল (কাগজ থেকে কিছু অংশ):

বিমূর্ত

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

কাগজ থেকে স্ন্যাপশট

(সমস্ত বিবরণ, সূত্র ইত্যাদি জন্য সরবরাহিত লিঙ্ক দেখুন)


এটিও একটি দুর্দান্ত সমাধান। ধন্যবাদ!
বিভ্রান্ত

এটি একটি দুর্দান্ত সমাধান। আমি স্বচ্ছ অঞ্চলগুলির সাথে পিএনজি ফাইলগুলিতে চেষ্টা করেছি। এখানে ফলাফল: jsfiddle.net/confile/5CD4N এটিকে কাজ করার জন্য আপনার কী কী ধারণা আছে?
বিভ্রান্ত

1
এই জেনিয়াস! তবে অনুগ্রহ করে আপনি ঠিক কি করছেন তা ব্যাখ্যা করতে পারবেন? হ্যাঁ .. আমি পুরোপুরি ইন এবং আউটগুলি জানতে চাই ... সম্ভবত সংস্থানগুলি শিখতে হবে?
carinlyunchin

1
@ ক্যারিন যা একটি দুর্বল মন্তব্য ক্ষেত্রের জন্য কিছুটা হতে পারে :) তবে, পিক্সেলের একটি গ্রুপকে এই গ্রুপটি উপস্থাপন করার জন্য গড়ে একটি নতুন গড়ের ফলাফলকে কমিয়ে দিচ্ছে। এটি কার্যকরভাবে একটি নিম্ন-পাস ফিল্টার যা সামগ্রিকভাবে কিছু অস্পষ্টতা পরিচয় করিয়ে দেয়। তীক্ষ্ণতা হ্রাস ক্ষতিপূরণ জন্য কেবল একটি তীক্ষ্ণ সমঝোতা প্রয়োগ করুন। তীক্ষ্ণভাবে চিহ্নিত হওয়ার সাথে সাথে আমরা এটির পরিবর্তে চিত্রের সাথে মিশ্রিত করতে পারি তাই আমরা ধারালোকরণের স্তরটি নিয়ন্ত্রণ করতে পারি। আশা করি কিছু অন্তর্দৃষ্টি দেয়।

21

আপনি যদি কেবল ক্যানভাস ব্যবহার করতে চান তবে সেরা ফলাফলটি একাধিক পদক্ষেপের সাথে হবে। তবে এটি এখনও ভাল নয়। উন্নত মানের জন্য আপনার খাঁটি জেএস বাস্তবায়ন প্রয়োজন। আমরা সবেমাত্র পিকা প্রকাশ করেছি - ভেরিয়েবল মানের / গতির সাথে উচ্চ গতির ডাউনস্কেলার। সংক্ষেপে, এটি সর্বোচ্চ মানের (3 টি লোবযুক্ত ল্যাঙ্কজোস ফিল্টার) সহ 1280 * 1024px এবং s 0.1s এর মধ্যে 5000 * 3000px চিত্রকে আকার দেয় in পিকার ডেমো রয়েছে , যেখানে আপনি আপনার চিত্রগুলি, মানের স্তরগুলি এবং এমনকি মোবাইল ডিভাইসে চেষ্টা করতে পারেন play

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


16

কেন চিত্রগুলি পুনরায় আকার দিতে ক্যানভাস ব্যবহার করবেন? আধুনিক ব্রাউজারগুলি সকলেই বাইকুবিক ইন্টারপোলেশন ব্যবহার করে - ফটোশপ দ্বারা ব্যবহৃত একই প্রক্রিয়া (যদি আপনি এটি সঠিকভাবে করেন) - এবং তারা এটি ক্যানভাস প্রক্রিয়ার চেয়ে দ্রুত করে। আপনি যে চিত্রটি চান তা কেবল নির্দিষ্ট করুন (আনুপাতিক আকারে আকার পরিবর্তন করতে কেবলমাত্র একটি মাত্রা, উচ্চতা বা প্রস্থ ব্যবহার করুন)।

এটি IE এর পরবর্তী সংস্করণ সহ বেশিরভাগ ব্রাউজার দ্বারা সমর্থিত। পূর্ববর্তী সংস্করণগুলিতে ব্রাউজার-নির্দিষ্ট সিএসএসের প্রয়োজন হতে পারে

একটি চিত্র পুনরায় আকার দিতে একটি সাধারণ ফাংশন (jQuery ব্যবহার করে) এরকম হবে:

function resizeImage(img, percentage) {
    var coeff = percentage/100,
        width = $(img).width(),
        height = $(img).height();

    return {"width": width*coeff, "height": height*coeff}           
}

তারপরে এক বা উভয় মাত্রায় চিত্রটির আকার পরিবর্তন করতে কেবল ফিরে আসা মানটি ব্যবহার করুন।

স্পষ্টতই আপনি তৈরি করতে পারেন বিভিন্ন সংশোধন আছে, কিন্তু এটি কাজ হয়ে যায়।

নিম্নলিখিত পৃষ্ঠার কনসোলে নিম্নলিখিত কোডটি আটকান এবং মহাকর্ষগুলির কী ঘটে তা দেখুন:

function resizeImage(img, percentage) {
    var coeff = percentage/100,
        width = $(img).width(),
        height = $(img).height();

    return {"width": width*coeff, "height": height*coeff}           
}

$('.user-gravatar32 img').each(function(){
  var newDimensions = resizeImage( this, 150);
  this.style.width = newDimensions.width + "px";
  this.style.height = newDimensions.height + "px";
});

2
এছাড়াও মনে রাখবেন যে আপনি যদি কেবলমাত্র একটি মাত্রা নির্দিষ্ট করেন তবে (আধুনিক) ব্রাউজারটি স্বয়ংক্রিয়ভাবে চিত্রটির প্রাকৃতিক দিক অনুপাত বজায় রাখবে।
আন্দ্রে ডিওন

38
হতে পারে তাকে পুনরায় আকারিত চিত্রটি কোনও সার্ভারে প্রেরণ করা দরকার।
সের্গিউ প্যারাসিচিভ

2
@ সার্জিউ: প্রয়োজনীয় নয়, তবে মনে রাখবেন যে আপনি যদি খুব ছোট চিত্র থেকে খুব বড় আকারের হয়ে যান তবে আপনি কোনও সার্ভার থেকেও দুর্দান্ত ফলাফল পাচ্ছেন না।
রোবস্তো

2
@ রোবস্তো আমার পরে ছবিটি ক্যানভাসে রেখে সার্ভারে পরে পাঠাতে হবে। আমি একটি বৃহত চিত্র একটি ছোট একটিতে স্কেল করতে চান, একটি ক্যানভাসে রঙ পরিবর্তন করুন এবং ফলাফলটি সার্ভারে প্রেরণ করতে চাই। আপনি আমি কি করা উচিত বলে আপনি মনে করেন কি?
বিভ্রান্ত করুন

9
@ রোবস্তো এটিই সমস্যা। ক্লায়েন্টের উপর একটি ছোট চিত্র দেখানো সহজ। img.width nad img.height তাই তুচ্ছ। আমি এটি একবারে স্কেল করতে চাই এবং সার্ভারে আবারও নয়।
বিভ্রান্ত

8

এমন চিত্রগুলির সঠিক উত্তর নয় যাঁদের সত্যই চিত্রটির আকার পরিবর্তন করতে হবে, কেবল ফাইলের আকার সঙ্কুচিত করতে

"সরাসরি ক্যামেরা থেকে" ছবিগুলির সাথে আমার একটি সমস্যা ছিল যা আমার গ্রাহকরা প্রায়শই "সঙ্কুচিত" জেপিইজে আপলোড করেন।

এতটা সুপরিচিত নয় যে, ক্যানভাস জেপিইগির মান পরিবর্তন করতে (বেশিরভাগ ব্রাউজারে 2017) সমর্থন করে

data=canvas.toDataURL('image/jpeg', .85) # [1..0] default 0.92

এই কৌশলটি দিয়ে আমি> 10 এমবি থেকে 1 বা 2 এমবি দিয়ে 4 কে এক্স 3 কে ছবিগুলি হ্রাস করতে পারতাম, নিশ্চিত এটি আপনার প্রয়োজনের উপর নির্ভর করে।

এখানে দেখুন


4

উচ্চমানের চিত্র / ক্যানভাস পুনরায় আকার দেওয়ার জন্য এখানে পুনরায় ব্যবহারযোগ্য কৌণিক পরিষেবা দেওয়া আছে: https://gist.github.com/fisch0920/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
    })
})

4

এটি উন্নত হার্মাইটের আকার পরিবর্তনকারী ফিল্টার যা 1 জন কর্মী ব্যবহার করে যাতে উইন্ডো হিমায়িত হয় না।

https://github.com/calvintwr/blitz-hermite-resize

const blitz = Blitz.create()

/* Promise */
blitz({
    source: DOM Image/DOM Canvas/jQuery/DataURL/File,
    width: 400,
    height: 600
}).then(output => {
    // handle output
})catch(error => {
    // handle error
})

/* Await */
let resized = await blizt({...})

/* Old school callback */
const blitz = Blitz.create('callback')
blitz({...}, function(output) {
    // run your callback.
})

3

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

DrawImage () ফাংশন একটি রৈখিক-ক্ষেপক ব্যবহার করছে, সবচেয়ে কাছের-প্রতিবেশী পদ্ধতি রীস্যাম্পেলিং। আপনি যখন মূল আকারের অর্ধেকেরও বেশি আকার পরিবর্তন করছেন না তখন এটি ভাল কাজ করে

আপনি যদি একবারে সর্বোচ্চ অর্ধেক আকার পরিবর্তন করতে লুপ করেন তবে ফলাফলগুলি বেশ ভাল এবং পিক্সেল ডেটা অ্যাক্সেস করার চেয়ে অনেক দ্রুত হবে।

পছন্দসই আকারে পৌঁছানো পর্যন্ত এই ফাংশনটি একবারে অর্ধেক করে রাখুন:

  function resize_image( src, dst, type, quality ) {
     var tmp = new Image(),
         canvas, context, cW, cH;

     type = type || 'image/jpeg';
     quality = quality || 0.92;

     cW = src.naturalWidth;
     cH = src.naturalHeight;

     tmp.src = src.src;
     tmp.onload = function() {

        canvas = document.createElement( 'canvas' );

        cW /= 2;
        cH /= 2;

        if ( cW < src.width ) cW = src.width;
        if ( cH < src.height ) cH = src.height;

        canvas.width = cW;
        canvas.height = cH;
        context = canvas.getContext( '2d' );
        context.drawImage( tmp, 0, 0, cW, cH );

        dst.src = canvas.toDataURL( type, quality );

        if ( cW <= src.width || cH <= src.height )
           return;

        tmp.src = dst.src;
     }

  }
  // The images sent as parameters can be in the DOM or be image objects
  resize_image( $( '#original' )[0], $( '#smaller' )[0] );

আপনি কি দয়া করে একটি জিসফিল এবং কিছু ফলাফল চিত্র পোস্ট করতে পারেন?

নীচের লিঙ্কটিতে আপনি এই কৌশলটি ব্যবহার করে ফলাফলগুলি পেতে পারেন
জেসেস ক্যারিরা

1

সম্ভবত মানুষ আপনি এটি চেষ্টা করতে পারেন, যা আমি সবসময় আমার প্রকল্পে ব্যবহার করি this এইভাবে আপনি কেবলমাত্র উচ্চমানের চিত্রই পাবেন না, আপনার ক্যানভাসে অন্য কোনও উপাদান পেতে পারেন।

/* 
 * @parame canvas => canvas object
 * @parame rate => the pixel quality
 */
function setCanvasSize(canvas, rate) {
    const scaleRate = rate;
    canvas.width = window.innerWidth * scaleRate;
    canvas.height = window.innerHeight * scaleRate;
    canvas.style.width = window.innerWidth + 'px';
    canvas.style.height = window.innerHeight + 'px';
    canvas.getContext('2d').scale(scaleRate, scaleRate);
}

0

.85 এর পরিবর্তে , যদি আমরা 1.0 যোগ করি । আপনি সঠিক উত্তর পাবেন।

data=canvas.toDataURL('image/jpeg', 1.0);

আপনি পরিষ্কার এবং উজ্জ্বল চিত্র পেতে পারেন। দয়া করে চেক করুন


0

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

function resizeCanvas(canvas, newWidth, newHeight) {
  let ctx = canvas.getContext('2d');
  let buffer = document.createElement('canvas');
  buffer.width = ctx.canvas.width;
  buffer.height = ctx.canvas.height;
  let ctxBuf = buffer.getContext('2d');
  

  let scaleX = newWidth / ctx.canvas.width;
  let scaleY = newHeight / ctx.canvas.height;

  let scaler = Math.min(scaleX, scaleY);
  //see if target scale is less than half...
  if (scaler < 0.5) {
    //while loop in case target scale is less than quarter...
    while (scaler < 0.5) {
      ctxBuf.canvas.width = ctxBuf.canvas.width * 0.5;
      ctxBuf.canvas.height = ctxBuf.canvas.height * 0.5;
      ctxBuf.scale(0.5, 0.5);
      ctxBuf.drawImage(canvas, 0, 0);
      ctxBuf.setTransform(1, 0, 0, 1, 0, 0);
      ctx.canvas.width = ctxBuf.canvas.width;
      ctx.canvas.height = ctxBuf.canvas.height;
      ctx.drawImage(buffer, 0, 0);

      scaleX = newWidth / ctxBuf.canvas.width;
      scaleY = newHeight / ctxBuf.canvas.height;
      scaler = Math.min(scaleX, scaleY);
    }
    //only if the scaler is now larger than half, double target scale trick...
    if (scaler > 0.5) {
      scaleX *= 2.0;
      scaleY *= 2.0;
      ctxBuf.canvas.width = ctxBuf.canvas.width * scaleX;
      ctxBuf.canvas.height = ctxBuf.canvas.height * scaleY;
      ctxBuf.scale(scaleX, scaleY);
      ctxBuf.drawImage(canvas, 0, 0);
      ctxBuf.setTransform(1, 0, 0, 1, 0, 0);
      scaleX = 0.5;
      scaleY = 0.5;
    }
  } else
    ctxBuf.drawImage(canvas, 0, 0);

  //wrapping things up...
  ctx.canvas.width = newWidth;
  ctx.canvas.height = newHeight;
  ctx.scale(scaleX, scaleY);
  ctx.drawImage(buffer, 0, 0);
  ctx.setTransform(1, 0, 0, 1, 0, 0);
}

-1

context.scale(xScale, yScale)

<canvas id="c"></canvas>
<hr/>
<img id="i" />

<script>
var i = document.getElementById('i');

i.onload = function(){
    var width = this.naturalWidth,
        height = this.naturalHeight,
        canvas = document.getElementById('c'),
        ctx = canvas.getContext('2d');

    canvas.width = Math.floor(width / 2);
    canvas.height = Math.floor(height / 2);

    ctx.scale(0.5, 0.5);
    ctx.drawImage(this, 0, 0);
    ctx.rect(0,0,500,500);
    ctx.stroke();

    // restore original 1x1 scale
    ctx.scale(2, 2);
    ctx.rect(0,0,500,500);
    ctx.stroke();
};

i.src = 'https://static.md/b70a511140758c63f07b618da5137b5d.png';
</script>

-1

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

এই পুনরায় আকার দেওয়ার জন্য আপনি 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 size 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
        }
    };
}}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.