天天看點

RGB源資料操作:圖檔順時針180°鏡像、順時針180°旋轉

一、BMP圖檔順時針180°鏡像  1.1 原圖檔

RGB源資料操作:圖檔順時針180°鏡像、順時針180°旋轉
1.2 編譯運作過程

[wbyq@wbyq linux_c]$ gcc app.c 
[wbyq@wbyq linux_c]$ ls
1.bmp  1.c  2.c  666.bmp  888.bmp  a.out  app.c  test.c
[wbyq@wbyq linux_c]$ ./a.out 
傳入的參數格式: ./a.out <原圖檔的名稱> <新圖檔的名稱>
[wbyq@wbyq linux_c]$ ./a.out 888.bmp 2.bmp
原圖檔頭讀取14位元組.
原圖檔類型:BM.
原檔案大小:3529754.
原檔案的資料偏移量:54.
原圖檔參數結構讀取40位元組.
原圖檔寬:1566
原圖檔高:751
原圖檔像素位:24
新圖檔頭成功寫入:14 位元組.
新圖檔的參數結構成功寫入:40 位元組.      

1.3 鏡像的效果

RGB源資料操作:圖檔順時針180°鏡像、順時針180°旋轉

1.4 源代碼

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#pragma pack(1) //強制1個位元組對齊
//BMP的檔案頭
struct _BMP_HEAD
{
    char type[2]; //圖檔的類型 "BM"
    unsigned int size; //檔案大小
    unsigned short  r1; //保留1
    unsigned short  r2; //保留2
    unsigned int seek; //資料偏移位元組(真實像素點資料)
};
 
//BMP的參數資訊
struct _BMP_INFO
{
    unsigned int size; //目前結構體大小
    unsigned int w; //寬度
    unsigned int h; //高度
    unsigned short flag; //固定為1
    unsigned short bit; //像素點的位數
    unsigned int r1; //壓縮方式  0
    unsigned int r2; //水準分辨率
    unsigned int r3; //垂直分辨率
    unsigned int r4; //垂直分辨率
    unsigned int r5; //引用色彩
    unsigned int r6; //關鍵色彩
};
 
int main(int argc,char **argv)
{
    int cnt;
    if(argc!=3)
    {
        printf("傳入的參數格式: ./a.out <原圖檔的名稱> <新圖檔的名稱>\n");
        return 0;
    }
    /*1. 打開原圖檔*/
    FILE *src_fp=fopen(argv[1],"rb");
    if(src_fp==NULL)
    {
        printf("%s 圖檔打開失敗.\n",argv[1]);
        return 0;
    }
    /*2. 讀取圖檔的頭資訊*/
    struct _BMP_HEAD src_bmp_head;
    cnt=fread(&src_bmp_head,1,sizeof(struct _BMP_HEAD),src_fp);
    printf("原圖檔頭讀取%d位元組.\n",cnt);
    printf("原圖檔類型:%c%c.\n",src_bmp_head.type[0],src_bmp_head.type[1]);
    printf("原檔案大小:%d.\n",src_bmp_head.size);
    printf("原檔案的資料偏移量:%d.\n",src_bmp_head.seek);
 
    /*3. 讀取圖檔的參數資訊*/
    struct _BMP_INFO src_bmp_info;
    cnt=fread(&src_bmp_info,1,sizeof(struct _BMP_INFO),src_fp);
    printf("原圖檔參數結構讀取%d位元組.\n",cnt);
    printf("原圖檔寬:%d\n",src_bmp_info.w);
    printf("原圖檔高:%d\n",src_bmp_info.h);
    printf("原圖檔像素位:%d\n",src_bmp_info.bit);
 
    /*4. 建立一張新的BMP圖檔*/
    FILE *new_fp=fopen(argv[2],"wb");
    if(new_fp==NULL)
    {
        printf("%s 檔案建立失敗.\n",argv[2]);
        return 0;
    }
    /*5. 建立BMP的檔案頭*/
    struct _BMP_HEAD new_bmp_head;
    memset(&new_bmp_head,0,sizeof(struct _BMP_HEAD));
    //圖檔的類型
    new_bmp_head.type[0]='B';
    new_bmp_head.type[1]='M';
    //檔案大小
    new_bmp_head.size=54+src_bmp_info.w*src_bmp_info.h*3;
    //資料偏移量
    new_bmp_head.seek=54;
    //寫檔案頭
    cnt=fwrite(&new_bmp_head,1,sizeof(struct _BMP_HEAD),new_fp);
    printf("新圖檔頭成功寫入:%d 位元組.\n",cnt);
 
    /*6. 寫檔案參數資訊*/
    struct _BMP_INFO new_bmp_info;
    memset(&new_bmp_info,0,sizeof(struct _BMP_INFO));
    //目前結構體大小
    new_bmp_info.size=sizeof(struct _BMP_INFO);
    //圖檔的寬度和高度
    new_bmp_info.w=src_bmp_info.w;
    new_bmp_info.h=src_bmp_info.h;
    //圖檔的顔色位數
    new_bmp_info.bit=24;
    //标志位
    new_bmp_info.flag=1;
    //寫入檔案參數資訊
    cnt=fwrite(&new_bmp_info,1,sizeof(struct _BMP_INFO),new_fp);
    printf("新圖檔的參數結構成功寫入:%d 位元組.\n",cnt);
 
    /*7. 寫入位圖資料*/
    int w,h;
    int one_line_byte=src_bmp_info.w*3;  //一行的位元組數
    while(one_line_byte%4!=0)one_line_byte++;  //補齊4的倍數
 
    char *one_line_data=malloc(one_line_byte);
    for(h=src_bmp_info.h-1;h>=0;h--)
    {
        //從頭開始偏移
        fseek(src_fp,one_line_byte*h+54,SEEK_SET);
        fread(one_line_data,1,one_line_byte,src_fp); //讀取圖檔資料
        fwrite(one_line_data,1,one_line_byte,new_fp); //寫資料
    }
 
    /*8. 關閉檔案*/
    fclose(new_fp);
    fclose(src_fp);
    free(one_line_data);
    return 0;
}      

二、BMP圖檔順時針180°翻轉

2.1 原圖檔

RGB源資料操作:圖檔順時針180°鏡像、順時針180°旋轉

2.2 編譯運作過程 

[wbyq@wbyq linux_c]$ gcc app.c 
[wbyq@wbyq linux_c]$ ./a.out 666.bmp 1.bmp
原圖檔頭讀取14位元組.
原圖檔類型:BM.
原檔案大小:919254.
原檔案的資料偏移量:54.
原圖檔參數結構讀取40位元組.
原圖檔寬:800
原圖檔高:383
原圖檔像素位:24
新圖檔頭成功寫入:14 位元組.
新圖檔的參數結構成功寫入:40 位元組.
需要補齊:0位元組.
[wbyq@wbyq linux_c]$ eog 1.bmp       

2.3 翻轉後的效果

RGB源資料操作:圖檔順時針180°鏡像、順時針180°旋轉

2.6 代碼--支援任意尺寸圖檔

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#pragma pack(1) //強制1個位元組對齊
//BMP的檔案頭
struct _BMP_HEAD
{
    char type[2]; //圖檔的類型 "BM"
    unsigned int size; //檔案大小
    unsigned short  r1; //保留1
    unsigned short  r2; //保留2
    unsigned int seek; //資料偏移位元組(真實像素點資料)
};
 
//BMP的參數資訊
struct _BMP_INFO
{
    unsigned int size; //目前結構體大小
    unsigned int w; //寬度
    unsigned int h; //高度
    unsigned short flag; //固定為1
    unsigned short bit; //像素點的位數
    unsigned int r1; //壓縮方式  0
    unsigned int r2; //水準分辨率
    unsigned int r3; //垂直分辨率
    unsigned int r4; //垂直分辨率
    unsigned int r5; //引用色彩
    unsigned int r6; //關鍵色彩
};
 
int main(int argc,char **argv)
{
    int cnt;
    if(argc!=3)
    {
        printf("傳入的參數格式: ./a.out <原圖檔的名稱> <新圖檔的名稱>\n");
        return 0;
    }
    /*1. 打開原圖檔*/
    FILE *src_fp=fopen(argv[1],"rb");
    if(src_fp==NULL)
    {
        printf("%s 圖檔打開失敗.\n",argv[1]);
        return 0;
    }
    /*2. 讀取圖檔的頭資訊*/
    struct _BMP_HEAD src_bmp_head;
    cnt=fread(&src_bmp_head,1,sizeof(struct _BMP_HEAD),src_fp);
    printf("原圖檔頭讀取%d位元組.\n",cnt);
    printf("原圖檔類型:%c%c.\n",src_bmp_head.type[0],src_bmp_head.type[1]);
    printf("原檔案大小:%d.\n",src_bmp_head.size);
    printf("原檔案的資料偏移量:%d.\n",src_bmp_head.seek);
 
    /*3. 讀取圖檔的參數資訊*/
    struct _BMP_INFO src_bmp_info;
    cnt=fread(&src_bmp_info,1,sizeof(struct _BMP_INFO),src_fp);
    printf("原圖檔參數結構讀取%d位元組.\n",cnt);
    printf("原圖檔寬:%d\n",src_bmp_info.w);
    printf("原圖檔高:%d\n",src_bmp_info.h);
    printf("原圖檔像素位:%d\n",src_bmp_info.bit);
 
    /*4. 建立一張新的BMP圖檔*/
    FILE *new_fp=fopen(argv[2],"wb");
    if(new_fp==NULL)
    {
        printf("%s 檔案建立失敗.\n",argv[2]);
        return 0;
    }
    /*5. 建立BMP的檔案頭*/
    struct _BMP_HEAD new_bmp_head;
    memset(&new_bmp_head,0,sizeof(struct _BMP_HEAD));
    //圖檔的類型
    new_bmp_head.type[0]='B';
    new_bmp_head.type[1]='M';
    //檔案大小
    new_bmp_head.size=54+src_bmp_info.w*src_bmp_info.h*3;
    //資料偏移量
    new_bmp_head.seek=54;
    //寫檔案頭
    cnt=fwrite(&new_bmp_head,1,sizeof(struct _BMP_HEAD),new_fp);
    printf("新圖檔頭成功寫入:%d 位元組.\n",cnt);
 
    /*6. 寫檔案參數資訊*/
    struct _BMP_INFO new_bmp_info;
    memset(&new_bmp_info,0,sizeof(struct _BMP_INFO));
    //目前結構體大小
    new_bmp_info.size=sizeof(struct _BMP_INFO);
    //圖檔的寬度和高度
    new_bmp_info.w=src_bmp_info.w;
    new_bmp_info.h=src_bmp_info.h;
    //圖檔的顔色位數
    new_bmp_info.bit=24;
    //标志位
    new_bmp_info.flag=1;
    //寫入檔案參數資訊
    cnt=fwrite(&new_bmp_info,1,sizeof(struct _BMP_INFO),new_fp);
    printf("新圖檔的參數結構成功寫入:%d 位元組.\n",cnt);
 
    int one_line_byte=src_bmp_info.w*3;
    while(one_line_byte%4!=0)one_line_byte++;
    
    int val_byte=one_line_byte-src_bmp_info.w*3; //相差的位元組數
    
    printf("需要補齊%d位元組.\n",val_byte);
    
    /*7. 寫入位圖資料*/
    int w,h;
    int seek=0;
    int c=0;
    for(h=src_bmp_info.h;h>=0;h--)
    {
        seek=h*one_line_byte+54;
        seek-=val_byte; //減去原圖檔的補齊資料
        for(w=0;w<src_bmp_info.w;w++)
        {
            seek-=3;
            //從頭開始偏移
            fseek(src_fp,seek,SEEK_SET);
            fread(&c,1,3,src_fp); //讀取圖檔資料
            fwrite(&c,1,3,new_fp); //寫資料
        }
        if(val_byte)fwrite(&c,1,val_byte,new_fp); //如果需要補齊,就寫補齊資料
    }
 
    /*8. 關閉檔案*/
    fclose(new_fp);
    fclose(src_fp);
    return 0;
}      

繼續閱讀