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. |
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.
- Components of a Mark
- Creating a Mark with End-User Interaction
- Creating a Mark Using Low-Level Calls
- Modifying Marks
- Modifying Marks Programmatically
- Deleting Marks
- Clipboard Operations
- Undoing Edits
- Iterating Through Marks
- Iterating Through Blocks
- ART Textflow Functionality
- Working With Mark Groups
- Saving Marks to File
- Importing Marks to an Image
- Edit Mode vs. Run Mode
Components of a Mark
All mark objects contain the following components:
- A Mark Attributes structure
- An index block
- A group block
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
- global 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:
- who last edited the file or mark
- user preferences, such as preferred line thickness
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. Each of these ones have a corresponding global block to hold default values for toolbar created marks:
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 the mark belongs to |
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 sectionMark 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 Working With Mark Groups section 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 below Modifying Marks By the End User and .
Modifying Marks By the End User
The end user modifies a mark by clicking the mouse over it. When you receive the Windows message WM_LBUTTONDOWN, call ART_GUI_interaction_process(). ART automatically updates the mark's attributes structure and appropriate blocks when the user is modifying the mark.
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 automatical moving of the overflowed text from one text mark to another one.
The textflow functionality consists of two following functions:
- ART_GUI_text_flow() - This function links texts of given annotation marks and distributes it between these marks according to their bounds so that all of them do not have overflowed text excluding may be the last one.
- ART_GUI_text_overflow_check() - This function checks the mark with text overflowed.
And of one callback function:
- LPFNIG_ART_TEXTOVERFLOWNOTIFYFUNC - This callback function provides you with the possibility to change the mark bounds or apply ART_GUI_text_flow() function after resizing of the text mark bounds.
Currently ART textflow functionality can be applied only for Typed Text, Attach-a-Note and TEXT From FILEmark 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.
- To save the marks to an .ART file, call the ART_file_export(), method, supplying the name of the .ART file to export. If an .ART file exists you can set a flag to indicate whether the new file replaces or overwrites the existing file. You can also append new mark objects to the existing ART file. If the existing file has multiple pages you can specify which page the new file overwrites, or where it should be inserted.
- To burn the marks into the image, call the ART_image_burn_in() function. Marks can be burned in by group, list, selection, etc., depending on what setting you choose. See Chapter "ART Component API Function Reference" for more detailed information.
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:
- Editmode lets users create or edit marks.
- Run mode lets users operate on hot spot, audio, and button activities.
- View-only mode allows users to view marks--not add or modify them.
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:
- ART_MODE_EDIT
- ART_MODE_RUN
- ART_MODE_VIEW
- LPFNIG_ART_MODIFYNOTIFYFUNC
- LPFNIG_ART_OVERRIDEDRAWNOTIFYFUNC
- LPFNIG_ART_PREMODIFYNOTIFYFUNC
- LPFNIG_ART_SELECTNOTIFYFUNC