search
HomeWeb Front-endPS TutorialIntroduction to Photoshop filter development--Photoshop callback function

In the previous article, we introduced some of the most basic concepts and foundations for developing Photoshop filter plug-ins. Ps In order to meet the application needs of the plug-in, it also provides a large number of callback functions (or services) for the plug-in. For example, a filter can save the parameters set by the latest user after a call and apply them to the next call or display of the UI. This is done through the callback function of Ps. In this article we will explain some of the most important PS callback functions. After understanding this article, we will be able to use callback functions to complete the necessary work such as storing our filter parameters. This article will be much more complex and in-depth than the first one, but at the same time, from this article we can also get a glimpse of the internal secrets of PS: careful system design, perfect interface and complex working mechanism.

(1) Classification of callback functions:
The callback functions of PS can be divided into two types according to the location of obtaining them:
(1) Direct Callback: (can Directly called callback functions)
These callback functions are direct members of FilterRecord and can be obtained directly from the FilterRecord parameters. For example, AdvanceStateProc (update data), TestAbortProc (test user cancels), etc., fall into this category.
(2) CallBack Suite: (Receiving function set)
The recovery function set provided by the transfer function according to the function classification is a set of a set of callback functions. It is a pointer, which contains a set of sets The structure (struct) of the callback function, we can get a certain callback function set from FilterRecord, and then call the function in it.

The main callback function sets currently provided are:
Buffer Suite: Cache memory management (application and release of cache space).
UI Hook Suite: A set of functions related to UI operations.
Channel Ports Suite: Channel port reading and writing, used to read and write the real selection data inside PS! Rather than a copy copy.
            Descriptor Suite: Descriptor operation set, used for script recording systems, which itself contains two sub-suites (sub-function sets): "read" and "write".
Color Space Suite: Color space services (color conversion, etc.).
          Handle Suite: Handle management (PS encapsulated handle and memory management, similar to Buffer suite).
Error Suite: Receive and display error messages to users (receives different types of error message strings).
GetFileList Suite: Get the file list (get files, call the browser to browse the web, etc.).
GetPath Suite: Get the path.
ZString Suite: Encapsulates string processing.

For example, UI Hook Suite provides a set of callback functions related to UI. Its first version was defined as:

UI Hooks Suite Version1
#define kPSUIHooksSuiteVersion1 1 // suite version
typedef
struct
{
ProcessEventProc processEvent;
DisplayPixelsProc displayPixels;
ProgressProc progressBar;
TestAbortProc testAbort;
MainAppWindowProc MainAppWindow;
HostSetCursorProc SetCursor;
HostTickCountProc TickCount;
PluginNameProc GetPluginName;
} PSUIHooksSuite1;

# Please note that some callback functions are direct callbacks and are stored in a suite , such as testAbout and displayPixels. I speculate that in the early days, these function pointers were added to FilterRecord, but with the upgrade, more and more callback functions were added, which would cause FilterRecord to continuously upgrade and add members, making maintenance difficult, so Adobe began to add callback functions Classification is divided into several suites, and only the suite is placed in FilterRecord. In this way, when adding a function, you only need to add it to the corresponding suite and upgrade the suite without affecting the FilterRecord. In this way, some early callback functions are located in two places at the same time, FilterRecord and the suite to which they belong, so that they can be called directly or through the corresponding suite.


(2) Suite PEA (Plug-in function set management module (layer), my translated name, to be discussed) Suite PEA is a plug-in system used by some Adobe series software. It provides a common plug-in management core layer for the host program and a standard interface for plug-ins.
It is slightly different from the direct call in that the function set should be acquired (Acquired) before use, and the suite should be released (release) after use.
                                                                                     
                                                                                                                                                                                                  # );

Therefore, a function in the callback function set is called, in the following form:

Suite的获取和释放
ADMBasicSuite *sADMBasic;

//获取ADMBasic Suite:
filterParamBlock->sSPBasic->AcquireSuite(
              kADMBasicSuite,
              kADMBasicSuiteVersion,
              
&sADMBasic );

//调用
sADMBasic->Beep( );

//释放
filterParamBlock->sSPBasic->ReleaseSuite(
               kADMBasicSuite,
               kADMBasicSuiteVersion );


# (3) Part of the more important callback function profile

This Here we will introduce some recovery functions that I think are more important for the filter plug -in . Briefly introduce the location and use of these callback functions.
3.1 DisplayPixelsProc( )
Function: Output pixel data (draw a picture) at the specified position on the specified DC. (Of course, we can actually complete this function ourselves.)
Location: Direct Callback, UI Hook Suite;
Definition:
OSErr (*DisplayPixelsProc) (const PSPixelMap *source ,
CONST VRECT *SRCRECT, Int32 DStrow, Int32 DStcol,
UNSIGNED32 PlatformContext);
## Source Instructions:
Source: The first parameter is a structure that describes pixel information (PSPIXELMAP). pointer, which is defined as follows:

PSPixelMap Struct Define

typedef struct PSPixelMap{
int32 version; /
Version number                                                                                                                 # int32 imageMode; //
Mode
## int32 rowBytes; / /Scan line width
# int32 colBytes;       //Number of column bytes
int32 planeBytes; //Number of bytes per channel
void
*
baseAddr; //Pixel data starting address
//
--------------------// Omitted .. } PSPixelMap;
          srcRect: Source rectangle (copy range of the source image)
      dstRow, dstCol: Target starting point coordinates (upper left corner), because it is not stretched and drawn, so only the coordinates of the upper left corner are enough.
           platformContext: Under Windows system, that is, device context (DC);

3.2 Descriptor suite (descriptor function set)
The descriptor set is mainly used for the script system of PS. It is used to record (record) the information and parameters required during a series of actions in PS, and can be played back. It is divided into two sub-function sets: "read" and "write". We can use this function set to make PS's scripting system "know" our filters and record them into an action sequence.
The way to obtain it is to first get PIDescriptorParameters through FilterRecord:

PIDescriptorParameters Struct Define
typedef struct PIDescriptorParameters
{
int16 descriptorParametersVersion;
//Version number
## int16 playInfo; // Action playback identification: 0-dialog box optional; 1-dialog box required; 2-no dialog box;
## int16 recordInfo;
//Action recording identification: 0-The dialog box is not displayed; 1-The dialog box is displayed; 2-The dialog box is silent; ## PIDescriptorHandle descriptor;
//The handle of the descriptor is very important, we will use it to read and write data! ## WriteDescriptorProcs
*
writeDescriptorProcs; //"Write" sub-function Set## ReadDescriptorProcs*
readDescriptorProcs; //"read" sub Function set} PIDescriptorParameters;
Then we can get the "read" or "write" sub-function set:

Get the "read" and "write" sub-suite
//Get the descriptor parameter structure:
PIDescriptorParameters*## descParams = gFilterRecord- >descriptorParameters;
if (descParams == NULL) return err;

##//
Get the "read" sub-function set:
ReadDescriptorProcs
*## readProcs = gFilterRecord->descriptorParameters ->readDescriptorProcs; if
(readProcs == NULL) return err;
//
Get the "write" sub-function set: WriteDescriptorProcs
* writeProcs = gFilterRecord-> descriptorParameters->writeDescriptorProcs; if
(writeProcs == NULL) return err;
Having obtained two sub-function sets, we can call the functions under the corresponding sub-function sets to "read" and "write" our parameters. The use of the two sub-function sets is similar to the registry operation. Before reading and writing, we first need to open the corresponding descriptor. Therefore we first introduce the opening and closing descriptor operations.
      OpenReadDescriptorProc( ): Open a "read" descriptor
      Definition:
        PIReadDescriptor (*OpenReadDescriptorProc) (PIDescriptorHandle, DescriptorKeyIDArray);
            Parameter description:  
PIDescriptorHandle:
Descriptor handle, we will use it to read and write data in subsequent operations, similar to the Key of the registry.
        DescriptorKeyIDArray:
                uint32 array, stores the key set that needs to be queried.其相关定义为:
                  typedef unsigned long DescriptorKeyID;
                  typedef DescriptorKeyID DescriptorKeyIDArray[];

The elements in the array are the key names you need, that is, the parameter names you want to query, that is, which keys you want to query. Note that because it is an int32 type, each key can hold an ASCII code represented by 4 characters. If it is less than 4 bytes, it can be filled with spaces. For example, setting this parameter assignment can set {'Pam1','Pam2',NULL}, which means you need to query two parameters, 'Pam1' and 'Pam2'. For example, in the script system, the key of the Gaussian Blur (GaussianBlur) filter is 'GsnB'.
Each key value is obtained by calling GetKeyProc(). Each time a value is returned, the corresponding key in this string array will be set to empty ('\0'). Under normal circumstances, when you call CloseReadDescriptorProc(), this array will become all empty. Otherwise, it means that some keys have not been queried. At this time, you will lose your data or display the dialog box. Ask users to provide data.

##           CloseReadDescriptorProc(): Close a "read" descriptor     Definition:
     OSErr (*CloseReadDescriptorProc) (PIReadDescriptor);

Description; Close a descriptor. If an error occurs during reading, it will return the main error.


        GetKeyProc( ): Get a Key
        Definition:
           
(*GetKeyProc) (PIReadDescriptor descriptor, DescriptorKeyID *key, DescType *type, int16 *flags); Description: This function returns a KeyID (parameter name), descriptor type, and identification. According to the key returned by the function, it indicates which key is currently queried. We can then use the corresponding query function mentioned below to obtain the value of this key. Related type definitions:

     typedef unsigned long DescriptorKeyID;    typedef unsigned long DescriptorTypeID;

                                                                                       Definition: PIWriteDescriptor (*OpenWriteDescriptorProc) (void);
Description: Open a write descriptor, if failed, return NULL;CloseWriteDescriptorProc()
Definition:
OSErr ( *CloseWriteDescriptorProc) (PIWriteDescriptor descriptor, PIDescriptorHandle *newDescriptor);
Description:
This function closes a write descriptor and creates a new descriptor handle. You need to set the new descriptor to PIDescriptorParameteres to return it to the host program. The behavior of the function here is somewhat similar to SelectObject in GDI operations. In a GDI operation, when you set new properties on the device context, it returns the existing properties to you, expecting you to make a backup.

                                                                                                                                                                              ‐                                       ’ ’ s ’ s ’ s ’ s to ’ s ’ s               ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ​ ​ ​ ​ ​ ​ ​ ​I will explain them one by one. Here I only introduce the general form and explain them separately when necessary.                                                                                                                                                                                                                                             Most have relatively standardized characteristics (there are a few functions with exception forms, which we will introduce separately later), that is, reading starts with Get, writing starts with Put, the first parameter is the corresponding descriptor, and the second parameter is The corresponding type of data pointer used to receive query results (or to store written data). Assuming that the data type we need to query is TypeName, it is as follows:
      OSErr (*
Get
TypeName

Proc) (PIReadDescriptor descriptor, TypeName *dest); //Read OSErr (*PutTypeName
Proc) (PIWriteDescriptor descriptor,
DescriptorKeiD, Typename * Dest); // Write: Below we list the functions of all readable functions and write sub -function sets (at pilation. h): Read Descriptor sub-suite

##Code highlighting produced by Actipro CodeHighlighter (freeware)http:// www.php.cn/-->
////写子函数集成员,形式类似前面的函数,但都额外需要提供key
typedef struct WriteDescriptorProcs
 {
 int16 writeDescriptorProcsVersion;
 int16 numWriteDescriptorProcs;
 OpenWriteDescriptorProc  openWriteDescriptorProc;
 CloseWriteDescriptorProc closeWriteDescriptorProc;
 PutIntegerProc    putIntegerProc;
 PutFloatProc    putFloatProc;
 PutUnitFloatProc   putUnitFloatProc;
 PutBooleanProc    putBooleanProc;
 PutTextProc     putTextProc;
 PutAliasProc    putAliasProc;
 PutEnumeratedProc   putEnumeratedProc;
 PutClassProc    putClassProc;
 PutSimpleReferenceProc  putSimpleReferenceProc;
 PutObjectProc    putObjectProc;
 PutCountProc    putCountProc; 
 PutStringProc    putStringProc; 
 
/* Scoped classes are not for use by plug-ins in Photoshop 4.0 */
  PutScopedClassProc   putScopedClassProc;
 PutScopedObjectProc   putScopedObjectProc; 
 } WriteDescriptorProcs;


Reading and writing parameter examples:
Reading parameters from the script system: Suppose the key of our parameter is 'Pam1', we use a temporary variable param1 to receive it:

Read A Parameter Demo Code
PIReadDescriptor token = NULL; //Read operator
DescriptorKeyID key = NULL; //uint32, that is, char*, Key name
DescriptorTypeID type = NULL; //Descriptor Type
int32 flags = 0; #//Identification# DescriptorKeyIDArray array
= { 'Pam1', NULL }; //The key set to be queried
double param1; //The parameters we want to read //
Get the descriptor parameter structure## PIDescriptorParameters
*
descParams = gFilterRecord->descriptorParameters;     if
(descParams  
== NULL) return err; //
Get the "read" sub-function in Descriptor Suite Set
## ReadDescriptorProcs*
readProcs = gFilterRecord->descriptorParameters->readDescriptorProcs;     if (readProcs  
== NULL) return err;
if (descParams->descriptor != NULL)
{
         
//Open the "read" descriptor
##                                                   1 readProcs->openReadDescriptorProc(descParams->descriptor, array);        if
(token
!= NULL)                                                                                                                                     
##            
while(readProcs->
getKeyProc(token,
&key, &type, &#flags) && !err)                                                                                                                                                 ##             case 'Pam1
'
:/ /
Read our parameters
##                                                                                                                                                    >getFloatProc(token, &param1);                                                              #default:                                                                                                                                                                                                     Since #                                                                                                                                         

            err = readProcs->closeReadDescriptorProc(token);
            
//释放描述符
            gFilterRecord->handleProcs->disposeProc(descParams->descriptor);
            descParams
->descriptor = NULL;
        }
   }

        向脚本系统写入参数:同上面的例子:

Write Descriptor Demo Code
    OSErr err = noErr;
    PIWriteDescriptor token 
= NULL;
    PIDescriptorHandle h;
    const
double param1 = 1.05;

    PIDescriptorParameters
*    descParams = gFilterRecord->descriptorParameters;
    
if (descParams == NULL) return err;
    
    WriteDescriptorProcs
* writeProcs = gFilterRecord->descriptorParameters->writeDescriptorProcs;
    
if (writeProcs == NULL) return err;

    token 
= writeProcs->openWriteDescriptorProc();
    
if (token != NULL)
    {
        //写入参数~
        writeProcs
->putFloatProc(token,'Pam1',&param1);
        //释放描述符

        gFilterRecord
->handleProcs->disposeProc(descParams->descriptor);
        //关闭该“读”描述符
        writeProcs
->closeWriteDescriptorProc(token, &h);
        //把新的描述符返还给photoshop
        descParams
->descriptor = h;
    }


3.3 DescriptorRegistry suite: (Descriptor registration function set)
The descriptor registration function set is mainly used for the registration and acquisition of descriptors. This allows ps to be entrusted to save our parameters while the filter is called multiple times. It contains several key functions for registration, removal, and key acquisition.
      Register()
                                                                                                                                                                                                                                                                         .
                                                                                                                # or descriptor, //Descriptor handle
                                                                                                                                                                                                                                                                                             Remove a Key Definition:
OSErr (*Erase)
(
) /* IN */ const char* key // Unique string or ID
);
##Get()
Description: Returns a Key. The returned descriptor is a copy, so you must actively release it after use.
                                                                                                                                                         /* OUT */ PIActionDescriptor* descriptor / / Release him after use
);




3.4 ActionDescriptor suite: (Action descriptor function set)

## Action Descriptor function set,
is used to store keys (or objects) into descriptors, read them from descriptors, and other descriptor management. This function set contains both read and write functions, and the usage method is similar to the descriptor in the previous section. It is defined as follows:



PSActionDescriptorProcs Struct



Code highlighting produced by Actipro CodeHighlighter (freeware)http:// www.php.cn/-->typedef
struct
PSActionDescriptorProcs
{

 //
ALLOCATES: descriptor//Write parameters and register
SPErr WriteRegistryParameters(void)
{
SPErr err
= noErr;
#// Obtain SPBasicSuite, which is the basis for obtaining other Suites
## SPBasicSuite* basicSuite = gFilterRecord->sSPBasic;
// Descriptor registration function set pointer
## PSDescriptorRegistryProcs
*## registryProcs = NULL; //
Descriptor function set pointer PSActionDescriptorProcs
* descriptorProcs = NULL; //
Descriptor handle PIActionDescriptor descriptor
= NULL; //
Our parameters
double param1=0.1;
//
Get the descriptor registration function set err
= basicSuite->AcquireSuite(kPSDescriptorRegistrySuite,                                                       (const

void **)&registryProcs);//Get the action descriptor function set
## err = basicSuite ->AcquireSuite(kPSActionDescriptorSuite,                                                      (

const
void **)&descriptorProcs);                                                                                               ## descriptorProcs

->
Make(&descriptor); //Write us Parameters err =
descriptorProcs
->
PutFloat(descriptor, 'Pam1',param1); //Register the descriptor of the specified ID err = registryProcs- >Register(plugInUniqueID, descriptor, true);
//
Release descriptor

if
(descriptor
!= NULL) descriptorProcs->Free (descriptor);
//Release function set
if
(registryProcs
!= NULL) basicSuite->ReleaseSuite(kPSDescriptorRegistrySuite, kPSDescriptorRegi strySuiteVersion);
      
if (descriptorProcs 

!=
NULL)           basicSuite->ReleaseSuite(kPSActionDescriptorSuite,                                                                                                                                                                                                                                                      Example of reading our parameters:

Reading registered parameters
//Read registered parameters
SPErr ReadRegistryParameters(void)
{
SPErr err
= noErr;
/ /Get the basic function set, SPBasicSuite, and get other function sets through it
SPBasicSuite* basicSuite = gFilterRecord->sSPBasic;
PSDescriptorRegistryProcs
* registryProcs = NULL;
PSActionDescriptorProcs
* descriptorProcs = NULL;
PIActionDescriptor descriptor
= NULL;
double param1;

//Get the descriptor registration function set
## err = basicSuite-> AcquireSuite(kPSDescriptorRegistrySuite, #const

void **)&registryProcs); //

Get the action descriptor Function set
err
=
basicSuite->AcquireSuite(kPSActionDescriptorSuite ) ** )

&
descriptorProcs);
//Get the descriptor of the specified ID
## err = registryProcs->Get(plugInUniqueID, &descriptor);
//Read registered Parameter err
= descriptorProcs->GetFloat(descriptor, 'Pam1',&param1);
//Release descriptor
if (descriptor != NULL ) descriptorProcs
->Free(descriptor);
//Release descriptor registration function set
##       
if (registryProcs  != NULL)                                                                                                                #->
ReleaseSuite(kPSDescriptorRegistrySuite,                                                                                                                                                                                                                
##                                                                                                                                                                                                                        ##->
ReleaseSuite(kPSActionDescriptorSuite,                                                                                                                                                                                                            ## (4) Summary
This article, we introduced some photoshop to the plug -in (not just to the filter plug -in) recovery function. It is divided into two major categories, one is directly included in the plug-in parameter structure, called a direct callback function; the other is a callback function included in the callback function set.
                For the direct callback function, the text only explains that DisplayPixelsProc can be used to map on the device DC. Including AdvanceStateProc, TestAbortProc, and UpdateProgressProc mentioned in the first article, they are all direct callbacks, and some direct callback functions belong to a certain Suite.                                                                                                                                                            but also for the callback function set (Callback Suite), we focused on the reading, writing, registration and other operations in the Descriptor Suite in the callback function set. This function set can enable PS to record our filter parameters into the action sequence, or it can Register our filter parameters to save and read them across multiple calls. Other callback function sets such as memory management, color space services and other function sets have not been covered yet due to space limitations. (--By hoodlum1980)For more introduction to Photoshop filter development--Photoshop callback function related articles, please pay attention to the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Image Editing Essentials: Key Features of PhotoshopImage Editing Essentials: Key Features of PhotoshopMay 09, 2025 am 12:05 AM

Photoshop's core features include layers, selection tools, and adjustment tools. 1. The layer allows independent editing of image parts and supports layer style. 2. Selection tools such as lasso, magic wand and quick selection tools provide precise editing. 3. Adjustment tools such as color level, curve and hue/saturation can adjust images non-destructively.

My Purpose: Assisting with Photoshop-Related TasksMy Purpose: Assisting with Photoshop-Related TasksMay 08, 2025 am 12:18 AM

In Photoshop, the role of layer masks is to allow hidden or displayed portions of layers in a non-destructive manner. 1. The working principle of layer mask is to control the visibility of the layer through black, white and grayscale. 2. The basic usage includes image synthesis, such as synthesising the character image into a new background. 3. Advanced usage can be achieved by using gradient masks to achieve smooth image transition.

Photoshop and Free Alternatives: A Comparative LookPhotoshop and Free Alternatives: A Comparative LookMay 06, 2025 am 12:12 AM

Photoshop's powerful features include smart objects and neural filters, while free alternatives such as GIMP, Krita and Photopea do well in specific fields such as GIMP's layer functionality, Krita's digital paintings and online editing of Photopea.

Photoshop Color Grading: Elevate Your Images with Pro TechniquesPhotoshop Color Grading: Elevate Your Images with Pro TechniquesMay 05, 2025 am 12:07 AM

Color adjustment in Photoshop can be achieved through adjustment layers to make the image more professional. 1. Use color level, curve, hue/saturation and other tools to adjust the hue, saturation and brightness. 2. Apply LUT to create unique color effects. 3. Use adjustment layers to avoid image distortion and use the History panel to track adjustment steps.

Photoshop in the Real World: Examples of Its Diverse UsesPhotoshop in the Real World: Examples of Its Diverse UsesMay 04, 2025 am 12:15 AM

Photoshop's applications in the real world include artistic creation, scientific research and commercial marketing. 1) In artistic creation, it is used for digital painting and illustration. 2) In scientific research, it is used for image processing and data visualization. 3) In commercial marketing, it is used for advertising design and brand image shaping. The versatility of this software makes it widely used in various fields.

Beyond Editing: Photoshop's Creative CapabilitiesBeyond Editing: Photoshop's Creative CapabilitiesMay 03, 2025 am 12:12 AM

Adobe Photoshop goes beyond simple editing and becomes a creative tool for artists and designers. 1) It provides a wealth of tools such as brushes, stamp tools, blend modes and layer styles, supporting adjustments from basic images to complex digital paintings and 3D designs. 2) These tools implement functions through pixel-level operations, allowing users to create unique visual effects.

Photoshop: Exploring Pricing Models and OptionsPhotoshop: Exploring Pricing Models and OptionsMay 02, 2025 am 12:12 AM

Photoshop offers two pricing models: single purchase and subscription service. 1. Single purchase: Pay $699 in one lump sum, permanent use, but no updates and cloud services. 2. Subscription service: $20.99 per month or $239.88 per year, and the latest version and cloud services are available. 3. Enterprise plan: $33.99 per user per month, including team management and additional cloud storage. 4. Educational Offer: Students and teachers are $19.99 per month, including multiple CreativeCloud applications.

Photoshop: Mastering Layers and CompositionPhotoshop: Mastering Layers and CompositionMay 01, 2025 am 12:05 AM

The method to create a new layer in Photoshop is: 1. Click the "New Layer" button at the bottom of the layer panel; 2. Use the shortcut keys Ctrl Shift N (Windows) or Command Shift N (Mac). The layers are like transparent sheets on canvas, allowing design elements to be managed separately, non-destructive editing and experimenting, and improving design levels.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment