Michał Środek

Po prostu devBlog

Witaj na srodek.info

Jest to blog poświęcony nowoczelnym technologiom ułatwiającym tworzenie aplikacji internetowych. Znajdziesz tutaj porady na temat CSS3, JavaScript, designu, web-usability, standardów W3C.

Cześć! Nazywam się Michał Środek. Z zawodu programista php, z zamiłowania gitarzysta oraz fanatyk GNU/Linuksa(openSUSE® w laptopie). W branży aplikacji internetowych od 9 lat. Prywatnie bez dzieci i kota.

Pracuję wciąż nad własnym elastycznym i wydajnym frameworkiem MVC, kilkoma portalami internetowymi oraz mniejszymi bibliotekami php. Czekam na wasze opinie, zgłoszenia błędów oraz pomysły na dalszy rozwój.

Ta część strony jest w trakcie budowy a moje prace tymczasowo niedostępne.

W przypadku pytań, ofert pracy oraz ciekawych pomysłów proszę się ze mną kontaktować. Możesz mnie znaleźć i wysłać PW na php.pl(SHiP), jamendo.com(michalsrodek), goldenLine.pl, facebook.com lub nk.pl

17 Kwiecień 2010

Canvas — zarządzanie pikselami

Filed under: JavaScript — Tagi: , , — Michał Środek @ 17:26

Pra­cuję aktu­al­nie nad oskryp­to­wa­niem, które zosta­nie użyte na stro­nie mojego przy­ja­ciela(http://szescian.pl/). Sęk w tym, że jego bujna wyobraź­nia wyge­ne­ro­wała coś, z czym mogę mieć nie­małe pro­blemy. Mówiąc krótko: dużo mate­ma­tyki oraz sporo gene­ro­wa­nia wie­lo­ką­tów. Posta­no­wi­łem, że użyję do tego celu tech­no­lo­gii canvas. Mając chwilę czasu chciał­bym się z wami podzie­lić kil­koma faj­nymi tech­ni­kami. O ryso­wa­niu wie­lo­ką­tów napi­szę innym razem. Dzi­siaj chciał­bym poka­zać wam coś co dla wielu praw­do­po­dob­nie wyda­wa­łoby się nie­moż­liwe ;) . Spró­bu­jemy prze­kon­wer­to­wać, pik­sel po pik­selu, obrazy za pomocą Java­Script.

Jako obraz poglą­dowy wybra­łem jedno z moich zdjęć:

Spró­bujmy naj­pierw stwo­rzyć obiekt canvas, nadać mu iden­ty­fi­ka­tor oraz po pro­stu wczy­tać do niego obrazek.

<canvas id="myCanvas" width="600" height="150">Brak obsługi Canvas</canvas>
// wybranie elementu <canvas>
var myCanvas = document.getElementById('myCanvas');
 
// sprawdzenie czy można pobrać kontekst
if (myCanvas.getContext) {
  // pobranie "kontekstu 2d"
  var ctx = myCanvas.getContext('2d');
  if (ctx) {
 
  // stworzenie nowego obrazka
  var img = new Image();
  // okreslenie adresu
  img.src = '/examples/canvas1/mini.jpg';
 
  // stworzenie zdarzenie wywołanego po wczytaniu obrazka
  img.addEventListener('load', function () {
 
    // rysuj obrazek rozpoczynajac od wspolrzednych 0,0 pola canvas
    ctx.drawImage(this, 0,0, 150, 150);

Kolej­nym kro­kiem jest wczy­ta­nie infor­ma­cji o pliku. Chcę stwo­rzyć 3 mody­fi­ka­cje mojego zdję­cia więc robię to trzykrotnie.

   // Get the pixels.
    var imgdata = ctx.getImageData(0, 0, 150, 150);
    var imgdata2 = ctx.getImageData(0, 0, 150, 150);
    var imgdata3 = ctx.getImageData(0, 0, 150, 150);

Spró­bujmy wyko­nać pierw­sze prze­kształ­ce­nie pole­ga­jące na kon­wer­sji zdję­cia do palety szarości.

   var pix = imgd.data; 
   for (var i = 0, n = pix.length; i < n; i += 4) {
      pix[i] = 0.2989*pix[i] + 0.5870*pix[i+1] + 0.1140*pix[i+2]; // czerwony
      pix[i+1] = 0.2989*pix[i] + 0.5870*pix[i+1] + 0.1140*pix[i+2]; // zielony
      pix[i+2] = 0.2989*pix[i] + 0.5870*pix[i+1] + 0.1140*pix[i+2]; // niebieski
    }
    ctx.putImageData(imgdata, 150, 0);

Krót­kie wytłu­ma­cze­nie:
Naj­pierw została pobrana tablica pik­seli. Spo­sób zapisu danych na ich temat jest troszkę nie­ty­powy. Każdy pik­sel jest mie­sza­niną trzech(czerwony, zie­lony, nie­bie­ski) kolo­rów oraz współ­czyn­nika prze­zro­czy­sto­ści. Dla­tego, nasza tablica posiada 90 tys. elementów(150x150x4). Ska­cząc w pętli co cztery ele­menty, za każ­dym razem otrzy­mu­jemy nowy pik­sel do prze­ba­da­nia. Każdy z nich jest prze­kształ­cany na jeden z odcieni sza­ro­ści. Na końcu obraz jest umiesz­czany w miej­scu o współ­rzęd­nych 150,0(pierwszych 150 pik­seli zaj­muje nie­prze­kształ­cone zdję­cie, które umie­ści­li­śmy już wcześniej.

Spró­bujmy odwró­cić kolory:

 
   var pix = imgdata2.data;
   for (var i = 0, n = pix.length; i < n; i += 4) {
      pix[i] = 255 - pix[i]; // czerwony
      pix[i+1] = 255 - pix[i+1]; // zeilony
      pix[i+2] = 255 - pix[i+2]; // niebieski
    }
    ctx.putImageData(imgdata2, 300, 0);

Ostat­nim prze­kształ­ce­niem będzie zabawa z kolo­rami ;) . Wydzie­li­łem rów­nież pas pik­seli, który będzie prze­kształ­cany w inny spo­sób. W ten spo­sób można two­rzyć efekty punktowe(np. pod­świe­tlić na biało oczy).

   var pix = imgdata3.data;
 
   for (var i = 0, n = pix.length; i < n; i += 4) {
	  if(i<15000 || i> 75000){
              pix[i  ] = 25+pix[i]/2+pix[i+1]/5; // czerwony
              pix[i+1] = 25+pix[i+1]/2+pix[i+2]/5 ; // zielony
              pix[i+2] = 25+pix[i+2]/2+pix[i]/2; // niebieski
	  }
	  else
	  {
              pix[i  ] = pix[i]; // czerwony
              pix[i+1] = pix[i+1]/2+50 ; //zielony
              pix[i+2] = pix[i+2]/2+40; // niebieski
	  }
    }
    ctx.putImageData(imgdata3, 450, 0);

Oczy­wi­ście musimy jesz­cze uzu­peł­nić para­me­try funk­cji oraz zamknąć wszyst­kie nawiasy.

  }, false);
 
  }
}

Pamię­tajmy jed­nak, że ele­ment canvas jest nie­do­stepny w star­szych prze­glą­dar­kach Inter­net Explo­rer. Jeśli się nie mylę dopiero 9 wer­sja zacznie go obsłu­gi­wać poprawnie.

Cały przy­kład dostępny w postaci pliku js: canvas.js

Efekt dzia­ła­nia:
Brak obsługi Canvas

Dodaj arty­kuł do:

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Gwar
  • Reddit
  • Technorati
  • Twitter
  • Wykop

Komentarzy: 6 »

  1. Dla IE we wcze­śniej­szych wer­sjach napi­sano już skrypty, które emu­lują obiekt Canvas. Takie coś wal­nąć w komen­tarz warun­kowy i będzie dobrze ;)

    Komentarz by kilas — 18 kwietnia 2010, 0:00

  2. Teraz to mnie zagią­łeś :D Nie sądzi­łem, że coś takiego jest do wyko­na­nia… Z pew­no­ścią wyko­rzy­stam to w przy­szłych pro­jek­tach. Przyda się do minia­tu­rek w gale­rii. Dzięki i pozdra­wiam :)

    Komentarz by Oskar Wójcicki — 24 kwietnia 2010, 11:24

  3. Nie wiem czy wyko­rzy­sta­nie tego w gale­rii to świetny pomysł — wydaj­ność prze­glą­da­rek wciąż pozo­sta­wia wiele do życze­nia. Ja praw­do­po­dob­nie użyję tego w swoim blo­grollu, ale jesz­cze nie teraz ;].

    Komentarz by Michał Środek — 24 kwietnia 2010, 12:37

  4. Hm… możesz powie­dzieć dla­czego masz tak dziwny wzór do two­rze­nia gray scale?

    [code]
    pix[i] = 0.2989*pix[i] + 0.5870*pix[i+1] + 0.1140*pix[i+2];
    [/code]

    ja znam, śred­nią aryt­me­tyczną wszyst­kich skła­do­wych tj:

    [code]
    pix[i] = ( pix[i] + pix[i+1] + pix[i+2] ) / 3;
    [/code]

    poza tym liczysz to samo 3 razy. Przy­da­łaby się zmienna ;)

    Komentarz by luq — 5 czerwca 2010, 10:31

  5. a) Rze­czy­wi­ście liczę trzy razy to samo. Kwe­stia pod­sta­wie­nia do zmien­nych

    pix[i] = pix[i+1] = pix[i+2] = 0.2989*pix[i] + 0.5870*pix[i+1] + 0.1140*pix[i+2];

    b) Wzór ten wska­zał mi brat zaj­mu­jący się pro­gra­mo­wa­niem gra­fiki. Powie­dział mi, że wynika to z więk­szego sku­pia­nia uwagi na zie­lo­nych bar­wach przez ludz­kie oko(nie pamię­tam dokład­nie co powie­dział ale cho­dziło o ludzką per­cep­cję barw). Wie­rzę mu na słowo ;) . Jak znajdę jakieś infor­ma­cje w sieci to wkleję link.

    EDIT:
    Zna­la­złem cie­kawy wpis na stac­ko­ver­flow http://stackoverflow.com/questions/687261/converting-rgb-to-grayscale-intensity

    To co poka­za­łem to Y-Greyscale (YIQ/NTSC): Red: 0.299 Green: 0.587 Blue: 0.114 ale są rów­nież inne rodzaje sza­ro­ści np.
    BT709 Grey­scale: Red: 0.2125 Green: 0.7154 Blue: 0.0721
    RMY Grey­scale: Red: 0.5 Green: 0.419 Blue: 0.081

    Komentarz by Michał Środek — 5 czerwca 2010, 12:18

  6. No bo wła­śnie już kie­dyś spo­tka­łem się z podob­nym wzo­rem i nie wie­dzia­łem dla­czego w taki spo­sób to ktoś liczy. Okej poczy­tam, dzięki za info :)

    Dla zain­te­re­so­wa­nych zro­bi­łem mały test, ja wygląda obra­zek po prze­kształ­ce­niu zgod­nie każ­dym algorytmem:

    orgi­nał

    R, G, B = (R+G+B) / 3
    Y-Greyscale
    RMY-Greyscale
    BT709-Greyscale

    Tak, btw. u Cie­bie wpi­suje się BBCode czy znacz­niki html‚a? <a> czy [link]?

    Komentarz by luq — 6 czerwca 2010, 17:53

Kanał RSS z komentarzami do tego wpisu. TrackBack URL

Dodaj komentarz