오래 전에 포토샵에서 필터 개발의 기본 개념을 간략하게 설명하고 필터와 PS의 협업 관계를 설명하고 빗방울 효과 필터의 데모를 제공하는 기사를 작성했습니다. 그런데 소스코드가 빠졌네요. 그리고 우리는 Photoshop 필터를 처음부터 어떻게 프로그래밍합니까? PS 필터 플러그인의 가장 간단한 기본 프레임워크를 어떻게 구축하고, 이를 기반으로 원하는 기능을 계속 추가하려면 어떻게 해야 할까요? 여기서는 한 네티즌이 나에게 던진 질문을 예로 들어 가장 기본적인 건설 프로젝트부터 답해보도록 하겠다. 이 예(또한 이 네티즌의 문제)는 그가 가장 간단한 필터를 만들고 싶어한다는 것입니다. 즉, 이미지를 "빨간색"으로 채우는 것입니다. PS 사용자의 경우 이는 매우 간단하고 쉬운 일입니다. 단축키 조작만 필요합니다. (필터는 일반적으로 더 복잡한 작업을 완료하는 데 사용됩니다.) 필터 작성 방법을 설명하기 위해 가장 기본적인 예부터 시작하겠습니다. 거울 과정. 예제의 소스 코드 다운로드 링크는 기사 끝에 첨부됩니다.
~ (1) 우리가 사용하는 개발 도구는 Photoshop SDK CS(기본적으로 일부 C++ 코드와 리소스 및 기타 파일로 구성된 배포 패키지)와 쌍을 이루는 Visual Studio .NET 2005 버전입니다. 사용되는 개발 언어는 C와 C++입니다.
그럼 C#이나 다른 언어를 사용해도 괜찮을까요? 현재로서는 불가능할 것 같습니다. 따라서 포토샵 필터를 개발하려면 개발자에게 가장 중요한 C 및 C++에 대한 탄탄한 기초가 있어야 합니다. 물론 개발자가 영상 처리에 익숙하고 디지털 신호 처리에 대한 기본 지식이 있으면 더 좋겠죠.
(2) 도구 준비가 끝나면 VS2005를 열고 새 프로젝트를 만듭니다. 프로젝트 템플릿으로 Visual C++의 Win32를 선택합니다. 프로젝트 이름에는 "FillRed" 필터와 같이 생성하려는 필터의 이름을 입력합니다. 이는 아래와 같이 이 필터가 빨간색을 채우는 데 사용된다는 의미입니다.
확인을 클릭한 후 팝업 설정 대화상자에서 "애플리케이션 설정"을 클릭하고 애플리케이션 유형에서 "DLL"을 선택한 후 확인을 클릭합니다.
일부 설정은 다음과 같습니다.(a) 일반적으로 프로젝트에서 사용하는 문자 집합을 "멀티바이트 문자 집합 사용"으로 변경하는 것을 좋아합니다. char*를 사용하고 double 인용문의 문자열 유형을 직접 사용합니다. 물론 유니코드도 사용할 수 있지만 둘이 사용하는 문자열 함수는 서로 다릅니다. 원하는대로 설정할 수 있습니다.
(b) 프로젝트는 기본적으로 DLL로 출력되어 있습니다. Photoshop의 필터 파일 확장자는 8bf이므로 링커->일반에서 출력 파일 확장자를 8bf로 설정했습니다. 아래 그림과 같이 변경합니다.~ "파일 포함" 선택: 옵션의 VC++ 포함 디렉터리에 여러 Photoshop SDK 폴더를 추가하면 파일을 찾을 수 없다는 오류를 보고하지 않고 프로젝트를 더 쉽게 컴파일할 수 있습니다. 아래와 같이:
이 소스 파일의 코드는 다음과 같습니다. 다음과 같이 교체되었습니다:
// 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();
//보조 기능, 직사각형 복사
void CopyPsRect(Rect* src, Rect* dest )
{
목적지->왼쪽 = src->왼쪽;
목적지->상단 = src->top;
dest->right = src-> 오른쪽;
목적지->하단 = src-> ;bottom;
}
//보조 기능, 직사각형을 빈 직사각형으로 설정
void ZeroPsRect(Rect* dest)
{
dest-> 왼쪽 = 0;
목적지-> 상위 = 0;
대상-> 오른쪽 = 0;
목적지->하단 = 0;
}
//DLLMain
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
dllInstance = static_cast<HINSTANCE>(hModule);
return TRUE;
}
#ifdef _MANAGED
#pragma 관리(팝)
#endif
//============= = ================================================ = ===================================
// --------------- ps가 호출하는 함수 필터 ---- ------------------------------- -
//=================================== == =============================================== == =============
DLLExport void PluginMain( const int16 선택기, void * filterRecord, int32 *data, int16 *결과)
{
gData = data;
gResult = 결과;
if (선택기 == filterSelectorAbout )
{
>"FillRed 필터: 빨간색 채우기 -- by Hoodlum1980",
"FillRed 소개", MB_OK); 🎜 > (FilterRecordPtr)filterRecord; sSPBasic = gFilterRecord->sSPBasic;
}
스위치
(선택기)
> //DoAbout();
케이스 filterSelectorParameters: DoParameters();
break
;case filterSelectorPrepare: DoPrepare();
break; case
filterSelectorStart t: DoStart() ; break;
case filterSelectorContinue: DoContinue();중단;
🎜>중단;
기본값
: filterBadParameters; 여기서 매개변수를 준비합니다. 이 필터 예에서는 아직 아무것도 할 필요가 없습니다.
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)
반품
;
// 첫 번째 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);
//Set inRect, outRect
ZeroPsRect(&gFilterRecord->inRect) //PS는 필요하지 않습니다. 원본 이미지에 어떤 색상이 있는지 알려주세요.
CopyPsRect(&m_Tile, & gFilterRecord->outRect);
데이터는 인터리브 배포) gFilterRecord
->inLoPlane = 0 ; gFilterRecord->
inHiPlane = 0; gFilterRecord->
outLoPlane = 0; gFilterRecord->
outHiPlane = (gFilterRecord- >비행기 -1);}
//
현재 패치가 여기에서 처리됩니다. 사용자가 Esc를 누르면 다음 호출은 Finishvoid
DoContinue( ){ <🎜입니다. >if
(gFilterRecord
== NULL) return;
//
위치 픽셀
int
평면 = gFilterRecord->outHiPlane - gFilterRecord-> outLoPlane + 1 //채널 수 (uint8*)gFilterRecord->
outData;//스캔 줄 너비(바이트)
int stride = gFilterRecord->outRowBytes;
// 출력 직사각형을 m_Tile
CopyPsRect(&gFilterRecord->에 복사합니다. outRect, &m_Tile);
🎜> j = 0 ; j< (m_Tile.bottom 🎜>- m_Tile.top); 🎜>) { for (int i =
0; i< (m_Tile.right - m_Tile.left); i++) ~ > = 0 //빨간색 pData[ i*planes + j*stride + 1 ] = 0; i*planes
+
j*
보폭+ 2 ]
= 255 //
파랑 } } //처리 완료 여부 판단 if(m_Tile.right >= gFilterRecord->filterRect.right && m_Tile.bottom >= gFilterRecord->filterRect.bottom)
{
//处理结束
ZeroPsRect(&gFilterRecord->inRect);
ZeroPsRect(&gFilterRecord->outRect);
ZeroPsRect(&gFilterRecord->maskRect);
반환;
}
//设置下一个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);
//모든 채널 요청(데이터는 인터리브 분산됨)
gFilterRecord-> ;inLoPlane = 0;
gFilterRecord-> >inHiPlane = 0;
gFilterRecord->outLoPlane = 0;
gFilterRecord->outHiPlane = (gFilterRecord->비행기 -1 ; 🎜>void
DoFinish()
{}
위 코드도 필터입니다. 기본 프레임워크에서 DLL이 제공하는 내보내기 기능 중 하나가 PluginMain 기능임을 알 수 있습니다. 이미지를 128*128 픽셀 슬라이스로 분할하여 PS와 DLL 간에 더 적은 양의 데이터를 전송할 수 있습니다. 특히 매우 큰 이미지의 경우 슬라이싱 처리는 Photoshop에서 권장하는 64*64 또는 128*128 크기를 처리하는 데 도움이 됩니다. 호출 프로세스는 시작 호출에서 첫 번째 타일(Tile)을 초기화한 다음 첫 번째 타일을 outRect로 설정하는 것입니다. 이는 PS에게 직사각형을 수신할 버퍼를 제공하도록 요청한다는 의미입니다. inRect의 경우 단지 채우는 중이므로 이미지의 원래 색상은 신경 쓰지 않으므로 inRect를 "빈 직사각형"으로 설정할 수 있습니다. 이미지 채널 여기서는 코드의 직관성과 단순성을 위해 RGB 이미지, 즉 3채널 이미지만을 고려합니다. 첫 번째 outRect를 설정한 후 PS는 continue 호출을 순서대로 시작하고 패치는 모든 패치가 처리될 때까지 왼쪽에서 오른쪽으로, 위에서 아래로 콜라주됩니다. inData 및 outData는 PS가 필터에 제공하는 애플리케이션 데이터이자 "쓰기 저장 버퍼"입니다. 하나는 읽기용이고 다른 하나는 필터가 PS에 요청을 알릴 때 채워지는 데이터에 의해 제어됩니다. 작동 시간은 경계를 넘어서는 안 됩니다.
~ 포인터가 범위를 벗어나면
Photoshop 프로그램이 중단됩니다!
Photoshop에서 PIPL 리소스를 올바르게 인식하고 로드하려면 필터에 PIPL 리소스를 삽입해야 합니다. PS에서 제공한 문서에 따르면 PIPL의 발음은 플러그인 속성 목록을 의미하는 "pipple"입니다. 플러그인 모듈 메타데이터(메타데이터)를 나타내는 데 사용되는 유연하고 확장 가능한 데이터 구조입니다. pipl에는 일부 태그는 물론 각 플러그인을 제어하는 다양한 정적 속성 등을 포함하여 Photoshop이 플러그인 모듈을 인식하고 로드하는 데 필요한 모든 정보가 포함되어 있습니다. 필터에는 하나 이상의 "pipl" 구조가 포함될 수 있습니다.
필터용 pipl 리소스를 삽입하는 과정은 다음과 같습니다. 먼저 프로젝트에 *.r(Macintosh Rez 파일) 파일을 추가한 후 cl.exe를 사용하여 이 파일을 *.rr 파일. 마지막으로 Ps SDK에서 제공하는 리소스 변환 도구인 CnvtPipl.Exe를 사용하여 *.rr 파일을 *.pipl 파일로 변환한 후 필터용 *.rc 리소스 파일을 추가하고 rc 파일 끝에 pipl 파일이 있습니다.
ps sdk는 공통 속성 정의를 포함한 공통 r 파일인 PIGeneral.r 파일을 제공했습니다.
(a) 다음으로 프로젝트에 r 파일을 추가하고 리소스 관리자에서 "Resource Files" 폴더를 마우스 오른쪽 버튼으로 클릭한 다음 클릭하여 새 파일을 추가하고 "FillRed.r"을 입력합니다. 파일 이름. 파일을 두 번 클릭하여 열고 다음 내용을 복사하세요.
// 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"
第二行表示使用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。
Photoshop 도움말 메뉴의 하위 메뉴인 플러그인 정보에서 우리가 작성한 "FillRed Filter..." 항목을 볼 수 있습니다. 이 항목을 클릭하면 PS가 관련 호출을 시작하고 팝업이 표시됩니다. - 메시지박스.
~ . 예를 들어 Photoshop SDK의 디렉터리는 특정 환경에 따라 조정되어야 합니다. PS SDK에서 제공하는 리소스 변환 도구도 프로젝트 폴더에 포함되어 있습니다. (참고: 첨부 파일에는 전체 PS SDK가 포함되어 있지 않습니다.) http://files.cnblogs.com/hoodlum1980/FillRed.rar
이 섹션에서는 프로젝트 생성부터 Pipl 리소스 삽입까지 기본 필터 프레임워크를 구축합니다. 그러나 그 기능은 매우 기본적이고 간단합니다. 앞으로는 대화 상자 리소스를 도입하고 PS가 대화 상자 표면 그리기 필터 미리 보기 그래픽 및 필터에 대한 매개 변수를 읽을 수 있도록 하는 등 이 예제를 계속해서 풍부하게 해야 할 수도 있습니다. 곧.
Photoshop 필터 작성 방법에 대한 더 많은 관련 기사(1)를 보려면 PHP 중국어 웹사이트를 주목하세요!