TweetFollow Us on Twitter

Jul 94 Challenge
Volume Number:10
Issue Number:7
Column Tag:Programmers’ Challenge

Programmers’ Challenge

By Mike Scanlin, MacTech Magazine Regular Contributing Author

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Color Space Conversion

Typically, when an RGB image is compressed into JPEG data, it is first converted into separate luminance (Y) and chrominance (U and V) components. Although JPEG doesn’t specify which color space conversion to use, a commonly used one is:

Y     0.29900000   0.58700000   0.11400000     R
U  = -0.16873590  -0.33126410   0.50000000  *  G
V     0.50000000  -0.41868760  -0.08131241     B

where R, G and B are unsigned chars (0..255). For the outputs, Y is an unsigned char (0..255) while U and V are signed chars (-128..127).

The prototype of the two functions you write are:


/* 1 */
void *RGBtoYUVInit(void);

void RGBtoYUV(rPtr, gPtr, bPtr, 
              yPtr, uPtr, vPtr,
              numPixels,privateDataPtr)
unsigned char *rPtr;
unsigned char *gPtr;
unsigned char *bPtr;
unsigned char *yPtr;
  signed char *uPtr;
  signed char *vPtr;
unsigned long numPixels;
         void *privateDataPtr;

This month you’re being given a chance to have a separate initialization routine that will not be timed (only the RGBtoYUV will count towards your time). It can create whatever lookup tables RGBtoYUV may need and return a pointer to that private data. The return value from RGBtoYUVInit will be passed to RGBtoYUV as the privateDataPtr parameter. You decide what it points to (if anything).

There are two key aspects to writing RGBtoYUV. The first is that it has to be fast (as always). The second, though, is that it has to be accurate (or else when someone reconstructs the image with the inverse conversion image quality will be lost). Even though the outputs are only 8 bits, the matrix coefficients require much more than that to represent. Your output values must equal what you would get if you carried out the matrix math with complete precision and then rounded the results down to 8 bits as the last step (with .5 rounding down to zero). For instance, if R = 3, G = 17 and B = 23 then: Y = 3*.299 + 17*.587 + 23*.114 which is 13.498. When rounded this becomes 13 which is what you should return as part of the buffer that yPtr points to.

Each of the pointers to the RGB input data and YUV output data point to a buffer filled with data of one component (so there are 6 buffers total). numPixels is between 1 and 1,000,000 and is the size of each buffer. If numPixels were 100 then rPtr would point to 100 red values and gPtr and bPtr would point to 100 corresponding green and blue values. Your routine would then set the 100 bytes pointed to by yPtr to the appropriate Y values (and likewise for the U and V values, too).

The RGB and YUV buffers will be allocated for you. Your initialization routine may allocate up to 1MB of lookup tables if it wants to (it will be able to get a contiguous 1MB piece if it needs it).

TWO MONTHS AGO WINNER

We have a new first-time winner this month. Congrats to Troy Anderson (Paradise Valley, AZ) for his somewhat large but definitely fast entry in the Flip Horizontal challenge. He was faster than second place winner Bob Boonstra (Westford, MA) in every case that I tested. No small feat considering that Bob is a three-time Challenge winner. Troy also beat another three-time winner, Bill Karsh (Chicago, IL), in almost every test case. Unfortunately, Bill may have been too ecstatic with his win last month to test every possible case this month and unfortunately I had to disqualify his entry for lack of correctness.

Here are the code sizes and times. The time numbers represents the sum of the times for many different inputs (different depths, different rowBytes, etc). Numbers in parens after a person’s name indicate how many times that person has finished in the top 5 places of all previous Programmer Challenges, not including this one:

Name time code+data

Troy Anderson 759 2442

Bob Boonstra (8) 818 1564

Allen Stenger (5) 1069 1318

Michael Panchenko 2952 616

