• c++生成缩略图


    转载:https://bbs.csdn.net/topics/360165636  3楼

    1.先把较大的图片,转换成BMP(假定是12 x 12),没点24bits(RGB各一个byte):
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。
    。 。 。 。 。 。 。 。 。 。 。 。

    假定你要让它变成2 x 2的图像,你可以将上面的点阵分成2 x 2个 6 x 6的点阵。
    针对每个6 x 6的点阵,把所有点的R、G、B的值加起来,分别得到sum_R、sum_G和sum_B,那么得到
    点的颜色值就是(sum_R/36, sum_G/36, sum_B/36)
    这样以来,36个点就缩小为一个点了。

    2.

    位图文件可看成由4个部分组成:位图文件头(bitmap-file header)、位图信息头(bitmap-information header)、彩色表(color table)和定义位图的字节(位图数据,即图像数据,Data Bits 或Data Body)阵列

    位图文件头包含有关于文件类型、文件大小、存放位置等信息,在Windows 3.0以上版本的位图文件中用BITMAPFILEHEADER结构来定义:

    typedef struct tagBITMAPFILEHEADER {
    
        /* bmfh */
    
        UINT bfType;
    
        DWORD bfSize;
    
        UINT bfReserved1;
    
        UINT bfReserved2;
    
        DWORD bfOffBits;
    
    } BITMAPFILEHEADER;

    其中:

    bfType

    说明文件的类型.(该值必需是0x4D42,也就是字符'BM')

    注意:查ascii表B 0x42,M0x4d,bfType为两个字节,B为low字节,M为high字节所以bfType=0x4D42,而不是0x424D.

    bfSize: 说明文件的大小,用字节为单位

    bfReserved1: 保留,必须设置为0

    bfReserved2:保留,必须设置为0

    bfOffBits:说明从文件头开始到实际的图象数据之间的字节的偏移量。

    位图信息用BITMAPINFO结构来定义,它由位图信息头(bitmap-information header)和彩色表(color table)组成,前者用BITMAPINFOHEADER结构定义,后者用RGBQUAD结构定义。

    BITMAPINFO结构具有如下形式:

    typedef struct tagBITMAPINFO {
    
        /* bmi */
    
        BITMAPINFOHEADER bmiHeader;
    
        RGBQUAD bmiColors[1];
    
    } BITMAPINFO;

    bmiHeader

    说明BITMAPINFOHEADER结构,其中包含了有关位图的尺寸及位格式等信息

    bmiColors

    说明彩色表RGBQUAD结构的阵列,其中包含索引图像的真实RGB值。

    BITMAPINFOHEADER结构包含有位图文件的大小、压缩类型和颜色格式,其结构定义为:

    typedef struct tagBITMAPINFOHEADER {
    
        /* bmih */
    
        DWORD biSize;
    
        LONG biWidth;
    
        LONG biHeight;
    
        WORD biPlanes;
    
        WORD biBitCount;
    
        DWORD biCompression;
    
        DWORD biSizeImage;
    
        LONG biXPelsPerMeter;
    
        LONG biYPelsPerMeter;
    
        DWORD biClrUsed;
    
        DWORD biClrImportant;
    
    } BITMAPINFOHEADER;

    biSize

    说明BITMAPINFOHEADER结构所需要的字数。注:这个值并不一定是BITMAPINFOHEADER结构的尺寸,它也可能是sizeof(BITMAPV4HEADER)的值,或是sizeof(BITMAPV5HEADER)的值。这要根据该位图文件的格式版本来决定,不过,就现在的情况来看,绝大多数的BMP图像都是BITMAPINFOHEADER结构的(可能是后两者太新的缘故吧:-)。

    biWidth

    说明图象的宽度,以象素为单位

    biHeight

    说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。(注:当高度值是一个负数时(正向图像),图像将不能被压缩(也就是说biCompression成员将不能是BI_RLE8或BI_RLE4)。

    biPlanes

    为目标设备说明位面数,其值将总是被设为1

    biBitCount

    说明比特数/象素,其值为1、4、8、16、24、或32

    biCompression

    说明图象数据压缩的类型。其值可以是下述值之一:

    BI_RGB:没有压缩;

    BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);

    BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成

    BI_BITFIELDS:每个象素的比特由指定的掩码决定。

    biSizeImage

    说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0

    biXPelsPerMeter

    说明水平分辨率,用象素/米表示

    biYPelsPerMeter

    说明垂直分辨率,用象素/米表示

    biClrUsed

    说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)

    biClrImportant

    说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。

    彩色表定位

    应用程序可使用存储在biSize成员中的信息来查找在BITMAPINFO结构中的彩色表,如下所示:

    pColor = ((LPSTR) pBitmapInfo + (WORD) (pBitmapInfo->bmiHeader.biSize))

    下面的代码生成一个BMP格式的图片的缩略图。原图必须大于新图。

    #define _CRT_SECURE_NO_WARNINGS
    
    #include<windows.h>
    #include<stdio.h>
    #include<assert.h>
    #include<iostream>
    
    using namespace std;
    
    #define NEWWIDTH 380    //新图宽度
    #define NEWHEIGHT 310    //新图高度
    
    //--------------------------------------------------Rothstein----------------------------------------------------------
    class Rothstein
    {
    public:
        Rothstein(int p, int q);
        int operator[] (int i) { return myData[i]; }
        void Permute();
        void PrintData();
        ~Rothstein();
    private:
        char *myData;
        int myP, myQ;
    };
    
    Rothstein::Rothstein(int p, int q)
    {
        myP = p;
        myQ = q;
        myData = new char[p];
    
        if (p <= q) {
            memset(myData, 1, p);
            return;
        }
    
        char *ptr = myData;
        int diff = p - q;
        int  curr = q;
        for (int i = 0; i < p; i++)     //if we want to permute the code, we need <<1
        {
            if (curr < p)
            {
                *ptr = 0;
                curr += q;
            }
            else
            {
                *ptr = 1;
                curr -= diff;
            }
            ptr++;
        }
    }
    
    void Rothstein::Permute()
    {
        int temp = myData[0];
    
        for (int i = 0; i < myP - 1; i++)
            myData[i] = myData[i + 1];
    
        myData[myP - 1] = temp;
    }
    
    void Rothstein::PrintData()
    {
        for (int i = 0; i < myP; i++)
        {
            cout << myData[i] << " ";
        }
        cout << "
    ";
    }
    
    Rothstein::~Rothstein()
    {
        delete myData;
    }
    //--------------------------------------------------Rothstein----------------------------------------------------------
    
    //--------------------------------------------------RowRothstein----------------------------------------------------------
    class RowRothstein
    {
    public:
        RowRothstein(int largerSize, int bpp); //increment according to byte per pixel
        int operator[] (int i) { return myData[i]; }
        void PrintData();
    private:
        int myData[NEWWIDTH];
    };
    
    RowRothstein::RowRothstein(int largerSize, int bpp)
    {    
        Rothstein rot(largerSize, NEWWIDTH);
        int j = 0;
        int oldData = 0;
        for (int i = 0; i < largerSize; i++)
        {
            if (rot[i])
            {
                myData[j++] = (i - oldData)*bpp; //increment in bytes per pixel * number of pixels
                oldData = i;
            }
        }
    }
    
    void RowRothstein::PrintData()
    {
        for (int i = 0; i < NEWWIDTH; i++)
        {        
            cout << myData[i] << "	";
        }
        cout << "
    ";
    }
    //--------------------------------------------------RowRothstein----------------------------------------------------------
    
    //--------------------------------------------------ColRothstein----------------------------------------------------------
    class ColRothstein
    {
    public:
        ColRothstein(int largerSize, int bpl); //increment according to byte perl line 
        int operator[] (int i) { return myData[i]; }
        void PrintData();
    
    private:
        int myData[NEWHEIGHT];
    };
    
    ColRothstein::ColRothstein(int largerSize, int bpl)
    {
        Rothstein rot(largerSize, NEWHEIGHT);
        int j = 0;
        int oldData = 0;
        for (int i = 0; i < largerSize; i++)
        {
            if (rot[i])
            {
                myData[j++] = (i - oldData) * bpl; //increment by number of lines * bytes per line
                oldData = i;
            }
        }
    }
    
    void ColRothstein::PrintData()
    {
        for (int i = 0; i < NEWHEIGHT; i++)
        {
            cout << myData[i] << "	";
        }
        cout << "
    ";
    }
    //--------------------------------------------------ColRothstein----------------------------------------------------------
    
    BYTE* bits = NULL;
    BYTE* newbits = NULL;
    FILE* file = NULL;
    BITMAPFILEHEADER bf;//位图文件头
    unsigned newwidth, newheight, newimagesize, newbfsize;
    unsigned bmiSize;
    unsigned imageSize;
    int bpp, bpl;
    RowRothstein *rotRow;
    ColRothstein *rotCol;
    struct {
        BITMAPINFOHEADER bmiHeader;//包含了有关位图的尺寸及位格式等信息
        RGBQUAD bmiColors[256];//说明彩色表RGBQUAD结构的阵列,其中包含索引图像的真实RGB值
    } bmi;//位图信息
    
    void InitDevice()
    {
        newwidth = NEWWIDTH;
        newheight = NEWHEIGHT;
        //-------byte per pixel 3   original image byte per line 800 x 3 = 2400
        bpp = 3;
        bpl = bmi.bmiHeader.biWidth * bpp;
    
        rotRow = new RowRothstein(bmi.bmiHeader.biWidth, bpp);
        rotCol = new ColRothstein(bmi.bmiHeader.biHeight, bpl);
    
    }
    
    void ResizeImage(unsigned char* src, unsigned char* dst)
    {
        unsigned char* oldp;  //pointer to the pix in the old image
        int oldcol = 0;
    
        for (int row = 0; row < NEWHEIGHT; row++)
        {
            src += (*rotCol)[row];
            oldp = src;
            for (int col = 0; col < NEWWIDTH;)
            {    //unroll 10 times;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
                oldp += (*rotRow)[col++];
                memcpy(dst, oldp, bpp);
                dst += bpp;
            }
        }
    }
    
    void LoadBMP(char* filename)
    {
        if (!(file = fopen(filename, "rb"))) {
            goto done;
        }
    
        if (fread(&bf, 1, sizeof(bf), file) != sizeof(bf)) {
            goto done;
        }
    
        if (bf.bfType != *(WORD*) "BM") {//判断是否是bmp文件,bmp文件位图文件头的bfType一定是"BM"(0x4D42)
            goto done;
        }
    
        bmiSize = bf.bfOffBits - sizeof(bf);//bfOffBits:从文件头开始到实际的图象数据之间的字节的偏移量
        if (bmiSize > sizeof(bmi)) {
            goto done;
        }
        if (fread(&bmi, 1, bmiSize, file) != bmiSize) {
            goto done;
        }
        //biWidth:图像宽度,以像素为单位 
        /* biHeight:图象的高度,以象素为单位。如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。
        当高度值是一个负数时(正向图像),图像将不能被压缩 */
        //biBitCount:说明比特数/象素,其值为1、4、8、16、24、或32
        imageSize = (bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount / 8 + 3 & ~3) * bmi.bmiHeader.biHeight;
        bits = new BYTE[imageSize];
    
        if (fread(bits, 1, imageSize, file) != imageSize) {
            goto done;
        }
    
        assert(bmi.bmiHeader.biHeight >= NEWHEIGHT);//原图片应该比缩略图大
        assert(bmi.bmiHeader.biWidth >= NEWWIDTH);//原图片应该比缩略图大
    
        cout << "image size is " << imageSize << "
    ";
        cout << "color is " << bmi.bmiHeader.biBitCount << "
    ";
        cout << "width is " << bmi.bmiHeader.biWidth << " height is " << bmi.bmiHeader.biHeight << "
    ";
    
    done:
        if (file) {
            fclose(file);
        }
    
    }
    
    void ProcessBMP(char* filename)
    {
        newimagesize = (newwidth* bmi.bmiHeader.biBitCount / 8 + 3 & ~3)* newheight;
        newbits = new BYTE[newimagesize];
        int bytes_per_line = bmi.bmiHeader.biBitCount / 8 * bmi.bmiHeader.biWidth + 3 & ~3;
    
        ResizeImage((unsigned char*)bits, (unsigned char*)newbits);
    
        int filesize = sizeof(bf)+bmiSize + newimagesize;
        bf.bfSize = filesize;
        bmi.bmiHeader.biWidth = newwidth;
        bmi.bmiHeader.biHeight = newheight;
        bmi.bmiHeader.biSizeImage = newimagesize;
    
        if (!(file = fopen(filename, "wb"))) {
            goto done;
        }
        if (fwrite(&bf, 1, sizeof(bf), file) != sizeof(bf)) {
            goto done;
        }
    
        if (fwrite(&bmi, 1, bmiSize, file) != bmiSize) {
            goto done;
        }
    
        if (fwrite(newbits, 1, newimagesize, file) != newimagesize) {
            goto done;
        }
    done:
        if (file) {
            fclose(file);
        }
        if (bits) {
            delete[] bits;
        }
        if (newbits) {
            delete[] newbits;
        }
    
        if (rotRow) {
            delete rotRow;
        }
        if (rotCol) {
            delete rotCol;
        }
    }
    
    int main(int argc, char* argv[])
    {
        char* infile;
        char* outfile;
    
        {
            infile = "test.bmp";
            outfile = "test2.bmp"; 
            
            LoadBMP(infile);
            InitDevice();
            ProcessBMP(outfile);
        }
        system("pause");
        return 0;
    }
  • 相关阅读:
    Qt5对付中文真好用
    Qt5下的常见问题————C1083
    macbook pro retina 编程字体推荐
    boost::xml————又一次失败的尝试
    boost::xml——基本操作以及中文乱码解决方案 (续)
    C++单元测试2
    C++单元测试
    生成dll文件的示例
    咋一看你能看明白吗?
    boost::function实践——来自《Beyond the C++ Standard Library ( An Introduction to Boost )》
  • 原文地址:https://www.cnblogs.com/Toya/p/12531989.html
Copyright © 2020-2023  润新知