Création d'un éditeur d'images à l'aide de CamanJS Création de filtres personnalisés et de modes de fusion

Dans le premier tutoriel de notre série d’éditeurs d’images CamanJS, nous n’utilisions que des filtres intégrés pour éditer nos images. Cela nous a limité à quelques effets de base tels que la luminosité, le contraste et 18 autres filtres plus complexes portant des noms tels que Vintage, Sunrise, etc. Ils étaient tous faciles à appliquer, mais nous ne contrôlions pas totalement les pixels individuels de l'image souhaitée. éditer.

Dans le deuxième tutoriel, nous avons appris à propos des calques et des modes de fusion, ce qui nous a permis de mieux contrôler les images que nous étions en train de modifier. Par exemple, vous pouvez ajouter un nouveau calque sur le canevas, le remplir d’une couleur ou d’une image, puis le placer sur le calque parent, auquel un mode de fusion est appliqué. Cependant, nous ne créions toujours pas nos propres filtres et les modes de fusion que nous pouvions appliquer étaient limités à ceux déjà fournis par CamanJS..

Le but de ce tutoriel sera de vous apprendre à créer vos propres modes de fusion et filtres. Nous allons également traiter certains bugs présents dans la bibliothèque et comment vous pouvez les corriger lorsque vous utilisez CamanJS dans vos propres projets.. 

Créer de nouveaux modes de fusion

Par défaut, CamanJS propose dix modes de fusion. Ce sont normal, multiplier, écran, superposition, différence, addition, exclusion, softLight, éclaircir et assombrir. La bibliothèque vous permet également d’enregistrer vos propres modes de fusion. De cette façon, vous pouvez contrôler la manière dont les pixels correspondants du calque actuel et du calque parent se mélangent afin de produire le résultat final..

Vous pouvez créer un nouveau mode de fusion en utilisant Caman.Blender.register ("blend_mode", rappel);. Ici, mode de fusion est le nom que vous souhaitez utiliser pour identifier le mode de fusion que vous créez. La fonction de rappel accepte deux paramètres contenant les valeurs RVB de différents pixels du calque actuel et les pixels correspondants du calque parent. La fonction retourne un objet avec les valeurs finales pour le rgb canaux.

Voici un exemple de mode de fusion personnalisé qui définit la valeur des canaux individuels d'un pixel sur 255 si la valeur de ce canal pour le pixel correspondant dans le calque parent est supérieure à 128. Si la valeur est inférieure à 128, la valeur finale du canal est le résultat de la soustraction de la valeur actuelle du canal de la couche de la valeur du canal parent. Le nom de ce mode de fusion est maxrgb.

Caman.Blender.register ("maxrgb", fonction (rgbaLayer, rgbaParent) return r: rgbaParent.r> 128? 255: rgbaParent.r - rgbaLayer.r, g: rgbaParent.g> 128? 255: rgbaParent.g - rgbaLayer.g, b: rgbaParent.b> 128? 255: rgbaParent.b - rgbaLayer.b;);

Créons un autre mode de fusion de la même manière. Cette fois, les valeurs finales du canal seront définies sur 0 si la valeur du canal correspondant au pixel correspondant dans le calque parent est supérieure à 128. Si la valeur du canal du calque parent est inférieure à 128, le résultat final sera l'ajout de les valeurs de canal pour le calque actuel et le calque parent du pixel particulier. Ce mode de fusion a été nommé minrgb.

Caman.Blender.register ("minrgb", fonction (rgbaLayer, rgbaParent) return r: rgbaParent.r < 128 ? rgbaParent.r + rgbaLayer.r : 0, g: rgbaParent.g < 128 ? rgbaParent.g + rgbaLayer.r : 0, b: rgbaParent.b < 128 ? rgbaParent.r + rgbaLayer.r : 0 ; );

Vous devriez essayer de créer vos propres modes de fusion pour la pratique.

Création de nouveaux filtres basés sur les pixels

CamanJS comprend deux grandes catégories de filtres. Vous pouvez soit opérer sur l’ensemble de l’image, pixel par pixel, soit modifier une image à l’aide d’un noyau de convolution. Un noyau de convolution est une matrice qui détermine la couleur d'un pixel donné en fonction des pixels qui l'entourent. Dans cette section, nous allons nous concentrer sur les filtres basés sur les pixels. Les manipulations du noyau seront abordées dans la section suivante.

Les filtres basés sur les pixels reçoivent la valeur des canaux RVB pour un pixel à la fois. Les valeurs RVB finales pour ce pixel particulier ne sont pas affectées par les pixels environnants. Vous pouvez créer vos propres filtres en utilisant Caman.Filter.register ("nom_filtre", rappel);. Tout filtre que vous créez doit appeler le processus() méthode. Cette méthode accepte le nom du filtre et une fonction de rappel en tant que paramètres..

L'extrait de code suivant vous montre comment créer un filtre à base de pixels qui transforme les images en niveaux de gris. Ceci est effectué en calculant la luminescence de chaque pixel, puis en définissant la valeur des canaux individuels pour qu'elle soit égale à la luminescence calculée..

Caman.Filter.register ("niveaux de gris", fonction () this.process ("niveaux de gris", fonction (rgba) var lumin = (0.2126 * rgba.r) + (0.7152 * rgba.g) + (0.0722 * rgba .b); rgba.r = lumin; rgba.g = lumin; rgba.b = lumin;); retourne ceci;);

Vous pouvez créer un filtre de seuil de la même manière. Cette fois, nous allons permettre aux utilisateurs de passer une valeur seuil. Si la luminosité d'un pixel particulier est supérieure à la limite fournie par l'utilisateur, ce pixel devient blanc. Si la luminosité d'un pixel particulier est inférieure à la limite fournie par l'utilisateur, ce pixel deviendra noir..

Caman.Filter.register ("seuil", fonction (limite) this.process ("seuil", fonction (rgba) var lumin = (0.2126 * rgba.r) + (0,7152 * rgba.g) + (0,0722 * rgba.b); rgba.r = lumin> limite? 255: 0; rgba.g = lumin> limite? 255: 0; rgba.b = lumin> limite? 255: 0;); retourne ceci;);

En guise d’exercice, vous devriez essayer de créer vos propres filtres à base de pixels qui, par exemple, augmentent la valeur d’un canal particulier pour tous les pixels..

Au lieu de manipuler la couleur du pixel actuel, CamanJS vous permet également de définir la couleur des pixels aux emplacements absolus et relatifs. Malheureusement, ce comportement est un peu buggé, nous devrons donc réécrire certaines méthodes. Si vous regardez le code source de la bibliothèque, vous remarquerez que des méthodes telles que getPixel () et putPixel () appeler les méthodes coordonnéesToLocation () et locationToCoordinates () sur ce. Cependant, ces méthodes ne sont pas définies sur le prototype mais sur la classe elle-même..

Un autre problème avec la bibliothèque est que le putPixelRelative () méthode utilise le nom de la variable maintenantLoc au lieu de newLoc dans deux endroits différents. Vous pouvez vous débarrasser de ces deux problèmes en ajoutant le code suivant dans votre script.

Caman.Pixel.prototype.coordinatesToLocation = Caman.Pixel.coordinatesToLocation Caman.Pixel.prototype.locationToCoordinates = Caman.Pixel.locationToCoordinates Caman.Pixel.prototype.locationToCoordinates = Caman.Pixel.locationToCoordinates Caman.Pixel.prototype.locationToCoordinates = Fonction, image, image, image if (this.c == null) throw "Nécessite un contexte CamanJS";  newLoc = this.loc + (this.c.dimensions.width * 4 * (vert * -1)) + (4 * horiz); if (newLoc> this.c.pixelData.length || newLoc < 0)  return;  this.c.pixelData[newLoc] = rgba.r; this.c.pixelData[newLoc + 1] = rgba.g; this.c.pixelData[newLoc + 2] = rgba.b; this.c.pixelData[newLoc + 3] = rgba.a; return true; ;

Après avoir corrigé le code, vous devriez maintenant pouvoir créer un filtre reposant sur putPixelRelative () sans aucun problème. Voici un tel filtre que j'ai créé.

Caman.Filter.register ("effacé", fonction (ajuster) this.process ("effacé", fonction (rgba) if (Math.random () < 0.25)  rgba.putPixelRelative(2, 2,  r: 255, g: 255, b: 255, a: 255 );  ); return this; );

Ce filtre définit au hasard la valeur des pixels deux lignes plus haut et deux colonnes à droite du pixel actuel en blanc. Cela efface des parties de l'image. D'où le nom du filtre.

Création de nouveaux filtres basés sur la manipulation du noyau

Comme je l'ai mentionné précédemment, CamanJS vous permet de créer des filtres personnalisés dans lesquels la couleur du pixel actuel est déterminée par les pixels qui l'entourent. Fondamentalement, ces filtres couvrent chaque pixel de l'image que vous modifiez. Un pixel de l'image sera entouré de huit autres pixels. Les valeurs de ces neuf pixels de l'image sont multipliées par les entrées correspondantes de la matrice de convolution. Tous ces produits sont ensuite additionnés pour obtenir la valeur de couleur finale du pixel. Vous pouvez en savoir plus sur le processus dans la documentation de GIMP..

Tout comme les filtres basés sur les pixels, vous pouvez définir vos propres filtres de manipulation du noyau en utilisant Caman.Filter.register ("nom_filtre", rappel);. La seule différence est que vous allez maintenant appeler processKernel () à l'intérieur de la fonction de rappel.

Voici un exemple de création d'un filtre de relief utilisant la manipulation du noyau.

Caman.Filter.register ("emboss", function () this.processKernel ("emboss", [-2, -1, 0, -1, 1, 1, 0, 1, 2]););

La démonstration suivante de CodePen montrera tous les filtres que nous avons créés dans ce tutoriel en action.

Dernières pensées

Dans cette série, j'ai couvert presque tout ce que CamanJS a à offrir en termes de retouche d'images. Vous devriez maintenant pouvoir utiliser tous les filtres intégrés, créer de nouveaux calques, appliquer des modes de fusion à ces calques et définir vos propres modes de fusion et fonctions de filtrage..

Vous pouvez également consulter le guide sur le site Web de CamanJS pour en savoir plus sur tout ce que j'ai pu manquer. Je vous recommande également de lire le code source de la bibliothèque afin d'en apprendre davantage sur la manipulation d'images. Cela vous aidera également à découvrir d’autres bugs dans la bibliothèque..