第16章 调色板管理器_16.4 一个DIB位图库的实现(2)

//接上一篇

//DibPal.h

/*-----------------------------------------------------------------
DIBPAL.H header file for DIBPAL.C
-----------------------------------------------------------------*/
#pragma  once;
#include <windows.h>
#include "DibHelp.h"
HPALETTE DibPalDibTable(HDIB hdib);
HPALETTE DibPalAllPurpose(void);
HPALETTE DibPalUniformGrays(int iNum);
HPALETTE DibPalUniformColors(int iNumR, int iNumG, int iNumB);
HPALETTE DibPalVga(void);
HPALETTE DibPalPopularity(HDIB hdib, int iRes);
HPALETTE DibPalMedianCut(HDIB hdib, int iRes);

//DibPal.c

#include "DibPal.h"
/*-------------------------------------------------------------------
DibPalDibTable:根据DIB颜色表创建一个调色板
-------------------------------------------------------------------*/
HPALETTE DibPalDibTable(HDIB hdib)
{
    HPALETTE hPalette;
    LOGPALETTE* plp;
    RGBQUAD   rgb;
    int i, iNum;
    if (0 == (iNum = DibNumColors(hdib)))
        return NULL;
    plp = malloc(sizeof(LOGPALETTE) + (iNum - 1)*sizeof(PALETTEENTRY));
    plp->palVersion = 0x0300;
    plp->palNumEntries = iNum;
    for (i = 0; i < iNum; i++)
    {
        DibGetColor(hdib, i, &rgb);
        plp->palPalEntry[i].peRed = rgb.rgbRed;
        plp->palPalEntry[i].peGreen = rgb.rgbGreen;
        plp->palPalEntry[i].peBlue = rgb.rgbBlue;
        plp->palPalEntry[i].peFlags = 0;
    }
    hPalette = CreatePalette(plp);
    free(plp);
    return hPalette;
}
/*-------------------------------------------------------------------
DibPalAllPurpose:创建一个通用的调色板,共有247种颜色,但15种是从20种
系统保留颜色中复制或匹配出来的。
-------------------------------------------------------------------*/
HPALETTE DibPalAllPurpose(void)
{
    HPALETTE hPalette;
    LOGPALETTE* plp;
    int i, incr, R, G, B;
    plp = malloc(sizeof(LOGPALETTE) + 246 * sizeof(PALETTEENTRY));
    plp->palVersion = 0x0300;
    plp->palNumEntries = 247;

    //下面的循环会计算31种灰度色阶,但其中3种会匹配20种系统保留颜色
    for (i = 0, G = 0, incr = 8; G <= 0xFF; i++, G += incr)
    {
        plp->palPalEntry[i].peRed = (BYTE)G;
        plp->palPalEntry[i].peGreen = (BYTE)G;
        plp->palPalEntry[i].peBlue = (BYTE)G;
        plp->palPalEntry[i].peFlags = 0;
        incr = ((incr == 9) ? 8 : 9);
    }
    //下面的循环负责创建216种颜色,但其中8种会匹配20种系统保留颜色,另外的4种会匹配
    //上面产生的灰度色阶
    for (R = 0; R <= 0xFF; R += 0x33)
        for (G = 0; G <= 0xFF; G += 0x33)
            for (B = 0; B <= 0xFF; B += 0x33)
            {
                plp->palPalEntry[i].peRed = (BYTE)R;   //i从31开始
                plp->palPalEntry[i].peGreen = (BYTE)G;
                plp->palPalEntry[i].peBlue = (BYTE)B;
                plp->palPalEntry[i].peFlags = 0;
                i++;
            }
    hPalette = CreatePalette(plp);
    free(plp);
    return hPalette;
}
/*-------------------------------------------------------------------
DibPalUniformGrays:创建具有相同间隔的灰度色阶(将256分成相同的iNum份)
-------------------------------------------------------------------*/
HPALETTE DibPalUniformGrays(int iNum)
{
    HPALETTE hPalette;
    LOGPALETTE* plp;
    int i;
    if (iNum <= 0)
        return NULL;
    plp = malloc(sizeof(LOGPALETTE) + (iNum - 1)*sizeof(PALETTEENTRY));
    plp->palVersion = 0x0300;
    plp->palNumEntries = iNum;
    for (i = 0; i < iNum; i++)
    {
        plp->palPalEntry[i].peRed =                  //peRed =peGreen =peBlue =(i*255/(iNum-1))
            plp->palPalEntry[i].peGreen =
            plp->palPalEntry[i].peBlue = (BYTE)(i * 255 / (iNum - 1));
        plp->palPalEntry[i].peFlags = 0;
    }
    hPalette = CreatePalette(plp);
    free(plp);
    return hPalette;
}
/*-------------------------------------------------------------------
DibPalUniformColors:创建iNumR*iNumG*iNumB调色板
-------------------------------------------------------------------*/
HPALETTE DibPalUniformColors(int iNumR, int iNumG, int iNumB)
{
    HPALETTE hPalette;
    LOGPALETTE* plp;
    int i, iNum, R, G, B;
    if ((iNum = iNumR*iNumG*iNumB) <= 0)
        return NULL;
    plp = malloc(sizeof(LOGPALETTE) + (iNum - 1)*sizeof(PALETTEENTRY));
    plp->palVersion = 0x0300;
    plp->palNumEntries = iNum;

    i = 0;
    for (R = 0; R < iNumR; R++)
        for (G = 0; G < iNumG; G++)
            for (B = 0; B < iNumB; B++)
            {
                plp->palPalEntry[i].peRed = (BYTE)((R * 255 / iNumR - 1));
                plp->palPalEntry[i].peGreen = (BYTE)((G * 255 / iNumG - 1));
                plp->palPalEntry[i].peBlue = (BYTE)((B * 255 / iNumB - 1));
                plp->palPalEntry[i].peFlags = 0;
                i++;
            }
    hPalette = CreatePalette(plp);
    free(plp);
    return hPalette;
}
/*-------------------------------------------------------------------
DibPalVga:创建一个基于标准显示器的16色调色板
-------------------------------------------------------------------*/
HPALETTE DibPalVga(void)
{
    static RGBQUAD rgb[16] = { 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x80, 0x00,
        0x00, 0x80, 0x00, 0x00,
        0x00, 0x80, 0x80, 0x00,
        0x80, 0x00, 0x00, 0x00,
        0x80, 0x00, 0x80, 0x00,
        0x80, 0x80, 0x00, 0x00,
        0x80, 0x80, 0x80, 0x00,
        0xC0, 0xC0, 0xC0, 0x00,
        0x00, 0x00, 0xFF, 0x00,
        0x00, 0xFF, 0x00, 0x00,
        0x00, 0xFF, 0xFF, 0x00,
        0xFF, 0x00, 0x00, 0x00,
        0xFF, 0x00, 0xFF, 0x00,
        0xFF, 0xFF, 0x00, 0x00,
        0xFF, 0xFF, 0xFF, 0x00 };
    HPALETTE hPalette;
    LOGPALETTE* plp;
    int i;
    plp = malloc(sizeof(LOGPALETTE) + (16 - 1)*sizeof(PALETTEENTRY));
    plp->palVersion = 0x0300;
    plp->palNumEntries = 16;
    for (i = 0; i < 16; i++)
    {
        plp->palPalEntry[i].peRed = rgb[i].rgbRed;
        plp->palPalEntry[i].peGreen = rgb[i].rgbGreen;
        plp->palPalEntry[i].peBlue = rgb[i].rgbBlue;
        plp->palPalEntry[i].peFlags = 0;
    }
    hPalette = CreatePalette(plp);
    free(plp);
    return hPalette;
}
/*-------------------------------------------------------------------
优化调色板使用到的宏
-------------------------------------------------------------------*/
#define PACK_RGB(R,G,B,iRes)  ((int)(R) | ((int)(G)<<(iRes)) |     \
                              ((int)(B) <<((iRes)+(iRes))))
