js canvas 101 التعامل مع العنصر Canvas باستخدام جافاسكربت (التعديل على الصور)


Lujain

سنتطرّق في هذا الدّرس إلى طريقة إنشاء رسم بياني باستخدام Canvas قبل أن نتطرّق إلى بعض عمليات التّعديل على الصّور وبعض التّحولات، ثم سنختم بإنشاء معرض جميل للصّور.

canvas-javascript.png

أنصحم بالاطّلاع على المقالات السّابقة حول Canvas هنا على أكاديمية حسوب قبل مواصلة القراءة.

رسم الصور

تُستخدم الدالة ()drawImage لتصيير الكائن image على العنصر canvas، تأخذ الدالة ()drawImage عدة أشكال overloaded وذلك بتغيير نوع وعدد المعاملات كما سنرى في الأمثلة المقبلة.

الشكل الأول:

drawImage(image, x, y)

تقوم برسم CanvasImageSource محدّدة بالمعامل image في الإحداثيات (x,y).

رسم خط بياني بسيط باستخدام الدالة ()drawImage

سأعرض مثالًا يستخدم صورة خارجية كخلفية لرسم خط بياني بسيط. يتيح لك استخدام الخلفيات أو backdrops من أن تجعل السكربت الخاص بك أصغر بكثير وتجنب الحاجة لكتابة الشيفرات البرمجية لتوليد الخلفية.

سأستخدم في هذا المثال صورة واحدة لذا يمكنني استخدام معالج حدث التحميل load event handler لتنفيذ جمل الرسم. 

تقوم الدالة ()drawImage بوضع صورة الخلفية عند الإحداثيات (0, 0) والمحدّدة بالزاوية اليسارية العليا للعنصر canvas.

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var img = new Image();
  img.onload = function(){
    ctx.drawImage(img,,);
    ctx.beginPath();
    ctx.moveTo(30,96);
    ctx.lineTo(70,66);
    ctx.lineTo(103,76);
    ctx.lineTo(170,15);
    ctx.stroke();
  };
  img.src = 'https://mdn.mozillademos.org/files/5395/backdrop.png';
}

سيظهر الرسم البياني مع صورة الخلفية على الشكل التالي:

­í©¡ 1.png

التحجيم Scaling

تتيح لك الدالة ()drawImage تحديد حجم الصور وفق ما ترغب وذلك بإضافة معاملين إضافيين هما الطول والعرض:

drawImage(image, x, y, width, height) 

من خلال الخاصيتين width و height تستطيع إعطاء الحجم المناسب للصورة عند رسمها على الـ canvas.

تبليط صورة Tiling an image

في المثال التالي سأستخدم الصورة أدناه وأكررها عدّة مرات على مساحة الـ canvas بعد تحجيمها لتبدو كلوحة جدارية. 

سنحتاج لإنشاء حلقتي تكرار واستدعاء الدالة:

drawImage(image, x, y, width, height)

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

سأقوم بتحجيم الصورة إلى ثلث حجمها الأصلي وهو 50x30 بكسل.

­í©¡2.png

ملاحظة: قد تبدو الصور ضبابية عند التحجيم وذلك بحسب نوع التحجيم (تكبير أو تصغير) كذلك إن كانت بعض الصور تحوي نصوصًا قد يؤدي تصغير حجمها إلى جعل النصوص غير مقروءة.

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var img = new Image();
  img.onload = function(){
    for (var i=;i<4;i++){
      for (var j=;j<3;j++){
        ctx.drawImage(img,j*50,i*38,50,38);
      }
    }
  };
  img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
}

ستظهر الصورة على الشكل التالي:

­í©¡3.png

استعرض المثال على jsfiddle.

التشريح Slicing

الاستخدام الثالث والأخير للدالة ()drawImage هو قص الصور حيث تأخذ الدالة ثمان معاملات:

drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

تحدد الدالة أعلاه مساحة الصورة التي يحددها المستطيل الذي زاويته اليسارية العليا محدّدة بـ (sx, sy) وطوله وعرضه محدّد بـ (sWidth ، sHeight) وتقوم برسمه على الـ canvas في الموضع (dx, dy) وتحدد قيمة التحجيم بالمعاملين (dWidth و dHeight).

لتستطيع فهم عمل المعاملات بوضوح انظر للصورة التالية: 

­í©¡ 4.png

كما تلاحظ أنه تم تحديد مساحة الصورة المراد قصها اعتمادًا على قيمة المعاملات في الدالة:

drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

تعتبر أداة التشريح او القص مفيدة عندما تريد عمل تراكيب حيث يمكن أن يكون لديك عدة عناصر في ملف صورة واحد وتستخدم الدالة ()drawImage لتجميعها برسم كامل على سبيل المثال يمكنك أن تقوم بإنشاء رسم بياني كصورة png وتكون كل النصوص اللازمة لوضعها على الرسم البياني موجودة في ملف واعتمادًا على البيانات يمكنك تغيير حجم الرسم البياني بكل سهولة.

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

تأطير الصورة Framing an image

سأقوم بعرض مثال أستخدم فيه نفس الصورة السابقة لقصها باستخدام الدالة ()drawImage ووضعها بداخل إطار Frame:

<html>
 <body onload="draw();">
   <canvas id="canvas" width="150" height="150"></canvas>
   <div style="display:none;">
     <img id="source" src="https://mdn.mozillademos.org/files/5397/rhino.jpg" width="300" height="227">
     <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150">
   </div>
 </body>
</html>
function draw() {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');

  // Draw slice
  ctx.drawImage(document.getElementById('source'),
                33, 71, 104, 124, 21, 20, 87, 104);

  // Draw frame
  ctx.drawImage(document.getElementById('frame'),,);
}

ستظهر الصورة على الشكل التالي:

­í©¡5.png

استعرض المثال على jsfiddle.

حان الوقت الآن لإنشاء معرض صور واستخدام الأدوات التي تعلمناها في التعامل مع الصور في canvas سيكون المعرض عبارة عن جدول يحوي مجموعة صور. 

عند تحميل الصفحة يقوم العنصر canvas بإدراج الصور ورسم إطار حول كل صورة.  في حالتنا هذه سيكون لكل صورة طول وعرض ثابتين وكذلك الإطار. 

سنقوم باسترداد صورة الإطار من الرابط: 

https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png

Canvas_picture_frame.png

ثم إنشاء حلقة تكرار للإنشاء رقعة canvas لكل صورة ومن ثم رسم الصورة ويتم ذلك باستخدام الدالة:

parentNode.insertBefore

تقوم هذه الدالة بإدراج الصورة قبل إدراج عنصر canvas في عناصر DOM:

 // Insert before the image
      document.images.parentNode.insertBefore(canvas,document.images);

بعد إنشاء عنصر canvas وإدراج الصورة نقوم باستخدام سياق التصيير واستدعاء الدالة ()drawImage لرسم الصورة على الرقعة:

ctx.drawImage(document.images,15,20);

إضافة بعض التنسيقات CSS:

body { 
  background:  -100px repeat-x url(https://mdn.mozillademos.org/files/5415/bg_gallery.png) #4F191A; 
  margin: 10px; 
}

img { 
  display: none; 
}

table { 
  margin:  auto; 
}

td { 
  padding: 15px; 
}

السكربت أدناه يقوم برسم الصور مع الإطار:

function draw() {

  // Loop through all images
  for (var i=;i<document.images.length;i++){

    // Don't add a canvas for the frame image
    if (document.images[i].getAttribute('id')!='frame'){

      // Create canvas element
      canvas = document.createElement('canvas');
      canvas.setAttribute('width',132);
      canvas.setAttribute('height',150);

      // Insert before the image
      document.images[i].parentNode.insertBefore(canvas,document.images[i]);

      ctx = canvas.getContext('2d');

      // Draw image to canvas
      ctx.drawImage(document.images[i],15,20);

      // Add frame
      ctx.drawImage(document.getElementById('frame'),,);
    }
  }
}

ستظهر الصورة على الشكل التالي:

­í©¡6.png

استعراض المثال على jsfiddle.

التحكم بسلوك التحجيم Scaling Behavior

كما ذكرت سابقًا أن عملية تحجيم الصورة يمكن أن تؤدي إلى تشويهها أو جعلها تبدو غير واضحة. يمكنك استخدام  الخاصية imageSmoothingEnabled للتحكم باستخدام خوارزمية تنعيم أو تمهيد الصورة Smoothing وذلك بتحديد القيمة التي تأخذها إما true أو false

ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;

التحولات Transformations

يوفّر سياق التصيير Rendering Context في canvas مجموعة من الدوال لتطبيق التحولات على الأشكال في canvas كالتحريك، النقل، الدوران والتحجيم حيث يمكنك تطبيق هذه الخصائص بطرق مختلفة على الأشكال البسيطة في الرقعة canvas والحصول على أشكال معقدة أو متحركة بكل سهولة. 
قبل البدء بالتعرّف على دوال التحولات التي يوفرها سياق التصيير دعونا نلقي نظرة على حالتين لا غنى عنهما سنستخدمهما بمجرد البدء بتوليد أشكال معقدة باستخدام خصائص التحويل في canvas.

حالتي الحفظ والاستعادة Saving and restoring state

  • ()save: تقوم هذه الدالة بحفظ الحالة التي تكون عليها الرقعة في الوقت الحالي.
  • ()restore: تعيد هذه الدالة أحدث حالة كانت عليها الرقعة canvas.

يتم تخزين حالات الرقعة في الـ stack أو المجمع حيث أنه في كل مرة يتم فيها استدعاء الدالة ()save يتم وضع حالة الرسم الحالية في المجمع.

مم تتكون حالة الرسم؟

تتكون حالة الرسم من العناصر التالية: 

  • التحولات التي يمكن تطبيقها في سياق التصيير كالنقل translate، الدوران rotate والتحجيم scale. 
  • القيم الحالية للخصائص التالية:
    • strokeStyle,  fillStyle
    • globalAlpha
    • lineWidth,  lineCap,  lineJoin
    • miterLimit
    • lineDashOffset
    • shadowOffsetX, shadowOffsetY
    • shadowBlur, shadowColor
    • globalCompositeOperation
    • font, textAlign, textBaseline
    • direction
    • imageSmoothingEnabled
  • مسار clipping path الحالي.

ملاحظة: يمكنك استدعاء الدالة ()save عدة مرات كما تريد.

في كل مرة يتم فيها استدعاء الدالة ()restore يتم أخذ آخر حالة حفظ موجودة في المجمع واسترجاع جميع الإعدادات الأخيرة المحفوظة.

سنكمل في الدرس المقبل شرح دوال التحولات وعرض مثال واضح عن استخدام حالتي الحفظ والاستعادة في سياق التصيير بالإضافة إلى شرح التحولات وطرق التعامل معها مع عرض مثال لكل خاصية تحول لترى كيف يمكنك عمل مجموعة من الأشكال المعقدة وتحريكها على عنصر الرقعة canvas.

المصادر



1 شخص أعجب بهذا


تفاعل الأعضاء


شكرا لك على هذا الشرح  مآأبحث عنه هو تحويل div الى صورة  ونجحت في ذلك عبر الكود التالي :

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script type="text/javascript" src="../dist/html2canvas.js"></script>
<script>

  $('#save_image_locally').ready(function(){
    html2canvas($('#imagesave'), 
    {
      onrendered: function (canvas) {
        var a = document.createElement('a');
        // toDataURL defaults to png, so we need to request a jpeg, then convert for file download.
        a.href = canvas.toDataURL("image/jpeg").replace("image/jpeg", "image/octet-stream");
        a.download = 'somefilename.jpg';
        a.click();
      }
    });
  });

</script>

المشكل هو انه يقوم بحفظ الصورة على الحاسوب وما اريده هو حفظها على الإستضافة وشكرا

 

شارك هذا التعليق


رابط هذا التعليق
شارك على الشبكات الإجتماعية


يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن