Nanashi-softプログラマ専用Photoshopプラグイン開発


◇Photoshopプラグイン開発 -そのソースを貼っておく-

興味がある人向けにソースを貼っておきますので,
各自,元のサンプルDissolve.cppとdiffしてどこを書き換えたか見てください

これを元に,綺麗な 16bit減色プラグインを製作してくれる人が出てくる事を期待します('-'*)
// 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.
//-------------------------------------------------------------------------------

// project header files
#include "Dissolve.h"
#include "DissolveUI.h"
#include "DissolveScripting.h"
#include "DissolveRegistry.h"
#include "FilterBigDocument.h"
#include 

//-------------------------------------------------------------------------------
// global variables
//-------------------------------------------------------------------------------
// parameters passed into PluginMain that need to be global to the project
FilterRecord * gFilterRecord = NULL;
intptr_t * gDataHandle = NULL;
int16 * gResult = NULL;	// all errors go here
SPBasicSuite * sSPBasic = NULL;

// pointers to our data and parameters defined in Dissolve.h
Data * gData = NULL;
Parameters * gParams = NULL;

//-------------------------------------------------------------------------------
// local routines
//-------------------------------------------------------------------------------
// the six main routines of the plug in
void DoAbout(void);
void DoParameters(void);
void DoPrepare(void);
void DoStart(void);
void DoContinue(void);
void DoFinish(void);

void DoFilter(void);
void CalcProxyScaleFactor(void);
void ConvertRGBColorToMode(const int16 imageMode, FilterColor& color);
void ScaleRect(VRect& destination, const int16 num, const int16 den);
void ShrinkRect(VRect& destination, const int16 width, const int16 height);
void CopyRect(VRect& destination, const VRect& source);
void LockHandles(void);
void UnlockHandles(void);
void CreateParametersHandle(void);
void InitParameters(void);
void CreateDataHandle(void);
void InitData(void);
void DissolveRectangle(void* data, 
int32 dataRowBytes, 
void* mask, 
int32 maskRowBytes, 
VRect tileRect, 
uint8 color,
int32 depth);



//-------------------------------------------------------------------------------
//
//	PluginMain
//	
//	All calls to the plug in module come through this routine.
//
//	Inputs:
//	const int16 selector	Host provides selector indicating what
//	command to do.
//
//	Inputs and Outputs:
//	FilterRecord *filterRecord	Host provides a pointer to parameter block
//	containing pertinent data and callbacks.
//	See PIFilter.h
//
//	intptr_t *data	Use this to store a handle or pointer to our global
//	data structure, which is maintained by the
//	host between calls to the plug in.
//
//	Outputs:
//	int16 *result	Returns error result. Some errors are handled
//	by the host, some are silent, and some you
//	must handle. See PIGeneral.h.
//
//-------------------------------------------------------------------------------
DLLExport MACPASCAL void PluginMain(const int16 selector,
	FilterRecordPtr filterRecord,
	intptr_t * data,
	int16 * result)
{
	// update our global parameters
	gFilterRecord = filterRecord;
	gDataHandle = data;
	gResult = result;

	if (selector == filterSelectorAbout)
	{
		sSPBasic = ((AboutRecord*)gFilterRecord)->sSPBasic;
	}
	else
	{
	sSPBasic = gFilterRecord->sSPBasic;

	if (gFilterRecord->bigDocumentData != NULL)
		gFilterRecord->bigDocumentData->PluginUsing32BitCoordinates = true;
	}

	// do the command according to the selector
	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:
			break;
	}

	// unlock our handles used by gData and gParams
	if (selector != filterSelectorAbout)
		UnlockHandles();
}



//-------------------------------------------------------------------------------
//
// DoParameters
//
// Makes sure we have valid Data and Parameters handle(s). Locks and initializes
// these items.
// 
// NOTE:
// This routine is NOT guaranteed to be called by Photoshop. If a user enters the
// CTRL-F keyboard shortcut to invoke the last filter command this routine will
// NOT be called. If the filter is ran by the actions pallete or an automation
// plug in this routine will NOT be called.
//
// NOTE:
// The fields in the gFilterRecord are not all valid at this stage.
//-------------------------------------------------------------------------------
void DoParameters(void)
{
	if (gFilterRecord->parameters == NULL)
		CreateParametersHandle();
	if ((*gDataHandle) == 0)
		CreateDataHandle();
	if (*gResult == noErr)
	{
		LockHandles();
		InitParameters();
		InitData();
	}
}



//-------------------------------------------------------------------------------
//
// DoPrepare
//
// Almost identical to DoParameters. Make sure we have valid Data and Parameters
// handle(s) and lock and initialize as necessary. Sets the bufferSpace and 
// maxSpace variables in the gFilterRecord so memory is used at an optimum.
//
// NOTE:
// The fields in the gFilterRecord are not all valid at this stage. We will take a
// guess at the actual tile size information.
// 
//-------------------------------------------------------------------------------
void DoPrepare(void)
{
	if (gFilterRecord->parameters != NULL && (*gDataHandle) != 0)
		LockHandles();
	else
	{
		if (gFilterRecord->parameters == NULL)
			CreateParametersHandle();
		if ((*gDataHandle) == 0)
			CreateDataHandle();
		if (*gResult == noErr)
		{
			LockHandles();
			InitParameters();
			InitData();
		}
	}

	// we don't need any buffer space
	gFilterRecord->bufferSpace = 0; 

	// give as much memory back to Photoshop as you can
	// we only need a tile per plane plus the maskData
	// inTileHeight and inTileWidth are invalid at this
	// point. Assume the tile size is 256 max.
	VRect filterRect = GetFilterRect();
	int32 tileHeight = filterRect.bottom - filterRect.top;
	int32 tileWidth = filterRect.right - filterRect.left;
	if (tileHeight > 256)
		tileHeight = 256;
	if (tileWidth > 256)
		tileWidth = 256;

	int32 tileSize = tileHeight * tileWidth;
	int32 planes = gFilterRecord->planes;
	if (gFilterRecord->maskData != NULL)
		planes++;
	// duplicate because we have two copies, inData and outData
	planes *= 2;

	int32 totalSize = tileSize * planes;
	// this is worst case and can be dropped considerably
	if (gFilterRecord->maxSpace > totalSize)
		gFilterRecord->maxSpace = totalSize;
}



//-------------------------------------------------------------------------------
//
// DoStart
//
// The main filtering routine for this plug in. See if we have any registry
// parameters from the last time we ran. Determine if the UI needs to be
// displayed by reading the script parameters. Save the last dialog parameters
// in case something goes wrong or the user cancels.
//
//-------------------------------------------------------------------------------
void DoStart(void)
{
	LockHandles();

	// see if we have any information in the Photoshop registry
	ReadRegistryParameters();

	// save parameters
	int16 lastDisposition = gParams->disposition;
	int16 lastPercent = gParams->percent;
	Boolean lastIgnoreSelection = gParams->ignoreSelection;

	// does the user want a dialog
	Boolean isOK = true;
	Boolean displayDialog;
	OSErr err = ReadScriptParameters(&displayDialog);
	err; // turn off compiler warning for now

	// run the dialog on the specific OS
	if (!err && displayDialog)
		isOK = DoUI();

	// we know we have enough information to run without next time
	gData->queryForParameters = false;

	if (isOK)
	{
		// the main processing routine
		DoFilter();
	}
	else
	{
		// restore if the user hit cancel
		gParams->disposition = lastDisposition;
		gParams->percent = lastPercent;
		gParams->ignoreSelection = lastIgnoreSelection;
		*gResult = userCanceledErr;
	}
}



//-------------------------------------------------------------------------------
//
// DoContinue
//
// If we get here we probably did something wrong. This selector was needed
// before advanceState() was in the FilterRecord*. Now that we use advanceState()
// there is nothing for us to do but set all the rectangles to 0 and return.
//
//-------------------------------------------------------------------------------
void DoContinue(void)
{
	VRect zeroRect = { 0, 0, 0, 0 };

	SetInRect(zeroRect);
	SetOutRect(zeroRect);
	SetMaskRect(zeroRect);
}



//-------------------------------------------------------------------------------
//
// DoFinish
//
// Everything went as planned and the pixels have been modified. Now record
// scripting parameters and put our information in the Photoshop Registry for the
// next time we get called. The Registry saves us from keeping a preferences file.
//
//-------------------------------------------------------------------------------
void DoFinish(void)
{
	LockHandles();
	WriteScriptParameters();
	WriteRegistryParameters();
}



//-------------------------------------------------------------------------------
//
// DoFilter
//
// Randomly change the pixel values based on the parameters the user gave us from
// our dialog box or scripting. We do this a tile at a time making sure the rect.
// we ask for is in the bounds of the filterRect.
//
//-------------------------------------------------------------------------------
void DoFilter(void)
{
	// make the random number generated trully random
	srand((unsigned)time(NULL));

	int32 tileHeight = gFilterRecord->outTileHeight;
	int32 tileWidth = gFilterRecord->outTileWidth;

	if (tileWidth == 0 || tileHeight == 0)
	{
		*gResult = filterBadParameters;
		return;
	}

	VRect filterRect = GetFilterRect();
	int32 rectWidth = filterRect.right - filterRect.left;
	int32 rectHeight = filterRect.bottom - filterRect.top;

	CreateDissolveBuffer(tileWidth, tileHeight);

	// round up to the nearest horizontal and vertical tile count
	int32 tilesVert = (tileHeight - 1 + rectHeight) / tileHeight;
	int32 tilesHoriz = (tileWidth - 1 + rectWidth) / tileWidth;

	// Fixed numbers are 16.16 values 
	// the first 16 bits represent the whole number
	// the last 16 bits represent the fraction
	gFilterRecord->inputRate = (int32)1 << 16;
	gFilterRecord->maskRate = (int32)1 << 16;

	// variables for the progress bar, our plug in is so fast
	// we probably don't need these
	int32 progressTotal = tilesVert * tilesHoriz;
	int32 progressDone = 0;

	// loop through each tile makeing sure we don't go over the bounds
	// of the rectHeight or rectWidth
	for (int32 vertTile = 0; vertTile < tilesVert; vertTile++)
	{
		for (int32 horizTile = 0; horizTile < tilesHoriz; horizTile++)
		{
			UpdateDissolveBuffer(tileWidth, tileHeight);

			VRect filterRect = GetFilterRect();
			VRect inRect = GetInRect();

			inRect.top = vertTile * tileHeight + filterRect.top;
			inRect.left = horizTile * tileWidth + filterRect.left;
			inRect.bottom = inRect.top + tileHeight;
			inRect.right = inRect.left + tileWidth;

			if (inRect.bottom > rectHeight)
				inRect.bottom = rectHeight;
			if (inRect.right > rectWidth)
				inRect.right = rectWidth;

			SetInRect(inRect);

			// duplicate what's in the inData with the outData
			SetOutRect(inRect);

			// get the maskRect if the user has given us a selection
			if (gFilterRecord->haveMask)
			{
				SetMaskRect(inRect);
			}

			for (int16 plane = 0; plane < gFilterRecord->planes; plane++)
			{
				// we want one plane at a time, small memory foot print is good
				gFilterRecord->outLoPlane = gFilterRecord->inLoPlane = plane;
				gFilterRecord->outHiPlane = gFilterRecord->inHiPlane = plane;

				// update the gFilterRecord with our latest request
				*gResult = gFilterRecord->advanceState();
				if (*gResult != noErr) return;

				// muck with the pixels in the outData buffer
				uint8 color = 255;
				int16 expectedPlanes = CSPlanesFromMode(gFilterRecord->imageMode, 0);

				if (plane < expectedPlanes)
					color = gData->color[plane];

				color=(uint8)plane;
				DissolveRectangle(gFilterRecord->outData,
				gFilterRecord->outRowBytes,
				gFilterRecord->maskData,
				gFilterRecord->maskRowBytes,
				GetOutRect(), 
				color,
				gFilterRecord->depth);
			}

			// uh, update the progress bar
			gFilterRecord->progressProc(++progressDone, progressTotal);

			// see if the user is impatient or didn't mean to do that
			if (gFilterRecord->abortProc())
			{
				*gResult = userCanceledErr;
				return;
			}
		}
	}
	DeleteDissolveBuffer();
}



//-------------------------------------------------------------------------------
//
// DissolveRectangle
//
// This is our core algorithm for changing pixels randomly to a new color. We
// have to look at the maskPixel and the ignoreSelection parameter to know if we
// should or should not modify the pixel. This routine gets a little messy
// because it handles both 8 bit, 16 bit and 32 bit images.
//
//-------------------------------------------------------------------------------

void DissolveRectangle(void* data, 
	int32 dataRowBytes, 
	void* mask, 
	int32 maskRowBytes, 
	VRect tileRect, 
	uint8 color,
	int32 depth)
{
	static int8 amari[4]={0,0,0,0};	//余りを保持する変数
	static uint8 oldcolor[4]={0,0,0,0};	//1つ前のドットの色

	uint8* pixel = (uint8*)data;
	uint16* bigPixel = (uint16*)data;
	float* fPixel = (float*)data;
	uint8* maskPixel = (uint8*)mask;
	//	Ptr dissolve = gData->dissolveBuffer;

	int32 rectHeight = tileRect.bottom - tileRect.top;
	int32 rectWidth = tileRect.right - tileRect.left;

	uint16 bigColor = (uint16)(((uint32)color * 1285 + 5) / 10);
	float fColor = (float)((float)color / (float)255);

	for(int32 pixelY = 0; pixelY < rectHeight; pixelY++)
	{
		for(int32 pixelX = 0; pixelX < rectWidth; pixelX++)
		{

			bool leaveItAlone = false;
			if (maskPixel != NULL && !(*maskPixel) && !gParams->ignoreSelection)
				leaveItAlone = true;

			//	if (*dissolve && !leaveItAlone)
			if (!leaveItAlone)
			{
				if (depth == 32)
					*fPixel = fColor;
				else if (depth == 16)
					*bigPixel = bigColor;
				else {
					uint8 savecolor=*pixel;
					if(*pixel != oldcolor[color]){
						if(0xff < (int)*pixel + (int)amari[color]){
							*pixel = 0xff;
						}else if((int)*pixel + (int)amari[color] < 0){
							*pixel = 0x00;
						}else{
							*pixel = *pixel + amari[color];
						}
					}
					oldcolor[color]=savecolor;

					if(*pixel & 0x08){
						amari[color] = -0x0f + (*pixel & 0x0f);
						*pixel = *pixel | 0x0f;
					}else{
						amari[color] = *pixel & 0x0f;
						*pixel = *pixel & 0xf0;
					}
				}
			}
			pixel++;
			bigPixel++;
			fPixel++;
			//	dissolve++;
			if (maskPixel != NULL)
				maskPixel++;
		}
		pixel += (dataRowBytes - rectWidth);
		bigPixel += (dataRowBytes / 2 - rectWidth);
		fPixel += (dataRowBytes / 4 - rectWidth);
		if (maskPixel != NULL)
			maskPixel += (maskRowBytes - rectWidth);
	}
}



//-------------------------------------------------------------------------------
//
// CreateParametersHandle
//
// Create a handle to our Parameters structure. Photoshop will take ownership of
// this handle and delete it when necessary.
//-------------------------------------------------------------------------------
void CreateParametersHandle(void)
{
	gFilterRecord->parameters = gFilterRecord->handleProcs->newProc(sizeof(Parameters));
	if (gFilterRecord->parameters == NULL)
		*gResult = memFullErr;
}



//-------------------------------------------------------------------------------
//
// InitParameters
//
// Initialize our UI parameters. gParams is guaranteed to point at something
//-------------------------------------------------------------------------------
void InitParameters(void)
{
	gParams->disposition = 1;
	gParams->ignoreSelection = false;
	gParams->percent = 50;
}



//-------------------------------------------------------------------------------
//
// CreateDataHandle
//
// Create a pointer to our Data structure. Photoshop will take ownership of this
// and give it back to use on any future calls.
//-------------------------------------------------------------------------------
void CreateDataHandle(void)
{
	Handle h = gFilterRecord->handleProcs->newProc(sizeof(Data));
	if (h != NULL)
		*gDataHandle = (intptr_t)h;
	else
		*gResult = memFullErr;
}


