home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / prefs / nsprefui / src / grayramp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  5.1 KB  |  146 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include <windows.h>
  20.  
  21. // Fixed-point number used to represent gray scale intensities. There
  22. // are 16-bits for the fractional part and 0 bits for the integral part
  23. typedef WORD    INTENSITY;
  24.  
  25. // Makes a fixed-point number given a floating-point intensity. Rounds up
  26. #define MAKE_INTENSITY(intensity)\
  27.     ((INTENSITY)((intensity) * 65535. + .5))
  28.  
  29. // The number of displayable colors used. 9 is the largest number of colors
  30. // we can use for the range intensity range .5 .. .75
  31. #define NUM_COLORS    9
  32.  
  33. static WORD
  34. RGB555(UINT nGray)
  35. {
  36.     // We're passed a gray level that is 8-bit, and we want one that
  37.     // is 5-bit
  38.     WORD    wGray555 = nGray >> 3;
  39.  
  40.     return (WORD)(wGray555 + (wGray555 << 5) + (wGray555 << 10));
  41. }
  42.  
  43. // Makes a horizontal gray scale ramp from (128,128,128) to (192,192,192)
  44. // of the specified width and height. Returns a top-down packed DIB with
  45. // a bit-count of 16
  46. LPBITMAPINFOHEADER
  47. MakeGrayScaleRamp(DWORD nWidth, DWORD nHeight)
  48. {
  49.     LPBITMAPINFOHEADER    lpBmInfoHeader;
  50.     LPWORD                lpBits;
  51.     INTENSITY            nLevels[NUM_COLORS];
  52.     INTENSITY            nThresholds[NUM_COLORS - 1];
  53.     WORD                nColors[NUM_COLORS];
  54.  
  55.     // Each row of the DIB data needs to be a DWORD multiple
  56.     if (nWidth & 0x01)
  57.         nWidth++;  // make the width an even number
  58.  
  59.     // Allocate a BITMAPINFOHEADER structure, and room for the image data
  60.     lpBmInfoHeader = (LPBITMAPINFOHEADER)HeapAlloc(GetProcessHeap(), 0,
  61.         sizeof(BITMAPINFOHEADER) + nWidth * nHeight * sizeof(WORD));
  62.  
  63.     if (!lpBmInfoHeader)
  64.         return NULL;
  65.     
  66.     // Initialize the BITMAPINFOHEADER structure
  67.     lpBmInfoHeader->biSize             = sizeof(BITMAPINFOHEADER);
  68.     lpBmInfoHeader->biWidth         = nWidth;
  69.     lpBmInfoHeader->biHeight         = -1 * nHeight;
  70.     lpBmInfoHeader->biPlanes         = 1;
  71.     lpBmInfoHeader->biBitCount         = 16;
  72.     lpBmInfoHeader->biCompression     = BI_RGB;
  73.     lpBmInfoHeader->biSizeImage     = 0;
  74.     lpBmInfoHeader->biXPelsPerMeter = 0;
  75.     lpBmInfoHeader->biYPelsPerMeter = 0;
  76.     lpBmInfoHeader->biClrUsed         = 0;
  77.     lpBmInfoHeader->biClrImportant     = 0;
  78.  
  79.     // Compute the array of quantized levels
  80.     for (int i = 0; i < NUM_COLORS; i++)
  81.         nLevels[i] = MAKE_INTENSITY(.5) + INTENSITY(DWORD(MAKE_INTENSITY(.25)) * i / (NUM_COLORS - 1));
  82.  
  83.     // Compute the threshold array
  84.     for (i = 0; i < NUM_COLORS - 1; i++)
  85.         nThresholds[i] = (nLevels[i] + nLevels[i + 1]) / 2;
  86.  
  87.     // Compute the 5-5-5 colors we're going to use
  88.     for (i = 0; i < NUM_COLORS; i++)
  89.         nColors[i] = RGB555(128 + 64 * i / (NUM_COLORS - 1));
  90.     
  91.     // Get a pointer to the bits. Since this is a packed DIB the bitmap array
  92.     // immediately follows the BITMAPINFO header
  93.     lpBits = (LPWORD)((LPSTR)lpBmInfoHeader + lpBmInfoHeader->biSize);
  94.  
  95.     // Initialze the gray scale ramp to the desired intensities. Just do the first
  96.     // row and replicate that for each additional row
  97.     for (DWORD x = 0; x < nWidth; x++)
  98.         lpBits[x] = MAKE_INTENSITY(.515625) + INTENSITY(DWORD(MAKE_INTENSITY(.21875)) * x / (nWidth - 1));
  99.         // lpBits[x] = MAKE_INTENSITY(.5) + INTENSITY(DWORD(MAKE_INTENSITY(.25)) * x / (nWidth - 1));
  100.  
  101.     // Now replicate the other rows
  102.     for (DWORD y = 1; y < nHeight; y++)
  103.         memcpy(lpBits + y * nWidth, lpBits, nWidth * sizeof(WORD));
  104.  
  105.     // Go a row at a time and convert each pixel to its nearest displayable
  106.     // intensity. Use Floyd Steinberg error diffusion to spread the error (difference
  107.     // between the exact intensity and the displayable intensity) over the nearby pixels
  108.     for (y = 0; y < nHeight; y++) {
  109.         for (x = 0; x < nWidth; x++) {
  110.             DWORD    error;
  111.  
  112.             // Find which quantized level to use
  113.             for (i = 0; i < NUM_COLORS - 1; i++)
  114.                 if (*lpBits < nThresholds[i])
  115.                     break;
  116.  
  117.             error = DWORD(*lpBits - nLevels[i]);
  118.             *lpBits = nColors[i];
  119.             
  120.             // Spread 7/16 of the error to the pixel to the right
  121.             if (x + 1 < nWidth)
  122.                 *(lpBits + 1) += INTENSITY(error * 7 >> 4);
  123.  
  124.             // Don't spread the error downward if this is the bottom row
  125.             if (y + 1 < nHeight) {
  126.                 // Spread 3/16 of the error to the pixel below and to the left
  127.                 if (x > 0)
  128.                     *(lpBits + nWidth - 1) += INTENSITY(error * 3 >> 4);
  129.  
  130.                 // Spread 5/16 of the error to the pixel below
  131.                 *(lpBits + nWidth) += INTENSITY(error * 5 >> 4);
  132.     
  133.                 // Spread 1/16 of the error below and to the right
  134.                 if (x + 1 < nWidth)
  135.                     *(lpBits + nWidth + 1) += INTENSITY(error >> 4);
  136.             }
  137.  
  138.             // Move to the next pixel
  139.             lpBits++;
  140.         }
  141.     }
  142.  
  143.     return lpBmInfoHeader;
  144. }
  145.  
  146.