ImageGear for C and C++ on Windows v19.4 - Updated
Working with ART Marks
User Guide > How to Work with... > Annotations > Annotation API: ART > Working with ART Marks

Once you attach ART component you can annotate any image that you load into ImageGear. ART internally tracks the marks that are associated with an image. The end-user can save the image with the marks in a separate file with the .ART filename extension. Anytime the image is reloaded, a simple import call is used to "re-apply" the annotations.

You can also "burn in" the marks so they become part of the image and are not stored separately.

If the image is saved as a TIFF file, the annotations are automatically embedded in the TIFF file.

This option can be disabled - see "Saving Marks to File", below.

If a TIFF file with embedded annotations is loaded, the annotations are automatically "re-applied."

ART annotations saved to a separate file (.ART) can be read only by software that supports .ART files, such as ImageGear and the Imaging for Windows 95 and Imaging for Windows NT Wang products.

The XML schema used for ART 3.0 annotations is defined in ARTXMLStorage.xsd
This section provides information about the following:

Components of a Mark

All mark objects contain the following components:

The Mark Attributes structure is a set of attributes associated with a mark object. Attributes that do not apply are ignored.

The index block contains an unique number that is used for the mark object identification. When new mark object is created its index is generated (by incrementing 1 to the number just assigned) and stored in the global index block.

This unique number (32-bit unsigned integer) is used to refer to the mark in many of ART's operations. It cannot be modified.

The group block contains a NULL-terminated string that acts as the name of the block. It is initialized to the value contained in the global group block. If you have not set the global group block, a default value of "(Untitled)" is used. See the section ART Component Important Structures and Types or i_ART.h for more information about these structures.

ART refers to all data blocks associated with marks as "named blocks." Each data block has a unique 8-byte name for identification. All names that are less than 8 bytes are padded with NULLs. The ART component uses two kinds of named blocks:

Mark blocks contain data for individual marks. Global blocks contain data that is used to define the next mark created, as well as to store data that is not associated with an individual mark.

This diagram above shows the components of a mark. Central to any mark is the Mark Attributes structure. In addition, each mark contains a pointer to a list that includes the index and group blocks and other mandatory blocks, that vary depending on the type of mark, and an unlimited number of user-defined blocks. User-defined blocks contain data that might be useful to the developer.

You can define as many user-defined blocks as you want. Information that might be stored in a user-defined block includes:

Note that the block shown in the list can occur in any order.

When a mark is created by the end user from the ART toolbar, a mark attributes structure is created and filled automatically with global settings, that can be modified using ART_GUI_tool_set(). If there are other mandatory blocks pertaining to the type of mark created, these are created automatically by ART and filled with values from global blocks. The global blocks are previously initialized.

When a mark is created using ART_mark_create(), which is a lower-level method of creation, the group and index blocks are created automatically; any other mandatory blocks pertaining to the type of mark created need to be added one at a time using the ART_mark_block_create() function.

The following named blocks are defined by ART in the i_ART.h file:

ART_BLOCK_ANODAT Used by many mark types to hold points and rotation information.
ART_BLOCK_FILNAM Name of file used for Image Reference, Text from File, and Audio.
ART_BLOCK_DIB Embedded DIB image.
ART_BLOCK_GROUP Name of group to which the mark belongs.
ART_BLOCK_INDEX Unique index number for mark.
ART_BLOCK_ANTEXT For text mark types. Orientation and length of text, in bytes.

Creating a Mark with End-User Interaction

End users can create a mark using the ART toolbar, or developers can created them "manually" by using lower-level calls. This section describes how to create marks with user interaction through the ART toolbar.

You may create your own marks and have them appear automatically on any image loaded while ART is also loaded, by registering the LPFNIG_ART_DRAWNOTIFYFUNC callback function.

When a button is selected from the toolbar, ART updates the mark's attributes as the user modifies it. Once the end user creates the mark, control returns to the application.

The following constants define the mark types:

ART_MARK_IMAGE_EMBEDDED ART_MARK_FILLED_POLYGON
ART_MARK_IMAGE_REFERENCE ART_MARK_HOLLOW_POLYGON
ART_MARK_STRAIGHT_LINE ART_MARK_POLYLINE
ART_MARK_FREEHAND_LINE ART_MARK_AUDIO
ART_MARK_HOLLOW_RECTANGLE ART_MARK_HOLLOW_ELLIPSE
ART_MARK_FILLED_RECTANGLE ART_MARK_FILLED_ELLIPSE
ART_MARK_TYPED_TEXT ART_MARK_ARROW
ART_MARK_TEXT_FROM_FILE ART_MARK_HOT_SPOT
ART_MARK_TEXT_STAMP ART_MARK_REDACTION
ART_MARK_ATTACH_A_NOTE ART_MARK_ENCRYPTION
ART_MARK_FORM ART_MARK_RULER
ART_MARK_PROTRACTOR ART_MARK_BUTTON
ART_MARK_PIN_UP_TEXT ART_MARK_HIGHLIGHTER
ART_MARK_RTF_EDIT  

Call the function ART_GUI_toolbar_create() to display the toolbar. You then set the case statements in the LPFNART_GUI_TOOLBARNOTIFYFUNC callback function for each button. The function ART_GUI_toolbar_button_get() tells the status of any button on the toolbar. ART automatically initializes whatever blocks are needed by the mark with global settings. The global settings are set prior to the mark being created; the best place to do that is the case statement for each type of mark in the LPFNART_GUI_TOOLBARNOTIFYFUNC callback function.

ART makes internal calls to create the mark object. Modifications to the attributes structure are made interactively by ART as the end user drags, drops and re-sizes a mark. Here is a short example case statement that is used for a Hot Spot mark that is created from the toolbar:

 
Copy Code
ART_MARK_ATTRIBUTES ma; /* Mark Attributes Structure */
. . .
switch (dwButtonID)
{
case ART_BUTTON_HOT_SPOT:
ma.dwType = ART_MARK_HOT_SPOT;
ma.rgbColor1.rgbRed   = 0xFF;
ma.bVisible = TRUE;
ART_GUI_tool_set(hIGear, &ma);
ART_GUI_interaction_process(hIGear, IG_GRP_DEFAULT, hWnd, msg, 
nUserMode, &pt);
break;

Call ART_GUI_interaction_process() when a button is pressed down over the image is. When the user mode parameter is set to ART_MODE_EDIT and the left mouse button is pressed over the image, ART takes control of all Windows messages received during creation. When the mark is finished, control returns to your application the line after ART_GUI_interaction_process().

You should set the ART user mode to ART_MODE_VIEW to give ImageGear back control of the mouse functions.

Creating a Mark Using Low-Level Calls

If you need to create a mark without the end user, call ART_mark_create(). You supply this function a structure of type ART_MARK_ATTRIBUTES, and it returns a unique index to the mark.

ART_mark_create() automatically creates the index and group blocks for your object. You have to add other required named blocks (their types depend on the mark object) one at a time using ART_mark_block_create_ex(). To see what blocks are required by each mark type look at the section Mark Objects: Descriptions, Types and Attributes.To display the mark call ART_GUI_mark_paint().

Modifying Marks

Most often, marks are modified interactively by the end user. Whether a mark can be modified depends on its access setting. A mark has write-access or is read-only. Access can be applied to a group of marks. See the "Working With Mark Groups" section below for a discussion about group operations.

To check the access of a mark, call ART_mark_is_access_granted(). To set the access of a mark, call ART_mark_block_create(). To set the access for a group of marks, call ART_group_access().

There are differences in the way you handle modifying marks, depending on who modifies the mark - you or the end user. See the "Modifying Marks By the End User" section next.

Modifying Marks By the End User

The end user modifies a mark by clicking the mouse over it. ART automatically updates the mark's attributes structure and appropriate blocks when the user is modifying the mark.

When you receive the Windows message WM_LBUTTONDOWN, call ART_GUI_interaction_process().

Another way to allow the end user to modify a mark is to set up "property sheets" for each mark object. Use ART_GUI_property_sheet_create() to obtain a handle to a property sheet. ART automatically creates a property sheet that is appropriate for the type of mark modified. The property sheet for each mark is different. Control is passed back to the application once the end user clicks OK. ART_GUI_property_sheet_create() simply returns a handle to a property sheet - it does not display it or get the user's input. The following sequence of calls processes property sheets:

ART_GUI_property_sheet_create() Get the handle to a property sheet.
ART_GUI_property_sheet_init() Initialize values to mark attributes structure's values and one or more named blocks.
ART_GUI_property_sheet_show() Displays the property sheet. When this function returns, the property sheet will disappear from the screen.
ART_GUI_property_sheet_query() Query the mark attributes and one or more named blocks.
ART_GUI_property_sheet_destroy() Free the property sheet resource.

If ART_GUI_property_sheet_show() returns TRUE, it means the user pressed OK and the user might have caused the mark attributes or named blocks to be changed.

Call ART_mark_modify() to make the changes permanently to the mark attributes structure. Call ART_mark_block_create() to overwrite the old data with the new. To redraw the mark with the new attributes, call ART_GUI_mark_paint().

Modifying Marks Programmatically

To modify marks programmatically, you set the attributes for block data, and call ART_mark_modify() or ART_mark_block_create_ex()to update that information. Call ART_GUI_mark_paint() to see the changes.

Deleting Marks

To delete a mark, call ART_mark_delete() with the index number you supply. To delete a group of marks, call ART_group_delete(). When a mark is deleted, the unique index identifiers of the remaining marks are not changed.

The callback function LPFNIG_ART_DELETENOTIFYFUNC is used to create a function that is called each time the user tries to delete a mark. If you return TRUE from a callback of this type, the mark is deleted.

Clipboard Operations

ART marks can be cut from and copied to the clipboard as well as pasted into an image individually or in groups.

The names of all functions that handle clipboard operations begin with ART_edit_. This group includes functions that undo changes made to marks. See the next section for a discussion about performing undos.

ART_edit_copy() Copies an array of marks to the clipboard
ART_edit_cut() Cuts an array of marks to the clipboard
ART_edit_paste() Pastes any available marks from the clipboard into the current HIGEAR image
ART_edit_paste_count() Queries the clipboard for the number marks available for pasting

To see the results of cutting or pasting the marks associated with an image, call ART_GUI_mark_paint() function.

Undoing Edits

As with Clipboard operations, undo begins with ART_edit_. The scope is determined by what is recorded. ART component supplies the following functions for "undoing edits":

ART_edit_undo_enable() Enable or disable undo operations.
ART_edit_undo() Reverses any changes made to any mark
ART_edit_undo_clear() Clears all pending undos from memory
ART_edit_undo_count() Returns (in lpUndoCount) the number of times that ART_edit_undo() can be called (you can limit your undo loop)
ART_edit_undo_record() Enables or disables the recording of every action

The example below shows ART_edit_undo_record() being set "on" before each mark in the image is deleted. Once the deletion loop has been completed, recording is shut "off" by calling ART_edit_undo_record() a second time with the last argument set to FALSE.

 
Copy Code
/* Record all the deletes so that when an ART_edit_undo()  */
/* is called, the deleted marks will be restored at once,  */
/* instead of being restored individually. */
ART_edit_undo_record(hIGear, TRUE);
ART_mark_selected_first(hIGear, &hMarkIndex);
while (hMarkIndex != ART_INVALID_ID)
{
hMarkDelete = hMarkIndex;
ART_mark_selected_next(hIGear, &hMarkIndex);
ART_mark_delete(hIGear, hMarkDelete);
}
/* Turn off undo recording */
ART_edit_undo_record(hIGear, FALSE);
ART_GUI_mark_paint(hIGear, 
IG_GRP_DEFAULT, ART_INVALID_ID, hWnd, TRUE);

A call to ART_edit_undo() restores all marks that were modified while recording was on. This means that all deleted marks are restored at once. If ART_edit_undo_record() was not used, then ART_edit_undo() would have to be called many times to restore all of the deleted marks.

Iterating Through Marks

ART component provides two functions that iterate through all of the marks associated with the current HIGEAR image. ART_mark_first() returns the index of the first mark. ART_mark_next() returns the index of the next mark. To iterate through all marks, call ART_mark_first(), then call ART_mark_next() within a loop, with a line such as:

 
Copy Code
ART_mark_first(hIGear, &hMarkIndex);
while (hMarkIndex != ART_INVALID_ID)
{
...
   ART_mark_next(hIGear, &hMarkIndex);
}

ART returns ART_INVALID_ID when there are no more marks to iterate through.

As you iterate through the marks, you can pass the returned index of each mark to any of the mark modification functions.

Iterating Through Blocks

ART supplies functions that let you iterate through both global blocks and mark blocks. To iterate through global blocks, use ART_global_block_first() and ART_global_block_next(). To iterate through the blocks that belong to an individual mark, use ART_mark_block_first() and ART_mark_block_next().

All of these block iteration functions set the block name to NULL when there are no more blocks to iterate through.

ART Textflow Functionality

The ART textflow functionality allows you to process several separated text marks as single text document. It includes the possibilities of checking of the text overflowing, calculating of the preferable mark bounds to draw the mark text in and automatic moving of the overflowed text from one text mark to another one.

The textflow functionality consists of the following:

And of one callback function:

Currently ART textflow functionality can be applied only for Typed Text, Attach-a-Note and Text from File mark types.

Working With Mark Groups

Each mark received a group name when it is created. If you do not assign it a name, ART assigns it the default group name "(Untitled)". Group names provide a convenient way to associate groups of marks so that you can modify, delete, send to the front or back of the stacking order, change access, perform clipboard operation, and select attributes.

The group name for the next mark created comes from the Global Group Block. To set it to a new name, you need to overwrite the block in the following manner:

 
Copy Code
LPSTR lpszGroup = "New Group";
ART_global_block_create(hIGear, ART_BLOCK_GROUP, lpszGroup, lstrlen(lpszGroup) + 1);

All named block names that are less than 8 bytes must be padded with NULLs. See ART Component Important Structures and Types for the composition of a Global Group Block structure.

All names of functions that operate on groups begin with ART_group_. Here are the names of the functions that operate on groups:

ART_group_access() Sets access of a group to allow for edit or read only access.
ART_group_bring_to_front() Moves group to the front of the stacking order.
ART_group_delete() Deletes a group.
ART_group_edit_copy() Copies a group to the clipboard.
ART_group_edit_cut() Cuts a group to the clipboard.
ART_group_select() Selects all marks in a group.
ART_group_send_to_back() Sends a group to the back of the stacking order.
ART_group_visible() Makes marks visible or invisible.

Use ART_edit_paste() and ART_edit_paste_count() to perform paste operations on groups of marks.

Saving Marks to File

When the set of marks belonging to a HIGEAR image are saved, they can be saved separately into a file with filename extension ".ART", burned permanently into the image, or embedded into an image file. You can embed marks into TIFF files only.

If you are saving a TIFF file, the annotations are automatically saved as an embedded file. Use ART_control_option_set() with the appropriate setting if you do not want the annotations to be embedded into the file:

 
Copy Code
nErrcount=ART_control_option_set(hIGear, ART_CONTROL_SAVE_ENABLE, FALSE)"

Importing Marks to an Image

An .ART file can be imported into any loaded HIGEAR image as long as the ART component is attached. If the .ART file to import has multiple pages, you can specify the number of the page to load. To import an .ART file for association with the current HIGEAR file call ART_file_import().

Edit Mode vs. Run Mode

ART component applications can operate in three different modes:

It is recommended that you set your application to be in Edit mode any time a toolbar button is selected, and that you set it to Run mode when none of the buttons on the toolbar are selected.

To set your application mode, use the ART_GUI_interaction_process() function using one of these constants: