home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Graphics 2D / MacGamma / MacGamma.cpp < prev    next >
Encoding:
Text File  |  2000-09-28  |  20.1 KB  |  530 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        MacGamma.cpp
  3.  
  4.     Contains:    Functions to enable Mac OS device gamma adjustments using 3 channel 256 element 8 bit gamma ramps
  5.  
  6.     Written by:    Geoff Stahl (ggs)
  7.  
  8.     Copyright:    Copyright © 1999 Apple Computer, Inc., All Rights Reserved
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <7>     8/25/99    ggs     Added usage notes
  13.          <6>     8/25/99    ggs     Fixed handling of 1 -> 3 channel gamma conversions in get and set
  14.          <5>     7/14/99    ggs     Added sample code notice
  15.          <4>     5/20/99    ggs     Added handling for gamma tables with different data widths,
  16.                                     number of entries, and channels.  Forced updates to 3 channels
  17.                                     (poss. could break on rare card, but very unlikely).  Added
  18.                                     quick update with BlockMove for 3x256x8 tables. Updated function
  19.                                     names.
  20.          <3>     5/20/99    ggs     Cleaned up and commented
  21.          <2>     5/20/99    ggs     Added system wide get and restore gamma functions to enable
  22.                                     restoration of original for all devices.  Modified functionality
  23.                                     to return pointers vice squirreling away the memory.
  24.          <1>     5/20/99    ggs     Initial Add
  25.  
  26.     Disclaimer:    You may incorporate this sample code into your applications without
  27.                 restriction, though the sample code has been provided "AS IS" and the
  28.                 responsibility for its operation is 100% yours.  However, what you are
  29.                 not permitted to do is to redistribute the source as "DSC Sample Code"
  30.                 after having made changes. If you're going to re-distribute the source,
  31.                 we require that you make it clear in the source that the code was
  32.                 descended from Apple Sample Code, but that you've made changes.
  33.  
  34. */
  35.  
  36. // Usage notes: 
  37.  
  38. // SetDeviceGammaRampXX may not return until the VBL following their call, depending on the display driver,
  39. // this is due to the handling of the Control call by the driver.
  40.  
  41. // Startup and Shutdown:
  42.  
  43. // GetSystemGammas (...) must be called to save the system gammas prior to using MacGamma
  44. // RestoreSystemGamms (...)  must be called before exiting to restore original gamma
  45. // DisposeSystemGammas (...) can then be used to dispose of the system gammas
  46.  
  47. // Suspend and Resume:
  48.  
  49. // RestoreSystemGamms (...); DisposeSystemGammas (...); should also be called prior to suspend and
  50. // GetSystemGammas (...) should be called when resuming
  51. // this prevents users from saving display settings with your gammas
  52.  
  53.  
  54. // system includes ----------------------------------------------------------
  55.  
  56. #include <Devices.h>
  57. #include <Files.h>
  58. #include <MacTypes.h>
  59. #include <QDOffscreen.h>
  60. #include <Quickdraw.h>
  61. #include <video.h>
  62.  
  63.  
  64. // project includes ---------------------------------------------------------
  65.  
  66. #include "MacGamma.h"
  67.  
  68.  
  69. // structures (internal/private) -----------------------------------------------
  70.     
  71. struct recDeviceGamma                                            // storage for device handle and gamma table
  72. {
  73.     GDHandle hGD;                                                // handle to device
  74.     GammaTblPtr pDeviceGamma;                                    // pointer to device gamma table
  75. };
  76. typedef recDeviceGamma * precDeviceGamma;
  77.  
  78. struct recSystemGamma                                            // storage for system devices and gamma tables
  79. {
  80.     short numDevices;                                            // number of devices
  81.     precDeviceGamma * devGamma;                                    // array of pointers to device gamma records
  82. };
  83. typedef recSystemGamma * precSystemGamma;
  84.  
  85.  
  86. // prototypes (internal/private) --------------------------------------------
  87.  
  88. // 5/20/99: (ggs) changed functional specification
  89.  
  90. OSErr GetGammaTable(GDHandle gd, GammaTblPtr * ppTableGammaOut);        // Returns the device gamma table pointer in ppDeviceTable
  91. Ptr CreateEmptyGammaTable (short channels, short entries, short bits);    // creates an empty gamma table of a given size, assume no formula data will be used
  92. Ptr CopyGammaTable (GammaTblPtr pTableGammaIn);                            // given a pointer toa device gamma table properly iterates and copies
  93. void DisposeGammaTable (Ptr pGamma);                                    // disposes gamma table returned from GetGammaTable, GetDeviceGamma, or CopyGammaTable 
  94. Ptr GetDeviceGamma (GDHandle hGD);                                        // returns pointer to copy of orginal device gamma table in native format
  95. void RestoreDeviceGamma (GDHandle hGD, Ptr pGammaTable);                // sets device to saved table
  96.  
  97.  
  98. // functions (internal/private) ---------------------------------------------
  99.  
  100. // GetGammaTable
  101.  
  102. // Returns the device gamma table pointer in ppTableGammaOut
  103.  
  104. OSErr GetGammaTable (GDHandle hGD, GammaTblPtr * ppTableGammaOut)
  105. {
  106.     VDGammaRecord   DeviceGammaRec;
  107.     CntrlParam        cParam;
  108.     OSErr            err;
  109.     
  110.     cParam.ioCompletion = NULL;                                        // set up control params
  111.     cParam.ioNamePtr = NULL;
  112.     cParam.ioVRefNum = 0;
  113.     cParam.ioCRefNum = (**hGD).gdRefNum;
  114.     cParam.csCode = cscGetGamma;                                    // Get Gamma commnd to device
  115.     *(Ptr *)cParam.csParam = (Ptr) &DeviceGammaRec;                    // record for gamma
  116.  
  117.     err = PBStatus( (ParmBlkPtr)&cParam, 0 );                        // get gamma
  118.     
  119.     *ppTableGammaOut = (GammaTblPtr)(DeviceGammaRec.csGTable);        // pull table out of record
  120.     
  121.     return err;    
  122. }
  123.  
  124. // --------------------------------------------------------------------------
  125.  
  126. // CreateEmptyGammaTable
  127.  
  128. // creates an empty gamma table of a given size, assume no formula data will be used
  129.  
  130. Ptr CreateEmptyGammaTable (short channels, short entries, short bits)
  131. {
  132.     GammaTblPtr        pTableGammaOut = NULL;
  133.     short            tableSize, dataWidth;
  134.  
  135.     dataWidth = (bits + 7) / 8;                                        // number of bytes per entry
  136.     tableSize = sizeof (GammaTbl) + (channels * entries * dataWidth);
  137.     pTableGammaOut = (GammaTblPtr) NewPtrClear (tableSize);            // allocate new tabel
  138.  
  139.     if (pTableGammaOut)                                                // if we successfully allocated
  140.     {
  141.         pTableGammaOut->gVersion = 0;                                // set parameters based on input
  142.         pTableGammaOut->gType = 0;
  143.         pTableGammaOut->gFormulaSize = 0;
  144.         pTableGammaOut->gChanCnt = channels;
  145.         pTableGammaOut->gDataCnt = entries;
  146.         pTableGammaOut->gDataWidth = bits;
  147.     }
  148.     return (Ptr)pTableGammaOut;                                        // return whatever we allocated
  149. }
  150.  
  151. // --------------------------------------------------------------------------
  152.  
  153. // CopyGammaTable
  154.  
  155. // given a pointer toa device gamma table properly iterates and copies
  156.  
  157. Ptr CopyGammaTable (GammaTblPtr pTableGammaIn)
  158. {
  159.     GammaTblPtr        pTableGammaOut = NULL;
  160.     short            tableSize, dataWidth;
  161.  
  162.     if (pTableGammaIn)                                                // if there is a table to copy 
  163.     {
  164.         dataWidth = (pTableGammaIn->gDataWidth + 7) / 8;            // number of bytes per entry
  165.         tableSize = sizeof (GammaTbl) + pTableGammaIn->gFormulaSize +
  166.                     (pTableGammaIn->gChanCnt * pTableGammaIn->gDataCnt * dataWidth);
  167.         pTableGammaOut = (GammaTblPtr) NewPtr (tableSize);            // allocate new table
  168.         if (pTableGammaOut)                                            
  169.             BlockMove( (Ptr)pTableGammaIn, (Ptr)pTableGammaOut, tableSize);    // move everything
  170.     }
  171.     return (Ptr)pTableGammaOut;                                        // return whatever we allocated, could be NULL
  172. }
  173.  
  174. // --------------------------------------------------------------------------
  175.  
  176. // DisposeGammaTable
  177.  
  178. // disposes gamma table returned from GetGammaTable, GetDeviceGamma, or CopyGammaTable 
  179. // 5/20/99: (ggs) added
  180.  
  181. void DisposeGammaTable (Ptr pGamma)
  182. {
  183.     if (pGamma)
  184.         DisposePtr((Ptr) pGamma);                                    // get rid of it
  185. }
  186.  
  187. // --------------------------------------------------------------------------
  188.  
  189. // GetDeviceGamma
  190.  
  191. // returns pointer to copy of orginal device gamma table in native format (allocates memory for gamma table, call DisposeDeviceGamma to delete)
  192. // 5/20/99: (ggs) change spec to return the allocated pointer vice storing internally
  193.  
  194. Ptr GetDeviceGamma (GDHandle hGD)
  195. {
  196.     GammaTblPtr        pTableGammaDevice = NULL;
  197.     GammaTblPtr        pTableGammaReturn = NULL;    
  198.     OSErr            err;
  199.     
  200.     err = GetGammaTable (hGD, &pTableGammaDevice);                    // get a pointer to the devices table
  201.     if ((noErr == err) && pTableGammaDevice)                        // if succesful
  202.         pTableGammaReturn = (GammaTblPtr) CopyGammaTable (pTableGammaDevice); // copy to global
  203.  
  204.     return (Ptr) pTableGammaReturn;
  205. }
  206.  
  207. // --------------------------------------------------------------------------
  208.  
  209. // RestoreDeviceGamma
  210.  
  211. // sets device to saved table
  212. // 5/20/99: (ggs) now does not delete table, avoids confusion
  213.  
  214. void RestoreDeviceGamma (GDHandle hGD, Ptr pGammaTable)
  215. {
  216.     VDSetEntryRecord setEntriesRec;
  217.     VDGammaRecord    gameRecRestore;
  218.     CTabHandle      hCTabDeviceColors;
  219.     Ptr                csPtr;
  220.     OSErr            err = noErr;
  221.     
  222.     if (pGammaTable)                                                // if we have a table to restore                                
  223.     {
  224.         gameRecRestore.csGTable = pGammaTable;                        // setup restore record
  225.         csPtr = (Ptr) &gameRecRestore;
  226.         err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr);    // restore gamma
  227.  
  228.         if ((noErr == err) && (8 == (**(**hGD).gdPMap).pixelSize))    // if successful and on an 8 bit device
  229.         {
  230.             hCTabDeviceColors = (**(**hGD).gdPMap).pmTable;            // do SetEntries to force CLUT update
  231.             setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable;
  232.             setEntriesRec.csStart = 0;
  233.             setEntriesRec.csCount = (**hCTabDeviceColors).ctSize;
  234.             csPtr = (Ptr) &setEntriesRec;
  235.             
  236.             err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); // SetEntries in CLUT
  237.         }
  238.     }
  239. }
  240.  
  241.  
  242. // functions (external/public) ----------------------------------------------
  243.  
  244. // GetSystemGammas
  245.  
  246. // returns a pointer to a set of all current device gammas in native format (returns NULL on failure, which means reseting gamma will not be possible)
  247. // 5/20/99: (ggs) added
  248.  
  249. Ptr GetSystemGammas (void)                                        
  250. {
  251.     precSystemGamma pSysGammaOut;                                    // return pointer to system device gamma info
  252.     short devCount = 0;                                                // number of devices attached
  253.     Boolean fail = false;
  254.  
  255.     pSysGammaOut = (precSystemGamma) NewPtr (sizeof (recSystemGamma)); // allocate for structure
  256.     
  257.     GDHandle hGDevice = GetDeviceList ();                            // top of device list
  258.     do                                                                // iterate
  259.     {
  260.         devCount++;                                                    // count devices                    
  261.         hGDevice = GetNextDevice (hGDevice);                        // next device
  262.     } while (hGDevice);
  263.     
  264.     pSysGammaOut->devGamma = (precDeviceGamma *) NewPtr (sizeof (precDeviceGamma) * devCount); // allocate for array of pointers to device records
  265.     if (pSysGammaOut)
  266.     {
  267.         pSysGammaOut->numDevices = devCount;                        // stuff count
  268.         
  269.         devCount = 0;                                                // reset iteration
  270.         hGDevice = GetDeviceList ();
  271.         do
  272.         {
  273.             pSysGammaOut->devGamma [devCount] = (precDeviceGamma) NewPtr (sizeof (recDeviceGamma));      // new device record
  274.             if (pSysGammaOut->devGamma [devCount])                    // if we actually allocated memory
  275.             {
  276.                 pSysGammaOut->devGamma [devCount]->hGD = hGDevice;                                          // stuff handle
  277.                 pSysGammaOut->devGamma [devCount]->pDeviceGamma = (GammaTblPtr)GetDeviceGamma (hGDevice); // copy gamma table
  278.             }
  279.             else                                                    // otherwise dump record on exit
  280.              fail = true;
  281.             devCount++;                                                // next device
  282.             hGDevice = GetNextDevice (hGDevice);                        
  283.         } while (hGDevice);
  284.     }
  285.     if (!fail)                                                        // if we did not fail
  286.         return (Ptr) pSysGammaOut;                                    // return pointer to structure
  287.     else
  288.     {
  289.         DisposeSystemGammas (&(Ptr)pSysGammaOut);                    // otherwise dump the current structures (dispose does error checking)
  290.         return NULL;                                                // could not complete
  291.     }
  292. }
  293.  
  294. // --------------------------------------------------------------------------
  295.  
  296. // RestoreSystemGammas
  297.  
  298. // restores all system devices to saved gamma setting
  299. // 5/20/99: (ggs) added
  300.  
  301. void RestoreSystemGammas (Ptr pSystemGammas)
  302. {
  303.     precSystemGamma pSysGammaIn = (precSystemGamma) pSystemGammas;
  304.     if (pSysGammaIn)
  305.         for (short i = 0; i < pSysGammaIn->numDevices; i++)            // for all devices
  306.             RestoreDeviceGamma (pSysGammaIn->devGamma [i]->hGD, (Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma);    // restore gamma
  307. }
  308.  
  309. // --------------------------------------------------------------------------
  310.  
  311. // DisposeSystemGammas
  312.  
  313. // iterates through and deletes stored gamma settings
  314. // 5/20/99: (ggs) added
  315.  
  316. void DisposeSystemGammas (Ptr* ppSystemGammas)
  317. {
  318.     precSystemGamma pSysGammaIn;
  319.     if (ppSystemGammas)
  320.     {
  321.         pSysGammaIn = (precSystemGamma) *ppSystemGammas;
  322.         if (pSysGammaIn)
  323.         {
  324.             for (short i = 0; i < pSysGammaIn->numDevices; i++)        // for all devices
  325.                 if (pSysGammaIn->devGamma [i])                        // if pointer is valid
  326.                 {
  327.                     DisposeGammaTable ((Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma); // dump gamma table
  328.                     DisposePtr ((Ptr) pSysGammaIn->devGamma [i]);                       // dump device info
  329.                 }
  330.             DisposePtr ((Ptr) pSysGammaIn->devGamma);                // dump device pointer array        
  331.             DisposePtr ((Ptr) pSysGammaIn);                            // dump system structure
  332.             *ppSystemGammas = NULL;
  333.         }    
  334.     }
  335. }
  336.  
  337. // --------------------------------------------------------------------------
  338.  
  339. // GetDeviceGammaRampGD
  340.  
  341. // retrieves the gamma ramp from a graphics device (pRamp: 3 arrays of 256 elements each)
  342.  
  343. Boolean GetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp)
  344. {
  345.     GammaTblPtr        pTableGammaTemp = NULL;
  346.     long             indexChan, indexEntry;
  347.     OSErr            err;
  348.     
  349.     if (pRamp)                                                            // ensure pRamp is allocated
  350.     {
  351.         err = GetGammaTable (hGD, &pTableGammaTemp);                    // get a pointer to the current gamma
  352.         if ((noErr == err) && pTableGammaTemp)                            // if successful
  353.         {                                                            
  354.             // fill ramp
  355.             unsigned char * pEntry = (unsigned char *) &pTableGammaTemp->gFormulaData + pTableGammaTemp->gFormulaSize; // base of table
  356.             short bytesPerEntry = (pTableGammaTemp->gDataWidth + 7) / 8; // size, in bytes, of the device table entries
  357.             short shiftRightValue = pTableGammaTemp->gDataWidth - 8;      // number of right shifts device -> ramp
  358.             short channels = pTableGammaTemp->gChanCnt;    
  359.             short entries = pTableGammaTemp->gDataCnt;                                    
  360.             if (3 == channels)                                            // RGB format
  361.             {                                                            // note, this will create runs of entries if dest. is bigger (not linear interpolate)
  362.                 for (indexChan = 0; indexChan < channels; indexChan++)
  363.                     for (indexEntry = 0; indexEntry < 256; indexEntry++)
  364.                         *((unsigned char *) pRamp + (indexChan * 256) + indexEntry) = 
  365.                           *(pEntry + indexChan * entries * bytesPerEntry + indexEntry * entries * bytesPerEntry / 256) >> shiftRightValue;
  366.             }
  367.             else                                                        // single channel format
  368.             {
  369.                 for (indexChan = 0; indexChan < 768; indexChan += 256)    // repeat for all 3 channels (step by ramp size)
  370.                     for (indexEntry = 0; indexEntry < 256; indexEntry++) // for all entries set vramp value
  371.                         *((unsigned char *) pRamp + indexChan + indexEntry) = 
  372.                           *(pEntry + indexEntry * entries * bytesPerEntry / 256) >> shiftRightValue;
  373.             }
  374.             return true;
  375.         }
  376.     }
  377.     return false;
  378. }
  379.  
  380. // --------------------------------------------------------------------------
  381.  
  382. // GetDeviceGammaRampGW
  383.  
  384. // retrieves the gamma ramp from a graphics device associated with a GWorld pointer (pRamp: 3 arrays of 256 elements each)
  385.  
  386. Boolean GetDeviceGammaRampGW (GWorldPtr pGW, Ptr pRamp)
  387. {
  388.     GDHandle hGD = GetGWorldDevice (pGW);
  389.     return GetDeviceGammaRampGD (hGD, pRamp);
  390. }
  391.  
  392. // --------------------------------------------------------------------------
  393.  
  394. // GetDeviceGammaRampCGP
  395.  
  396. // retrieves the gamma ramp from a graphics device associated with a CGraf pointer (pRamp: 3 arrays of 256 elements each)
  397.  
  398. Boolean GetDeviceGammaRampCGP (CGrafPtr pGraf, Ptr pRamp)
  399. {
  400.     CGrafPtr pGrafSave;
  401.     GDHandle hGDSave;
  402.     GetGWorld (&pGrafSave, &hGDSave);
  403.     SetGWorld (pGraf, NULL);
  404.     GDHandle hGD = GetGDevice ();
  405.     Boolean fResult = GetDeviceGammaRampGD (hGD, pRamp);
  406.     SetGWorld (pGrafSave, hGDSave);
  407.     return fResult;
  408. }
  409.  
  410. // --------------------------------------------------------------------------
  411.  
  412. // SetDeviceGammaRampGD
  413.  
  414. // sets the gamma ramp for a graphics device (pRamp: 3 arrays of 256 elements each (R,G,B))
  415.  
  416. Boolean SetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp)
  417. {
  418.     VDSetEntryRecord setEntriesRec;
  419.     VDGammaRecord    gameRecRestore;
  420.     GammaTblPtr        pTableGammaNew;
  421.     GammaTblPtr        pTableGammaCurrent = NULL;
  422.     CTabHandle      hCTabDeviceColors;
  423.     Ptr                csPtr;
  424.     OSErr            err;
  425.     short             dataBits, entries, channels = 3;                        // force three channels in the gamma table
  426.     
  427.     if (pRamp)                                                                // ensure pRamp is allocated
  428.     {
  429.         err= GetGammaTable (hGD, &pTableGammaCurrent);                        // get pointer to current table
  430.         if ((noErr == err) && pTableGammaCurrent)
  431.         {
  432.             dataBits = pTableGammaCurrent->gDataWidth;                        // table must have same data width
  433.             entries = pTableGammaCurrent->gDataCnt;                            // table must be same size
  434.             pTableGammaNew = (GammaTblPtr) CreateEmptyGammaTable (channels, entries, dataBits); // our new table
  435.             if (pTableGammaNew)                                                // if successful fill table
  436.             {    
  437.                 unsigned char * pGammaBase = (unsigned char *) &pTableGammaNew->gFormulaData + pTableGammaNew->gFormulaSize; // base of table
  438.                 if ((256 == entries) && (8 == dataBits))                         // simple case: direct mapping
  439.                     BlockMove ((Ptr)pRamp, (Ptr)pGammaBase, channels * entries); // move everything
  440.                 else                                                        // tough case handle entry, channel and data size disparities
  441.                 {
  442.                     short bytesPerEntry = (dataBits + 7) / 8;                 // size, in bytes, of the device table entries
  443.                     short shiftRightValue = 8 - dataBits;                    // number of right shifts ramp -> device
  444.                     shiftRightValue += ((bytesPerEntry - 1) * 8);              // multibyte entries and the need to map a byte at a time most sig. to least sig.
  445.                     for (short indexChan = 0; indexChan < channels; indexChan++) // for all the channels
  446.                         for (short indexEntry = 0; indexEntry < entries; indexEntry++) // for all the entries
  447.                         {
  448.                             short currentShift = shiftRightValue;            // reset current bit shift
  449.                             long temp = *((unsigned char *)pRamp + (indexChan << 8) + (indexEntry << 8) / entries); // get data from ramp
  450.                             for (short indexByte = 0; indexByte < bytesPerEntry; indexByte++) // for all bytes
  451.                             {
  452.                                 if (currentShift < 0)                        // shift data correctly for current byte
  453.                                     *(pGammaBase++) = temp << -currentShift;
  454.                                 else
  455.                                     *(pGammaBase++) = temp >> currentShift;
  456.                                 currentShift -= 8;                            // increment shift to align to next less sig. byte
  457.                             }
  458.                         }
  459.                 }
  460.                 
  461.                 // set gamma
  462.                 gameRecRestore.csGTable = (Ptr) pTableGammaNew;                // setup restore record
  463.                 csPtr = (Ptr) &gameRecRestore;
  464.                 err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr);    // restore gamma (note, display drivers may delay returning from this until VBL)
  465.                 
  466.                 if ((8 == (**(**hGD).gdPMap).pixelSize) && (noErr == err))    // if successful and on an 8 bit device
  467.                 {
  468.                     hCTabDeviceColors = (**(**hGD).gdPMap).pmTable;            // do SetEntries to force CLUT update
  469.                     setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable;
  470.                     setEntriesRec.csStart = 0;
  471.                     setEntriesRec.csCount = (**hCTabDeviceColors).ctSize;
  472.                     csPtr = (Ptr) &setEntriesRec;
  473.                     err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr);    // SetEntries in CLUT
  474.                 }
  475.                 DisposeGammaTable ((Ptr) pTableGammaNew);                    // dump table
  476.                 if (noErr == err)
  477.                     return true;
  478.             }
  479.         }
  480.     }
  481.     else                                                                    // set NULL gamma -> results in linear map
  482.     {
  483.         gameRecRestore.csGTable = (Ptr) NULL;                                // setup restore record
  484.         csPtr = (Ptr) &gameRecRestore;
  485.         err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr);            // restore gamma
  486.         
  487.         if ((8 == (**(**hGD).gdPMap).pixelSize) && (noErr == err))            // if successful and on an 8 bit device
  488.         {
  489.             hCTabDeviceColors = (**(**hGD).gdPMap).pmTable;                    // do SetEntries to force CLUT update
  490.             setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable;
  491.             setEntriesRec.csStart = 0;
  492.             setEntriesRec.csCount = (**hCTabDeviceColors).ctSize;
  493.             csPtr = (Ptr) &setEntriesRec;
  494.             err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr);    // SetEntries in CLUT
  495.         }
  496.         if (noErr == err)
  497.             return true;
  498.     }
  499.     return false;                                                            // memory allocation or device control failed if we get here
  500. }
  501.  
  502. // --------------------------------------------------------------------------
  503.  
  504. // SetDeviceGammaRampGW
  505.  
  506. // sets the gamma ramp for a graphics device associated with a GWorld pointer (pRamp: 3 arrays of 256 elements each (R,G,B))
  507.  
  508. Boolean SetDeviceGammaRampGW (GWorldPtr pGW, Ptr pRamp)
  509. {
  510.     GDHandle hGD = GetGWorldDevice (pGW);
  511.     return SetDeviceGammaRampGD (hGD, pRamp);
  512. }
  513.  
  514. // --------------------------------------------------------------------------
  515.  
  516. // SetDeviceGammaRampCGP
  517.  
  518. // sets the gamma ramp for a graphics device associated with a CGraf pointer (pRamp: 3 arrays of 256 elements each (R,G,B))
  519.  
  520. Boolean SetDeviceGammaRampCGP (CGrafPtr pGraf, Ptr pRamp)
  521. {
  522.     CGrafPtr pGrafSave;
  523.     GDHandle hGDSave;
  524.     GetGWorld (&pGrafSave, &hGDSave);
  525.     SetGWorld (pGraf, NULL);
  526.     GDHandle hGD = GetGDevice ();
  527.     Boolean fResult = SetDeviceGammaRampGD (hGD, pRamp);
  528.     SetGWorld (pGrafSave, hGDSave);
  529.     return fResult;
  530. }