Design our filter parameters.
Our filter has completed one of the most basic tasks, that is, "filling", so we can configure the filling color, and in addition, we can set the opacity of the filling color. Therefore, we introduce the following parameters and define them as a struct, including an RGB fill color and an opacity (0~ 100):
//======================================
//Define our parameters
//======================================
typedef struct _MYPARAMS
{
COLORREF fillColor// fill color
Int opacity; //percentage (0~ 100)
} MYPARAMS
(2) Now we add a dialog resource. The editing dialog module is shown below. Then we set the control ID for the main control.
Note that VC will rewrite the rc file after editing the resource file, so before compiling the project, we need to manually open the rc file and add # include "fillred.pipl" again.
Otherwise, PS will not correctly identify the compiled filter and load it into the filter menu.
(3) Let's add a window program to this dialog box. To this end, we added ParamDlg.h and ParamDlg.cpp files to the project.
Please note that because the window procedure is located in our DLL, we must declare the window procedure as a DLL export function in order to let the system know the address of the function.
The writing of window program belongs to the field of windows programming completely (please refer to related books for this knowledge), so I won't introduce how to write window program in detail here. But it is worth mentioning that I introduced a UI feature in PS, which is its font setting dialog box in PS. When the mouse hovers over the label (static label) in front of the control, the cursor shape can be changed to a special cursor. Press and drag the mouse left and right, and the values of related controls will automatically increase or decrease according to the direction of mouse movement, similar to the effect of slider controls. So I added this function to the window process, which will make the code of the window process look a little more complicated, but this function (probably invented by PS? ) Very interesting and novel. For this reason, I also introduced a customized cursor file. The specific code is not posted, please refer to the code in ParamDlg.cpp file in the project source code.
(4) Based on the first article, we need to rewrite some codes in FillRed.cpp.
Because now we have introduced the opacity parameter, the opacity algorithm is: (opacity = 0~ 100).
Result value = input value * (1- opacity * 0.0 1)+ fill color * opacity * 0.01;
(a) For DoStart and DoContinue: We need to know the original color in the original picture, so that our inRect and inHiPlane will no longer be empty rectangles. This is reflected in the DoStart and DoContinue functions. We modify inRect and inHiPlane to make them consistent with outRect and outHiPlane, so that PS will send the original image data to us through inData.
(b) When the user clicks the filter menu, it will start with a parameter call, so we will set a flag here to indicate that the dialog box needs to be displayed.
(c) When the user clicks on the "Recent Filter" menu, it will start from preparing to call, which means that we don't need to display the dialog box, but directly fetch the previous cache parameters. To this end, we introduce ReadParams and WriteParams functions. That is, we use the callback function set provided by PS to exchange data between our parameters and PS script system.
Let's take a look at the changes that have taken place in the DoContinue function. The algorithm is mainly changed, and the data of inRect and inHiPlane is changed to request PS to send data. The first patch is set in the DoStart () function, and the modifications to inRect and inHiPlane are the same. At the same time, in the DoStart function, it is decided whether to display the dialog box according to the preset flag.
//DLLMain
BOOL API entry DllMain(HMODULE HMODULE,
The reason for the call,
LPVOID lpReserved
)
{
dllInstance = static _ cast & ltHINSTANCE & gt(hModule);
if(ul _ reason _ for _ call = = DLL _ PROCESS _ ATTACH | | ul _ reason _ for _ call = = DLL _ THREAD _ ATTACH)
{
//Initialize our parameters when loading DLL!
gParams.fillColor = RGB(0,0,255);
gparams . opacity = 100;
}
Return TRUE
}
#ifdef _MANAGED
#pragma hosting (pop)
#endif
//===================================================================================================
//-function called by ps.
//===================================================================================================
Dll export void plugin main (const int16 selector, void * filterRecord, int32 *data, int 16 *result).
{
GData = data;
GResult = result;
gFilterRecord =(FilterRecordPtr)filter record;
if(selector = = filterSelectorAbout)
ssp basic =((about record *)gFilterRecord)-& gt; sSPBasic
other
ssp basic = gFilterRecord-& gt; sSPBasic
Switch (selector)
{
Case Filter Selector About:
do about();
Break;
Case filter selector parameters:
DoParameters();
Break;
Case filter selector preparation:
DoPrepare();
Break;
Case filter selection or start:
do start();
Break;
Case Filter Selection or Continue:
DoContinue();
Break;
Case filter selection or completion:
do finish();
Break;
Default value:
* gResult = filterBadParameters
Break;
}
}
//Displays the About dialog box.
void DoAbout()
{
about record * about ptr =(about record *)gFilterRecord;
PlatformData * platform =(platform data *)(about ptr-& gt; platform data);
HWND hwnd = (HWND) platform->; hwnd
MessageBox(hwnd, "FillRed filter: fill color-by hood1980", "about FillRed", MB _ ok);
}
//Prepare parameters here. As far as this filter is concerned, we don't need to do anything for the time being.
Empty DoParameters ()
{
//Parameter call description. The user clicks the original menu and asks to display the dialog box.
m _ ShowUI = TRUE
//Set the parameter address
if(gFilterRecord-& gt; Parameter == NULL)
gFilterRecord-& gt; Parameter = (handle) (&; gParams);
}
//Tell the PS (host) filter how much memory it needs at this time.
void DoPrepare()
{
if(gFilterRecord! = empty)
{
gFilterRecord-& gt; buffer space = 0;
gFilterRecord-& gt; maxSpace = 0;
//Set the parameter address
if(gFilterRecord-& gt; Parameter == NULL)
gFilterRecord-& gt; Parameter = (handle) (&; gParams);
}
}
//inRect: rectangular area where the filter requests PS to send.
//outRect: The rectangular area that the filter notifies PS to receive.
//filterRect: PS informs the filter of the rectangular area to be processed.
//Because we fill it with a fixed red color, we don't actually need to ask PS to send data.
//So you can set inRect to NULL here, and PS will not pass the data to the filter.
void DoStart()
{
BOOL showDialog
if(gFilterRecord == NULL)
Return;
//Read parameter values from the script system into gParams.
OSErr err = read params(& amp; showDialog);
//Do you need to display a dialog box?
If (! Error & amp& ampshowDialog)
{
platform data * platform =(platform data *)(gFilterRecord-& gt; platform data);
HWND HWND parent =(HWND)platform-& gt; hwnd
//Show dialog box
int n result = DialogBoxParam(dllininstance,MAKEINTRESOURCE(IDD_PARAMDLG),hWndParent,(DLGPROC)ParamDlgProc,0);
if(nResult == IDCANCEL)
{
//Cancel being selected.
ZeroPsRect(& amp; gFilterRecord-& gt; in rect);
ZeroPsRect(& amp; gFilterRecord-& gt; outRect);
ZeroPsRect(& amp; gFilterRecord-& gt; mask rect);
write params();
//Note: (1) If PS users are informed to choose to cancel, PS will not initiate the call completion!
// (2) As long as the start call is successful, PS guarantees to initiate the Finish call.
* gResult = userCanceledErr
Return;
}
}
//We initialize the first tile and then start calling.
m _ tile . left = gFilterRecord-& gt; filterRect.left
m _ tile . top = gFilterRecord-& gt; filterRect.top
m _ tile . right = min(m _ tile . left+tile size,gFilterRecord-& gt; filter rect . right);
m _ tile . bottom = min(m _ tile . top+tile size,gFilterRecord-& gt; filter rect . bottom);
//Set inRect,outRect
//ZeroPsRect(& amp; gFilterRecord-& gt; in rect); //We don't need PS to tell us what color it is on the original picture, because we just need to fill it in.
copy psrect(& amp; m _ Tile & amp; gFilterRecord-& gt; in rect); //Now we need to request the same area as outRect.
copy psrect(& amp; m _ Tile & amp; gFilterRecord-& gt; outRect);
//Request all channels (then data is interleaved)
gFilterRecord-& gt; inlo plane = 0;
gFilterRecord-& gt; inhi plane =(gFilterRecord-& gt; Aircraft-1); ;
gFilterRecord-& gt; out loplane = 0;
gFilterRecord-& gt; outh iplane =(gFilterRecord-& gt; Aircraft-1);
}
//The current patch is processed here. Please note that if the user presses Esc, the next call will end.
void DoContinue()
{
Int index; //pixel index
if(gFilterRecord == NULL)
Return;
//Positioning pixels
int planes = gFilterRecord-& gt; outh iplane-gFilterRecord-& gt; out loplane+ 1; //number of channels
//Fill color
uint 8 r = getr value(gparams . fill color);
uint 8g = GetGValue(gparams . fill color);
uint 8 b = getb value(gparams . fill color);
int opacity = gParams.opacity
uint 8 * pDataIn =(uint 8 *)gFilterRecord-& gt; inData
uint 8 * pdata out =(uint 8 *)gFilterRecord-& gt; outData
//Scan line width (bytes)
int stride = gFilterRecord-& gt; outRowBytes
//We copy the output rectangle to m_Tile.
copy psrect(& amp; gFilterRecord-& gt; outRect & amp; m _ Tile);
for(int j = 0; j & lt(m _ tile . bottom-m _ tile . top); j++)
{
for(int I = 0; I< (m _ tile.right-m _ tile.left); i++)
{
Exponent = i * plane +j * stride;
//For the sake of simplicity, we regard the image as RGB format by default (it should not be done).
pDataOut[ index ] =
(uint8) ((pdatin [index] * (100-opacity) +r * opacity)/100); //Red
pDataOut[ index+ 1 ] =
(uint8) ((pdatin [index+1] * (100-opacity) +g * opacity)/100); //Green
pDataOut[ index+2 ] =
(uint8) ((pdatin [index+2] * (100-opacity) +b * opacity)/100); //Blue
}
}
//Judge whether it has been processed.
if(m _ tile . right & gt; = gFilterRecord-& gt; filterRect.right & amp& ampm _ Tile.bottom & gt= gFilterRecord-& gt; filterRect.bottom)
{
//End of processing
ZeroPsRect(& amp; gFilterRecord-& gt; in rect);
ZeroPsRect(& amp; gFilterRecord-& gt; outRect);
ZeroPsRect(& amp; gFilterRecord-& gt; mask rect);
Return;
}
//Set the next tile
if(m _ tile . right & lt; gFilterRecord-& gt; filterRect.right)
{
//Move one space to the right
m _ tile . left = m _ tile . right;
m _ tile . right = min(m _ tile . right+tile size,gFilterRecord-& gt; filter rect . right);
}
other
{
//Wrap the line down and return to the beginning of the line
m _ tile . left = gFilterRecord-& gt; filterRect.left
m _ tile . right = min(m _ tile . left+tile size,gFilterRecord-& gt; filter rect . right);
m _ tile . top = m _ tile . bottom;
m _ tile . bottom = min(m _ tile . bottom+tile size,gFilterRecord-& gt; filter rect . bottom);
}
//ZeroPsRect(& amp; gFilterRecord-& gt; in rect);
copy psrect(& amp; m _ Tile & amp; gFilterRecord-& gt; in rect); //Now we need to request the same area as outRect.
copy psrect(& amp; m _ Tile & amp; gFilterRecord-& gt; outRect);
//Request all channels (then data is interleaved)
gFilterRecord-& gt; inlo plane = 0;
gFilterRecord-& gt; inhi plane =(gFilterRecord-& gt; Aircraft-1); ;
gFilterRecord-& gt; out loplane = 0;
gFilterRecord-& gt; outh iplane =(gFilterRecord-& gt; Aircraft-1);
}
//The processing is over. We don't need to do anything here for the time being.
void DoFinish()
{
//Clear the flags that need to be displayed in the UI.
m _ ShowUI = FALSE
//Record parameters
write params();
(5) Read and write our parameters from the PS script system. We added ParamsScripting.h and ParamsScripting.cpp to the project. The code is as follows. ReadParams and WriteParams methods are introduced. This section mainly involves the descriptor callback function set of PS, which is complicated, so I won't explain it here because of my energy. For details, please refer to an article about PS callback function set and code comments in my previous essay. The relevant codes are as follows:
# contains "stdafx.h"
# contains "ParamsScripting.h"
# include & ltstdio.h & gt
OSErr read params(BOOL * showDialog)
{
OSErr err = noErr
PIReadDescriptor token = NULL///read operator
Descriptor keyidkey = null//uint32, that is, char*, key name.
DescriptorTypeID type = NULL
Int32 flag = 0;
Int32 intValue// receives the return value.
char text[ 128];
//Key to read
DescriptorKeyIDArray keys = { KEY _ fill color,KEY_OPACITY,NULL };
If (showDialog! = empty)
* showDialog = m _ ShowUI
//Used for recording and playing, used for recording and playing actions.
PIDescriptorParameters * desc params = gFilterRecord-& gt; Descriptor parameters;
if (descParams == NULL)
Return err
read descriptor procs * read procs = gFilterRecord-& gt; Descriptor parameters->; readDescriptorProcs
if (readProcs == NULL)
Return err
if(desc params-& gt; Descriptor! = empty)
{