The best way to do well at the Flip Horizontal problem is to write dedicated code to handle each possible depth. That’s exactly what Troy did. He then went even further by special casing certain common cases, such as when rowBytes is a multiple of four.

Troy also solved the flip-byte problem (that exists when the depth is less than 8) the same way that almost everyone else did: with a lookup table for each case (1-bit, 2-bit and 4-bit). For example, when you’re flipping a bitmap horizontally it becomes necessary to flip all 8 bits in a byte. With a 256 element lookup table you can do this in a single lookup.

The 8-bit, 16-bit and 32-bit deep cases are all very similar. Troy reuses similar code by letting the preprocessor fill in the types of his variables (he uses the #define T for this purpose).

Another way of doing this, if the code is similar enough for each case, is to make the whole routine a macro and have it take a parameter which represents the type (byte, short, etc) that you want the code generated for. For instance, Bob Boonstra created this macro:


/* 2 */
/* Macro DoFlipHoriz 
 handles cases where a pixel is one byte, word, or longword in size.
 */
#define DoFlipHoriz(tp) \
{ \
/* loopCount=numCols/2 has already been calculated. */ \
  if (0 < loopCount) do { \
    register tp *p,*q; \
    p = (tp *)base; \
    q = p+numCols; \
    cCount = loopCount; \
    do { \
      register tp temp; \
      temp = *p; \
      *p++ = *--q; \
      *q = temp; \
    } while (--cCount); \
    base += rowBytes; \
  } while (--rCount); \
}
and then uses it like this in part of his solution:

    register short cCount,rCount,loopCount;
    rCount = numRows;
    loopCount = numCols>>1;
    if (8 == pixSize) DoFlipHoriz(uchar) 
    else if (16==pixSize) DoFlipHoriz(ushort)
    else /*if (32==pixSize)*/ DoFlipHoriz(ulong)

You’ll get 3 copies of the macro’s code, each for a different size pixel.
Here’s Troy’s winning solution:

// MacTech Magazine Programmers' Challenge
// May, 1994
// Submitted by Troy Anderson
// 
// Copyright (c) 1994 Troy L. Anderson

#include <QDOffscreen.h>

typedef unsigned char UCHAR;

prototypes
void FlipPixMapHorz( PixMapHandle thePixMapHndl);

static void Flip_Long(  PixMapHandle theMap, 
                        short rowBytes,
                        short depth,
                        Rect* area);

static void Flip_Word(  PixMapHandle theMap, 
                        short rowBytes,
                        short depth,
                        Rect* area);

static void ExchangeWords_Long( PixMapHandle theMap, 
                                short rowBytes,
                                short depth,
                                Rect* area);

static void ExchangeWords_Word( PixMapHandle theMap, 
                                short rowBytes,
                                short depth,
                                Rect* area);

static void ExchangeWords_Byte( PixMapHandle theMap, 
                                short rowBytes,
                                short depth,
                                Rect* area);


FlipPixMapHorz
// This could be made a bit faster by in-lining the functions, but this 
is much clearer,
// and not very much slower.
void FlipPixMapHorz( PixMapHandle thePixMapHndl)
{
  short   rowBytes = (**thePixMapHndl).rowBytes & 0x7fff;
  Boolean longAligned = rowBytes % 4 == 0;
  short   depth = (**thePixMapHndl).pixelSize;
  Rect    bounds = (**thePixMapHndl).bounds;
  
  switch( depth)
  {
    case  1:
    case  2:
    case  4:
      if (longAligned)
        Flip_Long(  thePixMapHndl, 
                    rowBytes,
                    depth,
                    &bounds);
      else
        Flip_Word(  thePixMapHndl,
                    rowBytes,
                    depth,
                    &bounds);
      break;

    case  8:
      ExchangeWords_Byte( thePixMapHndl,
                          rowBytes,
                          depth,
                          &bounds);
      break;
    
    case  16:
      ExchangeWords_Word( thePixMapHndl,
                          rowBytes,
                          depth,
                          &bounds);
      break;
      
    case  32:
      ExchangeWords_Long( thePixMapHndl,
                          rowBytes,
                          depth,
                          &bounds);
      break;
  }
}


ExchangeWords_Long
long word alignment version
static void ExchangeWords_Long( PixMapHandle theMap,
                                short rowBytes,
                                short depth,
                                Rect* area)
{
#undef T
#define T long

  short       rowCells = rowBytes / sizeof(T);
  short       numCells = ((area->right - area->left) * 
                      depth + sizeof(T)*8 - 1) / 
                      (sizeof(T)*8);
  T           temp;
  register T  *cellPtr1, *cellPtr2;
  T           *aRow;
  T           *firstRow = (T*)GetPixBaseAddr( theMap);
  T           *lastRow = firstRow + rowCells * 
                        (long)(area->bottom - area->top);

    // Flip the words in each row
  for ( aRow = firstRow; aRow < lastRow; aRow += rowCells)
    for ( cellPtr1 = aRow + numCells-1, cellPtr2 = aRow;
        cellPtr1 > cellPtr2; 
        cellPtr1--, cellPtr2++)
      temp = *cellPtr1, // swap them 
      *cellPtr1 = *cellPtr2, 
      *cellPtr2 = temp;
}


ExchangeWords
word alignment version
static void ExchangeWords_Word( PixMapHandle theMap,
                                short rowBytes,
                                short depth,
                                Rect* area)
{
#undef T
#define T short

  short       rowCells = rowBytes / sizeof(T);
  short       numCells = ((area->right - area->left) * 
                      depth + sizeof(T)*8 - 1) / 
                      (sizeof(T)*8);
  T           temp;
  register T  *cellPtr1, *cellPtr2;
  T           *aRow;
  T           *firstRow = (T*)GetPixBaseAddr( theMap);
  T           *lastRow = firstRow + rowCells * 
                        (long)(area->bottom - area->top);

    // Flip the words in each row
  for ( aRow = firstRow; aRow < lastRow; aRow += rowCells)
    for ( cellPtr1 = aRow + numCells-1, cellPtr2 = aRow;
        cellPtr1 > cellPtr2; 
        cellPtr1--, cellPtr2++)
      temp = *cellPtr1, // swap them 
      *cellPtr1 = *cellPtr2, 
      *cellPtr2 = temp;
}

ExchangeWords
byte alignment version
static void ExchangeWords_Byte( PixMapHandle theMap,
                                short rowBytes,
                                short depth,
                                Rect* area)
{
#undef T
#define T char

  short       rowCells = rowBytes / sizeof(T);
  short       numCells = ((area->right - area->left) * 
                      depth + sizeof(T)*8 - 1) / 
                      (sizeof(T)*8);
  T           temp;
  register T  *cellPtr1, *cellPtr2;
  T           *aRow;
  T           *firstRow = (T*)GetPixBaseAddr( theMap);
  T           *lastRow = firstRow + rowCells * 
                        (long)(area->bottom - area->top);

    // Flip the words in each row
  for ( aRow = firstRow; aRow < lastRow; aRow += rowCells)
    for ( cellPtr1 = aRow + numCells-1, cellPtr2 = aRow;
        cellPtr1 > cellPtr2; 
        cellPtr1--, cellPtr2++)
      temp = *cellPtr1, // swap them 
      *cellPtr1 = *cellPtr2, 
      *cellPtr2 = temp;
}


Inverse tables
// Inverse tables used to flip the bits in a byte - 
// index is input, value is inverse of index

// This is the 1-bit per pixel table
static char byteFlips1[] ={ 
  0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 
  0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
  0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 
  0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
  0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 
  0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 
  0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 
  0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 
  0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 
  0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 
  0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 
  0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 
  0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 
  0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 
  0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 
  0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 
  0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 
  0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 
  0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 
  0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 
  0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 
  0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 
  0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 
  0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
  0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 
  0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
  0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 
  0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 
  0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 
  0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 
  0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 
  0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff  };
              
// This is the 2-bits per pixel table
static char byteFlips2[] ={ 
  0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0, 
  0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0,
  0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4, 
  0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4,
  0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8, 
  0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8, 
  0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc, 
  0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc, 
  0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1, 
  0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1, 
  0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5, 
  0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5, 
  0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9, 
  0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9, 
  0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd, 
  0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd, 
  0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2, 
  0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2, 
  0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6, 
  0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6, 
  0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda, 
  0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa, 
  0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde, 
  0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe, 
  0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3, 
  0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3, 
  0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7, 
  0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7, 
  0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb, 
  0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb, 
  0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf, 
  0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff  };
            
// This is the 4-bits per pixel table
static char byteFlips4[] ={ 
  0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 
  0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
  0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 
  0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1, 
  0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 
  0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2, 0xe2, 0xf2, 
  0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 
  0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3, 
  0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, 
  0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4, 
  0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, 
  0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 
  0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, 
  0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 
  0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 
  0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 
  0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 
  0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, 
  0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, 
  0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, 
  0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a, 
  0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, 
  0x0b, 0x1b, 0x2b, 0x3b, 0x4b, 0x5b, 0x6b, 0x7b, 
  0x8b, 0x9b, 0xab, 0xbb, 0xcb, 0xdb, 0xeb, 0xfb, 
  0x0c, 0x1c, 0x2c, 0x3c, 0x4c, 0x5c, 0x6c, 0x7c, 
  0x8c, 0x9c, 0xac, 0xbc, 0xcc, 0xdc, 0xec, 0xfc, 
  0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d, 
  0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd, 
  0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e, 
  0x8e, 0x9e, 0xae, 0xbe, 0xce, 0xde, 0xee, 0xfe, 
  0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f, 
  0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff  };


Flip_Long
static void Flip_Long(  PixMapHandle theMap, 
                        short rowBytes,
                        short depth,
                        Rect* area)
{
#undef T
#define T long

  register UCHAR  temp;
  short           rowCells = rowBytes / sizeof(T);
  long            bitsPerRow = (area->right - area->left) *
                          (long)depth - 1;
  short           numCells = (bitsPerRow + sizeof(T)*8) /
                          (sizeof(T)*8);
  T*              cellPtr;
  T*              aRow;
  T*              firstRow = (T*)GetPixBaseAddr( theMap);
  T*              lastRow = firstRow + rowCells * 
                      (long)(area->bottom - area->top);
  
  register T*     cellPtr1, *cellPtr2;

  short           numBitsToShift = ((sizeof(T)*8) -
                      (bitsPerRow % (sizeof(T)*8) + 1));
  T               shiftMask;
  T*              shiftCellPtr;
  char*           flipTable;
  
  

  switch(depth)
  {
    case 1:
      flipTable = byteFlips1;
      break;
    case 2:
      flipTable = byteFlips2;
      break;
    case 4:
      flipTable = byteFlips4;
      break;
  }
            

  if (numBitsToShift)
  {
    shiftMask = (1L << numBitsToShift) - 1;

    for ( aRow = firstRow; 
        aRow < lastRow;
        aRow += rowCells)
    {
      // With each pair of cells in the row (one on the left, the other 
on the right),
      // flip the pixels in the individual cells and swap the cells with 
one another.
      for ( cellPtr1 = aRow + numCells - 1, cellPtr2 = aRow;
          cellPtr1 > cellPtr2;
          cellPtr1--, cellPtr2++)
      {
        temp = ((UCHAR*)cellPtr1)[0];
        ((UCHAR*)cellPtr1)[0] = 
            flipTable[((UCHAR*)cellPtr2)[3]];
        ((UCHAR*)cellPtr2)[3] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[1];
        ((UCHAR*)cellPtr1)[1] = 
            flipTable[((UCHAR*)cellPtr2)[2]];
        ((UCHAR*)cellPtr2)[2] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[2];
        ((UCHAR*)cellPtr1)[2] = 
            flipTable[((UCHAR*)cellPtr2)[1]];
        ((UCHAR*)cellPtr2)[1] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[3];
        ((UCHAR*)cellPtr1)[3] = 
            flipTable[((UCHAR*)cellPtr2)[0]];
        ((UCHAR*)cellPtr2)[0] = flipTable[temp];
      }
      
      // If there's an odd number of cells in the row,  there is one 
cell we haven't
      // touched.   It needs to be flipped.
      if (cellPtr1 == cellPtr2)
      {
        temp = ((UCHAR*)cellPtr1)[0];
        ((UCHAR*)cellPtr1)[0] = 
            flipTable[((UCHAR*)cellPtr1)[3]];
        ((UCHAR*)cellPtr1)[3] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[1];
        ((UCHAR*)cellPtr1)[1] = 
            flipTable[((UCHAR*)cellPtr1)[2]];
        ((UCHAR*)cellPtr1)[2] = flipTable[temp];
      }

      // Slide the pixels to the left
      for ( shiftCellPtr = aRow;
          shiftCellPtr < aRow + rowCells;
          shiftCellPtr++)
      {
        // shift the bits over
        *shiftCellPtr <<= numBitsToShift;
          
        // bring in the bits from the next cell - garbage will be brought 
in during
        // the last iteration, but it’s put into the last cell, outside 
the bounds of the 
        // image (but still in the data area)
        *shiftCellPtr |= shiftMask & 
                        (*(shiftCellPtr+1) >> 
                          (sizeof(T)*8 - numBitsToShift));
      }
    }
  }
  else  // no need to shift pixels, otherwise, just the same as previous 
loop
    for ( aRow = firstRow; aRow < lastRow; aRow += rowCells)
    {
      // With each pair of cells in the row (one on the  left, the other 
on the right),
      // flip the pixels in the individual cells and swap the cells with 
one another.
      for ( cellPtr1 = aRow + numCells - 1, cellPtr2 = aRow;
            cellPtr1 > cellPtr2;
            cellPtr1--, cellPtr2++)
      {
        temp = ((UCHAR*)cellPtr1)[0];
        ((UCHAR*)cellPtr1)[0] =
            flipTable[((UCHAR*)cellPtr2)[3]];
        ((UCHAR*)cellPtr2)[3] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[1];
        ((UCHAR*)cellPtr1)[1] = 
            flipTable[((UCHAR*)cellPtr2)[2]];
        ((UCHAR*)cellPtr2)[2] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[2];
        ((UCHAR*)cellPtr1)[2] = 
            flipTable[((UCHAR*)cellPtr2)[1]];
        ((UCHAR*)cellPtr2)[1] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[3];
        ((UCHAR*)cellPtr1)[3] = 
            flipTable[((UCHAR*)cellPtr2)[0]];
        ((UCHAR*)cellPtr2)[0] = flipTable[temp];
      }
      
      // If there are an odd number of cells in the row,
      // there is one cell we haven't touched.
      // It needs to be flipped.
      if (cellPtr1 == cellPtr2)
      {
        temp = ((UCHAR*)cellPtr1)[0];
        ((UCHAR*)cellPtr1)[0] = 
            flipTable[((UCHAR*)cellPtr1)[3]];
        ((UCHAR*)cellPtr1)[3] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[1];
        ((UCHAR*)cellPtr1)[1] = 
            flipTable[((UCHAR*)cellPtr1)[2]];
        ((UCHAR*)cellPtr1)[2] = flipTable[temp];
      }
    }
  }
}


Flip_Word
static void Flip_Word(  PixMapHandle theMap, 
                        short rowBytes,
                        short depth,
                        Rect* area)
{
#undef T
#define T short

  register UCHAR  temp;
  short           rowCells = rowBytes / sizeof(T);
  long            bitsPerRow = (area->right - area->left) *
                          (long)depth - 1;
  short           numCells = (bitsPerRow + sizeof(T)*8) /
                          (sizeof(T)*8);
  T*              cellPtr;
  T*              aRow;
  T*              firstRow = (T*)GetPixBaseAddr( theMap);
  T*              lastRow = firstRow + rowCells * 
                      (long)(area->bottom - area->top);
  
  register T*     cellPtr1, *cellPtr2;

  short           numBitsToShift = ((sizeof(T)*8) -
                      (bitsPerRow % (sizeof(T)*8) + 1));
  T               shiftMask;
  T*              shiftCellPtr;
  char*           flipTable;
  
  

  switch(depth)
  {
    case 1:
      flipTable = byteFlips1;
      break;
    case 2:
      flipTable = byteFlips2;
      break;
    case 4:
      flipTable = byteFlips4;
      break;
  }
            

  if (numBitsToShift)
  {
    shiftMask = (1L << numBitsToShift) - 1;

    for ( aRow = firstRow; aRow < lastRow; aRow += rowCells)
    {
      // With each pair of cells in the row (one on the left, the other 
on the right),
      // flip the pixels in the individual cells and swap the cells with 
one another.
      for ( cellPtr1 = aRow + numCells - 1, cellPtr2 = aRow;
          cellPtr1 > cellPtr2;
          cellPtr1--, cellPtr2++)
      {
        temp = ((UCHAR*)cellPtr1)[0];
        ((UCHAR*)cellPtr1)[0] = 
            flipTable[((UCHAR*)cellPtr2)[1]];
        ((UCHAR*)cellPtr2)[1] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[1];
        ((UCHAR*)cellPtr1)[1] =
            flipTable[((UCHAR*)cellPtr2)[0]];
        ((UCHAR*)cellPtr2)[0] = flipTable[temp];
      }
      
      // If there's an odd number of cells in the row, there is one cell 
we haven't
      // touched.   It needs to be flipped.
      if (cellPtr1 == cellPtr2)
      {
        temp = ((UCHAR*)cellPtr1)[0];
        ((UCHAR*)cellPtr1)[0] = 
            flipTable[((UCHAR*)cellPtr1)[1]];
        ((UCHAR*)cellPtr1)[1] = 
            flipTable[temp];
      }

      // Slide the pixels to the left
      for ( shiftCellPtr = aRow;
          shiftCellPtr < aRow + rowCells;
          shiftCellPtr++)
      {
      // shift the bits over
        *shiftCellPtr <<= numBitsToShift;
          
      // bring in the bits from the next cell - garbage will be brought 
in during last 
      // iteration, but it’s put into the last
        // cell, outside the bounds of the image (but still in the data 
area)
        *shiftCellPtr |= shiftMask & 
                        (*(shiftCellPtr+1) >> 
                          (sizeof(T)*8 - numBitsToShift));
      }
    }
  }
  else  // no need to shift pixels, otherwise,  just the same as previous 
loop
    for ( aRow = firstRow; aRow < lastRow; aRow += rowCells)
    {
      // With each pair of cells in the row (one on the 
      // left, the other on the right), flip the pixels
      // in the individual cells and swap the cells with
       // one another.
      for ( cellPtr1 = aRow + numCells - 1, cellPtr2 = aRow;
            cellPtr1 > cellPtr2;
            cellPtr1--, cellPtr2++)
      {
        temp = ((UCHAR*)cellPtr1)[0];
        ((UCHAR*)cellPtr1)[0] = 
            flipTable[((UCHAR*)cellPtr2)[1]];
        ((UCHAR*)cellPtr2)[1] = flipTable[temp];
        
        temp = ((UCHAR*)cellPtr1)[1];
        ((UCHAR*)cellPtr1)[1] = 
            flipTable[((UCHAR*)cellPtr2)[0]];
        ((UCHAR*)cellPtr2)[0] = flipTable[temp];
      }
      
      // If there are an odd number of cells in the row,
      // there is one cell we haven't touched.
      // It needs to be flipped.
      if (cellPtr1 == cellPtr2)
      {
        temp = ((UCHAR*)cellPtr1)[0];
        ((UCHAR*)cellPtr1)[0] = 
            flipTable[((UCHAR*)cellPtr1)[1]];
        ((UCHAR*)cellPtr1)[1] = flipTable[temp];
      }
    }
  }
}
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

GarageSale 6.9.2 - Create outstanding eB...
GarageSale is a slick, full-featured client application for the eBay online auction system. Create and manage your auctions with ease. With GarageSale, you can create, edit, track, and manage... Read more
calibre 2.17 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
OmniGraffle Pro 6.1.2 - Create diagrams,...
OmniGraffle Pro helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use... Read more
OmniGraffle 6.1.2 - Create diagrams, flo...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
RoboForm 2.0.2 - Password manager; syncs...
RoboForm is a password manager that offers one-click login, mobile syncing, easy form filling, and reliable security. Password Manager. RoboForm remembers your passwords so you don't have to! Just... Read more
Apple MainStage 3.1 - Live performance t...
Love the sound you got on your recording? MainStage 3 makes it easy to bring all the same instruments and effects to the stage. Everything from the Sound Library and Smart Controls you're familiar... Read more
Freeway Pro 7.0.2 - Drag-and-drop Web de...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With its user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more
A Better Finder Rename 9.44 - File, phot...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more
Stacks 2.6.9 - New way to create pages i...
Stacks is a new way to create pages in RapidWeaver. It's a plugin designed to combine drag-and-drop simplicity with the power of fluid layout. Features: Fluid Layout: Stacks lets you build pages... Read more
Sid Meier's Civilization: Beyond Ea...
Sid Meier's Civilization: Beyond Earth is a new science-fiction-themed entry into the award-winning Civilization series. Set in the future, global events have destabilized the world leading to a... Read more

Mediocre, the Team Behind Smash Hit, is...
Mediocre, the Team Behind Smash Hit, is Teasing Their Latest Unnamed Project Posted by Jessica Fisher on January 26th, 2015 [ permalink ] | Read more »
Heroes of Gaia Review
Heroes of Gaia Review By Campbell Bird on January 26th, 2015 Our Rating: :: TIMERS OF MIGHT AND MAGICUniversal App - Designed for iPhone and iPad This free-to-play rpg looks a lot like Heroes of Might and Magic, but it’s poor... | Read more »
Choice Provisions is Set to Launch Destr...
Choice Provisions is Set to Launch Destructamundo on iOS This Month Posted by Tre Lawrence on January 23rd, 2015 [ permalink ] Choice Provisions – home stable to | Read more »
King of Thieves – An Interview With Zept...
Ahead of the release of ZeptoLab’s King of Thieves, we were able to ask ZeptoLab’s co-founder, Semyon Voinov, a few questions about the inspiration behind the game and what that means for the Cut the Rope franchise. | Read more »
Handle Review
Handle Review By Jennifer Allen on January 23rd, 2015 Our Rating: :: SPEEDY ORGANIZINGUniversal App - Designed for iPhone and iPad Handle is a very convenient way of juggling your emails, To Do list, and Calendar all through one... | Read more »
The New Disney Inquizitive App Offers a...
The New Disney Inquizitive App Offers a Place for Fans to Take Disney Quizzes Posted by Tre Lawrence on January 23rd, 2015 [ permalink ] | Read more »
Hands-On With Cut the Rope Developer Zep...
Marking quite a departure from ZeptoLab’s past successes, namely the Cut The Rope series, King of Thieves is shaping up to be quite promising. Due for release in February, we were lucky enough to have some time with a preview build to see exactly... | Read more »
Fast Fishing Review
Fast Fishing Review By Jennifer Allen on January 23rd, 2015 Our Rating: :: LIVES UP TO ITS NAMEUniversal App - Designed for iPhone and iPad Fishing is far from relaxing in Fast Fishing, but it is fun.   | Read more »
Head Back to Dark World of Arnashia in B...
Head Back to Dark World of Arnashia in Blood Brothers 2 Posted by Jessica Fisher on January 23rd, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Saved Review
Saved Review By Jennifer Allen on January 23rd, 2015 Our Rating: :: SIMPLE BUDGETINGiPhone App - Designed for the iPhone, compatible with the iPad Saved is a convenient and speedy way of adding expenses and keeping track of your... | Read more »

Price Scanner via MacPrices.net

Stir Kinetic Desk M1 Standing Or Sitting Desk...
The age of the standing desk is upon us, and according to medical research, it’s arriving none too soon. The World Health Organization (WHO), reports that 60 to 85 percent of people worldwide lead... Read more
Bosch Opens North American eBike Conversion H...
Following its entry into the U.S. eBike market in early 2014, Bosch has established a new headquarters office for Bosch eBike Systems (http://www.bosch-ebike.us) in Southern California, expanding the... Read more
13-inch 2.4GHz Retina MacBook Pro (Apple refu...
The Apple Store has previous-generation Apple Certified Refurbished 13″ 2.4GHz/128GB Retina MacBook Pros available for $999. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.4GHz/... Read more
13-inch 2.6GHz Retina MacBook Pro on sale for...
Adorama has the 13″ 2.6GHz/128GB Retina MacBook Pro on sale for $1189.99, $110 off MSRP. Shipping is free, and Adorama charges NY & NJ sales tax only. Read more
College Student Deals are back, additional $5...
Take an additional $50 off all MacBooks and iMacs at Best Buy Online with their College Students Deals Savings, valid through April 11, 2015. Anyone with a valid .EDU email address can take advantage... Read more
iPhone 6 and 6 Plus GIve Apple Half Of US Mob...
Chicago-based Consumer Intelligence Research Partners, LLC (CIRP) have released analysis of the results of its research on mobile phone manufacturers for the calendar quarter that ended December 31,... Read more
Save $100 on MacBook Airs with 256GB of stora...
B&H Photo has 256GB MacBook Airs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 1.4GHz/256GB MacBook Air: $999 $100 off MSRP - 13″ 1.4GHz/256GB MacBook... Read more
21-inch 2.7GHz iMac on sale for $1179, save $...
B&H Photo has the 21″ 2.7GHz iMac on sale for $1179 including free shipping plus NY sales tax only. Their price is $120 off MSRP, and it’s the lowest price available for this model from any... Read more
iPhone Usage Rates by State Correlate With Ed...
Chitika Insights notes that despite iPhones being the largest source of smartphone Internet traffic in North America, their latest study finds a relatively high degree of variation of iPhone usage... Read more
ProGearX Extendable Pole “Pov/Selfie Stick” M...
There’s something inescapably narcissistic about the concept of selfies as they’ve developed as a smartphone-driven social (particularly social media) phenomenon that rubs me the wrong way. However,... Read more

Jobs Board

*Apple* Acura/Subaru Service Technicians - A...
Apple Automotive is one of the fastest growing dealer…and it shows. Consider making the switch to the Apple Automotive Group today! At Apple Automotive , Read more
Business Development Manager - *Apple* Pay...
**Job Summary** Apple Pay is seeking an experienced business development manager to support the identification, recruitment, negotiation and ongoing management of Read more
*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* Lead Operator, GSOC - Apple (United...
**Job Summary** Apple is seeking an exceptional, customer service oriented and experienced persons to fulfill the role of Apple Lead Operator (ALO) as part of the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.