Maison >interface Web >Tutoriel PS >Comment écrire un filtre Photoshop (1)
Il y a longtemps, j'ai écrit un article qui décrivait brièvement les concepts de base du développement de filtres dans Photoshop, décrivait la relation de collaboration entre les filtres et PS, et proposait également une démonstration du filtre à effet goutte de pluie. Mais le code source manque. Et nous allons nous demander comment programmer un filtre Photoshop à partir de zéro ? Comment pouvons-nous construire le cadre de base le plus simple du plug-in de filtre PS, puis continuer à ajouter les fonctions que nous souhaitons sur cette base ? Ici, je vais répondre à une question qui m'a été posée par un internaute à titre d'exemple, en partant du projet de construction le plus basique. Cet exemple (également le problème de cet internaute) est qu'il veut créer le filtre le plus simple, qui consiste simplement à remplir l'image de "rouge". Pour les utilisateurs de PS, c'est bien sûr une chose très simple et facile. Cela ne nécessite qu'une opération de touche de raccourci (les filtres sont généralement utilisés pour effectuer des tâches plus complexes). Nous partirons de cet exemple le plus basique pour expliquer comment écrire des filtres. processus. Un lien de téléchargement du code source pour l'exemple sera joint à la fin de l'article.
(1) L'outil de développement que nous utilisons est la version Visual Studio .NET 2005, avec Photoshop SDK CS (essentiellement le package de distribution composé de code C et de ressources). Les langages de développement utilisés sont C et C++.
Alors, est-il acceptable d'utiliser C# ou d'autres langages ? À l’heure actuelle, ce n’est pas réalisable. Par conséquent, pour développer des filtres Photoshop, les développeurs doivent avoir une bonne base en C et C, ce qui est le plus important. Bien sûr, il serait préférable que le développeur soit familiarisé avec le traitement d'images et ait des connaissances de base en traitement du signal numérique.(2) Après avoir préparé les outils, nous ouvrons VS2005 et créons un nouveau projet. Nous choisissons Win32 de Visual C comme modèle de projet. Pour le nom du projet, nous saisissons le nom du filtre que nous voulons créer, comme le filtre "FillRed", ce qui signifie que ce filtre sert à remplir du rouge, comme indiqué ci-dessous :
Après avoir cliqué sur OK, dans la boîte de dialogue contextuelle des paramètres, cliquez sur « Paramètres de l'application », sélectionnez « DLL » dans le type d'application, puis cliquez sur OK.Certains paramètres sont les suivants :
(a) En général, j'aime modifier le jeu de caractères utilisé par le projet pour "utiliser un jeu de caractères multi-octets", ce qui permet Nous devons utiliser char* et utiliser directement double Le type de chaîne de la citation. Bien entendu, Unicode peut également être utilisé, mais les fonctions de chaîne utilisées par les deux seront différentes. Vous pouvez le configurer comme vous le souhaitez.(b) Le projet a été généré sous forme de DLL par défaut. Puisque l'extension du fichier de filtre de Photoshop est 8bf, nous définissons l'extension du fichier de sortie sur 8bf dans Linker->General. Modifiez-le comme indiqué ci-dessous.
Sélectionnez « Inclure les fichiers » : ajoutez plusieurs dossiers du SDK Photoshop au répertoire d'inclusion VC de l'option. Cela nous permettra de compiler plus facilement le projet sans signaler une erreur indiquant que le fichier est introuvable. Comme indiqué ci-dessous : Le code de ce fichier source est remplacé comme suit : // FillRed.cpp : 定义 DLL 应用程序的入口点。
//
#include "stdafx.h"
#include "PiFilter.h"
#include <stdio.h>
#ifdef _MANAGED
#pragma managed(push, off)
#endif
#ifndef DLLExport
#define DLLExport extern "C" __declspec(dllexport)
#endif
//=======================================
// 全局变量
//=======================================
//dll instance
HINSTANCE dllInstance;
FilterRecord* gFilterRecord;
int32* gData;
int16* gResult;
SPBasicSuite* sSPBasic = NULL;
#define TILESIZE 128 //贴片大小:128 * 128
Rect m_Tile; //当前图像贴片(128*128)
//=======================================
// 函数列表
//=======================================
//辅助函数,拷贝矩形
void CopyPsRect(Rect* src, Rect* dest);
//辅助函数,把一个矩形置为空矩形
void ZeroPsRect(Rect* dest);
void DoParameters();
void DoPrepare();
void DoStart();
void DoContinue();
void DoFinish();
//辅助函数,拷贝矩形
void CopyPsRect(Rect* src, Rect* dest)
{
dest->left = src->left;
dest->top = src->top;
dest->right = src->right;
dest->bottom = src->bottom;
}
//辅助函数,把一个矩形置为空矩形
void ZeroPsRect(Rect* dest)
{
dest->left = 0;
dest->top = 0;
dest->right = 0;
dest->bottom = 0;
}
//DLLMain
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
dllInstance = static_cast<HINSTANCE>(hModule);
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
//===================================================================================================
//------------------------------------ 滤镜被ps调用的函数 -------------------------------------------
//===================================================================================================
DLLExport void PluginMain(const int16 selector, void * filterRecord, int32 *data, int16 *result)
{
gData = data;
gResult = result;
if (selector == filterSelectorAbout)
{
//显示关于对话框
MessageBox(GetActiveWindow(), "FillRed Filter: 填充红色-- by hoodlum1980", "关于 FillRed", MB_OK);
}
else
{
gFilterRecord = (FilterRecordPtr)filterRecord;
sSPBasic = gFilterRecord->sSPBasic;
}
switch (selector)
{
case filterSelectorAbout:
//DoAbout();
break;
case filterSelectorParameters:
DoParameters();
break;
case filterSelectorPrepare:
DoPrepare();
break;
case filterSelectorStart:
DoStart();
break;
case filterSelectorContinue:
DoContinue();
break;
case filterSelectorFinish:
DoFinish();
break;
default:
*gResult = filterBadParameters;
break;
}
}
//这里准备参数,就这个滤镜例子来说,我们暂时不需要做任何事
void DoParameters()
{
}
//在此时告诉PS(宿主)滤镜需要的内存大小
void DoPrepare()
{
if(gFilterRecord != NULL)
{
gFilterRecord->bufferSpace = 0;
gFilterRecord->maxSpace = 0;
}
}
//inRect : 滤镜请求PS发送的矩形区域。
//outRect : 滤镜通知PS接收的矩形区域。
//filterRect : PS通知滤镜需要处理的矩形区域。
//由于我们是使用固定的红色进行填充,实际上我们不需要请求PS发送数据
//所以这里可以把inRect设置为NULL,则PS不向滤镜传递数据。
void DoStart()
{
if(gFilterRecord == NULL)
return;
//我们初始化第一个Tile,然后开始进行调用
m_Tile.left = gFilterRecord->filterRect.left;
m_Tile.top = gFilterRecord->filterRect.top;
m_Tile.right = min(m_Tile.left + TILESIZE, gFilterRecord->filterRect.right);
m_Tile.bottom = min(m_Tile.top + TILESIZE, gFilterRecord->filterRect.bottom);
//设置inRect, outRect
ZeroPsRect(&gFilterRecord->inRect); //我们不需要PS告诉我们原图上是什么颜色,因为我们只是填充
CopyPsRect(&m_Tile, &gFilterRecord->outRect);
//请求全部通道(则数据为interleave分布)
gFilterRecord->inLoPlane = 0;
gFilterRecord->inHiPlane = 0;
gFilterRecord->outLoPlane = 0;
gFilterRecord->outHiPlane = (gFilterRecord->planes -1);
}
//这里对当前贴片进行处理,注意如果用户按了Esc,下一次调用将是Finish
void DoContinue()
{
if(gFilterRecord == NULL)
return;
//定位像素
int planes = gFilterRecord->outHiPlane - gFilterRecord->outLoPlane + 1; //通道数量
uint8 *pData=(uint8*)gFilterRecord->outData;
//扫描行宽度(字节)
int stride = gFilterRecord->outRowBytes;
//我们把输出矩形拷贝到 m_Tile
CopyPsRect(&gFilterRecord->outRect, &m_Tile);
for(int j = 0; j< (m_Tile.bottom - m_Tile.top); j++)
{
for(int i = 0; i< (m_Tile.right - m_Tile.left); i++)
{
//为了简单明了,我们默认把图像当作RGB格式(实际上不应这样做)
//pData[ i*planes + j*stride + 0 ] = 0; //Red
//pData[ i*planes + j*stride + 1 ] = 0; //Green
pData[ i*planes + j*stride + 2 ] = 255; //Blue
}
}
//判断是否已经处理完毕
if(m_Tile.right >= gFilterRecord->filterRect.right && m_Tile.bottom >= gFilterRecord->filterRect.bottom)
{
//处理结束
ZeroPsRect(&gFilterRecord->inRect);
ZeroPsRect(&gFilterRecord->outRect);
ZeroPsRect(&gFilterRecord->maskRect);
return;
}
//设置下一个tile
if(m_Tile.right < gFilterRecord->filterRect.right)
{
//向右移动一格
m_Tile.left = m_Tile.right;
m_Tile.right = min(m_Tile.right + TILESIZE, gFilterRecord->filterRect.right);
}
else
{
//向下换行并回到行首处
m_Tile.left = gFilterRecord->filterRect.left;
m_Tile.right = min(m_Tile.left + TILESIZE, gFilterRecord->filterRect.right);
m_Tile.top = m_Tile.bottom;
m_Tile.bottom = min(m_Tile.bottom + TILESIZE, gFilterRecord->filterRect.bottom);
}
ZeroPsRect(&gFilterRecord->inRect);
CopyPsRect(&m_Tile, &gFilterRecord->outRect);
//请求全部通道(则数据为interleave分布)
gFilterRecord->inLoPlane = 0;
gFilterRecord->inHiPlane = 0;
gFilterRecord->outLoPlane = 0;
gFilterRecord->outHiPlane = (gFilterRecord->planes -1);
}
//处理结束,这里我们暂时什么也不需要做
void DoFinish()
{
}
void DoFinish();
//Fonction auxiliaire, copier le rectangle
void CopyPsRect(Rect* src, Rect* dest )
{
dest->gauche =src->gauche;
dest->haut =src->haut;
dest->droite =src-> droite;
dest->bas =src-> ;bas;
}
//Fonction auxiliaire, définir un rectangle sur un rectangle vide
void ZeroPsRect(Rect* dest)
{
dest-> gauche = 0;
dest-> haut = 0;
dest-> droite = 0;
dest->bas = 0;
}
//DLLMain
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
dllInstance = static_castHINSTANCE>(hModule);
retour VRAI;
}
#ifdef _MANAGED
#pragma géré(pop)
#endif
//============= = ================================================== = ====================================
// ---------------------------------------- La fonction appelée par ps pour le filtre ---- -------------------------------------------- -
//==================================== == ================================================= == =============
DLLExport void PluginMain( const sélecteur int16, void * filterRecord, int32 *données, int16 *résultat)
{
gData = données;
gRésultat = résultat;
if (sélecteur == filterSelectorÀ propos )
{
>"FillRed Filtre : Remplir rouge -- par hoodlum1980",
"À propos de FillRed", MB_OK); 🎜 > (FilterRecordPtr)filterRecord; sSPBasic = gFilterRecord->sSPBasic;
}
commutateur
(sélecteur)
🎜> //DoAbout();
>cas filterSelectorParameters : DoParameters();
pause
;case filterSelectorPrepare: DoPrepare();
pause; case
filterSelectorStar t: DoStart() ; break;
case filterSelectorContinue : DoContinue();pause;
🎜>pause;
par défaut
: filterBadParameters; Préparez les paramètres ici. Pour cet exemple de filtre, nous n'avons encore rien à faire
void
DoParameters(){ }//À ce moment, indiquez au PS (hôte) la taille de mémoire requise pour le filtre
void
DoPrepare()
{
if(gFilterRecord !=
NULL) { gFilterRecord
->
bufferSpace
= 0
; gFilterRecord->
maxSpace
= 0; }
}
//inRect : Le filtre demande la zone rectangulaire envoyée par PS. //outRect : La zone rectangulaire reçue par la notification de filtre PS.
//filterRect : La zone rectangulaire que le filtre de notification PS doit traiter. //Puisque nous remplissons avec une couleur rouge fixe, nous n'avons en fait pas besoin de demander à PS d'envoyer des données //
Donc ici, vous pouvez définir inRect sur NULL, alors PS ne transmettra pas les données au filtre.
void DoStart()
{ if
(gFilterRecord ==NULL)
retour;
// Nous initialisons le premier Tile puis commençons à appeler
m_Tile.left =
gFilterRecord- > filterRect.left; m_Tile.top =
gFilterRecord->filterRect.top ;
m_Tile.right
= min(m_Tile.left
TILESIZE, gFilterRecord-> filterRect.right);m_Tile.bottom = min(m_Tile.top TILESIZE, gFilterRecord->filterRect.bottom);
//Définir inRect, outRect
ZeroPsRect( &gFilterRecord->inRect); //Nous n'avons pas besoin de PS pour dites-nous l'original Quelle est la couleur de l'image, car nous remplissons simplement
CopyPsRect(&m_Tile, &gFilterRecord->outRect);
//Demander tous les canaux (données pour la distribution entrelacée)
gFilterRecord->inLoPlane = 0;
gFilterRecord->inHiPlane = 0;
gFilterRecord->outLoPlane = 0 ;
gFilterRecord->outHiPlane = (gFilterRecord-> ;avions -1);
}
//Le patch actuel est traité ici. Notez que si l'utilisateur appuie sur Echap, le prochain appel sera Terminer
void. DoContinue()
{
if(gFilterRecord == NULL)
retour;
//Pixel de positionnement
int avions = gFilterRecord->outHiPlane - gFilterRecord ->outLoPlane 1 // Nombre de chaînes >(uint8*
)gFilterRecord->outData; //Largeur de ligne de balayage (octets)
int foulée = gFilterRecord->outRowBytes;
// Nous copions le rectangle de sortie dans m_Tile
CopyPsRect(&gFilterRecord-> outRect, &m_Tile);
🎜> j = 0 ; j (m_Tile.bottom - m_Tile.top) ; >) >(int i = 0
; je (m_Tile.right - m_Tile.left) ) { 🎜>pData[ i*avions j*stride 0 ] = 0; //Rouge *avions j*stride 1 ] = 0; avions j*foulée
2
] = 255
>Bleu } } }//
Déterminer si le traitement a été terminé if(m_Tile.right >= gFilterRecord->filterRect.right && m_Tile.bottom >= gFilterRecord->filterRect.bottom)
{
//处理结束
ZeroPsRect(&gFilterRecord->inRect);
ZeroPsRect(&gFilterRecord->outRect);
ZeroPsRect(&gFilterRecord->maskRect);
return;
}
//设置下一个tile
if(m_Tile.right gFilterRecord- >filterRect.right)
{
//向右移动一格
m_Tile.left = m_Tile.right;
m_Tile.right = min(m_Tile.right TILESIZE, gFilterRecord->filterRect.right);
}
else
{
//向下换行并回到行首处
m_Tile.left = gFilterRecord->filterRect.left;
m_Tile.right = min(m_Tile.left TILESIZE, gFilterRecord->filterRect.right);
m_Tile. top = m_Tile.bottom;
m_Tile.bottom = min(m_Tile.bottom TILESIZE, gFilterRecord->filterRect.bottom);
}
ZeroPsRect(&gFilterRecord->inRect);
CopyPsRect(&m_Tile, &gFilterRecord->outRect);
//Demander tous les canaux (les données sont distribuées entrelacées)
gFilterRecord-> ;inLoPlane = 0;
gFilterRecord-> >inHiPlane = 0;
gFilterRecord->outLoPlane = 0;
gFilterRecord->outHiPlane = (gFilterRecord->avions -1 ; 🎜>void
DoFinish()
{}
Le code ci-dessus est également un filtre À partir du framework de base, nous pouvons voir que l'une des fonctions d'exportation que fournira la DLL est la fonction PluginMain. Nous segmenterons l'image en tranches de 128*128 pixels, ce qui permet de transférer une plus petite quantité de données entre le PS et le. filtrer à chaque fois. Surtout pour les très grandes images, le traitement de découpage aidera à gérer les situations de mémoire restreinte, ce qui est également préconisé par Photoshop. Le processus d'appel consiste à initialiser la première tuile (Tile) dans l'appel de démarrage, puis nous définissons la première tuile sur outRect, ce qui signifie que nous demandons à PS de fournir un tampon pour recevoir le rectangle Les données traitées à l'emplacement. Quant à inRect, puisque nous ne faisons que remplir, nous ne nous soucions pas de la couleur d'origine de l'image, donc inRect peut être défini sur "rectangle vide". Canaux d'images Ici, par souci d'intuitivité et de simplicité du code, nous considérons uniquement les images RVB, c'est-à-dire les images à 3 canaux. Après avoir défini le premier outRect, PS commencera à appeler continue dans l'ordre, et les correctifs seront collés de gauche à droite et de haut en bas jusqu'à ce que tous les correctifs soient traités. Notez que inData et outData sont les données d'application et le "tampon de réécriture" fourni par PS au filtre. L'un est destiné à la lecture et l'autre à l'écriture. Leurs tailles sont contrôlées par les données renseignées lorsque le filtre informe PS de la demande. Le Temps Opérationnel ne doit jamais franchir ses limites.
Pointeur hors limite Cela fera planter le programme Photoshop !
Pour plus de détails sur le code principal de ce filtre, veuillez consulter les commentaires du code et l'explication dans mon article précédent. Et la documentation officielle du PS SDK. Nous ne détaillerons pas ici le principe du code, car il est très simple. Tous les codes ci-dessus doivent faire référence aux fichiers d'en-tête dans le SDK PS.
Mais la prochaine étape consiste à investir dans les ressources du PIPL.
Les ressources PIPL doivent être insérées dans le filtre afin d'être correctement reconnues et chargées par Photoshop. Selon la documentation fournie par PS, PIPL se prononce « pipple », ce qui signifie Plug-In Property List. Il s'agit d'une structure de données flexible et extensible utilisée pour représenter les métadonnées du module de plug-in (métadonnées). pipl inclut toutes les informations permettant à Photoshop de reconnaître et de charger les modules de plug-in, y compris certaines balises, ainsi que diverses propriétés statiques qui contrôlent chaque plug-in, etc. Votre filtre peut contenir une ou plusieurs structures "pipl".
Le processus d'insertion des ressources pipl pour les filtres est le suivant. Tout d'abord, nous devons ajouter un fichier *.r (fichier Macintosh Rez) au projet, puis utiliser cl.exe pour compiler ce fichier en un. Fichier *.rr. Enfin, utilisez CnvtPipl.Exe, un outil de conversion de ressources fourni par Ps SDK, pour convertir le fichier *.rr en fichier *.pipl, puis ajoutez un fichier de ressources *.rc pour le filtre et incluez le fichier *.rr. fichier pipl à la fin du fichier rc.
ps sdk nous a fourni un fichier r commun, comprenant des définitions d'attributs communs, qui est le fichier PIGeneral.r.
(a) Ensuite, nous ajouterons un fichier r au projet, cliquez avec le bouton droit sur le dossier "Resource Files" dans le gestionnaire de ressources, cliquez pour ajouter un nouveau fichier et entrez "FillRed.r" comme nom de fichier. Double-cliquez sur le fichier pour l'ouvrir et copiez le contenu suivant :
// ADOBE SYSTEMS INCORPORATED // Copyright 1993 - 2002 Adobe Systems Incorporated // All Rights Reserved // // NOTICE: Adobe permits you to use, modify, and distribute this // file in accordance with the terms of the Adobe license agreement // accompanying it. If you have received this file from a source // other than Adobe, then your use, modification, or distribution // of it requires the prior written permission of Adobe. //------------------------------------------------------------------------------- #define plugInName "FillRed Filter" #define plugInCopyrightYear "2009" #define plugInDescription \ "FillRed Filter.\n\t - http:\\www.cnblogs.com\hoodlum1980" #include "E:\Codes\Adobe Photoshop CS2 SDK\samplecode\common\includes\PIDefines.h" #ifdef __PIMac__ #include "Types.r" #include "SysTypes.r" #include "PIGeneral.r" #include "PIUtilities.r" #include "DialogUtilities.r" #elif defined(__PIWin__) #define Rez #include "PIGeneral.h" #include "E:\Codes\Adobe Photoshop CS2 SDK\samplecode\common\resources\PIUtilities.r" #include "E:\Codes\Adobe Photoshop CS2 SDK\samplecode\common\resources\WinDialogUtils.r" #endif resource 'PiPL' ( 16000, "FillRed", purgeable ) { { Kind { Filter }, Name { plugInName }, Category { "Demo By hoodlum1980" }, Version { (latestFilterVersion << 16) | latestFilterSubVersion }, #ifdef __PIWin__ CodeWin32X86 { "PluginMain" }, #else CodeMachOPowerPC { 0, 0, "PluginMain" }, #endif SupportedModes { noBitmap, doesSupportGrayScale, noIndexedColor, doesSupportRGBColor, doesSupportCMYKColor, doesSupportHSLColor, doesSupportHSBColor, doesSupportMultichannel, doesSupportDuotone, doesSupportLABColor }, EnableInfo { "in (PSHOP_ImageMode, GrayScaleMode, RGBMode," "CMYKMode, HSLMode, HSBMode, MultichannelMode," "DuotoneMode, LabMode," "Gray16Mode, RGB48Mode, CMYK64Mode, Lab48Mode)" }, PlugInMaxSize { 2000000, 2000000 }, FilterCaseInfo { { /* array: 7 elements */ /* Flat data, no selection */ inStraightData, outStraightData, doNotWriteOutsideSelection, doesNotFilterLayerMasks, doesNotWorkWithBlankData, copySourceToDestination, /* Flat data with selection */ inStraightData, outStraightData, doNotWriteOutsideSelection, doesNotFilterLayerMasks, doesNotWorkWithBlankData, copySourceToDestination, /* Floating selection */ inStraightData, outStraightData, doNotWriteOutsideSelection, doesNotFilterLayerMasks, doesNotWorkWithBlankData, copySourceToDestination, /* Editable transparency, no selection */ inStraightData, outStraightData, doNotWriteOutsideSelection, doesNotFilterLayerMasks, doesNotWorkWithBlankData, copySourceToDestination, /* Editable transparency, with selection */ inStraightData, outStraightData, doNotWriteOutsideSelection, doesNotFilterLayerMasks, doesNotWorkWithBlankData, copySourceToDestination, /* Preserved transparency, no selection */ inStraightData, outStraightData, doNotWriteOutsideSelection, doesNotFilterLayerMasks, doesNotWorkWithBlankData, copySourceToDestination, /* Preserved transparency, with selection */ inStraightData, outStraightData, doNotWriteOutsideSelection, doesNotFilterLayerMasks, doesNotWorkWithBlankData, copySourceToDestination } } } };
Cnvtpipl.exe "$(ProjectDir)$(InputName).rr" "$(ProjectDir)$(InputName).pipl"
其中,第一行表示使用 CL.EXE 把该文件编译为 *.rr文件,上面的“/I”选项表示需要的包含目录。
第二行表示使用PS SDK中的 Cnvtpipl.exe 工具把 rr文件编译为 pipl文件,请注意为了简单,我把该工具复制到了项目的源文件所在文件夹下面。它位于SDK的路径是:“\samplecode\resources\cnvtpipl.exe”。
(b)下面我们为项目添加一个 rc文件,同样右键点击“资源文件”,添加一个FillRed.rc文件。
这是一个windows的资源文件,我们暂时还不需要任何资源,所以我们直接用文本方式打开IDE自动生成的RC文件,在结尾处添加下面的一行:
// #endif // APSTUDIO_INVOKED #endif // 英语(美国)资源 ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // 从 TEXTINCLUDE 3 资源生成。 // #include "FillRed.pipl" ///////////////////////////////////////////////////////////////////////////// #endif // 不是 APSTUDIO_INVOKED
(5)我们编译项目,即可在项目的输出目录中看到 生成 FillRed.8bf 文件,下面我们把这个文件复制到 Photoshop的滤镜文件夹下面,例如我的Photoshop CS的滤镜所在目录是:“D:\Program Files\Adobe\Photoshop CS\增效工具\滤镜”
最后我们启动Photoshop,Photoshop会扫描插件目录,并把我们的滤镜加载到相应的菜单上,我们选择一个矩形选区,然后点击我们制作的滤镜相应菜单,即可看到效果,如下图所示。注意,下面的例子的效果是我仅仅把蓝通道填充了255。
Dans le sous-menu du menu Aide de Photoshop - À propos des plug-ins -, vous pouvez voir l'élément "FillRed Filter..." que nous avons écrit. Lorsque vous cliquez dessus, PS lancera un appel à propos et vous verrez une fenêtre contextuelle. -up MessageBox.
Par exemple, le répertoire du SDK Photoshop doit être ajusté en fonction de l'environnement spécifique. Les outils de conversion de ressources fournis par PS SDK sont également inclus dans le dossier du projet. (Remarque : la pièce jointe ne contient pas le SDK PS complet) http://files.cnblogs.com/hoodlum1980/FillRed.rar
Cette section décrit le mise en place d'un cadre de filtrage de base depuis la création du projet jusqu'à l'intégration des ressources pipl. Mais sa fonction est très basique et simple. À l'avenir, nous devrons peut-être continuer à enrichir cet exemple, notamment en introduisant des ressources de dialogue, en permettant à PS de mettre en cache et de lire nos paramètres pour notre filtre, y compris dans les graphiques d'aperçu du filtre de dessin de surface de dialogue et bientôt.
Pour plus d'articles sur la façon d'écrire un filtre Photoshop (1), veuillez faire attention au site Web PHP chinois !