ImageGear for C and C++ on Windows v19.9 - Updated
Getting Started with ART
User Guide > How to Work with... > Annotations > Annotation API: ART > Getting Started with ART

The following tutorial explains how to display the ART toolbar and how to respond to the selection of a button. Two buttons are discussed - the Typed Text button, and the Select button.

To save time, this tutorial hard-codes one image for display and loads with the click of a menu item. The focus of this tutorial is how to add ART component functionality to your ImageGear application. When complete, it displays the ART toolbar and responds to the selection of two buttons: the Typed Text button and the Select button.

At the top of your main program module, you need to place the main ART public header file. It is required for the ART prototypes and macros:

 
Copy Code
i_ART.h

In addition, if you plan on using ART's GUI tools, including the toolbar and property sheets (which this Tutorial does), you need to include:

 
Copy Code
artgui.h

Before you can load an image that can be marked up using ART functions, you need to attach the ART component using the ImageGear function IG_comm_comp_attach():

 
Copy Code
/*
To unlock the toolkit for deployment you must call the
IG_lic_solution_name_set, IG_lic_solution_key_set() and possibly the
IG_lic_OEM_license_key_set() functions.
See Licensing section in ImageGear User Manual for more details.
*/
...
IG_comm_comp_attach("ART");

The following code must be added to the application's main window procedure to allow ART to process mouse messages:

 
Copy Code
AT_POINT                pt;
LPARAM          lparam;
HIGEAR          hIGear;
HWND            hWnd;
MSG             msg;
AT_MODE         nUserMode;
                .       .       .
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_LBUTTONUP:
        if (IG_image_is_valid(hIGear))
        {
                pt.x = LOWORD(lParam);
                pt.y = HIWORD(lParam);
ART_GUI_interaction_process(hIGear,
       IG_GRP_DEFAULT, 
hWnd,msg, nUserMode, &pt);
        }
        break;

The following code is necessary to process the cursor messages:

 
Copy Code
    /* In addition to variables intitialized above: */
        HCURSOR         hCursor;
        POINT           ptPos;
        HWND    hwndToolbar
                .       .       .
        case WM_SETCURSOR:
                if (IG_image_is_valid(hIGear) && 
            LOWORD(lParam) == HTCLIENT)
                {
                        GetCursorPos(&ptPos);
                        ScreenToClient(hWnd, &ptPos);
                        pt.x = ptPos.x, pt.y = ptPos.y;
                  /* Ask ART to provide the cursor */
            ART_GUI_cursor_query        (hIGear, IG_GRP_DEFAULT, hWnd, nUserMode, &pt, &hCursor,
NULL);
                  SetCursor(hCursor);
                  return TRUE;
}
return DefWindowProc(hWnd, msg, wParam, lParam);

Create a menu item that displays the ART toolbar and registers a callback function of type LPFNART_GUI_TOOLBARNOTIFYFUNC to let you know when the user presses a toolbar button. For example, under a View Menu, you might have a menu item that says "Show Toolbar". Add the following code for "Show Toolbar":

 
Copy Code
LPFNART_GUI_TOOLBARNOTIFYFUNC ARTToolBarNotifyFunc;
        .       .       .
ART_GUI_toolbar_create  (hWnd, 13, 54, &hwndToolbar);
ART_GUI_toolbar_CB_register     (hwndToolbar, ART_GUI_CB_TOOLBAR, ARTToolBarNotifyFunc,
NULL);

Now write your code for the toolbar callback function that you just registered above:

 
Copy Code
BOOL FAR PASCAL ARTToolBarNotifyFunc(
        LPVOID  lpPrivate,              /* private callback data                                */
        DWORD   dwButtonID,     /* ID of button (mark type)     */
        UINT    nReason /* Reason for callback          */
)
{
        ART_MARK_ATTRIBUTES ma; /*annotation mark attribs       */
        DWORD   dwBlockSize;            /* Size of a named block        */
        LPART_TEXTPRIVDATA lpTextPriv; /*for text marks         */
        if (nReason == ART_GUI_TOOLBAR_BUTTON_SELECTED  )
        {
                memset(&ma, 0, sizeof(ART_MARK_ATTRIBUTES));
                switch (dwButtonID)
                {
                   case ART_BUTTON_SELECT_TOOL:
                        ART_GUI_tool_set(hIGear, NULL);
                        break;
                   case ART_BUTTON_TYPED_TEXT   :
                        ma.dwType = ART_MARK_TYPED_TEXT;
                        ma.rgbColor1.rgbRed   = 0xFF;
                        ma.bVisible = TRUE;
                        ma.lfFont.lfHeight = -15;
                        ma.lfFont.lfWeight = FW_NORMAL;
                        ma.lfFont.lfCharSet = DEFAULT_CHARSET;
                        ma.lfFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
                        ma.lfFont.lfClipPrecision = 
                           CLIP_DEFAULT_PRECIS;
                        ma.lfFont.lfQuality = DEFAULT_QUALITY;
                        ma.lfFont.lfPitchAndFamily = FF_SWISS;
                        lstrcpyn(ma.lfFont.lfFaceName, "Arial",
                        sizeof(ma.lfFont.lfFaceName));
                        /* clear out the previous text priv data */
                        dwBlockSize = sizeof(ART_TEXTPRIVDATA);
                        lpTextPriv = (LPART_TEXTPRIVDATA) 
                        LocalAlloc(LPTR, (UINT)dwBlockSize);
                        #ifdef WIN32
                memset(lpTextPriv, 0, (UINT)dwBlockSize);
                        #else
        _fmemset(lpTextPriv, 0, (UINT)dwBlockSize);
                        #endif
                        /* create a blank text data block */
                        ART_global_block_create(hIGear, 
                        ART_BLOCK_ANTEXT lpTextPriv, dwBlockSize);
                        LocalFree((HLOCAL)(UINT)(DWORD)lpTextPriv);
                        ART_GUI_tool_set(hIGear, &ma);
                        break;
                   }
          }
}

Note that this code checks to see when a button is selected, and if it is one of the two above-mentioned buttons. We then set any appropriate attributes or blocks, and then call the function ART_GUI_tool_set(), which sets the fields in the Mark Attributes structure (defined in artapi.h) and in doing so also sets the type of mark that is created. The dwType field of the Mark Attributes structure holds the type of mark to create.

When the Select button is chosen, no mark attributes structure is needed, so ART_GUI_tool_set() is called with its second argument set to NULL. The Select button is the only button on the toolbar that does not use a mark attributes structure.

In addition to having a Mark Attributes structure initialized for it, the Typed Text mark object needs to have a global block of type ART_BLOCK_ANTEXT created. See the section Mark Objects: Descriptions, Types and Attributes to know what kinds of global blocks are needed for each type of mark.

Create a menu item called Open under the File menu that loads a file. Add the following line of code:

 
Copy Code
nErrCount = IG_load_file("C:\anyPicture.jpg", &hIGear);

(You'll need to supply the image.)

ART supplies "property sheets" for each kind of mark. These give the user an interactive way to change the attributes of a mark. Next we add code that makes a property sheet appear any time the end user clicks the right mouse button over a mark (while in edit mode).

Add the following lines to the WM_RBUTTONDOWN case of your main window:

 
Copy Code
case WM_RBUTTONDOWN:
if (IG_image_is_valid(hIGear))
{
        rcHit.left = rcHit.right = LOWORD(lParam);
        rcHit.top = rcHit.bottom = HIWORD(lParam);
        ART_GUI_mark_hit_test(hIGear, hWnd, IG_GRP_DEFAULT, &rcHit, &hMarkIndex, 1,
&dwMarkCount,NULL, NULL);
        /* draw the property page */
        ART_mark_query(hIGear, hMarkIndex, &ma);
        IG_image_DIB_pntr_get(hIGear, &lpDIB);
        ART_GUI_property_sheet_create(hWnd, lpDIB, &hPropertySheet);
        ART_GUI_property_sheet_init     (hPropertySheet, ART_GUI_INIT_ATTRIBUTES, &ma, NULL,
NULL, 0L);
        ART_mark_block_first    (hIGear, hMarkIndex, &byBlockName);
        while (*byBlockName)
        {
    ART_mark_block_query(hIGear, hMarkIndex, &byBlockName, NULL, &dwBlockSize);
                if (dwBlockSize)
                {
            hGlobal = GlobalAlloc(GMEM_MOVEABLE, (UINT)dwBlockSize);
                        lpBlockData = GlobalLock(hGlobal);
                        if (lpBlockData)
                        {               ART_mark_block_query(hIGear, hMarkIndex,
&byBlockName,lpBlockData, &dwBlockSize);
        ART_GUI_property_sheet_init(hPropertySheet, ART_GUI_INIT_NAMED_BLOCK, NULL,
&byBlockName, lpBlockData, dwBlockSize);
                        }
                        GlobalUnlock(hGlobal);
                        GlobalFree(hGlobal);
                }
          ART_mark_block_next   (hIGear, hMarkIndex, &byBlockName);
        }
        if (ART_GUI_property_sheet_show (hPropertySheet))
        {
          ART_GUI_property_sheet_query(hPropertySheet, ART_GUI_QUERY_ATTRIBUTES ,&ma,
NULL, NULL, NULL);
          ART_mark_modify       (hIGear, hMarkIndex, &ma);
          ART_mark_block_first  (hIGear, hMarkIndex, &byBlockName);
          ART_GUI_property_sheet_query(hPropertySheet, ART_GUI_QUERY_ATTRIBUTES ,&ma,
NULL, NULL, NULL);
          ART_mark_modify       (hIGear, hMarkIndex, &ma);
          ART_mark_block_first  (hIGear, hMarkIndex, &byBlockName);
           {
                   hGlobal=GlobalAlloc(GMEM_MOVEAB(UINT)dwBlockSize);
      lpBlockData = GlobalLock(hGlobal);
      if (lpBlockData)
      {
             ART_GUI_property_sheet_query(hPropertySheet, ART_GUI_QUERY_NAMED_BLOCK,
NULL, &byBlockName, lpBlockData, &dwBlockSize);
          ART_mark_block_create(hIGear, hMarkIndex,
        &byBlockName, lpBlockData, dwBlockSize);
                   }
                   GlobalUnlock(hGlobal);
                   GlobalFree(hGlobal);
           }
      ART_mark_block_next(hIGear, hMarkIndex, &byBlockName);
   }
   ART_GUI_mark_paint   (hIGear, 
                  IG_GRP_DEFAULT, hMarkIndex, hWnd, TRUE);
    }
    ART_GUI_property_sheet_destroy      (hPropertySheet);
    break;
  }
  break;

Now you can compile and run your mini-application.

For a more elegant example of what you can do using the ART Component with Core ImageGear, please see the ART sample application.

For detailed information about using the ART component, see Legacy Annotation API: ART and ART Component API Reference.