Bouw een Canvas Image Editor met Canvas

We gaan er niet mee uit de voeten, er is gewoon geen tijd, maar we zullen zien hoe gemakkelijk het is om dingen te doen zoals roteren, vergroten of verkleinen, vertalen en zelfs subtiel kleurmanipulatie. Houd jezelf niet voor de gek dat we eindigen met een equivalent van Photoshop, hoewel dat in theorie mogelijk is, maar gezien het feit dat we binnen de grenzen van niets complexers werken dan een browser, vind ik persoonlijk het nog steeds behoorlijk opmerkelijk.

Deze tutorial bevat een screencast die beschikbaar is voor leden van Tuts + Premium.


Wat je nodig hebt voor deze tutorial

Als u een werkversie van de demo lokaal wilt produceren, moet u een op Webkit gebaseerde browser gebruiken, zoals Safari of Chrome of Opera. De demo werkt in Firefox, maar deze moet door een webserver worden uitgevoerd om de meeste functionaliteit te laten werken. Denk er niet eens aan om IE te gebruiken; alleen versie 9 benadert zelfs ondersteuning voor het canvas-element, en om eerlijk te zijn, zou ik IE9 zelfs niet vertrouwen om de code en functionaliteit correct weer te geven.


Ermee beginnen

De onderliggende HTML is echt vrij triviaal; alles wat we nodig hebben voor de structuur van de editor zijn de volgende basiselementen:

    Canvas afbeeldingseditor     
Opslaan Roteren Links Roteren Rechts Formaat wijzigen B & W Sepia

Sla de pagina op als image-editor.html. Afgezien van de standaard HTML-elementen die het skelet van de pagina vormen, hebben we een aangepaste stijlpagina, die we in een ogenblik zullen toevoegen, en een stylesheet die door jQuery UI wordt geleverd. Onder aan de pagina, net voor de afsluiting tag, we hebben een verwijzing naar jQuery (huidige versie op het moment van schrijven is 1.4.4), een verwijzing naar jQuery UI (huidige versie 1.8.7) en een lege scripttag waarin we de code plaatsen die geeft de editor zijn functionaliteit.

De jQuery UI-componenten die we in dit voorbeeld gebruiken, zijn aanpasbaar en dialoogvenster, en het thema is ui-lichtheid.

De zichtbare elementen op de pagina zijn vrij eenvoudig; we hebben een uiterlijk bevattende

element, waarbinnen twee wonen
elementen. De eerste bevat de element dat we zullen gebruiken om onze afbeelding te manipuleren. De tweede bevat een knoppenbalk die wordt gebruikt om de manipulaties uit te voeren. Van de ID kaart attributen gegeven aan elke knop moet vrij duidelijk zijn wat elke knop doet.


De stijlen toevoegen

Net als de HTML is de gebruikte CSS extreem eenvoudig en bestaat uit het volgende:

#imageEditor width: 482px; margin: auto; padding: 20px; rand: 1px vast # 4b4b4b; -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; background-color: #ababab;  #editorContainer display: block; width: 480px; Hoogte: 480px;  #editor display: block; marge: 0 20px 20px 0; rand: 1px vast # 4b4b4b;  #toolbar display: block; marge: 20 px 0 0;  #toolbar a margin-right: 10px; schetsen: none; color: # 4b4b4b;  #resizer border: 2px dashed # 000;  #tip padding: 5px; margin: 0; grens: 1px vast # 000; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; positie: absoluut; background-color: # fff; background-color: RGBA (255.255.255, 0,3); -moz-box-shadow: 1px 1px 1px rgba (0,0,0,0.5); -webkit-box-shadow: 1px 1px 1px rgba (0,0,0,0.5); box-shadow: 1px 1px 1px rgba (0,0,0,0.5); 

Bewaar deze als image-editor.css in dezelfde map als de HTML-pagina. Er is niets echt opmerkelijks hier, meestal de lay-out van de stijlen de editor en de samenstellende elementen op de manier geïllustreerd in de onderstaande screenshot:



Volledige screencast



Het leuke deel

Het enige wat u hoeft te doen, is de code toevoegen die de editor laat werken. Begin door de onderstaande code toe te voegen aan het lege > element onderaan de pagina:

(functie ($) // canvas ophalen en context var editor = document.getElementById ("editor"), context = editor.getContext ("2d"), // create image image = $ ("", src:" img / graffiti.png ", laad: function () context.drawImage (this, 0, 0);), // meer code om hier te volgen?) (jQuery);

Allereerst plaatsen we al onze code in een afsluiting en een alias van het jQuery-object als het $ karakter. Ik realiseer me dat jQuery zichzelf automatisch als het $ -teken voor ons kenmerkt, maar er zijn situaties waarin dit conflicten met andere code kan veroorzaken die mogelijk wordt gebruikt wanneer onze code door anderen wordt geïmplementeerd.

Dit is ook de aanbevolen manier om plug-ins te maken, dus als je dit eenvoudigweg elke keer doet dat jQuery wordt gebruikt, is het veel sneller en gemakkelijker om terug te gaan en code indien nodig in een plug-in te veranderen. Ik vind het gewoon handiger om al mijn jQuery-code binnen een dergelijke sluiting te schrijven. Het heeft ook andere voordelen, zoals het verwijderen van een afhankelijkheid van globale variabelen - alle variabelen die we maken zullen veilig worden verborgen voor andere codes buiten de sluiting in de meeste situaties.

Om met het canvas te werken, moeten we een verwijzing naar de context krijgen. Dit is een object dat het oppervlak van het canvas vertegenwoordigt waarop meest van de methoden voor het werken met het canvas worden genoemd. Een paar methoden kunnen rechtstreeks op het canvasobject worden aangeroepen, maar de meeste worden aangeroepen op het contextobject.

De context verkrijgen is een proces in twee stappen; we krijgen eerst een verwijzing naar de element zelf met behulp van de standaard JavaScript document.getElementById () methode, dan noemen we de getContext () methode op het canvas (dit is een dergelijke methode die direct op het canvaselement kan worden aangeroepen, en om een ​​goede reden!), opgeven 2d als de context. Op dit moment is 2d de enige context die alom bestaat, hoewel we in de toekomst misschien kunnen uitkijken naar het werken met 3D-contexten.

Zowel het canvas als de contextobjecten worden opgeslagen in variabelen op het hoogste niveau (het equivalent van globale variabelen waarbij we niet binnen een afsluiting werkten), zodat alle functies die we definiëren, hier gebruik van kunnen maken.

Na deze twee variabelen maken we een andere, genaamd beeld. We gebruiken hier jQuery om snel en moeiteloos een nieuw afbeeldingselement te maken. We hebben de src van een afbeelding (een voorbeeld, een royaltyvrije afbeelding is opgenomen in de codedownload), zodat we iets hebben om mee te werken en een onload gebeurtenishandler die de afbeelding gewoon op het canvas schildert als de afbeelding is geladen. Het is belangrijk om tijdens het werken met het canvas ervoor te zorgen dat alle gebruikte afbeeldingen volledig zijn geladen voordat ze aan het canvas worden toegevoegd.

Het beeld wordt op het canvas geschilderd met behulp van de drawImage () methode, die wordt aangeroepen op de context voorwerp. Deze methode neemt drie argumenten (het kan eventueel meer duren, zoals we verderop in het voorbeeld zullen zien); deze argumenten zijn de afbeelding die moet worden gebruikt (waarnaar wordt verwezen met de deze trefwoord), de X positie op het canvas om de afbeelding te tekenen en de Y positie op het canvas om de afbeelding te tekenen. De voorbeeldafbeelding is de exacte grootte van het canvas in dit voorbeeld en is voor de eenvoud volledig vierkant.

We zijn nu klaar om nog meer code toe te voegen in dit stadium. Er is een slepende komma na de afbeelding die we hebben gemaakt, dus het volgende stukje code dat we toevoegen, zal ook een variabele zijn.


Werkbalkfunctionaliteit toevoegen

Vervolgens moeten we de code toevoegen om de werkbalkknoppen te verwerken. We kunnen gewoon een reeks klikbehandelaars toevoegen, één voor elke knop die we willen toevoegen. Hoewel het gemakkelijk te doen is, zou het niet enorm efficiënt zijn en niet ongelooflijk goed schalen.

Idealiter willen we een enkele hoofdfunctie die een klik op een knop afhandelt en de juiste functie aanroept. Gelukkig is dit ook heel gemakkelijk. Voeg de volgende code direct toe na de afbeelding die we zojuist hebben gemaakt:

// toolbar functies tools = ; $ ("# werkbalk"). kinderen (). klik (functie (e) e.preventDefault (); // bel de relevante functietools [this.id] .call (this););

Zo simpel is het. Laten we bedenken wat deze code doet. De laatste variabele op het hoogste niveau die we maken, wordt gereedschap genoemd en deze bevat een leeg (in dit stadium) object. De functies voor elke individuele knop worden allemaal in dit object geplaatst, zoals we binnenkort zullen zien.

We voegen vervolgens een single toe Klik handler, gekoppeld aan alle kinderen van het element met het ID toolbar (een van de

elementen in de onderliggende HTML).

Binnen deze click-handling-functie stoppen we eerst het standaardgedrag van de browser, wat zou zijn om de link te volgen (dit voorkomt dat het ongewenste 'jump-to-top'-gedrag soms wordt getoond bij het gebruik van standaard elementen als knoppen).

Ten slotte passen we het JavaScript toe () aanroepen methode voor de functie vervat in de eigenschap van de hulpmiddelen object dat overeenkomt met de ID kaart kenmerk van de link waarop is geklikt. We hebben alleen de link nodig waarop is geklikt ID kaart kenmerk, we kunnen de standaard gebruiken deze sleutelwoord zonder het te verpakken in een jQuery-object. De () aanroepen methode vereist dat de deze sleutelwoord wordt ook als argument doorgegeven.

Nu, als we een functie toevoegen aan het gereedschap-object onder de eigenschap opslaan, telkens wanneer we op de werkbalkknop klikken met de ID kaart opslaan, de functie wordt gebeld. Dus alles wat we nu moeten doen is een functie toevoegen voor elk van onze werkbalkknoppen.


De bewerkte afbeelding opslaan

We beginnen met de save-functie omdat het vrij klein en gemakkelijk is. Voeg de volgende code toe aan de hulpmiddelen voorwerp:

// output naar  opslaan: function () var saveDialog = $ ("
") .appendTo (" body "); $ ("", src: editor.toDataURL ()). appendTo (saveDialog); saveDialog.dialog (aanpasbaar: false, modal: true, title:" Klik met de rechtermuisknop en kies 'Afbeelding opslaan als' ", width: editor. breedte + 35);,

Het eerste dat onze functie doet, is een nieuw maken

element en voeg het toe aan de van de pagina. Dit element zal worden gebruikt in combinatie met de dialoogvenstercomponent van jQuery UI om een ​​modaal dialoogvenster te produceren.

Vervolgens maken we een nieuw afbeeldingselement; deze keer hebben we het ingesteld src naar een base-64 gecodeerde weergave van alles wat zich in het canvas bevindt. Deze actie wordt uitgevoerd met behulp van de toDataURL () methode, die overigens een andere methode is die rechtstreeks op het canvaselement wordt aangeroepen. Eenmaal gemaakt, wordt de afbeelding toegevoegd aan de

element gemaakt in de vorige stap.

Ten slotte initialiseren we de dialoogcomponent; dit is gedaan met behulp van de dialoogvenster () methode, een methode toegevoegd door jQuery UI. Een letterlijk object wordt doorgegeven aan de dialoogvenster () methode waarmee we de verschillende configuratie-opties kunnen instellen. In dit geval configureren we de dialoog zodat deze niet kan worden aangepast en dus modaal is (een overlay wordt toegepast op de rest van de pagina terwijl het dialoogvenster open is). We hebben ook de titel van het dialoogvenster ingesteld op een tekenreeks met instructies voor wat u moet doen om het object op te slaan en het dialoogvenster groot genoeg te maken om het beeld te bevatten door de breedte in te stellen op de breedte van het canvaselement plus 35 pixels.


omwenteling

Een veelvoorkomend kenmerk van beeldeditors is de mogelijkheid om een ​​element te roteren en het gebruik van de ingebouwde canvasfunctionaliteit, het is vrij eenvoudig om dit in onze editor te implementeren. Voeg de volgende functies toe na de opslagfunctie:

roteren: functie (conf) // huidige afbeelding opslaan voordat $ wordt rondgestuurd ("", src: editor.toDataURL (), laad: function () // rotate canvas context.clearRect (0, 0, editor.width, editor.height); context.translate (conf.x, conf.y) ; context.rotate (conf.r); / / redraw opgeslagen afbeelding context.drawImage (this, 0, 0););, rotateL: function () var conf = x: 0, y: editor. hoogte, r: -90 * Math.PI / 180; tools.rotate (conf);, rotateR: function () var conf = x: editor.width, y: 0, r: 90 * Math.PI / 180; tools.rotate (conf);,

Dus we hebben drie nieuwe functies toegevoegd; een hoofdrotatiefunctie, en dan een functie elk voor de roteer links en roteer de rechter werkbalkknoppen. De rotateL () en rotater () functies die elk gewoon een aangepast configuratieobject bouwen en vervolgens de master bellen draaien() functie, die het configuratieobject doorgeeft. Het is de meester draaien() functie die daadwerkelijk de rotatie uitvoert. Een belangrijk punt om op te merken is dat het het canvas zelf is dat we draaien, niet het beeld op het canvas.

Het configuratieobject dat we maken in de rotateL () en rotater () functies is heel eenvoudig; het bevat drie eigenschappen - X, Y en r. De eigenschappen X en Y verwijs naar de hoeveelheid vertaling die vereist is en r is de hoeveelheid rotatie. Elke klik op een rotatieknop roteert het beeld met plus of min 90 graden.

In de rotateL () functie moeten we het canvas op dezelfde afstand als de hoogte van het canvas op de verticale as vertalen om ervoor te zorgen dat het beeld zichtbaar blijft nadat het canvas is geroteerd. Rotatie naar 'links' wordt geclassificeerd als negatieve rotatie als het tegen de klok in is. Bij het berekenen van de rotatiehoek kunnen we geen graden gebruiken, we moeten 90 graden omzetten (of -90 graden in dit geval) in radialen. Dit is gemakkelijk en vereist de volgende formule:

Het aantal graden vermenigvuldigd met Pi gedeeld door 180

De rotater () functie is net zo rechtdoorzee, deze keer vertalen we het canvas op de horizontale as in plaats van de verticale as en gebruiken we een positief getal voor rotatie in wijzerzin.

In de meester draaien() functie moeten we opnieuw een kopie van de huidige afbeelding op het canvas pakken, wat we doen door een nieuw afbeeldingselement te maken met jQuery en zijn src naar het resultaat van de toDataURL () methode opnieuw. Deze keer willen we de afbeelding terug naar het canvas tekenen zodra het canvas is geroteerd, dus we voegen er een toe onload gebeurtenishandler voor de afbeelding.

Nadat de afbeelding is geladen, wissen we eerst het canvas met behulp van de clearRect () methode. Deze methode neemt vier argumenten; de eerste twee argumenten zijn de X en Y coördineert om te beginnen met opruimen. De derde en vierde zijn de grootte van het te wissen gebied. We willen het hele canvas wissen zodat we beginnen bij 0,0 (de linkerbovenhoek van het canvas) en de volledige breedte en hoogte van het canvas wissen.

Nadat we het canvas hebben gewist, vertalen we het (verplaats het in essentie) met behulp van de vertalen() transformatie methode. We vertalen het ofwel de volledige hoogte, ofwel de volledige breedte van het canvas, afhankelijk van of het rotateL () of rotater () functie startte de rotatie. Het vertalen van het canvas is noodzakelijk omdat rotatie standaard rechtsonder op het canvas plaatsvindt, niet in het midden zoals je zou verwachten.

Vervolgens kunnen we het canvas draaien en vervolgens de afbeelding opnieuw naar het canvas terugtrekken. Hoewel we dezelfde afbeelding terug naar het canvas tekenen, is het canvas geroteerd, zodat het beeld ook automatisch wordt geroteerd. Nogmaals, we kunnen verwijzen naar de afbeelding die moet worden doorgegeven aan de drawImage () methode als deze omdat we in de load handler voor de afbeelding zitten en jQuery zorgt ervoor dat dit naar de afbeelding verwijst. De volgende schermafbeelding toont de afbeelding één keer naar links gedraaid:



Het formaat van de afbeelding wijzigen

Het formaat van de afbeelding is onze meest complexe interactie en de functie die daarvoor nodig is, is vrij groot, hoewel het formaat van het canvas zelf vrij triviaal is. Voeg de volgende functie toe aan het gereedschap-object na de rotatiefuncties waarnaar we zojuist hebben gekeken:

formaat wijzigen: function () // maakbaar formaat wijzigen via canvas var coords = $ (editor) .offset (), resizer = $ ("
", id:" resizer "). css (position:" absolute ", links: coords.left, top: coords.top, width: editor.width - 1, height: editor.height - 1). appendTo ("body"); var resizeWidth = null, resizeHeight = null, xpos = editor.offsetLeft + 5, ypos = editor.offsetTop + 5; resizer.resizable (aspectRatio: true, maxWidth: editor.width - 1, maxHeight : editor.height - 1, formaat wijzigen: functie (e, ui) resizeWidth = Math.round (ui.size.width); resizeHeight = Math.round (ui.size.height); // tooltip om nieuwe grootte var te tonen string = "Nieuwe breedte:" + resizeWidth + "px,
nieuwe hoogte: "+ resizeHeight +" px "; if ($ (" # tip "). length) $ (" # tip "). html (string); else var tip = $ (" ", id : "tip", html: string). css (links: xpos, top: ypos). appendTo ("body");, stop: functie (e, ui) // bevestigen resize, doe dan it var confirmDialog = $ ("
", html:" Afbeelding wordt verkleind naar "+ resizeWidth +" px breed en "+ resizeHeight +" px high.
Doorgaan? "); // init confirm-dialoog confirmDialog.dialog (aanpasbaar: false, modal: true, title:" Confirm resize? ", Buttons: Cancel: function () // ruimt $ (this) op. dialoogvenster ("sluiten"); resizer.remove (); $ ("# tip"). remove ();, Yes: function () // plaats $ (this) .dialog ("close"); resizer .remove (); $ ("# tip"). remove (); $ ("", src: editor.toDataURL (), laad: function () // verwijder oude afbeelding context.clearRect (0, 0, editor.width, editor.height); // formaat canvas editor.width = resizeWidth; editor .height = resizeHeight; // redraw opgeslagen afbeelding context.drawImage (this, 0, 0, resizeWidth, resizeHeight););););,

Dus laten we de stappen bekijken die vereist zijn door onze functie voor het wijzigen van de grootte. Ten eerste hebben we een manier nodig om de gebruiker aan te geven tot welke grootte de afbeelding moet worden aangepast, en de gebruiker heeft een manier nodig om het nieuwe formaat in te stellen. We willen vervolgens bevestigen of de gebruiker het nieuwe formaat wil toepassen en pas dan het nieuwe formaat toe. De nieuwe functie doet alle dingen, laten we eens kijken hoe.

Eerst krijgen we de coördinaten op de pagina van het canvaselement met behulp van jQuery offset () methode, zodat we weten waar het aanpasbare element moet worden geplaatst. We maken vervolgens een nieuw

element, dat de resizable wordt en geef het een id van verkleinen zodat we er gemakkelijk naar kunnen verwijzen. We hebben ook een aantal stijleigenschappen van het nieuwe element ingesteld om het over het canvas te plaatsen. Zodra deze stijlen zijn ingesteld, voegen we deze toe aan de van de pagina. De grootte kan worden weergegeven als een gestippelde rand rond de binnenkant van het canvas, zoals hieronder wordt weergegeven:


Vervolgens initialiseren we nog twee variabelen, maar stellen hun waarden in op nul voorlopig. Deze worden gebruikt om de breedte en hoogte op te slaan waarvan de grootte wijzigbaar is tot wanneer de grootte wordt gewijzigd. Deze variabelen worden ingevuld en later in de functie gebruikt. De xpos en YPOS variabelen worden gebruikt om een ​​tooltip te plaatsen die we in een oogwenk creëren. Ze positioneren de tooltip 5 pixels vanaf de linkerrand en de bovenrand van het canvas.

Vervolgens initialiseren we de aanpasbaarheid met behulp van jQuery UI's resizable () methode. We configureren de aanpasbare zodat de beeldverhouding vergrendeld is; ons beeld is vierkant, dus we willen dat het vierkant blijft, ongeacht de afmeting van het formaat. We zorgen er ook voor dat het beeld niet in omvang kan worden vergroot, zodat de kwaliteit van het beeld behouden blijft. Als het beeld werd vergroot in plaats van gekrompen, zou het worden geblokkeerd. De Maximale wijdte en maximale hoogte configuratie-opties zorgen ervoor dat de afbeelding alleen kleiner kan worden gemaakt. Beide zijn respectievelijk ingesteld op de huidige breedte en hoogte van het canvas.

De aanpasbare component heeft enkele aangepaste event-handlers die we kunnen toewijzen aan functies die zullen worden uitgevoerd wanneer deze aangepaste events worden geactiveerd. We gebruiken twee van deze gebeurtenishandlers voor dit voorbeeld; verkleinen, die elke keer dat de schaalgrootte wordt gewijzigd, wordt geactiveerd, en hou op die wordt afgevuurd zodra de grootte aanpasbaar is geëindigd.

De functie voor het wijzigen van de grootte kan twee argumenten ontvangen; de eerste is een gebeurtenisobject, dat we in dit voorbeeld niet hoeven te gebruiken, maar dat moet worden gedeclareerd om gebruik te maken van het tweede argument, dat we wel nodig hebben. Het tweede argument is een object dat nuttige informatie bevat over de grootte van de grootte, inclusief de grootte waarnaar deze is gewijzigd. Het eerste dat we in deze functie doen, is de nieuwe grootte van de grootte aan ons toe te wijzen resizeWidth en resizeHeight variabelen met behulp van eigenschappen van de ui object dat de functie ontvangt.

Het laatste wat deze functie doet is de tooltip maken die de gebruiker vertelt hoe groot de aanpasbaarheid momenteel is. Als deze tooltip al bestaat, hoeven we deze niet opnieuw te maken en kan de interne tekst gewoon worden ingesteld op een tekenreeks die de huidige grootte van de grootte van de grootte aangeeft. Als de knopinfo nog niet bestaat, zoals de eerste keer dat de grootte van de schaal wordt gewijzigd, maken we deze helemaal opnieuw. De tooltip wordt gepositioneerd met behulp van de xpos en YPOS die we eerder hebben gemaakt. De string is vanaf nul opgebouwd telkens wanneer de grootte wijzigbaar is. De tooltip zal als volgt verschijnen:


De stopfunctie, die eenmaal wordt uitgevoerd wanneer de wijziging van de grootte verandert, maakt eerst een nieuw dialoogvensterelement dat controleert of de bezoeker het nieuwe formaat op het canvas wil toepassen. Opnieuw is het dialoogvenster zo geconfigureerd dat het zelf niet aanpasbaar is en dus modaal is. We voegen ook een aantal knoppen toe aan dit dialoogvenster. De eerste is a annuleren knop, waarmee de bezoeker de grootte van de bewerking kan wijzigen zonder het nieuwe formaat toe te passen. Het enige wat we hier doen, is het huishouden, het verwijderen van de dialoog, de aanpasbaarheid en de tooltip.

We maken ook een Ja knop die het nieuwe formaat toepast. We doen ook dezelfde huishoudelijke taken hier, maar om de nieuwe maat toe te passen, maken we opnieuw een nieuwe afbeelding op dezelfde manier als we al verschillende keren hebben gedaan. Het nieuwe formaat van het canvas instellen is extreem eenvoudig; we geven alleen de waarden op waarvan de grootte is gewijzigd in de eigenschappen width en height van het canvaselement. Hier is het dialoogvenster, dat hetzelfde lijkt als het dialoogvenster Opslaan van eerder, alleen met verschillende inhoud:



De rgb-waarden van afzonderlijke pixels wijzigen

Ik heb eerder gezegd dat we volledige pixel-niveau controle hebben over de inhoud van het canvas-element, dus onze laatste twee knoppen op de werkbalkknop zullen precies dat doen. De eerste functie wordt gebruikt om de afbeelding in grijswaarden om te zetten, de tweede functie verandert de afbeelding in een sepiatint. We zullen eerst naar de grijsschaalfunctie kijken:

greyscale: function () // haal afbeeldingsgegevens var imgData = context.getImageData (0, 0, editor.width, editor.height), pxData = imgData.data, length = pxData.length; voor (var x = 0; x < length; x+=4)  //convert to grayscale var r = pxData[x], g = pxData[x + 1], b = pxData[x + 2], grey = r * .3 + g * .59 + b * .11; pxData[x] = grey; pxData[x + 1] = grey; pxData[x + 2] = grey;  //paint grayscale image back context.putImageData(imgData, 0, 0); ,

Het eerste dat deze functie moet doen, is de huidige pixelgegevens van het canvas ophalen. Wij gebruiken de getImageData () methode om dit te doen. Deze methode accepteert vier argumenten, die hetzelfde zijn als de clearRect () methode waar we eerder naar keken - de eerste twee argumenten zijn de X en Y posities om te beginnen met het verzamelen van gegevens van en de derde en vierde zijn de breedte en hoogte van het te bereiken gebied. We willen het hele canvas zodat we beginnen bij 0,0 (linksboven) en doorgaan voor de breedte en hoogte van het canvas. Het resulterende object dat door de methode wordt geretourneerd, wordt opgeslagen in de imgData veranderlijk.

Het object dat in deze variabele is opgeslagen, heeft een eigenschap genaamd gegevens; binnen deze eigenschap is een array met de r g b en alpha-waarden voor elke afzonderlijke pixel in het canvas, dus het eerste item in de array bevat de r waarde van de eerste pixel, het tweede item bevat de g waarde van de eerste pixel, de derde bevat de b waarde van de eerste pixel en het vierde item bevat de alpha-waarde van de eerste pixel. Deze array is ongelooflijk groot; een afbeelding van 480 bij 480 pixels bevat 230400 pixels en we hebben vier items voor elke afzonderlijke pixel. Dit maakt de array in totaal 921600 items lang! Deze lengte wordt ook opgeslagen voor gebruik in de voor loop die we hierna definiëren.

De for-lus is een beetje anders dan gebruikelijk voor loops. Onthoud dat de array kan worden georganiseerd in discrete blokken van 4 items, waarbij elk item in een enkel blok verwijst naar de individuele rgba-componenten, dus we doorlopen de array vier items tegelijk. Op elke iteratie krijgen we elke pixelcomponent en gebruiken dan de formule r * .3 + g * .59 + b * .11 om ze allemaal in grijswaarden om te zetten. Vervolgens slaan we de geconverteerde pixelcomponent weer op naar het oorspronkelijke array-item.

Nadat we de hele array in een lus hebben geplaatst, kunnen we de array-inhoud terug naar het canvas schrijven en elke originele pixel vervangen door de nieuwe tegenhanger in grijswaarden. putImageData () methode, die gewoon het tegenovergestelde doet getImageData ().

De sepiakleurfunctie is identiek aan de grijswaardenfunctie, behalve dat we een andere formule gebruiken om elk te converteren r g b component tot sepiatint:

sepia: function () // haal afbeeldingsgegevens var imgData = context.getImageData (0, 0, editor.width, editor.height), pxData = imgData.data, length = pxData.length; voor (var x = 0; x < length; x+=4)  //convert to grayscale var r = pxData[x], g = pxData[x + 1], b = pxData[x + 2], sepiaR = r * .393 + g * .769 + b * .189, sepiaG = r * .349 + g * .686 + b * .168, sepiaB = r * .272 + g * .534 + b * .131; pxData[x] = sepiaR; pxData[x + 1] = sepiaG; pxData[x + 2] = sepiaB;  //paint sepia image back context.putImageData(imgData, 0, 0); 

Hier is een foto van de afbeelding nadat deze is geconverteerd naar sepiatint:



Conclusie

In deze zelfstudie hebben we gezien hoe het canvas kan worden omgezet in een krachtige afbeeldingseditor die ons een deel van de functionaliteit biedt van de eenvoudige, op toepassingen gebaseerde afbeeldingseditors waarmee we vertrouwd zijn. Dit voorbeeld kan eenvoudig worden uitgebreid om andere functies toe te voegen, zoals bijsnijden en tekenen met een potloodtool, hoewel ik de toevoeging van deze functionaliteit aan u overlaat. Bedankt voor het lezen.