• 第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;
    }
  • 相关阅读:
    为什么使用指针比使用对象本身更好?
    基于回调的事件处理——基于回调的事件传播
    基于回调的事件处理——回调机制与监听机制
    基于监听的事件处理——直接绑定到标签
    基于监听的事件处理——匿名内部类作为事件监听器类
    基于监听的事件处理——Activity本身作为事件监听器
    基于监听的事件处理——外部类作为事件监听器类
    基于监听的事件处理——内部类作为事件监听器类
    基于监听的事件处理——事件和事件监听器
    基于监听的事件处理——监听的处理模型
  • 原文地址:https://www.cnblogs.com/5iedu/p/4701126.html
Copyright © 2020-2023  润新知