//-------------------------------------------------------------------------------
//
// InitData
//
// Initialize the gData pointer
//-------------------------------------------------------------------------------
void InitData(void)
{
	CopyColor(gData->colorArray[0], gFilterRecord->backColor);
	SetColor(gData->colorArray[1], 0, 0, 255, 0);
	SetColor(gData->colorArray[2], 255, 0, 0, 0);
	SetColor(gData->colorArray[3], 0, 255, 0, 0);
	for(int a = 1; a < 4; a++)
		ConvertRGBColorToMode(gFilterRecord->imageMode, gData->colorArray[a]);
	CopyColor(gData->color, gData->colorArray[gParams->disposition]);
	gData->proxyRect.left = 0;
	gData->proxyRect.right = 0;
	gData->proxyRect.top = 0;
	gData->proxyRect.bottom = 0;
	gData->scaleFactor = 1.0;
	gData->queryForParameters = true;
	gData->dissolveBufferID = NULL;
	gData->dissolveBuffer = NULL;
	gData->proxyBufferID = NULL;
	gData->proxyBuffer = NULL;
	gData->proxyWidth = 0;
	gData->proxyHeight = 0;
	gData->proxyPlaneSize = 0;
}



//-------------------------------------------------------------------------------
//
// CreateDissolveBuffer
//
// Updates the dissolve array varaibles in the gData block. This allows us to 
// process one plane at a time
//
// Global Inputs and Outputs:
//	BufferID gData->dissolveBufferID	ID number of the current buffer in use
//	if it exists we must delete and get
//	another one.
//
//	Ptr	gData->dissolveBuffer	Actual array containing the dissolve
//	from the current settings of
//	gParams->percent
//	
//-------------------------------------------------------------------------------
void CreateDissolveBuffer(const int32 width, const int32 height)
{
	BufferProcs *bufferProcs = gFilterRecord->bufferProcs;

	bufferProcs->allocateProc(width * height, &gData->dissolveBufferID);
	gData->dissolveBuffer = bufferProcs->lockProc(gData->dissolveBufferID, true);
}



//-------------------------------------------------------------------------------
//
// UpdateDissolveBuffer
//
// Updates the dissolve buffer array varaibles in the gData block. This allows us
// to process one plane at a time
//
// Global Inputs and Outputs:
//	Ptr	gData->dissolveBuffer	Actual array containing the dissolve
//	from the current settings of
//	gParams->percent
//	
//-------------------------------------------------------------------------------
void UpdateDissolveBuffer(const int32 width, const int32 height)
{
	if (gData->dissolveBuffer != NULL)
	{
		Ptr dissolve = gData->dissolveBuffer;
		for (int32 x = 0; x < width; x++)
		{
			for (int32 y = 0; y < height; y++)
			{
				*dissolve = ((unsigned16) rand()) % 100 < gParams->percent;
				dissolve++;
			}
		}
	}
}



//-------------------------------------------------------------------------------
//
// DeleteDissolveBuffer
//
// Deletes the dissolve array varaibles in the gData block.
//
// Global Inputs and Outputs:
//	BufferID gData->dissolveBufferID	ID number of the current buffer in use
//	if it exists we must delete and get
//	another one.
//
//	Ptr	gData->dissolveBuffer	Actual array containing the dissolve
//	from the current settings of
//	gParams->percent
//	
//-------------------------------------------------------------------------------
void DeleteDissolveBuffer(void)
{
	if (gData->dissolveBufferID != NULL)
	{
		gFilterRecord->bufferProcs->unlockProc(gData->dissolveBufferID);
		gFilterRecord->bufferProcs->freeProc(gData->dissolveBufferID);
		gData->dissolveBufferID = NULL;
		gData->dissolveBuffer = NULL;
	}
}



//-------------------------------------------------------------------------------
//
// SetupFilterRecordForProxy
//
// Called by the UI routine to set up the gFilterRecord with the proxy view
// information. CalcProxyScaleFactor sizes the proxy rectangle and calculates the
// scale factor. Then set up gFilterRecord and call advanceState() to init the
// inData with the pixel data for the display.
//
// Global Inputs and Outputs:
//	FilterRecord *gFilterRecord	inRect, inRowBytes, maskRect, etc. has all
//	the information needed to call 
//	advanceState so inData points to the proxy
//	pixel data and maskRect points to the 
//	selection data
//	
//-------------------------------------------------------------------------------
void SetupFilterRecordForProxy(void)
{
	CalcProxyScaleFactor();

	SetInRect(GetFilterRect()); // gFilterRecord->inRect = gFilterRecord->filterRect;

	VRect tempRect = GetInRect();

	ScaleRect(tempRect, 1, (int16)gData->scaleFactor);

	SetInRect(tempRect);

	SetMaskRect(GetInRect()); // gFilterRecord->maskRect = gFilterRecord->inRect;

	// Fixed numbers are 16.16 values 
	// the first 16 bits represent the whole number
	// the last 16 bits represent the fraction
	gFilterRecord->inputRate = (int32)gData->scaleFactor << 16;
	gFilterRecord->maskRate = (int32)gData->scaleFactor << 16;

	gFilterRecord->inputPadding = 255;
	gFilterRecord->maskPadding = gFilterRecord->inputPadding;

	gData->proxyWidth = gData->proxyRect.right - gData->proxyRect.left;
	gData->proxyHeight = gData->proxyRect.bottom - gData->proxyRect.top;
	gData->proxyPlaneSize = gData->proxyWidth * gData->proxyHeight;
}



//-------------------------------------------------------------------------------
//
// CalcProxyScaleFactor
//
// Called by the UI routine to change the size of the Proxy rectangle and 
// calculate the scale factor. This information is needed by the displayPixels
// routine and the advanceState routine.
//
// Global Inputs:
//	Rect gFilterRecord->filterRect	Rectangle to filter
//
// Global Inputs and Outputs:
//	Rect gData->proxyRect	Rectangle for the Proxy to display in
//	float gData->scaleFactor	Scale factor of the filterRect 
//	to the ProxyRect
//	
//-------------------------------------------------------------------------------
void CalcProxyScaleFactor(void)
{
	int32 filterHeight, filterWidth, itemHeight, itemWidth;
	VPoint fraction;

	VRect filterRect = GetFilterRect();

	// we place a black frame around the proxy and leave a black
	// between the frame and the actual pixel data
	ShrinkRect(gData->proxyRect, 2, 2);

	filterHeight = filterRect.bottom - filterRect.top;
	filterWidth = filterRect.right - filterRect.left;

	itemHeight = (gData->proxyRect.bottom - gData->proxyRect.top);
	itemWidth = (gData->proxyRect.right - gData->proxyRect.left);

	// make sure the proxy isn't bigger than the image after the calculation
	// this will make the proxy half the size for images smaller than the proxy
	if (itemHeight > filterHeight)
		itemHeight = filterHeight;

	if (itemWidth > filterWidth)
		itemWidth = filterWidth;

	fraction.h = ((filterWidth + itemWidth) / itemWidth);
	fraction.v = ((filterHeight + itemHeight) / itemHeight);

	// calculate the scale factor based on the smaller of height or width
	if (fraction.h > fraction.v) 
		gData->scaleFactor = ((float)filterWidth + (float)itemWidth) / (float)itemWidth;
	else
		gData->scaleFactor = ((float)filterHeight + (float)itemHeight) / (float)itemHeight;

	CopyRect(gData->proxyRect, filterRect);	
	ScaleRect(gData->proxyRect, 1, (int16)gData->scaleFactor);

	// recalculate the scale factor based on the actual proxy size
	// this will reduce rounding errors in the proxy view
	if (fraction.h > fraction.v) 
		gData->scaleFactor = (float)filterWidth / (float)(gData->proxyRect.right - gData->proxyRect.left);
	else
		gData->scaleFactor = (float)filterHeight / (float)(gData->proxyRect.bottom - gData->proxyRect.top);
}



//-------------------------------------------------------------------------------
//
// ConvertRGBColorToMode
//
// Convert the FilterColor from RGB mode to the imageMode using the color
// services call backs.
//
// Inputs:
//	int16 imageMode	Mode to convert the color to
// Inputs and Outputs:
//	FilterColor& color	RGB color to convert
//
//-------------------------------------------------------------------------------
void ConvertRGBColorToMode(const int16 imageMode, FilterColor& color)
{
	if (imageMode != plugInModeRGBColor)
	{
		ColorServicesInfo	csInfo;

		csInfo.selector = plugIncolorServicesConvertColor;
		csInfo.sourceSpace = plugIncolorServicesRGBSpace;
		csInfo.reservedSourceSpaceInfo = NULL;
		csInfo.reservedResultSpaceInfo = NULL;
		csInfo.reserved = NULL;
		csInfo.selectorParameter.pickerPrompt = NULL;
		csInfo.infoSize = sizeof(csInfo);

		csInfo.resultSpace = CSModeToSpace(gFilterRecord->imageMode);
		for (int16 a = 0; a < 4; a++)
			csInfo.colorComponents[a] = color[a];

		if (!(gFilterRecord->colorServices(&csInfo)))
			for (int16 b = 0; b < 4; b++)
				color[b] = (int8)csInfo.colorComponents[b];
	}
}



//-------------------------------------------------------------------------------
//
// LockHandles
//
// Lock the handles and get the pointers for gData and gParams
// Set the global error, *gResult, if there is trouble
//
//-------------------------------------------------------------------------------
void LockHandles(void)
{
	if (gFilterRecord->parameters == NULL || (*gDataHandle) == 0)
	{
		*gResult = filterBadParameters;
		return;
	}
	gParams = (Parameters*)gFilterRecord->handleProcs->lockProc(gFilterRecord->parameters, TRUE);
	gData = (Data*)gFilterRecord->handleProcs->lockProc((Handle)*gDataHandle, TRUE);
	if (gParams == NULL || gData == NULL)
	{
		*gResult = memFullErr;
		return;
	}
}



//-------------------------------------------------------------------------------
//
// UnlockHandles
//
// Unlock the handles used by the data and params pointers
//
//-------------------------------------------------------------------------------
void UnlockHandles(void)
{
	if ((*gDataHandle) != 0)
		gFilterRecord->handleProcs->unlockProc((Handle)*gDataHandle);
	if (gFilterRecord->parameters != NULL)
		gFilterRecord->handleProcs->unlockProc(gFilterRecord->parameters);
}



//-------------------------------------------------------------------------------
//
// ScaleRect
//
// Utility routine for scaling a rectangle by a rational
//
//-------------------------------------------------------------------------------
void ScaleRect(VRect& destination, const int16 num, const int16 den)
{
	if (den != 0)
	{
		destination.left = (int16)((destination.left * num) / den);
		destination.top = (int16)((destination.top * num) / den);
		destination.right = (int16)((destination.right * num) / den);
		destination.bottom = (int16)((destination.bottom * num) / den);
	}
}



//-------------------------------------------------------------------------------
//
// ShrinkRect
//
// Utility routine for shrinking a Rect by a width and height
//
//-------------------------------------------------------------------------------
void ShrinkRect(VRect& destination, const int16 width, const int16 height)
{
	destination.left = (int16)(destination.left + width);
	destination.top = (int16)(destination.top + height);
	destination.right = (int16)(destination.right - width);
	destination.bottom = (int16)(destination.bottom - height);
}



//-------------------------------------------------------------------------------
//
// CopyRect
//
// Utility routine for setting a Rect from a VRect
//
//-------------------------------------------------------------------------------
void CopyRect(VRect& destination, const VRect& source)
{
	destination.left = source.left;
	destination.top = source.top;
	destination.right = source.right;
	destination.bottom = source.bottom;
}



//-------------------------------------------------------------------------------
//
// CopyColor
//
// Utility routine for setting a FilterColor array from a FilterColor
//
//-------------------------------------------------------------------------------
void CopyColor(FilterColor& destination, const FilterColor& source)
{
	for (int a = 0; a < sizeof(FilterColor); a++)
		destination[a] = source[a];
}



//-------------------------------------------------------------------------------
//
// SetColor
//
// Utility routine for setting a FilterColor array from 4 color components
//
//-------------------------------------------------------------------------------
void SetColor(FilterColor& destination, 
	const uint8 a, 
	const uint8 b, 
	const uint8 c, 
	const uint8 d)
{
	destination[0] = a;
	destination[1] = b;
	destination[2] = c;
	destination[3] = d;
}



//-------------------------------------------------------------------------------
//
// CreateProxyBuffer
//
//-------------------------------------------------------------------------------
void CreateProxyBuffer(void)
{
	int32 proxySize = gData->proxyPlaneSize * gFilterRecord->planes;
	gFilterRecord->bufferProcs->allocateProc(proxySize, &gData->proxyBufferID);
	gData->proxyBuffer = gFilterRecord->bufferProcs->lockProc(gData->proxyBufferID, true);
}



//-------------------------------------------------------------------------------
//
// ResetProxyBuffer
//
//-------------------------------------------------------------------------------
extern "C" void ResetProxyBuffer(void)
{
	uint8* proxyPixel = (uint8*)gData->proxyBuffer;

	if (proxyPixel != NULL)
	{
		for (int16 plane = 0; plane < gFilterRecord->planes; plane++)
		{
			gFilterRecord->inLoPlane = plane;
			gFilterRecord->inHiPlane = plane;

			*gResult = gFilterRecord->advanceState();
			if (*gResult != noErr) return;

			uint8* inPixel = (uint8*)gFilterRecord->inData;

			for (int32 y = 0; y < gData->proxyHeight; y++)
			{
				uint8* start = inPixel;

				for (int32 x = 0; x < gData->proxyWidth; x++)
				{
					if (gFilterRecord->depth == 32)
					{
						float * reallyBigPixel = (float*)inPixel;
						if ( *reallyBigPixel > 1.0 )
							*reallyBigPixel = 1.0;
						if ( *reallyBigPixel < 0.0 )
							*reallyBigPixel = 0.0;
						*proxyPixel = (uint8)(*reallyBigPixel * 255);
inPixel+=4;
					} else if (gFilterRecord->depth == 16)
					{
						uint16* bigPixel = (uint16*)inPixel;
						*proxyPixel = (uint8)(*bigPixel * 10 / 1285);
						inPixel+=2;
					}
					else
					{
						*proxyPixel = *inPixel;
						inPixel++;
					}
					proxyPixel++;
				}
				inPixel = start + gFilterRecord->inRowBytes;
				// inPixel += (gFilterRecord->inRowBytes - gData->proxyWidth);
				// if (gFilterRecord->depth == 16)
				//	inPixel -= gData->proxyWidth;
			}
		}
	}
}



//-------------------------------------------------------------------------------
//
// UpdateProxyBuffer
//
//-------------------------------------------------------------------------------
extern "C" void UpdateProxyBuffer(void)
{
	Ptr localData = gData->proxyBuffer;

	if (localData != NULL)
	{
		UpdateDissolveBuffer(gData->proxyWidth, gData->proxyHeight);
		for (int16 plane = 0; plane < gFilterRecord->planes; plane++)
		{
			uint8 color = 255;
			uint16 expectedPlanes = CSPlanesFromMode(gFilterRecord->imageMode, 0); 
			if (plane < expectedPlanes)
				color = gData->color[plane];

			color=(uint8)plane;
			DissolveRectangle(localData, 
			gData->proxyWidth, 
			gFilterRecord->maskData, 
			gFilterRecord->maskRowBytes, 
			gData->proxyRect, 
				color,
				8);
			localData += (gData->proxyPlaneSize);
		}
	}
}



//-------------------------------------------------------------------------------
//
// DeleteProxyBuffer
//
//-------------------------------------------------------------------------------
void DeleteProxyBuffer(void)
{
	gFilterRecord->bufferProcs->unlockProc(gData->proxyBufferID);
	gFilterRecord->bufferProcs->freeProc(gData->proxyBufferID);
	gData->proxyBufferID = NULL;
	gData->proxyBuffer = NULL;
}



//-------------------------------------------------------------------------------
//
// DisplayPixelsMode
//
// Convert the imageMode into a display mode so we can use displayPixels.
// All of the 16 bit data is converted to 8 bit.
//
//-------------------------------------------------------------------------------
int32 DisplayPixelsMode(int16 mode)
{
	int32 returnMode = mode;
	switch (mode)
	{
		case plugInModeGray16:
		case plugInModeGray32:
			returnMode = plugInModeGrayScale;
			break;
		case plugInModeRGB96:
		case plugInModeRGB48:
			returnMode = plugInModeRGBColor;
			break;
		case plugInModeLab48:
			returnMode = plugInModeLabColor;
			break;
		case plugInModeCMYK64:
			returnMode = plugInModeCMYKColor;
			break;
		case plugInModeDeepMultichannel:
			returnMode = plugInModeMultichannel;
			break;
		case plugInModeDuotone16:
			returnMode = plugInModeDuotone;
			break;
	}
	return (returnMode);
}
// end Dissolve.cpp


TOPプログラマ専用Photoshopプラグイン開発

魔女っ子のヘアバンドメイナの実験場~ユ○ティちゃん衣装を脱いだイラスト版~メイナの実験場~ユ○ティちゃん衣装を脱いだイラスト版~