/*-------------------------------------------------------------------
AccumColorCounts:填充piCount参数,该参数是一个数组,里面存放每种
颜色被使用的次数
-------------------------------------------------------------------*/
static void AccumColorCounts(HDIB hdib, int* piCount, int iRes)
{
    int x, y, cx, cy, tmp;
    RGBQUAD  rgb;
    cx = DibWidth(hdib);
    cy = DibHeight(hdib);
    for (y = 0; y < cy; y++)
        for (x = 0; x < cx; x++)
        {
            DibGetPixelColor(hdib, x, y, &rgb);
            rgb.rgbRed >>= (8 - iRes);
            rgb.rgbGreen >>= (8 - iRes);
            rgb.rgbBlue >>= (8 - iRes);
            //每种颜色的使用次数存放在以颜色值为下标的数组元素中
            tmp = PACK_RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue, iRes);
            ++piCount[PACK_RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue, iRes)];
        }
}
/*-------------------------------------------------------------------
DibPalPopularity:流行度算法
1、选取最多256种RGB色值构成调色板
2、使用RGB色值权重最高的几位,如8位或24位,这里选择6位(很多显示设备
的解析度只有6,这样可以大大减少内存消耗。
-------------------------------------------------------------------*/
HPALETTE DibPalPopularity(HDIB hdib, int iRes)
{
    HPALETTE hPalette;
    int  i, iArraySize, iMask, iEntry, iCount, iIndex, R, G, B;
    int  *piCount; //数组,存放每种颜色使用的次数
    LOGPALETTE* plp;
    //有效性检查
    if (DibBitCount(hdib) < 16)
        return NULL;
    if (iRes<3 || iRes > 8)
        return NULL;
    //分配颜色使用次数的数组2^(3*iRes)
    iArraySize = 1 << (3 * iRes); // iRes为分辨率,表示通道颜色使用的位数
    iMask = (1 << iRes) - 1;//如iRes=6时,掩码为00 11 1111
    if (NULL == (piCount = calloc(iArraySize, sizeof(int))))
        return NULL;
    //获取每种颜色的使用次数
    AccumColorCounts(hdib, piCount, iRes);
    //设置调色板,最多236种
    plp = malloc(sizeof(LOGPALETTE) + 235 * sizeof(PALETTEENTRY));
    plp->palVersion = 0x0300;

    for (iEntry = 0; iEntry < 236; iEntry++)
    {
        //piCount数组中的最大值,为防止多次被找到,使用完后,该值被置0
        for (i = 0, iCount = 0; i < iArraySize; i++)
            if (piCount[i]>iCount)
            {
                iCount = piCount[i];
                iIndex = i;
            }
        if (iCount == 0)
            break;
        R = (iMask&  iIndex) << (8 - iRes);
        G = (iMask& (iIndex >> iRes)) << (8 - iRes);
        B = (iMask& (iIndex >> (iRes + iRes))) << (8 - iRes);
        plp->palPalEntry[iEntry].peRed = (BYTE)R;
        plp->palPalEntry[iEntry].peGreen = (BYTE)G;
        plp->palPalEntry[iEntry].peBlue = (BYTE)B;
        plp->palPalEntry[iEntry].peFlags = 0;
        piCount[iIndex] = 0; //将本轮找到的最大值置0,防止多次被找到
    }
    //当结束循环后iEntry保存的是实际被存储的颜色的数量、
    plp->palNumEntries = iEntry;
    //创建调色板,返回调色板句柄,并清除内存
    hPalette = CreatePalette(plp);
    free(plp);
    free(piCount);
    return hPalette;
}
/*-------------------------------------------------------------------
中分算法用到的数据结构
-------------------------------------------------------------------*/
typedef struct       //定义一个盒子的尺寸
{
    int Rmin, Rmax, Gmin, Gmax, Bmin, Bmax;
}MINMAX;
typedef struct     //为快速排序使用的
{
    int iBoxCount;     //盒子里面的点的数量
    RGBQUAD  rgbBoxAv;  //盒子内的平均颜色
}BOXES;
/*-------------------------------------------------------------------
FindAverageColor:找到一个盒子里的平均颜色,返回值为盒子里所有点被使
用的次数总和,即盒子里像素点的总数量
-------------------------------------------------------------------*/
static int FindAverageColor(int *piCount, MINMAX mm, int iRes, RGBQUAD* prgb)
{
    int R, G, B, iCount, iR, iG, iB, iTotal;
    iTotal = iR = iG = iB = 0;
    //遍历盒子中所有的颜色
    for (R = mm.Rmin; R <= mm.Rmax; R++)
        for (G = mm.Gmin; G <= mm.Gmax; G++)
            for (B = mm.Bmin; B <= mm.Bmax; B++)
            {
                //获取某一颜色被使用的次数
                iCount = piCount[PACK_RGB(R, G, B, iRes)];
                //根据颜色值,算出各分量的加权和
                iR += iCount*R;
                iG += iCount*G;
                iB += iCount*B;
                iTotal += iCount;
            }
    //计算出平均颜色
    prgb->rgbRed = (BYTE)((iR / iTotal) << (8 - iRes));
    prgb->rgbGreen = (BYTE)((iG / iTotal) << (8 - iRes));
    prgb->rgbBlue = (BYTE)((iB / iTotal) << (8 - iRes));
    //返回盒子里像素点的数量
    return iTotal;
}
/*-------------------------------------------------------------------
CutBox:将一个盒子分隔成两个
1、piCount:为所有像素点的被使用次数,是个数组。是个指针会被所有递归共用
2、mm为当前盒子的边界
3、iRes为颜色分辩率,会被所有递归共用
4、iLevel为嵌套层次
5、pBoxes为盒子的总数量(如256个),会被所有递归共用
6、piEntry为当前要分割的盒子索引,会被所有递归共用
-------------------------------------------------------------------*/
static void CutBox(int* piCount, int iBoxCount, MINMAX mm,
                   int iRes, int iLevel, BOXES* pboxes, int * piEntry)
{
    int iCount, R, G, B;
    MINMAX mmNew;
    //如果盒子里的没有像素点,则无需分隔,直接退出
    if (iBoxCount == 0)  //iBoxCount存放盒子里像素点的数量
        return;
    //如果嵌套层次等于8或盒里子只剩一个像素,则准备计算出该盒子的平均颜色
    //并将该盒子里的像素点的数量存储起来
    if (iLevel == 8 || (mm.Rmin == mm.Rmax &&
        mm.Gmin == mm.Gmax &&
        mm.Bmin == mm.Bmax))
    {
        pboxes[*piEntry].iBoxCount =
            FindAverageColor(piCount, mm, iRes, &pboxes[*piEntry].rgbBoxAv);
        (*piEntry)++;
    }
    //否则,如果盒子中,蓝色边长较长,则按该边来分成颜色数量相等的两个盒子
    else if ((mm.Bmax - mm.Bmin) > (mm.Rmax - mm.Rmin) &&
             (mm.Bmax - mm.Bmin) >(mm.Gmax - mm.Gmin))
    {
        //初始化计数变量iCount,并遍历蓝色边
        iCount = 0;
        for (B = mm.Bmin; B < mm.Bmax; B++)  //注意这里不取到最大值
        {
            for (R = mm.Rmin; R <= mm.Rmax; R++)
                for (G = mm.Gmin; G <= mm.Gmax; G++)
                    iCount += piCount[PACK_RGB(R, G, B, iRes)];  //将使用次数相加(即己经找到的像素数量)
            //如果己经找到的像素数量超过一半,则退出蓝色边长的查找
            if (iCount >= iBoxCount / 2)
                break;
            //如果下一个蓝色将达到最大值,也退出(蓝色边长的查找)
            if (B == mm.Bmax - 1)
                break;;
        }
        //这时己经按蓝色边长等分为两个具有相同数量的像素集合
        //分割盒子:第2个参数为新盒子的像素数量,第3个参数为新的蓝边的最大值和最小值
        mmNew = mm;
        mmNew.Bmin = mm.Bmin;
        mmNew.Bmax = B; //以B为界来分割
        CutBox(piCount, iCount, mmNew, iRes, iLevel + 1, pboxes, piEntry);
        mmNew = mm;
        mmNew.Bmin = B + 1;
        mmNew.Bmax = mm.Bmax; //以B为界来分割
        CutBox(piCount, iBoxCount - iCount, mmNew, iRes, iLevel + 1, pboxes, piEntry);
    }
    //否则,如果盒子中,红色边长较长,则按该边来分成颜色数量相等的两个盒子
    else if ((mm.Rmax - mm.Rmin) > (mm.Gmax - mm.Gmin))
    {
        //初始化计数变量iCount,并遍历红色边
        iCount = 0;
        for (R = mm.Rmin; R < mm.Rmax; R++)
        {
            for (G = mm.Gmin; G <= mm.Gmax; G++)
                for (B = mm.Bmin; B <= mm.Bmax; B++)
                    iCount += piCount[PACK_RGB(R, G, B, iRes)];  //将使用次数相加(即己经找到的像素数量)
            //如果己经找到的像素数量超过一半,则退出红色边长的查找
            if (iCount >= iBoxCount / 2)
                break;
            //如果下一个红色将达到最大值,也退出(红色边长的查找)
            if (R == mm.Rmax - 1)
                break;;
        }
        //这时己经按红色边长等分为两个具有相同数量的像素集合
        //分割盒子:第2个参数为新盒子的像素数量,第3个参数为新的蓝边的最大值和最小值
        mmNew = mm;
        mmNew.Rmin = mm.Rmin;
        mmNew.Rmax = R; //以R为界来分割
        CutBox(piCount, iCount, mmNew, iRes, iLevel + 1, pboxes, piEntry);
        mmNew = mm;
        mmNew.Rmin = R + 1;
        mmNew.Rmax = mm.Rmax; //以R为界来分割
        CutBox(piCount, iBoxCount - iCount, mmNew, iRes, iLevel + 1, pboxes, piEntry);
    }
    //否则,如果盒子中,绿色边长较长,则按该边来分成颜色数量相等的两个盒子
    else
    {
        //初始化计数变量iCount,并遍历绿色边
        iCount = 0;
        for (G = mm.Gmin; G < mm.Gmax; G++)
        {
            for (R = mm.Rmin; R <= mm.Rmax; R++)
                for (B = mm.Bmin; B <= mm.Bmax; B++)
                    iCount += piCount[PACK_RGB(R, G, B, iRes)];  //将使用次数相加(即己经找到的像素数量)
            //如果己经找到的像素数量超过一半,则退出绿色边长的查找
            if (iCount >= iBoxCount / 2)
                break;
            //如果下一个绿色将达到最大值,也退出(绿色边长的查找)
            if (G == mm.Gmax - 1)
                break;;
        }
        //这时己经按绿色边长等分为两个具有相同数量的像素集合
        //分割盒子:第2个参数为新盒子的像素数量,第3个参数为新的蓝边的最大值和最小值
        mmNew = mm;
        mmNew.Gmin = mm.Gmin;
        mmNew.Gmax = G; //以G为界来分割
        CutBox(piCount, iCount, mmNew, iRes, iLevel + 1, pboxes, piEntry);
        mmNew = mm;
        mmNew.Gmin = G + 1;
        mmNew.Gmax = mm.Gmax; //以G为界来分割
        CutBox(piCount, iBoxCount - iCount, mmNew, iRes, iLevel + 1, pboxes, piEntry);
    }
}
/*-------------------------------------------------------------------
Compare:提供给快速排序作比较函数
-------------------------------------------------------------------*/
static int Compare(const BOXES* pbox1, const BOXES* pbox2)
{
    return pbox1->iBoxCount > pbox2->iBoxCount;
}
/*-------------------------------------------------------------------
DibPalMedianCut:基于中分算法创建一个调色板
-------------------------------------------------------------------*/
HPALETTE DibPalMedianCut(HDIB hdib, int iRes)
{
    HPALETTE hPalette;
    LOGPALETTE* plp;
    BOXES boxes[256];
    MINMAX mm;
    int* piCount;
    int i, iArraySize, iDim, R, G, B, iCount, iTotal, iEntry = 0;
    //有效性验证
    if (DibBitCount(hdib) < 16)
        return NULL;
    if (iRes<3 || iRes >8)
        return NULL;
    //统计每种颜色被使用的次数
    iArraySize = 1 << (3 * iRes);
    if (NULL == (piCount = calloc(iArraySize, sizeof(int))))
        return NULL;
    AccumColorCounts(hdib, piCount, iRes);
    //计算大盒子的总尺寸
    iDim = 1 << iRes; //如每像素6位,则盒子每边的长度为2^6个像素
    mm.Rmax = mm.Gmax = mm.Bmax = 0;
    mm.Rmin = mm.Gmin = mm.Bmin = iDim - 1;
    iTotal = 0;
    //找出盒子长、宽、高(分别R、G、B)的边界范围
    for (R = 0; R < iDim; R++)
        for (G = 0; G < iDim; G++)
            for (B = 0; B < iDim; B++)
            {
                iCount = piCount[PACK_RGB(R, G, B, iRes)];
                if (iCount>0)  //如果颜色使用次数>0,表示该颜色是要用到的,否则是不用的颜色
                {
                    iTotal += iCount;
                    //找到各分量的最小值
                    if (R < mm.Rmin)  mm.Rmin = R;
                    if (G < mm.Gmin)  mm.Gmin = G;
                    if (B < mm.Bmin)  mm.Bmin = B;
                    //找到各分量的最大值
                    if (R > mm.Rmax)  mm.Rmax = R;
                    if (G > mm.Gmax)  mm.Gmax = G;
                    if (B > mm.Bmax)  mm.Bmax = B;
                }
            }
    //分割第一个盒子(递归函数)。当返回时boxes结构将有256种RGB值,每个盒子一种。
    //像素数量被记录在每个盒子的iBoxCount字段中,平均颜色存在rgbBoxAv中。
    //iEntry表示所有非空盒子的数量
    CutBox(piCount, iTotal, mm, iRes, 0, boxes, &iEntry);
    free(piCount);
    //按RGB颜色被使用的次数,降序排序boxes数组
    qsort(boxes, iEntry, sizeof(BOXES), Compare);
    plp = malloc(sizeof(LOGPALETTE) + (iEntry - 1)*sizeof(PALETTEENTRY));
    plp->palVersion = 0x0300;
    plp->palNumEntries = iEntry;
    for (i = 0; i < iEntry; i++)
    {
        plp->palPalEntry[i].peRed = boxes[i].rgbBoxAv.rgbRed;
        plp->palPalEntry[i].peGreen = boxes[i].rgbBoxAv.rgbGreen;
        plp->palPalEntry[i].peBlue = boxes[i].rgbBoxAv.rgbBlue;
        plp->palPalEntry[i].peFlags = 0;
    }
    hPalette = CreatePalette(plp);
    free(plp);
    return hPalette;
}

//DibConv.h

/*-------------------------------------
DIBCONV.H header file for DIBCONV.C
-------------------------------------*/
#pragma once
#include "DibHelp.h"
HDIB DibConvert(HDIB hdibSrc, int iBitCountDst);

//DibConv.c

/*--------------------------------------------------------------
DIBCONV.C -- Converts DIBs from one format to another
(c) Charles Petzold,1998
--------------------------------------------------------------*/
#include <windows.h>
#include "DibConv.h"
#include "DibPal.h"
HDIB DibConvert(HDIB hdibSrc, int iBitCountDst)
{
    HDIB hdibDst = NULL;
    int i, x, y, cx, cy, iBitCountSrc, cColors;
    RGBQUAD  rgb;
    HPALETTE hPalette;
    PALETTEENTRY pe;
    WORD  wNumEntries;
    cx = DibWidth(hdibSrc);
    cy = DibHeight(hdibSrc);
    iBitCountSrc = DibBitCount(hdibSrc);
    if (iBitCountSrc == iBitCountDst)
        return NULL;
    //带有颜色表的DIB转换为更大颜色表的DIB
    //如1位DIB转为4位或8位DIB,或4位DIB转为8位DIB,需要复制像素点阵和颜色表
    if ((iBitCountSrc < iBitCountDst) && (iBitCountDst <= 8)) //8位以下的带有颜色表
    {
        cColors = DibNumColors(hdibSrc);
        hdibDst = DibCreate(cx, cy, iBitCountDst, cColors);
        //设置颜色表
        for (i = 0; i < cColors; i++)
        {
            DibGetColor(hdibSrc, i, &rgb);
            DibSetColor(hdibDst, i, &rgb);
        }
        //设置像素颜色
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibSetPixel(hdibDst, x, y, DibGetPixel(hdibSrc, x, y));
            }
    }
    //目标没有颜色表(如16、24、32位)
    else if (iBitCountDst >= 16)
    {
        hdibDst = DibCreate(cx, cy, iBitCountDst, 0);
        //设置像素颜色
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibGetPixelColor(hdibSrc, x, y, &rgb);
                DibSetPixelColor(hdibDst, x, y, &rgb);
            }
    }
    //源没有颜色表的DIB(如16、24,32),而目标有颜色表
    else  if (iBitCountSrc >= 16 && iBitCountDst == 8) //目标是8位的
    {
        hPalette = DibPalMedianCut(hdibSrc, 6);
        GetObject(hPalette, sizeof(WORD), &wNumEntries);
        hdibDst = DibCreate(cx, cy, 8, (int)wNumEntries);
        //设置颜色表
        for (i = 0; i < (int)wNumEntries; i++)
        {
            GetPaletteEntries(hPalette, i, 1, &pe);
            rgb.rgbRed = pe.peRed;
            rgb.rgbGreen = pe.peGreen;
            rgb.rgbBlue = pe.peBlue;
            rgb.rgbReserved = 0;
            DibSetColor(hdibDst, i, &rgb);
        }
        //设置像素数据
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibGetPixelColor(hdibSrc, x, y, &rgb);
                DibSetPixel(hdibDst, x, y,
                            GetNearestPaletteIndex(hPalette,
                            RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue)));
            }
        DeleteObject(hPalette);
    }
    //目标是单色的DIB
    else if (iBitCountDst == 1)
    {
        hdibDst = DibCreate(cx, cy, 1, 0);
        hPalette = DibPalUniformGrays(2);
        //颜色表
        for (i = 0; i < 2; i++)
        {
            GetPaletteEntries(hPalette, i, 1, &pe);
            rgb.rgbRed = pe.peRed;
            rgb.rgbGreen = pe.peGreen;
            rgb.rgbBlue = pe.peBlue;
            rgb.rgbReserved = 0;
            DibSetColor(hdibDst, i, &rgb);
        }
        //设置像素数据
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibGetPixelColor(hdibSrc, x, y, &rgb);
                DibSetPixel(hdibDst, x, y,
                            GetNearestPaletteIndex(hPalette,
                            RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue)));
            }
        DeleteObject(hPalette);

    }
    //从8位或更高位的DIB,转为4位DIB
    else if (iBitCountSrc >= 8 && iBitCountDst == 4)
    {
        hdibDst = DibCreate(cx, cy, 4, 0);
        hPalette = DibPalVga();
        //颜色表
        for (i = 0; i < 16; i++)
        {
            GetPaletteEntries(hPalette, i, 1, &pe);
            rgb.rgbRed = pe.peRed;
            rgb.rgbGreen = pe.peGreen;
            rgb.rgbBlue = pe.peBlue;
            rgb.rgbReserved = 0;
            DibSetColor(hdibDst, i, &rgb);
        }
        //设置像素数据
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibGetPixelColor(hdibSrc, x, y, &rgb);
                DibSetPixel(hdibDst, x, y,
                            GetNearestPaletteIndex(hPalette,
                            RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue)));
            }
        DeleteObject(hPalette);
    } else
        hdibDst = NULL;
    return hdibDst;
}
时间: 2024-10-09 18:00:20

第16章 调色板管理器_16.4 一个DIB位图库的实现(2)的相关文章

第16章 调色板管理器_16.4 一个DIB位图库的实现(1)

16.4.1自定义的 DIBSTRUCT结构体 字段 含义 PBYTE *ppRow ①指向位图视觉上最上面的一行像素.(不管是自下而上,还是自上而下) ②放在第一个字段,为的是后面定义宏时可方便访问到 int iSignature =“Dib ”,是这个结构体的标志 HBITMAP hBitmap 存储了由CreateDIBSection返回的位图句柄(注意,实质是DIB,但兼有DDB的特点,可直接BitBlt) BYTE *pBits 指向像素阵列的指针,其指针值在CreateDIBSect

第16章 调色板管理器_16.1 调色板原理和使用

16.1 调色板的使用 16.1.1 调色板原理 注意: ①使用调色板前要创建逻辑调色板,选入并实现调色板.在映射过程中,逻辑调色板中的颜色会被相等匹配.或近似匹配.或新增加进系统调色板中(见后面分析) ②Windows规定,活动窗口(标题栏高亮显示的程序)的逻辑调色板(如果有的话)具有最高的实现优先权,这是因为活动窗口是当前与用户交互的窗口,应该保证其有最佳的颜色显示.非活动窗口的优先权是按Z顺序自上到下确定的(Z顺序就是重叠窗口的重叠顺序).活动窗口有权将其逻辑调色板作为前景调色板实现,非活

第16章 调色板管理器_16.2 调色板动画

16.2.1 弹球 (1)AnimatePallette(hPalette,uStart,uNum,&pe); ①必须运行在支持调色板的视频模式下(即256色,兼容256色不行) ②每个调色板条目PALETTEENTRY的peFlags要设为pC_RESERVED,才能出现动画 ③uStart是原始逻辑调色板表的索引,不是PALETTEENTRY数组的索引 ④该函数即改变了逻辑调色板的条目,又改变了系统调色板和映射表.所有窗口无需重绘,更改结果直接从视频显示器上反映出来.(可与SetPalett

第16章 调色板管理器_16.3 调色板和现实世界中的图像

16.3.1 调色板和紧凑DIB (1)对于16.24.32位的DIB,没有颜色表,就不必创建调色板.但在8位视频模式下,只会用标准的20种保留色来显示.由DIB颜色表创建的调色板被称为“原生调色板” (2)dwPixel =PackedDibGetPixel(pPackedDib,x,y),当这类函数多次调用时会使程序变慢. (3)很多函数,需要对OS/2兼容DIB作不同处理. [ShowDib3程序]——原生(Native)调色板 效果图 //PackedDIB.h文件 /*--------

流畅的python第十五章上下文管理器和else块学习记录

with 语句和上下文管理器for.while 和 try 语句的 else 子句 with 语句会设置一个临时的上下文,交给上下文管理器对象控制,并且负责清理上下文.这么做能避免错误并减少样板代码,因此 API 更安全,而且更易于使用.除了自动关闭文件之外,with 块还有很多用途 else 子句不仅能在 if 语句中使用,还能在 for.while 和 try 语句中使用 for 仅当 for 循环运行完毕时(即 for 循环没有被 break 语句中止)才运行 else 块.while 仅

转:OGRE场景管理器介绍

一个场景代表在虚拟世界中显示的物品.场景可以包括静态几何体(比如地形或者室内),模型(比如树.椅子等),光和摄像机.场景有下面种类.室内场景:可能由走廊.有家具的屋子和挂着装饰品的墙组成.室外场景:可能由山,树木,微微摇动的草地,飘着云彩的天空组成.Ogre提供了一套不同的场景管理器,每一种特别支持某种场景,本文档将列出Ogre提供的场景管理器和它们的优缺点. 1 选择一个场景管理器 2 八叉树场景管理器(Octree Scene Manager) 3 地形场景管理器(Terrain Scene

AWT布局管理器

布局管理器 容器内可以存放各种组件,而组件的位置和大小是由容器内的布局管理器来决定的.在AWT中为我们提供了以下5种布局管理器: ①   FlowLayout 流式布局管理器 ②   BorderLayout 边界布局管理器 ③   GridLayout 网格布局管理器 ④   CradLayout 卡片布局管理器 ⑤   GridBagLayout 网格包布局管理器 容器中组件的布局通常由布局管理器控制.每个Container(比如一个Panel或一个Frame)都有一个与他相关的缺省布局管理

HttpClient 4.3.6教程 第2章 连接管理 【翻译】

第2章 连接管理 2.1 持久连接 一个主机与另一端建立连接是十分复杂的,并且两个终端间要交换多个信息包,这会耗费不少时间.对于低级的HTTP消息来说握手连接是尤其重要的.如果在执行多个请求时重复使用公共的连接,那么就能大大提高数据吞吐率.HTTP/1.1默认允许HTTP连接可以被多个请求复用.HTTP/1.0也兼容终端为了多个请求去使用一个明确的机制来优先保持活跃的连接.HTTP代理也能在一定的同期时间里保持活跃的空闲连接,以免同样的目标主机随后还要请求.这种保持活跃连接的能力通常都会涉及持续

【java】浅析java组件中的布局管理器

这篇博文笔者介绍一下java组件中,常用的布局管理器.java组件中的布局方式有好几十种,所有的这些布局管理器都实现了java.awt.LayoutManager接口.接下来笔者介绍一下常用的5种布局管理器,FlowLayout.BorderLayout.GridLayout.GridBagLayout.CardLayout.BoxLayout.如果不希望使用布局管理器,可以调用组件的 setLayout(null); ,但是不建议设置layout为null,因为这样就失去了跨平台特性,和jav