WinImages F/x R7 Beta Program
WinImages: Another fine product from Black Belt Systems

Effects Plug-In Development

Easy-Plug
Clean - Fast - Easy!

Does the world really need another plug-in effects format?

Yes! It does - and we'll show you why!

A message to plug-in developers and potential plug-in developers

Please send your comments to: support@blackbeltsystems.com


Why should you concern yourself with this?

First of all, as a developer, you may be able to benefit directly from a truly easy to use plug-in format. But we're offering something immediately tangible as well:

If you are not currently a WinImages owner and you provide a suggestion we use, in return we'll provide you with a registered copy of the software, a $400 retail value.

If you already own it, we'll give you your next 2 upgrades free instead. That will include WinImages R7, the first version to support plug-ins.

WinImages is VERY powerful, and odds are you'll have a lot of fun with it. It does a lot more than Photoshop does, for instance, in many of the same venues - and it does many things in areas that Photoshop doesn't even address.


Black Belt Systems has designed a new effects plug-in format that is designed to be easy - very easy - for a programmer to approach; the idea is that it should take just a few minutes to code up something reasonable, and only a few seconds to code up something like "fill with black". If you've ever done Photoshop-style effects plug ins, you know that the documentation for these is quite deep and they are very much non-trivial to implement - you won't be whipping a brand new one out in a day!

But that's exactly what we'd like to accomplish - in fact, we'd like you to be able to whip one out in a few minutes. That's why it is worthwhile to create the new format - because it makes plug-in building extremely accessible.

In order to pull this off, we've been focused on the idea that the application should do as much as possible for the developer; that leaves you free to build cool stuff, and not screw with the user interface or a bunch of handshaking, maintenance, C++ classes, and etc. We animate everything for you if the user wants to animate, and we save and load all your settings automatically too. We even clean up your memory and image allocations for you if you forget, so you won't "leak." :-) Not only that, but we even script your plug-in without you having to lift a finger - so the user can do some amazing things, algorithmically driven. That's a whole bunch of stuff you won't have to do every time you write a plug-in.

This is not only good for you, as a developer, but it's also good for the users. Reduced complexity in all of those areas means:

Plug-in design is clean - it's easy - and it's fast.

Sound like something you'd like to get into? Then read on...

The plug in format itself is open, and we intend to provide incentive for developers to make plug-ins.

More Incentives?

Yes! We'll provide a free linked listing right on our website, where tens of thousands of WinImages owners can easily locate your product(s). That can link right to your website, where you can sell or give away the plugins.

Or, if you like, we will provide a VIRUS-FREE certification for plug-ins that:

  • Go through our free technical certification process
  • Are downloaded directly From our site
  • Are marketed directly through our site's secure server system

If these benefits interest you, then consider designing plug-ins using Easy-Plug!

We've got the system up and going now, and the initial feedback from our developers is good. You really CAN create a plug-in from scratch in minutes, and it'll be shippable - it really only depends on how complex the actual code to handle the image(s) is. Obviously, if the plug-in is a ray tracer, you'll be working on it for a while. :-) But if you wanted (for instance) to do a contrast or color fill plug-in, you could have it complete, ready to go, from scratch, in under a minute. Seriously.

Now, we'd like to open a discussion with you folks, because you, and people like you, are the general target audience for this.

Basically, we handle the UI for you; we make available a bunch of different things like floats, color wells, palettes, definable graphs, command buttons, integers, switches, text strings and radio buttons. There is very little you need to do to use these; basically, one or two lines of c does setup or fetch the value or update the value. This part we're very happy with, and want to leave as is.

So we're really talking about the "how the developer gets at images and image modification services" part of the plug-in system. We're asking you to assume the UI is handled and that the settings in your plug-in's dialog are trivial to get at (because they really are.)

There are two structures involved; the application passes the plug-in a structure like this: plugin(&plug); if the plug-in wants something from the application, it passes it a structure called a package like this: Svc(&package);

We give you direct, and easy, access to the user's selected image buffers (target, source for compositions, brush, and undo), to geometric warping layers which are a very special case of an image layer, and to selection masks and paths. Everything you are handed is in real memory, you can hit it right away and with no caveats (other than going outside its bounds of course!)

As well as your option to hit the buffers and masks directly, we also provide very easy and quite fast services to write the buffer in any or all of rgb, hsv, hsl spaces, either through the selection mask or raw, and you can read it anywhere in any of those spaces using services as well. Some examples of services in use:

Read RGBA:

struct package p;
  p.service = SVC_RGBr;
  p.img = &plug->ptgt;
  p.x = xposition;
  p.y = yposition;
  Svc(&p);

...returned value is in "p.rgbp"

Write RGBA "anywhere":


struct package p;
  p.service = SVC_RGBw;
  p.img = &plug->ptgt;
  p.x = xposition;
  p.y = yposition;
  p.rgbp = RGBAvalue; // rgbp.r, rgbp.g, rgbp.b, rgbp.a
  Svc(&p);

Write RGBA "thru the selection mask" (if it's masked off, it won't happen; if it's partially masked off, it'll be mixed with the image):


struct package p;
  p.service = SVC_RGBmw;
  p.img = &plug->ptgt;
  p.x = xposition;
  p.y = yposition;
  p.rgbp = RGBAvalue; // rgbp.r, rgbp.g, rgbp.b, rgbp.a
  Svc(&p);

Ask if pixel is included (saves lots of work in some types of plugins:


struct package p;
  p.service = SVC_QUERYMASK;
  p.img = &plug->ptgt;
  p.x = xposition;
  p.y = yposition;
  Svc(&p); // result 0 or 1 in p.v, 1 means selection mask includes this pixel

I can elaborate on any service, all of them are listed below.

We also provide conversion services for color spaces.

We provide services to read and write warp layers, which are special layers that apply geometric distortions to layers beneath them.

There are services to edit palettes, graphs and text files with one call.

Here's the current complete list of services, we would very much appreciate any suggestions for this.

Here is the current list of services and the two structures that are passed back and forth between the plug-in and the application - we'll be happy to answer any questions you might have about them, elaborate, etc.


//// services:

// These are services the plug-in can request
// ------------------------------------------
#define SVC_RESAMPLE	 1	// Take supplied *img, resample to x,y width and return in *img2.
							// These resamples are best when the desired x,y size is twice or less,
							// or, 1/2 or greater. If you need larger or smaller, for best quality,
							// call resample more than once and factor your sizes. It's quite fast.

							// The image(s) obtained this way persist for as long as your
							// plug-in routine lasts or until you dispose of them using SVC_DISPOSE.
                            // You can only dispose of images YOU got, not WinImages own images.
							// When you return to WinImages, your images are disposed of
							// automatically so you don't have to get rid of them unless you feel
                            // that it would free up more memory you no longer need. You can
							// retrieve as many images as you like using this mechanism (based
							// on available memory, of course!) Remember that img2 is a pointer,
							// you'll have to point to a struct pu_image of your own for this to
							// work. Plug-ins are stateless - that's why the images don't persist.

#define SVC_ABOUT		 2	// put up msg as an "About Box" dialog to the user
#define SVC_HSLr		 3	// get hslp (struct HSLA) data at x,y in *img
#define SVC_HSLw		 4	// put hslp (struct HSLA) data at x,y in *img
#define SVC_HSLmw		 5	// put hslp (struct HSLA) data at x,y in *img masked by mask
#define SVC_RGBr		 6	// get rgbp (struct RGBA) data at x,y in *img
#define SVC_RGBw		 7	// put rgbp (struct RGBA) data at x,y in *img
#define SVC_RGBmw		 8	// put rgbp (struct RGBA) data at x,y in *img masked by mask
#define SVC_RGB2HSL		 9	// convert variable rgbp to variable hslp
#define	SVC_HSL2RGB		10	// convert variable hslp to variable rgbp
#define SVC_DISPr		11	// read displacement at x,y in *img (if layer in LMD_WARP mode)
#define	SVC_DISPw		12	// write displacement at x,y in *img (if layer in LMD_WARP mode)
#define	SVC_EDITpal		13	// edit palette 'x' (0 or 1)
#define SVC_EDITpro		14	// edit profile 'x' (0 to 11)

#define	SVC_EDITtxt		15	// edit file specifed as complete path and file in path_file[]
							// if path_file is empty (1st char==0) then will edit new file.

#define	SVC_DISPOSE		16	// dispose of images you got from SVC_RESAMPLE. Use *img2 pointer.

#define	SVC_STROKELEN	17	// returns, in xdisp, the length of any area selection AS a brushstroke,
							// in pixels. Call this BEFORE you call SVC_STROKE so you can ascertain
							// how long the path is and decide how many brush placements you want to
							// make along it.

#define	SVC_STROKE		18	// Set 'x', returns 'x' points along the stroked path using *lp pointer
							// You have to set *img to the image that you want to stroke prior to
							//  calling the service. You only need ONE of these, so you can't call
							// this service more than once. FX will automatically destroy the *lp
							// resource when your plug-in exits.

#define SVC_ALPHASTATE	19	// update image's 'hasalpha' state. x=0=noalpha, x=1=hasalpha
#define SVC_RESET		20	// forces the plug-in to set it's defaults up fresh (overrides stored version)

#define SVC_HSVr		21	// get hslp (struct HSVA) data at x,y in *img
#define SVC_HSVw		22	// put hslp (struct HSVA) data at x,y in *img
#define SVC_HSVmw		23	// put hslp (struct HSVA) data at x,y in *img masked by mask
#define SVC_RGB2HSV		24	// convert variable rgbp to variable hslp
#define	SVC_HSV2RGB		25	// convert variable hslp to variable rgbp
#define SVC_QUERYMASK	26	// ask if *img pixel is completely masked off (0) or not (1), result in x
#define SVC_GETSAMPLE   27  // retrieve the current sample color and sample alpha into rgbp


//// structures:

struct pkg
{
	long				service;		// the service you desire (see plug_defines.h for SVC_ defines)
										// if the service goes ok, will stay the same as you set it on
										// on return of service call. Otherwise set to 0.
	struct pu_image		*img;			// image to be processed by WinImages
	struct pu_image		*img2;			// image to be produced by WinImages or on some calls to be
										// processed, on return, result. We manage storage.
	float				xdisp;			// warp x displacement to be read or written (warp layers only)
	float				ydisp;			// warp y displacement to be read or written (warp layers only)
	struct lineposits	*lp;			// for SVC_STROKE
	long				x,y;			// x and y for various service requests. x is sometimes an ordinal
	long				v;			// returned values
	struct RGBa			rgbp;			// pixel to be read or written in RGBA (non warp layers and images)
	struct HSLa			hslp;			// pixel to be read or written in HSLA (non warp layers and images)
	char				path[200];		// path of text to be edited with QuickEditor
	char				filename[200];	// filename of text to be edited with QuickEditor
	char				msg[200];		// fill with string for About dialog. Use /r/n to break lines.
};

// A plug contains the entire state of a plugin
// --------------------------------------------
struct plug
{
// communications and housekeeping
// -------------------------------
	long			ssize;				// this is the size of the structure as returned by sizeof()
	long			init;				// if non-zero, you need to set all the variables to good defaults
	long			iamok;				// communication back to the caller
	long			fc;					// function code
	long			bhit;				// button hit message (-1 == NO)
	struct pu_image	psrc;				// source image
	struct pu_image	ptgt;				// target image
	struct pu_image	pbru;				// brush image
	struct pu_image	pund;				// undo buffer image
	unsigned char	*msk;				// pointer to mask
	long			mx1;				// area selection details
	long			mx2;
	long			my1;
	long			my2;
	long			mxc;
	long			myc;
	long			areamode;			// area selection mode (see plug_defines.h, ID_A...)
										// segments and xcords and ycords can be used if
										// areamode is any of these:
/*
											ID_Afree
											ID_Apoly
											ID_Ashape
											ID_Aarc
											ID_Aspline
											ID_Abez
*/
										// otherwise, you must use the mask mechanism. Valid during
										// execute, and at no other time.

	long			segments;			// how many points on the line
	long			*xcords;			// x-coordinate list
	long			*ycords;			// y-coordinate list
	unsigned char	refresh[100];		// series of flags - non-zero means please redraw this element
	unsigned char	enables[100];		// series of flags - non-zero is enabled (see plug_objects.h)
	char			errors[200];		// non error, [0]=0. Error, fill with string. Use /r/n to break lines.

	// labels for various things
	// -------------------------
	char			r1[8][32];			// the labels for all the radio sub-buttons...
	char			r2[4][32];			// ...
	char			r3[4][32];			// ...
	char			r4[2][32];			// ...
	char			r5[2][32];			// ...
	char			a1[2][32];			// palette names
	char			labels[100][32];	// names for the various objects in the dialog (see plug_objects.h)
	char			g1[12][32];			// profile names

	// Everything below here is stored by WinImages in an ini file for your plug-in
	// ============================================================================
	char			na[32];				// plugin NAME (each plugin you make should have a unique name)
	long			version;			// version (must match for stored settings to be used by FX
	long			revision;			// revision (must match for stored settings to be used by FX
	// -----------------------------------------------------------------
	// developer number (we assign these to you, free - they are unique)
	// E-MAIL us at:   support@blackbeltsystems.com with your company or
	// organization or personal name, and we'll return your FREE developer
	// number. This number allows WinImages to tell your plugs from
	// someone else's even if they have the same name. The benefit is
	// that WinImages saves the settings for each plugin for the
	// user - so it needs to be able to uniquely identify
	// each plugin.
	// -----------------------------------------------------------------
	long			dev_key;
	// -----------------------------------------------------------------

	// Plug-in variables
	// -----------------
	struct RGBa		c[4];				// the colors
	long			t[4];				// the isolated transparency for the colors
	long			l[8];				// the integers
	long			cmin[8];			// current minimum setting for trends
	long			cmax[8];			// current maximum setting for trends
	long			amin[8];			// absolute minimum setting for trends
	long			amax[8];			// absolute maximum setting for trends
	float			f[8];				// the floats
	long			s[8];				// the switches
	long			r[5];				// the radiobuttons
	char			x[2][200];			// string variables
	struct palette	a[2];				// palettes 0 and 1			(see spalette.h for def)
	struct proffer  g[12];				// profiles 0 through 11	(see spalette.h for def)
};