Cómo escribir filtros de Photoshop (2)
(1) Diseñar nuestros parámetros de filtro.
Nuestro filtro realiza una tarea muy básica, que es un simple "relleno", por lo que podemos configurar el color del relleno, además de establecer la opacidad del color de relleno. Entonces, introduzcamos los siguientes parámetros, que se definen como una estructura que consta de un color de relleno RGB y una opacidad (0-100):
//============ = =========================
//Definir nuestros parámetros
/=== == = ================================
typedef estructura _MYPARAMS
{
COLORREF fillColor; //Color de relleno
int opacidad; //Porcentaje (0~100)
}. MYPARAMS;
(2) Ahora agregamos un recurso de diálogo. Edite el módulo de diálogo como se muestra a continuación.
Tenga en cuenta que después de editar el archivo de recursos, dado que VC reescribirá el archivo rc, aún debemos abrir manualmente el archivo rc y volver a agregar #include "FillRed.pipl" antes de compilar el proyecto.
De lo contrario, PS no reconocerá el filtro compilado y no lo cargará correctamente en el menú de filtro.
(3) A continuación, agregamos el procedimiento de ventana en el cuadro de diálogo. Para hacer esto, agregamos los archivos ParamDlg.h y ParamDlg.cpp a nuestro proyecto.
Tenga en cuenta que dado que el procedimiento de ventana está ubicado en nuestra DLL, debemos declarar el procedimiento de ventana como una función exportada a DLL para que el sistema conozca la dirección de la función.
Escribir procedimientos de ventana está completamente dentro del alcance de la programación de Windows (puede consultar los libros relevantes), por lo que no entraremos en detalles sobre cómo escribir procedimientos de ventana aquí. Pero vale la pena mencionar que introduje una función de interfaz de usuario en PS, es decir, en PS, como el cuadro de diálogo de configuración de fuente, cuando el mouse pasa sobre el control frente a la Etiqueta (etiqueta estática), la forma de la El cursor se puede cambiar. Como cursor especial, si presiona y arrastra el mouse hacia la izquierda o hacia la derecha, el valor del control relevante aumentará o disminuirá automáticamente según la dirección del movimiento del mouse, similar al efecto de un control deslizante. Esto tiene un efecto similar al de un control deslizante. Por lo tanto, agregué esta funcionalidad al procedimiento de ventana, lo que hace que el código del procedimiento de ventana parezca un poco más complicado, pero (¿tal vez fue inventado por PS? Para esto, también introduje un archivo de cursor personalizado. Consulte el código fuente del proyecto código en el archivo ParamDlg.cpp en lugar de publicar el código exacto
(4) Según el primer artículo, necesitamos reescribir algo de código en FillRed.cpp
Porque ahora. hemos introducido el parámetro de opacidad, el algoritmo de opacidad es: (opacidad = 0~ 100)
Valor del resultado = valor de entrada * (1- opacidad*0.01) + FillColor * opacidad *0.01;
(a) Para DoStart y DoContinue: necesitamos conocer el color original de la imagen original para que inRect e inHiPlane no sean rectángulos vacíos.
Esto se refleja en las funciones DoStart y DoContinue, donde modificamos inRect e inHiPlane para que sean consistentes con outRect y outHiPlane para que PS nos envíe los datos de la imagen sin procesar a través de inData.
(b) Cuando el usuario hace clic en el menú de filtro, comenzará con una llamada de parámetro, por lo que configuramos una bandera aquí para indicar que necesitamos mostrar el cuadro de diálogo.
(c) Cuando el usuario hace clic en el menú de filtro reciente, comenzará con una llamada de preparación, lo que significa que no necesitamos mostrar el cuadro de diálogo, solo obtener los parámetros previamente almacenados en caché. Para ello, introdujimos las funciones ReadParams y WriteParams. Es decir, utilizamos el conjunto de funciones de devolución de llamada proporcionadas por PS para intercambiar datos entre nuestros parámetros y el sistema de secuencias de comandos de PS.
A continuación, veremos los cambios en la función DoContinue. El principal cambio se produce en el algoritmo, que cambia los datos de inRect e inHiPlane para poder solicitar datos a PS. El primer parche se establece en la función DoStart(), los cambios en inRect e inHiPlane son los mismos. Además, en la función DoStart, la visualización del cuadro de diálogo se determinará en función del indicador establecido previamente.
//DLLMain
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
dllInstance = static_cast if (ul_reason_for_call == DLL_PROCESS_ATTACH || ul_reason_for_call == DLL_ THREAD_ATTACH) { // ¡Inicializa nuestros parámetros al cargar la DLL! gParams.fillColor = RGB(0, 0, 255); gParams.fillColor = RGB(0, 0, 255); { p> p> //cancelar seleccionado ZeroPsRect(&gFilterRecord->inRect); ZeroPsRect(&gFilterRecord->outRect); ZeroPsRect(&gFilterRecord- >maskRect); WriteParams(); //Nota: (1) Notificar a PS que el usuario elige cancelar evitará que PS inicie una llamada de finalización ! // (2) Siempre que la llamada de inicio sea exitosa, PS se asegurará de que se ejecute la llamada de finalización. *gResult = userCanceledErr; retorno; } } // Inicializamos el primer Tile y luego comenzamos a llamar m_Tile.left = gFilterRecord->.m_Tile.bottom = min(m_Tile.top + TILESIZE); // Establecer inRect, outRect //ZeroPsRect(&gFilterRecord->inRect); //No necesitamos que PS nos diga qué color tiene la imagen original porque simplemente la estamos llenando CopyPsRect ( &m_Tile, &gFilterRecord-> inRect); //Ahora necesitamos solicitar la misma área que outRect CopyPsRect(&m_Tile, &gFilterRecord-> outRect); // solicitar el canal completo (luego los datos se distribuyen intercalados) gFilterRecord->inLoPlane = 0; gFilterRecord->inHiPlane = (gFilterRecord->planes -1);; p> p> gFilterRecord->.outLoPlane = 0; gFilterRecord->outHiPlane = (gFilterRecord->aviones -1); } / / Procese el parche actual aquí, tenga en cuenta que si el usuario presiona la tecla Esc, la siguiente llamada será Finalizar void DoContinue() { int index; / /índice de píxeles if(gFilterRecord == NULL) return; int planes = gFilterRecord->outHiPlane - gFilterRecord->outLoPlane + 1 //número de canales //color de relleno uint8 r = GetRValue(gParams.fillColor);< uint8 g = GetGValue(gParams.fillColor); uint8 b = GetBValue(gParams.fillColor); int opacity = gParams.opacity; uint8 *pDataIn = (uint8*)gFilterRecord->inData; uint8 *pDataOut = (uint8*)gFilterRecord- >outData; // Ancho de línea de escaneo (en bytes) int stride = gFilterRecord-> outRowBytes; //Copiamos el rectángulo de salida a m_Tile CopyPsRect(&gFilterRecord->outRect, &m_Tile); for(int j = 0; j < (m_Tile.bottom - m_Tile.top);