PATHMac OS 8 and 9 Developer Documentation > Mutlimedia and Graphics > ColorSync Manager >

Managing Color With ColorSync


Performing Optimized Profile Searching

Starting with version 2.5, ColorSync provides a profile cache and a new routine, CMIterateColorSyncFolder , for optimized profile searching. The sample code shown in Listing 3-13 through Listing 3-15 takes advantage of optimized searching if ColorSync version 2.5 is available; if not, it performs a search that is compatible with earlier versions of ColorSync. The compatible search may take some advantage of the profile cache, but cannot provide fully optimized results.

As background for the code samples in Listing 3-13 to Listing 3-15 , you should be familiar with the topics described in the following sections:

IMPORTANT

You cannot use the ColorSync Manager search functions to search for ColorSync 1.0 profiles.

The CMIterateColorSyncFolder function uses ColorSync's profile cache to supply your application with information about the profiles currently available in the ColorSync Profiles folder. The function calls your callback routine once for each available profile, supplying your routine with the profile header, script code, name, and location, stored in a structure of type CMProfileIterateData .

Even though there may be many profiles available, CMIterateColorSyncFolder can take advantage of ColorSync's profile cache to return profile information quickly, and (if the cache is valid) without having to open any profiles. As a result, your routine may be able to perform its function, such as building a list of profiles to display in a pop-up menu, quickly and without having to open each file-based profile.

An Iteration Function for Profile Searching With ColorSync 2.5

The CMIterateColorSyncFolderCompat function, shown in Listing 3-15 , performs an optimized search using the CMIterateColorSyncFolder function if ColorSync version 2.5 is available. Otherwise, it calls the CMNewProfileSearch function, which is available in earlier versions of ColorSync.

When you call the CMIterateColorSyncFolderCompat function, you pass a universal procedure pointer to a filter procedure in the proc parameter. CMIterateColorSyncFolderCompat uses that filter procedure when it performs an optimized search with CMIterateColorSyncFolder . Listing 3-13 provides a sample filter procedure called MyIterateProc .

The MyIterateProc function is called once for each available profile and merely stores the names of all non-display profiles (such as printer and scanner profiles) at an arbitrary position in a list. You would do something similar, for example, to display a list of profiles in a dialog.

Note that the CMIterateColorSyncFolderCompat function works in a similar way for ColorSync 2.5 and for earlier versions, although the search is much more efficient with version 2.5. CMIterateColorSyncFolderCompat either calls the CMIterateColorSyncFolder function, which calls the MyIterateProc function once for each available profile, or it calls the CMNewProfileSearch function, which calls the ProfileSearchFilter function ( Listing 3-14 ) once for each available profile. The ProfileSearchFilter function in turn calls MyIterateProc, so similar processing occurs.

Listing 3-13 An iteration function for profile searching with ColorSync 2.5

Pascal OSErr MyIterateProc(CMProfileIterateData* data, void* refcon)
{
    Cell theCell;
    // Assume we can cast refCon to a ListHandle.
    ListHandle list = (ListHandle)refcon;
    
    /* Assume we're interested only in non-display profiles, such as printer
        and scanner profiles. */
    if (data->header.profileClass != cmDisplayClass)
    {
        /* This code adds the profile name at an arbitrary position
            in a list. You could do something similar to display a
            list of all available profiles. */
        cell.v = LAddRow(1,999,list);
        cell.h = 0;
        // The name data in the iterate data structure is in Pascal format,
            so we use the length byte to determine how many bytes to copy. */
        LSetCell((Ptr)data->name+1, name[0], cell, list);
        cell.h = 1;
        // Store the profile's location information with the cell.
        LSetCell((Ptr)data->location, sizeof(cmProfileLocation), cell, list);
    }
    // A more complicated function might need to return an error here.
    return noErr;
};

A Filter Function for Profile Searching Prior to ColorSync 2.5

To search for profiles prior to version 2.5 of the ColorSync Manager, you use the CMNewProfileSearch function. You supply CMNewProfileSearch with a search record of type CMSearchRecord that identifies the search criteria. If you also provide a pointer to a filter function, CMNewProfileSearch uses the function to eliminate profiles from the search based on additional criteria not defined by the search record. The ProfileSearchFilter function shown in Listing 3-14 provides an example of a filter routine for searching with the CMNewProfileSearch function.

Listing 3-14 defines the IterateCompatPtr data type, a pointer to a structure that stores search information. When you call the CMIterateColorSyncFolderCompat function shown in Listing 3-15 , you pass a reference to the MyIterateProc function ( Listing 3-13 ) in the proc parameter. If ColorSync 2.5 is not available, the CMIterateColorSyncFolderCompat function calls the CMNewProfileSearch function. It passes the ProfileSearchFilter function ( Listing 3-13 ) as the search filter and it passes an IterateCompatPtr pointer as the refCon parameter. It sets the proc field of the IterateCompatPtr pointer to the MyIterateProc function that you passed in the proc parameter.

The CMNewProfileSearch function calls the ProfileSearchFilter function ( Listing 3-13 ) once for each profile. The ProfileSearchFilter function simply casts the passed refCon pointer to an IterateCompatPtr, then calls the function specified by the pointer's proc field. As a result, the MyIterateProc function is called once for each profile, just as it is when CMIterateColorSyncFolderCompat calls CMIterateColorSyncFolder under ColorSync 2.5.

