Plugin Development Considerations
The development of Photoshop plugins, as well as any type of computer graphics software, requires certain key aspects to be taken into consideration. This article will discuss some of them in detail based on my experience, and explain why they are important. While this article has been written with Photoshop plugins in mind, it is applicable to any type of software / interface design.
Putting the technology aside, good interface design is quite possibly the single most important feature of any software, especially in Photoshop plugin development. A poorly designed interface can make the most powerful software virtually unusable. Understanding how to properly design and layout an interface is crucial, especially when taking into account the workflow required.
As much as this is a no brainer, it needs to be repeated: effective software interfaces should be designed in a logical manner. A considerable amount of pre-planning is about as important here as storyboarding is to a film. More often than not, various interface mock-ups may need to be designed in order to see which one works best. Even long after controls have been dropped into an interface and the plugin developed near completion, the interface will continue to evolve until it has been organized to be in its most logical and effective layout possible.
It’s important to break down what your software will do so as to know how to design the optimal interface for it. For example, Lumiere is a powerful plugin for creating sophisticated glows for Adobe Photoshop. The plugin works by selecting a set of pixels above a brightness tolerance level, diffusing the pixels and compositing them back on top of the source image. It’s of no coincidence that the interface has been broken down into three control groups that provide specific tools for each of these steps: selection, diffusion and output.
Each of these control groups focuses on features specific to that particular step. The control groups are bundled together within a group box and labeled accordingly. They are even presented in the order that the functions occur – first selection, then diffusion and finally output.
Since we’ve established that our control groups will handle local controllers for those specific functions, we’ll follow logic and place global controllers outside of control groups. What this does is establish to the user that local controllers affect specific functions whereas global controllers affect the entire effect as a whole.
A good example of local vs global controllers is seen in the Ultraflares interface. The controls on the right side are specific to each flare object and will be disabled if no object has been added. A scale control will scale that particular object only. Conversely, the global controls on the left side, specifically labeled global parameters, affect the entire effect. A global scale controller in this section will scale all objects at once.
Establishing this kind of interface logic benefits both you and the user in the long run. The user will be able to effortlessly pick up your other software as they now understand the logic behind your interface design structure. For the developer, it establishes a defined workflow that ties all their software together, thereby providing consistency between products.
Just like the principles of design, controller sizing is another important technique in establishing controller importance. For example, it could be argued that possibly the most important controls found within a software are those that apply or cancel the effect. For this reason, these buttons should be larger than the rest and placed in a prominent area so that they are easily accessible and clearly visible. MBL PRO features a Render Preview that is accessed frequently to toggle a live preview on and off. It is the most often used control on the interface. As a result, it has been placed first where it is most easily accessible, most clearly seen and larger than most so as to establish its importance in the software’s usage.
Controller color coding is another way to group important or interdependent controls together. In Ultraflares, the multi-iris object unlocks a groups of 11 grey-colored controls. Similarly, the object distance controllers have been color-coded green to signify that they work together.
In DOF PRO, toggling the aperture size limit from 45 to 255 colors the controller red to suggest use with caution (shown here disabled). Enabling and disabling controllers also helps tremendously in effective interface design. A typical case is shown below in the depth control group where specifying an alternate depth mode will enable or disable select controllers. This helps educate the user as to which controllers work in tandem with any particular mode. You can see this is not the only control group that features enabled and disabled controllers.
Good interface design makes the most out of limited space. Screen ‘real estate’ is a commodity and, when developing interfaces, you’ll easily run out of space sooner or later. Plugins are even more challenging as they tend to use a smaller interface window overlaid on top of the existing host’s UI.
While it may be tempting to simply make the interface larger, you’ll run into user compatibility issues doing this. Every user works at different screen resolutions and aspect ratios. Dual monitor setups produce unique spanned desktop resolutions and aspect ratios not previously anticipated. Additionally, laptops have smaller screens and therefore lower resolutions. Even those with with high resolution displays typically have the font size adjusted to a larger than default value which also messes with the interface.
Keeping the interface as small as possible will ensure maximum compatibility with as many systems as possible. A resizable interface is the best compromise as the user can decide how large to set it according to their own limitations. Ultraflares features a huge interface and therefore uses several tricks to optimize the space as best as possible. For example, when enlarging the interface beyond a certain width, the global parameters will shift over and drop, allowing the preview window to enlarge. Additionally, the user is able to close the flare browser, also allowing the preview window to enlarge instead of wasting precious space.
Sometimes, it’s effective to display useful information pertaining to the plugin performance. Ultraflares displays the number of cores a system has, while Lattice goes much more in depth and displays object types, points, lines, effectors and even frames per second. This type of statistical information combined with performance details allows the user to understand how bottlenecks affect the software, and in turn, how to avoid them.
Resolution checking should always be performed. What if the user’s laptop screen resolution is set to 1024×600 but your software interface runs at 1280×720? The user would be unable to access some of the controls on the interface rendering it unusable. Even worse, the OK and CANCEL buttons usually located at the bottom of the screen could be inaccessible thereby providing no way to quit the application and requiring a forced shutdown.
Enlarged font size in Windows also enlarges the interface and sometimes pushes it beyond its limits. This is different because the interface may be adhering to the specified resolution limits but the enlarged text pushes it beyond that. This is tricky to check.
Interface color scheme is an often debated subject in the computer graphics industry. Many professionals, myself included, prefer a darker interface as it’s easier on the eyes and allows one to focus exclusively on the image intensity and colors without competing against the app interface. Many app developers made a conscious shift to a darker interface years ago for this reason, such as Adobe, Autodesk, The Foundry, etc.
However, programmatically changing interface colors is a somewhat complicated task. While changing background interface color can be done with one line of code, certain elements such as push buttons, drop down menus, list boxes, etc, cannot be changed from the default Windows color, or have limitations on what details can be modified. This restriction was most likely done on purpose so as to maintain consistency between apps on the Windows environment. The workaround to this is to create custom buttons using ownerdraw controllers and substitute standard dropdown menus with context menus for instance, once again, requiring a custom created context menu button of a darker color. Sometimes these buttons have to be designed programmatically line by line requiring more lines of code than for the actual plugin function! Alternately, some developers have opted to create bitmap buttons instead. This requires embedding bitmaps into the compiled file which results in larger file sizes. Additionally, text cannot be modified as it is baked into the bitmap. Finally, separate button bitmaps must be created for hover, active, and inactive states. While all of this is possible, it is certainly tedious and laborious work often not worth the complete redesign of an interface.
It’s easy to get carried away with branding. Developers have the ability, after all, to place a bitmap instead of a background color in the interface. But more often than not, the old KISS methodology stands true: Keep It Simple Stupid. Busily branded backgrounds more often than not clutter an interface and draw attention away from the important parts. Bright or saturated interface bitmaps are harder on the eyes and often make it difficult to easily see specific controllers that may become hidden or masked by the bright colors. This translates to a slower workflow for the user. The controls are, after all, the most important part of an interface so why minimize their significance via a flashy background that serves no functional purpose?
Windows themes can also affect the interface layout and design. There is a significant difference, for example, between the Windows XP standard theme and the Windows 7 Aero theme. Every interface element gets changed to a more modern look. Themes can be enabled or disabled in the development of the interface, as a whole or even on a per-controller basis. While a more recent theme may provide a more modern look and feel, it also produces incompatibility issues with older operating systems such as running an Aero-enabled theme plugin on a Windows XP system that does not have it. In this case, the user will experience a layout with an unpredictable look.
Below is an example of interfaces shown using various Windows themes.
Today’s workstations are fully multithreaded with more and more cores becoming available as CPU technology continues to improve. As a result, multithreading support is an extremely important aspect of plugin / software development. A single threaded plugin will only use approximately 25% of a single CPU core in Photoshop on a quad-core machine. A fully multithreaded plugin will use every physical and virtual CPU core to its full extent: 100% The difference in speed is substantial. It is even possible to provide the user with affinity control so as to select specific cores for rendering with. This can allow the user to disable the primary core which tends to make the system sluggish during heavy processing loads.
More recently, GPU processing has become very exciting. Unlike CPUs that have a maximum number of 12, 24 or 36 cores for example, GPUs have literally thousands of cores available. The GeForce GTX 1080 Ti, for example, has 3584 NVIDIA cores available. While it is impossible to compare the performance of CPU cores to GPU cores, the speed differences are astounding. 3D renders which make use of the GPU for rendering are sometimes hundreds, if not thousands, of times faster than their CPU counterparts, depending on the task.
If your SDK provides tools for offloading calculations onto the GPU, it is highly recommended.
64 bit vs 32 bit is another important consideration. 32 bit technology is over a decade old and it has the limitation of being unable to access more than 4GB of system RAM, per app. This is a critical limitation in computer graphics and image procession when we are dealing with millions of pixels that depend specifically on RAM resources.
There are many other performance considerations to factor in that are more code-related. Some of these include avoiding division whenever possible, pre-computing variables outside of nested loops and only iterating through visible pixels within the preview window as opposed to hidden pixels lying outside the visible range of the preview window.
Hobbyists using Photoshop, After Effects or any other graphics app will most likely never go near the color depth options. Any professional, on the other hand, understands that working in a high color depth will result in significantly greater latitude for image processing and color grading.
The standard 8 bits per channel color depth provides you with 255 shades of red, green and blue. A 16 bits per channel color depth provides you with 32767 (or 32768 in Photoshop’s case) shades of red, green and blue. While 8 bits per channel may seem like it’s enough, it yields 8x8x8=24, 2^24=16,777,216 colors which results in some banding in subtle gradients. 16 bits per channel yields 16x16x16=48, 2^48=281.5 trillion colors. The industry standard color depth for 3D graphics is even higher – it is 32 bits per channel, also known as floating point. While Photoshop supports 32 bits per channel, only certain filters and functions are supported in this color depth.
One has to work with 32 bits per channel to truly understand how powerful it is. 3D renders that are completely overexposed in some areas can be fully restored to a legal white complete with their appropriate shading using 32 bits per channel color depth correction tools. With any other color depth, reducing an overexposed white will result in flat grey because the original color information beyond 255 or 32767 has been clipped and lost.
Jumping back to our discussion at hand, it’s important to provide at least 8 and 16 bits per channel color depth for any software intended for professional use. The function of the plugin, of course, will also dictate whether this is necessary or not. For example, software that produces a solid color shape will not benefit from any color depth greater than 8 bits per channel. As a matter of fact, an even lower color depth would suffice in this case. Likewise, software that produces a posterize effect (crushes an image’s color palette to a specified number of limited colours such as 4), will also not benefit from any color depth greater than 8 bits per channel. Conversely, software such as Ultraflares or Lumiere that produces fully shaded, intricately-coloured and variably-transparent effects will most definitely benefit from a higher color depth such as 16 bits per channel.
The Long Shadow plugin is an excellent example of this. It supports a feature where the shadow can be faded over distance. In 8 bits per channel mode, there are only 256 levels of transparency, while in 16 bits per channel mode there are 32767 thereby producing a much smoother fade.
An even more important factor to consider with color depth is when an image is of a particular color depth – let’s say 16 bits per channel, and the plugin supported color depth is of another – let’s say 8 bits per channel. In this case, either the plugin would have to be modified to support 16 bits per channel or the image would have to be converted to 8 bits per channel, thereby destroying all 16 bits per channel color information. There is no going back from this. A useful analogy would be like down-scaling an image and then trying to scale it back up to its original size once it’s been saved. Once an image has been down-sampled, the information is forever lost and it cannot be recovered. Scaling it back up will result in a blurry image. The same applies to down-sampling color depth.
What this means is that any knowledgeable professional will not sacrifice their image’s color depth so as to be able to use a plugin. In cases such as these, it will result in lost sales so it’s important to seriously consider the labor required in supporting multiple color depths.
There are basically two ways to programmatically handle multiple color depths.
One is to develop multiple functions for each color depth. This is sloppy and requires the duplication of code for each color depth resulting in far more code than is necessary.
The other is to handle all internal code as floating point, from 0.0-1.0 and scale to the appropriate color depth on output. This requires having only one master code that is flexible and can be easily scaled not just to 8 or 16 bits per channel, but also to any other color depth in the future.
There are many other considerations to factor into software development but we’ve covered some of the more important ones. As with design, these are guidelines, not rules. Ultimately, it’s up to you how you want to design your interface but in the end it should be logical and easy to use for all users. A well designed interface makes any software a pleasure to use.