Back to index

lightning-sunbird  0.9+nobinonly
nsImageClipboard.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Mike Pinkerton <pinkerton@netscape.com>
00024  *   Gus Verdun <gustavoverdun@aol.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039  
00040  
00041 #include "nsImageClipboard.h"
00042 #include "nsGfxCIID.h"
00043 #include "nsMemory.h"
00044 #include "prmem.h"
00045 #include "imgIEncoder.h"
00046 #ifdef MOZILLA_1_8_BRANCH
00047 #define imgIEncoder imgIEncoder_MOZILLA_1_8_BRANCH
00048 #endif
00049 #include "nsLiteralString.h"
00050 
00051 /* Things To Do 11/8/00
00052 
00053 Check image metrics, can we support them? Do we need to?
00054 Any other render format? HTML?
00055 
00056 */
00057 
00058 
00059 //
00060 // nsImageToClipboard ctor
00061 //
00062 // Given an nsIImage, convert it to a DIB that is ready to go on the win32 clipboard
00063 //
00064 nsImageToClipboard :: nsImageToClipboard ( nsIImage* inImage )
00065   : mImage(inImage)
00066 {
00067   // nothing to do here
00068 }
00069 
00070 
00071 //
00072 // nsImageToClipboard dtor
00073 //
00074 // Clean up after ourselves. We know that we have created the bitmap
00075 // successfully if we still have a pointer to the header.
00076 //
00077 nsImageToClipboard::~nsImageToClipboard()
00078 {
00079 }
00080 
00081 
00082 //
00083 // GetPicture
00084 //
00085 // Call to get the actual bits that go on the clipboard. If an error 
00086 // ocurred during conversion, |outBits| will be null.
00087 //
00088 // NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
00089 //
00090 nsresult
00091 nsImageToClipboard :: GetPicture ( HANDLE* outBits )
00092 {
00093   NS_ASSERTION ( outBits, "Bad parameter" );
00094 
00095   return CreateFromImage ( mImage, outBits );
00096 
00097 } // GetPicture
00098 
00099 
00100 //
00101 // CalcSize
00102 //
00103 // Computes # of bytes needed by a bitmap with the specified attributes.
00104 //
00105 PRInt32 
00106 nsImageToClipboard :: CalcSize ( PRInt32 aHeight, PRInt32 aColors, WORD aBitsPerPixel, PRInt32 aSpanBytes )
00107 {
00108   PRInt32 HeaderMem = sizeof(BITMAPINFOHEADER);
00109 
00110   // add size of pallette to header size
00111   if (aBitsPerPixel < 16)
00112     HeaderMem += aColors * sizeof(RGBQUAD);
00113 
00114   if (aHeight < 0)
00115     aHeight = -aHeight;
00116 
00117   return (HeaderMem + (aHeight * aSpanBytes));
00118 }
00119 
00120 
00121 //
00122 // CalcSpanLength
00123 //
00124 // Computes the span bytes for determining the overall size of the image
00125 //
00126 PRInt32 
00127 nsImageToClipboard::CalcSpanLength(PRUint32 aWidth, PRUint32 aBitCount)
00128 {
00129   PRInt32 spanBytes = (aWidth * aBitCount) >> 5;
00130   
00131   if ((aWidth * aBitCount) & 0x1F)
00132     spanBytes++;
00133   spanBytes <<= 2;
00134 
00135   return spanBytes;
00136 }
00137 
00138 
00139 //
00140 // CreateFromImage
00141 //
00142 // Do the work to setup the bitmap header and copy the bits out of the
00143 // image. 
00144 //
00145 nsresult
00146 nsImageToClipboard::CreateFromImage ( nsIImage* inImage, HANDLE* outBitmap )
00147 {
00148   nsresult result = NS_OK;
00149   *outBitmap = nsnull;
00150   
00151 /*
00152   //pHead = (BITMAPINFOHEADER*)pImage->GetBitInfo();
00153   //pImage->GetNativeData((void**)&hBitMap);
00154  if (hBitMap)
00155   {
00156          BITMAPINFO * pBMI;
00157          pBMI                    = (BITMAPINFO *)new BYTE[(sizeof(BITMAPINFOHEADER)+256*4)];
00158          BITMAPINFOHEADER * pBIH = (BITMAPINFOHEADER *)pBMI;
00159          pBIH->biSize            = sizeof(BITMAPINFOHEADER);
00160          pBIH->biBitCount        = 0;
00161          pBIH->biPlanes          = 1;
00162          pBIH->biSizeImage       = 0;
00163          pBIH->biXPelsPerMeter   = 0;
00164          pBIH->biYPelsPerMeter   = 0;
00165          pBIH->biClrUsed         = 0;                            // Always use the whole palette.
00166 
00167          pBIH->biClrImportant    = 0;
00168 
00169          // Get bitmap format.
00170 
00171          HDC hdc  =  ::GetDC(NULL);
00172          int rc   =  ::GetDIBits(hdc, hBitMap, 0, 0, NULL, pBMI, DIB_RGB_COLORS);
00173          NS_ASSERTION(rc, "rc returned false");
00174 
00175          nLength = CalcSize(pBIH->biHeight, pBIH->biClrUsed, pBIH->biBitCount, CalcSpanLength(pBIH->biWidth, pBIH->biBitCount));
00176 
00177          // alloc and lock
00178 
00179          mBitmap = (HANDLE)::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, nLength);
00180          if (mBitmap && (mHeader = (BITMAPINFOHEADER*)::GlobalLock((HGLOBAL) mBitmap)) )
00181          {
00182                  result = TRUE;
00183 
00184                  pBits = (PBYTE)&mHeader[1];
00185                  memcpy(mHeader, pBIH, sizeof (BITMAPINFOHEADER));
00186                  rc = ::GetDIBits(hdc, hBitMap, 0, mHeader->biHeight, pBits, (BITMAPINFO *)mHeader, DIB_RGB_COLORS);
00187                  NS_ASSERTION(rc, "rc returned false");
00188                  delete[] (BYTE*)pBMI;
00189                  ::GlobalUnlock((HGLOBAL)mBitmap); // we use mHeader to tell if we have to free it later.
00190 
00191          }
00192          ::ReleaseDC(NULL, hdc);
00193   }
00194   else
00195   {
00196 */
00197 
00198   inImage->LockImagePixels ( PR_FALSE );
00199   if ( inImage->GetBits() ) {
00200     BITMAPINFOHEADER* imageHeader = NS_REINTERPRET_CAST(BITMAPINFOHEADER*, inImage->GetBitInfo());
00201     NS_ASSERTION ( imageHeader, "Can't get header for image" );
00202     if ( !imageHeader )
00203       return NS_ERROR_FAILURE;
00204       
00205     PRInt32 imageSize = CalcSize(imageHeader->biHeight, imageHeader->biClrUsed, imageHeader->biBitCount, inImage->GetLineStride());
00206 
00207     // Create the buffer where we'll copy the image bits (and header) into and lock it
00208     BITMAPINFOHEADER*  header = nsnull;
00209     *outBitmap = (HANDLE)::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, imageSize);
00210     if (*outBitmap && (header = (BITMAPINFOHEADER*)::GlobalLock((HGLOBAL) *outBitmap)) )
00211     {
00212       RGBQUAD *pRGBQUAD = (RGBQUAD *)&header[1];
00213       PBYTE bits = (PBYTE)&pRGBQUAD[imageHeader->biClrUsed];
00214 
00215       // Fill in the header info.
00216 
00217       header->biSize          = sizeof(BITMAPINFOHEADER);
00218       header->biWidth         = imageHeader->biWidth;
00219       header->biHeight        = imageHeader->biHeight;
00220 
00221       header->biPlanes        = 1;
00222       header->biBitCount      = imageHeader->biBitCount;
00223       header->biCompression   = BI_RGB;               // No compression
00224 
00225       header->biSizeImage     = 0;
00226       header->biXPelsPerMeter = 0;
00227       header->biYPelsPerMeter = 0;
00228       header->biClrUsed       = imageHeader->biClrUsed;
00229       header->biClrImportant  = 0;
00230 
00231       // Set up the color map.
00232       
00233       nsColorMap *colorMap = inImage->GetColorMap();
00234       if ( colorMap ) {
00235         PBYTE pClr = colorMap->Index;
00236 
00237         NS_ASSERTION(( ((DWORD)colorMap->NumColors) == header->biClrUsed), "Color counts must match");
00238         for ( UINT i=0; i < header->biClrUsed; ++i ) {
00239           NS_WARNING ( "Cool! You found a test case for this! Let Gus or Pink know" );
00240           
00241           // now verify that the order is correct
00242           pRGBQUAD[i].rgbBlue  = *pClr++;
00243           pRGBQUAD[i].rgbGreen = *pClr++;
00244           pRGBQUAD[i].rgbRed   = *pClr++;
00245         }
00246       }
00247       else
00248         NS_ASSERTION(header->biClrUsed == 0, "Ok, now why are there colors and no table?");
00249 
00250       // Copy!!
00251       ::CopyMemory(bits, inImage->GetBits(), inImage->GetLineStride() * header->biHeight);
00252       
00253       ::GlobalUnlock((HGLOBAL)outBitmap);
00254     }
00255     else
00256       result = NS_ERROR_FAILURE;
00257   } // if we can get the bits from the image
00258   
00259   inImage->UnlockImagePixels ( PR_FALSE );
00260   return result;
00261 }
00262 
00263 nsImageFromClipboard :: nsImageFromClipboard ()
00264 {
00265   // nothing to do here
00266 }
00267 
00268 nsImageFromClipboard :: ~nsImageFromClipboard ( )
00269 {
00270 }
00271 
00272 //
00273 // GetEncodedImageStream
00274 //
00275 // Take the raw clipboard image data and convert it to a JPG in the form of a nsIInputStream
00276 //
00277 nsresult 
00278 nsImageFromClipboard ::GetEncodedImageStream (unsigned char * aClipboardData, nsIInputStream** aInputStream )
00279 {
00280   NS_ENSURE_ARG_POINTER (aInputStream);
00281   nsresult rv;
00282   *aInputStream = nsnull;
00283 
00284   // pull the size information out of the BITMAPINFO header and
00285   // initialize the image
00286   BITMAPINFO* header = (BITMAPINFO *) aClipboardData;
00287   PRInt32 width  = header->bmiHeader.biWidth;
00288   PRInt32 height = header->bmiHeader.biHeight;
00289   // neg. heights mean the Y axis is inverted and we don't handle that case
00290   NS_ENSURE_TRUE(height > 0, NS_ERROR_FAILURE); 
00291 
00292   unsigned char * rgbData = new unsigned char[width * height * 3 /* RGB */];
00293 
00294   if (rgbData) {
00295     BYTE  * pGlobal = (BYTE *) aClipboardData;
00296     // Convert the clipboard image into RGB packed pixel data
00297     rv = ConvertColorBitMap((unsigned char *) (pGlobal + header->bmiHeader.biSize), header, rgbData);
00298     // if that succeeded, encode the bitmap as a JPG. Don't return early or we risk leaking rgbData
00299     if (NS_SUCCEEDED(rv)) {
00300       nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/jpeg", &rv);
00301       if (NS_SUCCEEDED(rv)){
00302         rv = encoder->InitFromData(rgbData, 0, width, height, 3 * width /* RGB * # pixels in a row */, 
00303                                    imgIEncoder::INPUT_FORMAT_RGB, NS_LITERAL_STRING("transparency=none"));
00304         if (NS_SUCCEEDED(rv))
00305           encoder->QueryInterface(NS_GET_IID(nsIInputStream), (void **) aInputStream);
00306       }
00307     }
00308     delete [] rgbData;
00309   } 
00310   else 
00311     rv = NS_ERROR_OUT_OF_MEMORY;
00312 
00313   return rv;
00314 } // GetImage
00315 
00316 //
00317 // InvertRows
00318 //
00319 // Take the image data from the clipboard and invert the rows. Modifying aInitialBuffer in place.
00320 //
00321 void
00322 nsImageFromClipboard::InvertRows(unsigned char * aInitialBuffer, PRUint32 aSizeOfBuffer, PRUint32 aNumBytesPerRow)
00323 {
00324   if (!aNumBytesPerRow) 
00325     return; 
00326 
00327   PRUint32 numRows = aSizeOfBuffer / aNumBytesPerRow;
00328   unsigned char * row = new unsigned char[aNumBytesPerRow];
00329 
00330   PRUint32 currentRow = 0;
00331   PRUint32 lastRow = (numRows - 1) * aNumBytesPerRow;
00332   while (currentRow < lastRow)
00333   {
00334     // store the current row into a temporary buffer
00335     memcpy(row, &aInitialBuffer[currentRow], aNumBytesPerRow);
00336     memcpy(&aInitialBuffer[currentRow], &aInitialBuffer[lastRow], aNumBytesPerRow);
00337     memcpy(&aInitialBuffer[lastRow], row, aNumBytesPerRow);
00338     lastRow -= aNumBytesPerRow;
00339     currentRow += aNumBytesPerRow;
00340   }
00341 
00342   delete[] row;
00343 }
00344 
00345 //
00346 // ConvertColorBitMap
00347 //
00348 // Takes the clipboard bitmap and converts it into a RGB packed pixel values.
00349 //
00350 nsresult 
00351 nsImageFromClipboard::ConvertColorBitMap(unsigned char * aInputBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutBuffer)
00352 {
00353   PRUint8 bitCount = pBitMapInfo->bmiHeader.biBitCount; 
00354   PRUint32 imageSize = pBitMapInfo->bmiHeader.biSizeImage; // may be zero for BI_RGB bitmaps which means we need to calculate by hand
00355   PRUint32 bytesPerPixel = bitCount / 8;
00356   
00357   if (bitCount <= 4)
00358     bytesPerPixel = 1;
00359 
00360   // rows are DWORD aligned. Calculate how many real bytes are in each row in the bitmap. This number won't 
00361   // correspond to biWidth.
00362   PRUint32 rowSize = (bitCount * pBitMapInfo->bmiHeader.biWidth + 7) / 8; // +7 to round up
00363   if (rowSize % 4)
00364     rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
00365   
00366   // if our buffer includes a color map, skip over it 
00367   if (bitCount <= 8)
00368   {
00369     PRInt32 bytesToSkip = (pBitMapInfo->bmiHeader.biClrUsed ? pBitMapInfo->bmiHeader.biClrUsed : (1 << bitCount) ) * sizeof(RGBQUAD);
00370     aInputBuffer +=  bytesToSkip;
00371   }
00372 
00373   bitFields colorMasks; // only used if biCompression == BI_BITFIELDS
00374 
00375   if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
00376   {
00377     // color table consists of 3 DWORDS containing the color masks...
00378     colorMasks.red = (*((PRUint32*)&(pBitMapInfo->bmiColors[0]))); 
00379     colorMasks.green = (*((PRUint32*)&(pBitMapInfo->bmiColors[1]))); 
00380     colorMasks.blue = (*((PRUint32*)&(pBitMapInfo->bmiColors[2]))); 
00381     CalcBitShift(&colorMasks);
00382     aInputBuffer += 3 * sizeof(DWORD);
00383   } 
00384   else if (pBitMapInfo->bmiHeader.biCompression == BI_RGB && !imageSize)  // BI_RGB can have a size of zero which means we figure it out
00385   {
00386     // XXX: note use rowSize here and not biWidth. rowSize accounts for the DWORD padding for each row
00387     imageSize = rowSize * pBitMapInfo->bmiHeader.biHeight;
00388   }
00389 
00390   // The windows clipboard image format inverts the rows 
00391   InvertRows(aInputBuffer, imageSize, rowSize);
00392 
00393   if (!pBitMapInfo->bmiHeader.biCompression || pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS) 
00394   {  
00395     PRUint32 index = 0;
00396     PRUint32 writeIndex = 0;
00397      
00398     unsigned char redValue, greenValue, blueValue;
00399     PRUint8 colorTableEntry = 0;
00400     PRInt8 bit; // used for grayscale bitmaps where each bit is a pixel
00401     PRUint32 numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth; // how many more pixels do we still need to read for the current row
00402     PRUint32 pos = 0;
00403 
00404     while (index < imageSize)
00405     {
00406       switch (bitCount) 
00407       {
00408         case 1:
00409           for (bit = 7; bit >= 0 && numPixelsLeftInRow; bit--)
00410           {
00411             colorTableEntry = (aInputBuffer[index] >> bit) & 1;
00412             aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
00413             aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
00414             aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
00415             numPixelsLeftInRow--;
00416           }
00417           pos += 1;
00418           break;
00419         case 4:
00420           {
00421             // each aInputBuffer[index] entry contains data for two pixels.
00422             // read the first pixel
00423             colorTableEntry = aInputBuffer[index] >> 4;
00424             aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
00425             aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
00426             aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
00427             numPixelsLeftInRow--;
00428 
00429             if (numPixelsLeftInRow) // now read the second pixel
00430             {
00431               colorTableEntry = aInputBuffer[index] & 0xF;
00432               aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
00433               aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
00434               aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
00435               numPixelsLeftInRow--;
00436             }
00437             pos += 1;
00438           }
00439           break;
00440         case 8:
00441           aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbRed;
00442           aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbGreen;
00443           aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbBlue;
00444           numPixelsLeftInRow--;
00445           pos += 1;    
00446           break;
00447         case 16:
00448           {
00449             PRUint16 num = 0;
00450             num = (PRUint8) aInputBuffer[index+1];
00451             num <<= 8;
00452             num |= (PRUint8) aInputBuffer[index];
00453 
00454             redValue = ((PRUint32) (((float)(num & 0xf800) / 0xf800) * 0xFF0000) & 0xFF0000)>> 16;
00455             greenValue =  ((PRUint32)(((float)(num & 0x07E0) / 0x07E0) * 0x00FF00) & 0x00FF00)>> 8;
00456             blueValue =  ((PRUint32)(((float)(num & 0x001F) / 0x001F) * 0x0000FF) & 0x0000FF);
00457 
00458             // now we have the right RGB values...
00459             aOutBuffer[writeIndex++] = redValue;
00460             aOutBuffer[writeIndex++] = greenValue;
00461             aOutBuffer[writeIndex++] = blueValue;
00462             numPixelsLeftInRow--;
00463             pos += 2;          
00464           }
00465           break;
00466         case 32:
00467         case 24:
00468           if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
00469           {
00470             PRUint32 val = *((PRUint32*) (aInputBuffer + index) );
00471             aOutBuffer[writeIndex++] = (val & colorMasks.red) >> colorMasks.redRightShift << colorMasks.redLeftShift;
00472             aOutBuffer[writeIndex++] =  (val & colorMasks.green) >> colorMasks.greenRightShift << colorMasks.greenLeftShift;
00473             aOutBuffer[writeIndex++] = (val & colorMasks.blue) >> colorMasks.blueRightShift << colorMasks.blueLeftShift;
00474             numPixelsLeftInRow--;
00475             pos += 4; // we read in 4 bytes of data in order to process this pixel
00476           }
00477           else
00478           {
00479             aOutBuffer[writeIndex++] = aInputBuffer[index+2];
00480             aOutBuffer[writeIndex++] =  aInputBuffer[index+1];
00481             aOutBuffer[writeIndex++] = aInputBuffer[index];
00482             numPixelsLeftInRow--;
00483             pos += bytesPerPixel; // 3 bytes for 24 bit data, 4 bytes for 32 bit data (we skip over the 4th byte)...
00484           }
00485           break;
00486         default:
00487           // This is probably the wrong place to check this...
00488           return NS_ERROR_FAILURE;
00489       }
00490 
00491       index += bytesPerPixel; // increment our loop counter
00492 
00493       if (!numPixelsLeftInRow)
00494       {
00495         if (rowSize != pos)
00496         {
00497           // advance index to skip over remaining padding bytes
00498           index += (rowSize - pos);
00499         }
00500         numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth;
00501         pos = 0; 
00502       }
00503 
00504     } // while we still have bytes to process
00505   }
00506 
00507   return NS_OK;
00508 }
00509 
00510 void nsImageFromClipboard::CalcBitmask(PRUint32 aMask, PRUint8& aBegin, PRUint8& aLength)
00511 {
00512   // find the rightmost 1
00513   PRUint8 pos;
00514   PRBool started = PR_FALSE;
00515   aBegin = aLength = 0;
00516   for (pos = 0; pos <= 31; pos++) 
00517   {
00518     if (!started && (aMask & (1 << pos))) 
00519     {
00520       aBegin = pos;
00521       started = PR_TRUE;
00522     }
00523     else if (started && !(aMask & (1 << pos))) 
00524     {
00525       aLength = pos - aBegin;
00526       break;
00527     }
00528   }
00529 }
00530 
00531 void nsImageFromClipboard::CalcBitShift(bitFields * aColorMask)
00532 {
00533   PRUint8 begin, length;
00534   // red
00535   CalcBitmask(aColorMask->red, begin, length);
00536   aColorMask->redRightShift = begin;
00537   aColorMask->redLeftShift = 8 - length;
00538   // green
00539   CalcBitmask(aColorMask->green, begin, length);
00540   aColorMask->greenRightShift = begin;
00541   aColorMask->greenLeftShift = 8 - length;
00542   // blue
00543   CalcBitmask(aColorMask->blue, begin, length);
00544   aColorMask->blueRightShift = begin;
00545   aColorMask->blueLeftShift = 8 - length;
00546 }