Note that ProfileSearchFilter always returns true, indicating the profile should be filtered out of the search result returned by CMNewProfileSearch , because we've already gotten all the information we need from it. Note also that ProfileSearchFilter uses the require macro, which is defined in Poor Man's Exception Handling .

Listing 3-14 A filter function for profile searching prior to ColorSync 2.5

// Declare a structure to use for searching with ColorSync versions prior to 2.5.
typedef struct IterateCompat
{
    CMProfileIterateUPP     proc;
    OSErr                   osErr;
    void*                   refCon;
} IterateCompatRec, *IterateCompatPtr;

static pascal Boolean ProfileSearchFilter (CMProfileRef prof, void *refCon)
{
    OSErr                   theErr = noErr;
    IterateCompatPtr        refConCompatPtr;
    CMProfileIterateData    iterData;
    
    // Cast refcon to our type.
    refConCompatPtr = (IterateCompatPtr)refCon;
    
    // If we had an error from an earlier profile, give up
    //  by branching to cleanup location.
    theErr = refConCompatPtr->osErr;
    require(theErr == noErr, cleanup); // require is defined in Listing 3-3 on page -xcviii.
    
    // Try to get the profile's location.
    theErr = CMGetProfileLocation(prof, &iterData.location);
    require(theErr == noErr, cleanup);
    
    // Try to get the profile's header.
    theErr = CMGetProfileHeader(prof, (CMAppleProfileHeader*)&iterData.header);
    require(theErr == noErr, cleanup);
    
    // Try to get the profile's name.
    theErr = CMGetScriptProfileDescription(prof, iterData.name, &iterData.code);
    require(theErr == noErr, cleanup);
    
    iterData.dataVersion = cmProfileIterateDataVersion1;
    
    // Call the iterate callback routine.
    theErr = CallCMProfileIterateProc(refConCompatPtr->proc,
                                    &iterData, refConCompatPtr->refCon);
    require(theErr == noErr, cleanup);
    
cleanup:
    
    if (theErr)
        refConCompatPtr->osErr = theErr;
    
    return true; // exclude the profile;
}

A Compatible Function for Optimized Profile Searching

Listing 3-15 provides sample code that performs an optimized profile search if ColorSync 2.5 is available, but provides a search that is compatible with previous versions if ColorSync 2.5 is not available.

When ColorSync 2.5 is available, CMIterateColorSyncFolderCompat simply calls the function CMIterateColorSyncFolder , passing on the information it received through its parameters. As a result, CMIterateColorSyncFolder calls the MyIterateProc function, shown in Listing 3-13 , once for each available profile. Your version of MyIterateProc can examine the passed information for each profile and perform any required operation on the profiles it is interested in.

When ColorSync 2.5 is not available, CMIterateColorSyncFolderCompat sets up a search with the function CMNewProfileSearch . As part of this setup, it initializes a structure of type IterateCompatRec, defined in Listing 3-14 , which it passes to CMNewProfileSearch for the refCon parameter. The CMNewProfileSearch function in turn passes a pointer to the IterateCompatRec structure as the refCon parameter to ProfileSearchFilter, which it calls once for each available profile.

ProfileSearchFilter calls the MyIterateProc function, which gets a chance to handle each profile, just as it does in the case where ColorSync 2.5 is available. The main drawback is that without the availability of the profile cache and the CMIterateColorSyncFolder function, searching through the profiles is likely to be a much more time-consuming task.

Note that CMIterateColorSyncFolderCompat uses the require macro, which is defined in Poor Man's Exception Handling .

Listing 3-15 Optimized profile searching compatible with previous versions of ColorSync

CMError CMIterateColorSyncFolderCompat (CMProfileIterateUPP proc,
                                         unsigned long *seed,
                                         unsigned long *count,
                                         void *refCon)
{
    CMError theErr = noErr ;

    /* Presume the caller passed a pointer to MyIterateProc to this
            function in the proc parameter. */
    if ( ColorSync25Available() ) // This routine is shown in Listing 3-1 on page -xcii.
        return CMIterateColorSyncFolder(proc, seed, count, refCon);
    else
    {
        CMProfileSearchRef  searchResult;
        CMSearchRecord      searchSpec;
        unsigned long       count;
        IterateCompatRec    refConCompat;
        
        /* Set up a search record to pass to CMNewProfileSearch. Include
            procedure pointer to search filter from Listing 3-14 on page -cxxxi. */
        searchSpec.filter = NewCMProfileFilterProc(ProfileSearchFilter);
        searchSpec.searchMask = cmMatchAnyProfile;
        
        /* Set up our private data structure for compatible (pre-ColorSync 2.5)
            profile searching.
            Pass the pointer to the MyIterateProc function, which was
                presumably passed to this function in the proc parameter,
                on to our filter routine, ProfileSearchFilter,
                in the refCon parameter, using an IterateCompatRec structure. */
        refConCompat.proc = proc;
        refConCompat.osErr = noErr;
        refConCompat.refCon = refCon;
        
        // Start traditional search.
        theErr = CMNewProfileSearch(&searchSpec,
                            (void*)&refConCompat, &count, &searchResult);
        if (theErr == noErr)
        {
            // We don't use the result, but still must dispose of it.
            CMDisposeProfileSearch(searchResult);
            theErr = refConCompat.osErr;
        }
        DisposeRoutineDescriptor(searchSpec.filter);
    }

    return theErr;
}

© 1988-1999 Apple Computer, Inc. — (Last Updated 20 Jan 99)