我在Linux下见过这方面的源码。

解决方案 »

  1.   

    给你一份源程序吧。这可是我自己想出来的方法,使用时感觉还不错。
    BOOL CovtRGBToPal(HANDLE& hDib); //这儿的 hDib 存放的数据结构和
    bmp文件的结构一样,只是没有bmp文件的头结构BITMAPFILEINFO。我这儿
    用的是API的代码(因为我是用C++Builder的)。#ifdef NUM
    #undef NUM
    #endif
    #define NUM 0x2000struct RGBNum
    {
        int  Num;
        long RGB;
    };static int SortN(const void* p1, const void* p2)
    {
        int i,j,Y[2];
        RGBNum* pr[2];
        WORD C[3]={299,587,114};    pr[0] = (RGBNum*)p1;
        pr[1] = (RGBNum*)p2;
        if (pr[0]->Num == pr[1]->Num) {
            if (pr[0]->RGB==pr[1]->RGB)
                return 0;
            for(i=0; i<2; i++) {
                for(j=0,Y[i]=0;j<24;j+=8)
                    Y[i] += C[j/8]*((BYTE)
                        (pr[i]->RGB>>j));
            }
            return Y[1] - Y[0];
        }
        else
            return pr[1]->Num - pr[0]->Num;
    }static void MaskRGB(RGBNum* Data, DWORD Mask)
    {
        int n;
        int Size;
        RGBNum *pr;
        RGBNum *pr1;    Mask = RGB(Mask, Mask, Mask);
        for(n=0,pr=Data; n<NUM; n++) {
            pr->RGB &= Mask;  pr++;
        }    pr = Data + (NUM-1);
        Size = sizeof(RGBNum);
        for(n=NUM-1; n>0; n--,pr--) {
            if (pr->Num==0) continue;        DWORD nRGB = pr->RGB;
            for(pr1=pr-1; true; ) {
                if (pr1->RGB!=nRGB) {
                    if (pr1 == Data)
                        break;
                    pr1--;  continue;
                }
                pr1->Num += pr->Num;
                memset(pr, 0, Size);
                break;
            }
        }
        qsort(Data, NUM, sizeof(
            RGBNum), SortN);
    }BOOL CovtRGBToPal(HANDLE& hDib)
    {
        int    i,j;
        int    k,n;
        int    nClr;
        BYTE   Sht;
        BYTE   *pb;
        BYTE   *pb1;
        BYTE   Mask;
        BYTE   Pad0;
        BYTE   Pad1;
        DWORD  nRGB;
        DWORD  Size;
        HANDLE hMem;
        RGBNum *pr;
        HPALETTE hPal;
        RGBNum Count[NUM];
        PALETTEENTRY *ppe;
        LOGPALETTE* pLogPal;
        BITMAPINFOHEADER* pbih;    if (!hDib) return FALSE;
        pbih = (BITMAPINFOHEADER*)
            GlobalLock(hDib);
        if (!pbih) return FALSE;
        if (pbih->biBitCount!=24) {
            i = pbih->biBitCount;
            GlobalUnlock(hDib);
            return i<=8 ? 1 : 0;
        }    Sht = 0;   Mask = 0xFF;
        memset(Count, 0, sizeof
            (Count));
        pb = (BYTE*)pbih + 40;
        Pad0 = (pbih->biWidth*3)%4;
        if (Pad0!=0) Pad0 = 4 - Pad0;
        for(i=pbih->biHeight; i>0; i--,
            pb+=Pad0) {
            for(j=pbih->biWidth; j>0; j--,
                pb+=3) {
                nRGB = RGB(pb[2]&Mask, pb[
                    1]&Mask, pb[0]&Mask);
                pr = (RGBNum*)Count;
                for(n=0; n<NUM; n++,pr++) {
                    if (pr->Num == 0)
                        pr->RGB = nRGB;
                    else if(pr->RGB!=nRGB)
                        continue;
                    pr->Num++;  break;
                }
                if (n==NUM && Sht<3) {
                    while(Sht < 3) {
                        Sht++;  Mask <<= 1;
                        MaskRGB(Count,Mask);
                        if (Count[NUM-1].
                            Num == 0) {
                            j++;  pb -= 3;
                            break;
                        }
                    }
                }
            }
        }
        qsort(Count, NUM, sizeof(RGBNum),
            SortN);
        while(1) {
            for(nClr=NUM; nClr>0; nClr--)
                if (Count[nClr-1].Num!=0)
                    break;
            if (Sht==3 || nClr<=256) {
                nClr = min(nClr, 256);
                break;
            }
            for(i=1,n=0; i<256; i++)
                n += Count[i].Num;
            for(i=256,k=0; i<nClr; )
                k += Count[i++].Num;
            if (k*10 < k+n) {
                nClr = 256;  break;
            }        Sht++;  Mask <<= 1;
            MaskRGB(Count, Mask);
        }
        Size = ((pbih->biWidth+3)/4)*4
            *pbih->biHeight+40+4*nClr;
        if (Size > GlobalSize(hDib)) {
            //hDib is small picture
            GlobalUnlock(hDib);
            hMem = GlobalReAlloc(hDib,
                Size, GMEM_MOVEABLE);
            if (hMem==NULL) return 0;        hDib = hMem;
            pbih = (BITMAPINFOHEADER*)
                GlobalLock(hDib);
            if (pbih==NULL) return 0;
        }
        pLogPal = (LOGPALETTE*)(Count
            + nClr);
        pLogPal->palNumEntries = nClr;
        pLogPal->palVersion = 0x300;
        ppe = pLogPal->palPalEntry;
        for(i=0; i<nClr; i++,ppe++) {
            nRGB = Count[i].RGB;
            ppe->peRed   = GetRValue(nRGB);
            ppe->peGreen = GetGValue(nRGB);
            ppe->peBlue  = GetBValue(nRGB);
            ppe->peFlags = 0;
        }
        hPal = CreatePalette(pLogPal);
        if (hPal == NULL) {
            GlobalUnlock(hDib);  return 0;
        }
        Pad1 = pbih->biWidth % 4;
        if (Pad1!=0) Pad1 = 4-Pad1;
        pb1 = pb = (BYTE*)pbih + 40;
        for(i=0; i<pbih->biHeight; i++) {
            for(j=0; j<pbih->biWidth; j++) {
                *pb1 = GetNearestPaletteIndex
                    (hPal, RGB(pb[2]&Mask,pb[
                    1]&Mask,pb[0]&Mask));
                pb += 3;  pb1++;
            }
            pb += Pad0;   pb1 += Pad1;
        }
        pbih->biBitCount = 8;
        pbih->biClrUsed = nClr;
        i = Size - (40+4*nClr);
        pbih->biSizeImage = i;
        pb = (BYTE*)pbih + 40;
        memmove(pb+4*nClr, pb, i);
        ppe = pLogPal->palPalEntry;
        for(i=0; i<nClr; i++,ppe++) {
            *pb++ = ppe->peBlue;
            *pb++ = ppe->peGreen;
            *pb++ = ppe->peRed;  pb++;
        }
        GlobalUnlock(hDib);
        if (GlobalSize(hDib)>Size) {
            hMem = GlobalReAlloc(hDib,
                Size, GMEM_MOVEABLE);
            if (hMem) hDib = hMem;
        }
        return TRUE;
    }