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 << "\n";
}

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] << "\t";
    }
    cout << "\n";
}
//--------------------------------------------------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] << "\t";
    }
    cout << "\n";
}
//--------------------------------------------------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 << "\n";
    cout << "color is " << bmi.bmiHeader.biBitCount << "\n";
    cout << "width is " << bmi.bmiHeader.biWidth << " height is " << bmi.bmiHeader.biHeight << "\n";

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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM