it-swarm.dev

رسم قماش Html5: كيفية تطبيق الحواف

يرجى إلقاء نظرة على المثال التالي:

http://jsfiddle.net/MLGr4/47/

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

img = new Image();
img.onload = function(){
    canvas.width = 400;
    canvas.height = 150;
    ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, 400, 150);
}
img.src = "http://openwalls.com/image/1734/colored_lines_on_blue_background_1920x1200.jpg";

كما ترى ، فإن الصورة ليست ضد التعرجات على الرغم من أن يقال إن DrawImage يطبق مكافحة التعرجات تلقائيًا. لقد جربت العديد من الطرق المختلفة ولكن لا يبدو أنها تعمل. هل يمكن أن تخبرني كيف يمكنني الحصول على صورة ضد التعرجات؟ شكر.

73
Dundar

سبب

بعض الصور هي صعبة للغاية لأسفل العينة و {interpolate} _ مثل هذه الصورة ذات المنحنيات عندما تريد الانتقال من حجم كبير إلى صغير.

يبدو أن المتصفحات تستخدم عادةً الاستيفاء الثنائي الخطي (أخذ العينات 2x2) مع عنصر الطباعة بدلاً من أخذ العينات ثنائية التكعيب (4 × 4) لأسباب الأداء (المحتمل).

إذا كانت الخطوة ضخمة جدًا ، فلا يوجد ما يكفي من البكسلات التي يمكنك أخذ عينات منها والتي تنعكس في النتيجة.

من منظور إشارة/DSP ، يمكنك أن ترى هذا كقيمة عتبة للمرشح المنخفض تم تعيينها على درجة عالية جدًا ، مما قد يؤدي إلى التعرجات في حالة وجود العديد من الترددات (التفاصيل) في الإشارة.

حل

التحديث 2018:

إليك خدعة أنيقة يمكنك استخدامها للمتصفحات التي تدعم خاصية filter في السياق ثنائي الأبعاد. هذا يطمس الصورة التي هي في جوهرها تشبه إعادة التشكيل ، ثم يتم تصغيرها. يسمح هذا بخطوات كبيرة ولكنه يحتاج فقط إلى خطوتين وسحبين.

التمويه المسبق باستخدام عدد من الخطوات (الحجم الأصلي/حجم الوجهة/2) كنصف قطر (قد تحتاج إلى ضبط هذا على أساس heuristist المستعرض والخطوات الفردية/الزوجية - هنا مبسطة فقط):

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

if (typeof ctx.filter === "undefined") {
 alert("Sorry, the browser doesn't support Context2D filters.")
}

const img = new Image;
img.onload = function() {

  // step 1
  const oc = document.createElement('canvas');
  const octx = oc.getContext('2d');
  oc.width = this.width;
  oc.height = this.height;

  // steo 2: pre-filter image using steps as radius
  const steps = (oc.width / canvas.width)>>1;
  octx.filter = `blur(${steps}px)`;
  octx.drawImage(this, 0, 0);

  // step 3, draw scaled
  ctx.drawImage(oc, 0, 0, oc.width, oc.height, 0, 0, canvas.width, canvas.height);

}
img.src = "//i.stack.imgur.com/cYfuM.jpg";
body{ background-color: ivory; }
canvas{border:1px solid red;}
<br/><p>Original was 1600x1200, reduced to 400x300 canvas</p><br/>
<canvas id="canvas" width=400 height=250></canvas>

دعم عامل التصفية كـ ogf Oct/2018:

CanvasRenderingContext2D.filter                                                   
api.CanvasRenderingContext2D.filter                                               
On Standard Track, Experimental                                                   
https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/filter        
                                                                                  
DESKTOP >        |Chrome    |Edge      |Firefox   |IE        |Opera     |Safari   
:----------------|:--------:|:--------:|:--------:|:--------:|:--------:|:--------
filter !         |    52    |    ?     |    49    |    -     |    -     |    -    
                                                                                  
MOBILE >         |Chrome/A  |Edge/mob  |Firefox/A |Opera/A   |Safari/iOS|Webview/A
:----------------|:--------:|:--------:|:--------:|:--------:|:--------:|:--------
filter !         |    52    |    ?     |    49    |    -     |    -     |    52   
                                                                                  
! = Experimental                                                                  
                                                                                  
Data from MDN - "npm i -g mdncomp" (c) epistemex

تحديث 2017: هناك الآن خاصية جديدة محددة في المواصفات لإعداد جودة إعادة التشكيل:

context.imageSmoothingQuality = "low|medium|high"

حاليًا معتمد فقط في Chrome. تُترك الطرق الفعلية المستخدمة في كل مستوى للبائع لاتخاذ قرار ، ولكن من المعقول افتراض أن لانزوس لـ "عالية" أو ما يعادلها من حيث الجودة. هذا يعني أنه قد يتم تخطي التنحي تمامًا ، أو يمكن استخدام خطوات أكبر مع عدد أقل من عمليات إعادة الرسم ، حسب حجم الصورة و

دعم imageSmoothingQuality:

CanvasRenderingContext2D.imageSmoothingQuality
api.CanvasRenderingContext2D.imageSmoothingQuality
On Standard Track, Experimental
https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality

DESKTOP >              |Chrome    |Edge      |Firefox   |IE        |Opera     |Safari
:----------------------|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:
imageSmoothingQuality !|    54    |    ?     |    -     |    ?     |    41    |    Y

MOBILE >               |Chrome/A  |Edge/mob  |Firefox/A |Opera/A   |Safari/iOS|Webview/A
:----------------------|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:
imageSmoothingQuality !|    54    |    ?     |    -     |    41    |    Y     |    54

! = Experimental

Data from MDN - "npm i -g mdncomp" (c) epistemex

المتصفح. حتى ذلك الوقت..:
نهاية الإرسال

الحل هو استخدام التنحي _ للحصول على نتيجة مناسبة. التدرج يعني تقليل حجم الخطوات للسماح لنطاق الاستيفاء المحدود بتغطية وحدات البكسل الكافية لأخذ العينات.

سيسمح ذلك بنتائج جيدة أيضًا باستخدام الاستكمال الداخلي الثنائي الخط (يتصرف في الواقع كثيرًا مثل الثعبان المكعب عند القيام بذلك) ويكون مقدار الحمل ضئيلًا نظرًا لوجود عدد أقل من البكسلات للعينة في كل خطوة.

الخطوة المثالية هي الانتقال إلى {نصف الدقة في كل خطوة حتى تحدد الحجم المستهدف (بفضل Joe Mabel على ذكر هذا!).

تم التعديل كمان

استخدام القياس المباشر كما في السؤال الأصلي:

NORMAL DOWN-SCALED IMAGE

استخدام التنحي كما هو موضح أدناه:

DOWN-STEPPED IMAGE

في هذه الحالة ، ستحتاج إلى التنحي في 3 خطوات:

في الخطوة 1 ، نقوم بتقليل الصورة إلى النصف باستخدام قماش خارج الشاشة:

// step 1 - create off-screen canvas
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);

تقوم الخطوة 2 بإعادة استخدام اللوحة القماشية الموجودة خارج الشاشة وترسم الصورة التي تم تصغيرها إلى النصف مرة أخرى:

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

ونوجه مرة أخرى إلى قماش الرئيسية ، خفضت مرة أخرى إلى النصف ولكن إلى الحجم النهائي:

// step 3
ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5,
                  0, 0, canvas.width,   canvas.height);

تلميح:

يمكنك حساب إجمالي عدد الخطوات اللازمة ، باستخدام هذه الصيغة (تتضمن الخطوة الأخيرة لتعيين حجم الهدف):

steps = Math.ceil(Math.log(sourceWidth / targetWidth) / Math.log(2))
162
user1693593

أنا أوصي بيكا لمثل هذه المهام. جودته متفوقة على تقليص حجمها متعددة وسريعة للغاية في نفس الوقت. هنا هو التجريبي .

12
avalanche1

بالإضافة إلى إجابة Ken ، إليك حلًا آخر لإجراء الاختزال في النصفين (بحيث تبدو النتيجة جيدة باستخدام خوارزمية المستعرض):

  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] );

ائتمانات ل هذا المنصب

4
Jesús Carrera
    var getBase64Image = function(img, quality) {
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;
    var ctx = canvas.getContext("2d");

    //----- Origin draw ---
    ctx.drawImage(img, 0, 0, img.width, img.height);

    //------ reduced draw ---
    var canvas2 = document.createElement("canvas");
    canvas2.width = img.width * quality;
    canvas2.height = img.height * quality;
    var ctx2 = canvas2.getContext("2d");
    ctx2.drawImage(canvas, 0, 0, img.width * quality, img.height * quality);

    // -- back from reduced draw ---
    ctx.drawImage(canvas2, 0, 0, img.width, img.height);

    var dataURL = canvas.toDataURL("image/png");
    return dataURL;
    // return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
4
kamil

لقد أنشأت خدمة Angularقابلة لإعادة الاستخدام للتعامل مع تغيير حجم الصور عالية الجودة لأي شخص مهتم: https://Gist.github.com/fisch0920/37bac5e741eaec60e983

تشتمل الخدمة على مقاربة كين لتصغير الحجم خطوة بخطوة بالإضافة إلى نسخة معدلة من نهج الالتواء lanczos الموجود هنا .

قمت بتضمين كلا الحلين لأن لكل منهما إيجابيات/سلبيات خاصة بهم. يعتبر أسلوب الالتواء lanczos أعلى جودة على حساب كونه أبطأ ، في حين أن نهج تصغير الحجم التدريجي ينتج نتائج غير منحازة بشكل معقول وأسرع بشكل ملحوظ.

مثال للاستخدام:

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
    })
})
3
fisch2

في حالة استمرار البحث عن شخص آخر ، فهناك طريقة أخرى يمكنك من خلالها استخدام صورة الخلفية بدلاً من drawImage (). لن تفقد أي جودة الصورة بهذه الطريقة.

JS:

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
   var url = "http://openwalls.com/image/17342/colored_lines_on_blue_background_1920x1200.jpg";

    img=new Image();
    img.onload=function(){

        canvas.style.backgroundImage = "url(\'" + url + "\')"

    }
    img.src="http://openwalls.com/image/17342/colored_lines_on_blue_background_1920x1200.jpg";

العمل التجريبي

2
Munkhjargal Narmandakh