visual studio 2019与c语言生成纯色与随机条纹bmp图片并转化为jpg格式

visual studio 2019与c语言生成纯色与随机条纹bmp图片并转化为jpg格式(可用于图片生成,插入与测试,主要难点在于压缩图片,图片间不同格式的相互转化)

生成纯色代码如下:


#include 
#include 
#define w 200
#define h 200
#define MAX_SIZE 1024 * 1024 * 64
#pragma warning(disable:4996)

void WriteBMP(char* img, const char* filename)
{
    int l = (w * 3 + 3) / 4 * 4;
    int bmi[] = { l * h + 54,0,54,40,w,h,1 | 3 * 8 << 16,0,l * h,0,0,100,0 };
    FILE* fp = fopen(filename, "wb");
    fprintf(fp, "BM");
    fwrite(&bmi, 52, 1, fp);
    fwrite(img, 1, l * h, fp);
    fclose(fp);
}
int main()
{
    char img[w * h * 3];
    char rgb[3] = {0};
    int iBmpBit = 3;
    for (int i = 0; i < w  ; i++) {                    

        rgb[0] = 0;
        rgb[1] = 0;
        rgb[2] = 225;
        

        for (int ii = 1; ii < h; ii++) {

            int ntmp = (h - 1 - i) * iBmpBit * w + (ii)*iBmpBit;
            for (int j = 0; j < 3; j++)
                img[ntmp + j] = rgb[j];
       }

    }
        
    WriteBMP(img, "test.bmp");
    system("test.bmp");
    return 0;
}

效果如图:

visual studio 2019与c语言生成纯色与随机条纹bmp图片并转化为jpg格式_第1张图片

生成随机条纹代码如下:

#include 
#include 
#define w 200
#define h 200
#define MAX_SIZE 1024 * 1024 * 64
#pragma warning(disable:4996)

void WriteBMP(char* img, const char* filename)
{
    int l = (w * 3 + 3) / 4 * 4;
    int bmi[] = { l * h + 54,0,54,40,w,h,1 | 3 * 8 << 16,0,l * h,0,0,100,0 };
    FILE* fp = fopen(filename, "wb");
    fprintf(fp, "BM");
    fwrite(&bmi, 52, 1, fp);
    fwrite(img, 1, l * h, fp);
    fclose(fp);
}
int main()
{
    char img[w * h * 3];
    char rgb[3] = {0};
    int iBmpBit = 3;
    for (int i = 0; i < w  ; i++) { 
        
        rgb[0] =  rand() % 256; 
        rgb[1] =  rand() % 256;
        rgb[2] =  rand() % 256;       
        

        for (int ii = 1; ii < h; ii++) {

            int ntmp = (h - 1 - i) * iBmpBit * w + (ii)*iBmpBit;
            for (int j = 0; j < 3; j++)
                img[ntmp + j] = rgb[j];
       }

    }
        
    WriteBMP(img, "test.bmp");
    system("test.bmp");
    return 0;
}

 效果如下图:

visual studio 2019与c语言生成纯色与随机条纹bmp图片并转化为jpg格式_第2张图片

将bmp转化为jpg格式的代码如下:

#include 
#include 
#include 
#include 

#pragma warning(disable:4996)

//BMP像素结构体
typedef struct {
    unsigned char B, G, R;
}colorRGB;

typedef struct {
    unsigned char B, G, R, a;
}colorRGBa;

typedef struct {
    unsigned char length;
    unsigned short int value;
}bitstring;

#define PI 3.1415926

//写入文件操作
#define writebyte(b) fputc((b), fp_jpg)
#define writeword(w) writebyte((w)/256);writebyte((w)%256);

colorRGB* RGB_buf; // 24位
colorRGBa* RGBa_buf; // 32位
signed short int ximage, yimage; //图片的长和宽
FILE* fp_jpg;   //打开jpg文件

//二进制编码
static bitstring* code_u;
static bitstring* code_d; //长度以及编码

//存储YCbCr
static signed char YDU[64];
static signed char CbDU[64];
static signed char CrDU[64];

static signed short int D2[64];//存储z型编码后的值

static unsigned char bytecode = 0;
static signed char bytepos = 8;

//JPG头SOI1
//图像识别信息2
static struct APP0
{
    unsigned short int marker;            //段标识和类型FFE0
    unsigned short int length;            // 段长度 16
    unsigned char JFIFsignature[5];  // 存储ASCII码 "JFIF",'\0'
    unsigned char versionhi;         // 主版本号1
    unsigned char versionlo;         // 次版本号1
    unsigned char xyunits;           // 密度单位 0(无单位)
    unsigned short int xdensity;          // 水平方向的密度 1
    unsigned short int ydensity;          // 垂直方向的密度 1
    unsigned char thumbnwidth;       // 略缩图水平像素数目0
    unsigned char thumbnheight;      // 略缩图垂直像素数目0
}APP0info = { 0xFFE0,16,'J','F','I','F',0,1,1,0,1,1,0,0 };
//定义量化表3
static struct DQT {
    unsigned short int marker;   // 段标识和类型 0xFFDB
    unsigned short int length;   // 段长度
    unsigned char QTYinfo;  // 亮度QT值 00
    unsigned char Ytable[64];//内容
    unsigned char QTCbinfo; // 色度QT值 01
    unsigned char Cbtable[64];
} DQTinfo;
//图像基本信息SOF0  4
static struct  SOF0 {
    unsigned short int marker; //段标识和类型 0xFFC0
    unsigned short int length; // 段长度 17
    unsigned char precision;// 每个样本的位数
    unsigned short int height;   //图片高度
    unsigned short int width;     //图片宽度
    unsigned char nrofcomponents;//组件数量 3
    unsigned char IdY;  // 亮度= 1
    unsigned char HVY; // 采样系数 高位标识水平采样系数,低位表示垂直采样系数
    unsigned char QTY;  // 量化表号 0
    unsigned char IdCb; // 红色分量= 2
    unsigned char HVCb;
    unsigned char QTCb; // 1
    unsigned char IdCr; // 蓝色分量= 3
    unsigned char HVCr;
    unsigned char QTCr; // Normally equal to QTCb = 1
} SOF0info = { 0xFFC0,17,8,0,0,3,1,0x11,0,2,0x11,1,3,0x11,1 };
//定义huffman表 5
static struct DHT {
    unsigned short int marker;  //段标识和类型 0xFFC4
    unsigned short int length;  //段长度 19+n+....
    unsigned char HTYDCinfo; // 低4位HT号 第5位HT类型 高3位为0
    unsigned char YDC_codes[16]; //HT位表
    unsigned char YDC_values[12];// HT值表
    unsigned char HTYACinfo; // = 0x10
    unsigned char YAC_codes[16];
    unsigned char YAC_values[162];
    unsigned char HTCbDCinfo; // = 1
    unsigned char CbDC_codes[16];
    unsigned char CbDC_values[12];
    unsigned char HTCbACinfo; //  = 0x11
    unsigned char CbAC_codes[16];
    unsigned char CbAC_values[162];
} DHTinfo;
//扫描行开始  6
static struct SOS {
    unsigned short int marker;  //段标识和类型 0xFFDA
    unsigned short int length; //长度 12
    unsigned char nrofcomponents; // 扫描行内组件数量 通常为3
    unsigned char IdY; //1
    unsigned char HTY; //低4位是AC表号,高4位是DC表号
    unsigned char IdCb; //2
    unsigned char HTCb; //0x11
    unsigned char IdCr; //3
    unsigned char HTCr; //0x11
    unsigned char Ss, Se, Bf; // not interesting, they should be 0,63,0
} SOSinfo = { 0xFFDA,12,3,1,0,2,0x11,3,0x11,0,0x3F,0 };

//亮度量化表
static unsigned char DQT_Y[64] = {
  0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07,
  0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14,
  0x0d, 0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13,
  0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a,
  0x1c, 0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22,
  0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c,
  0x30, 0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39,
  0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32
};
//色差量化表
static unsigned char DQT_C[64] = {
  0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d,
  0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32,
  0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
  0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
  0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
  0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
  0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
  0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
};

//标准huffman表
static unsigned char dc_y_codes[17] = { 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 };
static unsigned char dc_y_values[12] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };

static unsigned char dc_cb_codes[17] = { 0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };
static unsigned char dc_cb_values[12] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };

static unsigned char ac_y_codes[17] = { 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d };
static unsigned char ac_y_values[162] = {
      0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
      0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
      0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
      0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
      0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
      0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
      0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
      0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
      0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
      0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
      0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
      0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
      0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
      0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
      0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
      0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
      0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
      0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
      0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
      0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
      0xf9, 0xfa };

static unsigned char ac_cb_codes[17] = { 0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 };
static unsigned char ac_cb_values[162] = {
      0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
      0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
      0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
      0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
      0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
      0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
      0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
      0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
      0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
      0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
      0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
      0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
      0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
      0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
      0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
      0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
      0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
      0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
      0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
      0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
      0xf9, 0xfa };

//z型编码
static unsigned char z[64] = { 0, 1, 5, 6,14,15,27,28,
          2, 4, 7,13,16,26,29,42,
          3, 8,12,17,25,30,41,43,
          9,11,18,24,31,40,44,53,
         10,19,23,32,39,45,52,54,
         20,22,33,38,46,51,55,60,
         21,34,37,47,50,56,59,61,
         35,36,48,49,57,58,62,63 };

//按位取值表
static unsigned short int mark[16] = { 1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768 };

void writefile(bitstring a)
{
    unsigned short int values = a.value;
    signed char leng_a = a.length;
    while (leng_a > 0)
    {
        if (values & mark[leng_a - 1]) //判断对应位置是否为1
            bytecode |= mark[bytepos - 1];//当前最高位至1
        leng_a--;
        bytepos--;
        if (bytepos <= 0)
        {
            if (bytecode == 0xff)
            {
                writebyte(0xff);
                writebyte(0x00);//说明ff不是段标志
            }
            else
                writebyte(bytecode);
            bytecode = 0;
            bytepos = 8;
        }
    }
}

void code_and_write(signed short int* DC, bitstring* DCtable, bitstring* ACtable)
{
    signed short int diff;
    unsigned char endpos, startpos, i = 1, nz;

    diff = D2[0] - *DC; //差值
    *DC = D2[0];
    //写入直流值
    if (diff == 0)
        writefile(DCtable[0]); //写入0的huffman编码
    else
    {
        writefile(DCtable[code_d[diff].length]);//写入diff长度的huffman编码
        writefile(code_d[diff]); //写入二进制编码
    }
    //写入交流值
    for (endpos = 63; (endpos > 0) && (D2[endpos] == 0); --endpos);
    if (endpos == 0)
    {
        writefile(ACtable[0x00]);
        return;
    }
    while (i <= endpos)
    {
        startpos = i;
        for (; (D2[i] == 0) && (i <= endpos); ++i);
        nz = i - startpos;
        for (; nz >= 16; nz -= 16)//长度大于16需要分多块
            writefile(ACtable[0xf0]);
        writefile(ACtable[nz * 16 + code_d[D2[i]].length]);
        writefile(code_d[D2[i]]);
        ++i;
    }
    if (endpos != 63)
        writefile(ACtable[0x00]);   //EOB
}


void DCT(signed char data[8][8], unsigned char* fdtbl, signed short int* outdata)
{
    float output[8][8], temp;
    double ALPHA, BETA;
    short u = 0;
    short v = 0;
    short i = 0;
    short j = 0;
    for (u = 0; u < 8; u++)
    {
        for (v = 0; v < 8; v++)
        {
            if (u == 0)
                ALPHA = sqrt(1.0 / 8);
            else
                ALPHA = sqrt(2.0 / 8);
            if (v == 0)
                BETA = sqrt(1.0 / 8);
            else
                BETA = sqrt(2.0 / 8);
            float tmp = 0.0;
            for (i = 0; i < 8; i++)
            {
                for (j = 0; j < 8; j++)
                {
                    tmp += data[i][j] * cos((2 * i + 1) * u * PI / (2.0 * 8)) * cos((2 * j + 1) * v * PI / (2.0 * 8));
                }
            }
            output[u][v] = ALPHA * BETA * tmp;
        }
    }

    // 量化
    for (i = 0; i < 8; i++)
        for (j = 0; j < 8; j++)
        {
            temp = output[i][j] / (float)((double)fdtbl[z[i * 8 + j]]);
            outdata[i * 8 + j] = (signed short int) ((signed short int)(temp + 16384.5) - 16384);
        }
}


void fdct_and_quan(signed char* data, unsigned char* table)
{
    float temp;
    signed short int D1[64];
    signed char mdata[8][8];
    unsigned char i, j;
    //离散余弦变换
    for (i = 0; i < 8; ++i)
        for (j = 0; j < 8; ++j)
            mdata[i][j] = data[8 * i + j];
    DCT(mdata, table, D1);
    //z型编码
    for (i = 0; i <= 63; i++)
        D2[z[i]] = D1[i];
}

void RGBtoYCbCr(unsigned short int x1, unsigned short int y1)
{
    unsigned char x, y;
    unsigned char pos = 0;
    unsigned long location;
    unsigned char R, G, B;
    location = y1 * ximage + x1;
    for (y = 0; y < 8; y++)
    {
        for (x = 0; x < 8; x++)
        {
            R = RGB_buf[location].R;
            G = RGB_buf[location].G;
            B = RGB_buf[location].B;
            YDU[pos] = (signed char)(((signed long int)(65536 * 0.299 + 0.5) * R + (signed long int)(65536 * 0.587 + 0.5) * G + (signed long int)(65536 * 0.114 + 0.5) * B) >> 16) - 128;
            CbDU[pos] = (signed char)(((signed long int)(65536 * -0.16874 + 0.5) * R + (signed long int)(65536 * -0.33726 + 0.5) * G + (signed long int)(65536 * 0.5 + 0.5) * B) >> 16);
            CrDU[pos] = (signed char)(((signed long int)(65536 * 0.5 + 0.5) * R + (signed long int)(65536 * -0.41869 + 0.5) * G + (signed long int)(65536 * -0.08131 + 0.5) * B) >> 16);
            location++; pos++;
        }
        location += ximage - 8;
    }
}

void leng_and_numbercode()
{
    signed long int n;
    signed long int one = 1, two = 2;
    unsigned char leng;

    //开辟空间
    code_u = (bitstring*)malloc(65535 * sizeof(bitstring));
    if (code_u == NULL)
    {
        printf("存储空间开辟失败");
        exit(0);
    }
    code_d = code_u + 32767;
    for (leng = 1; leng <= 15; ++leng)
    {
        for (n = one; n < two; ++n)
        {
            code_d[n].length = leng;
            code_d[n].value = (unsigned short int)n;
        }

        for (n = -(two - 1); n <= -one; ++n)
        {
            code_d[n].length = leng;
            code_d[n].value = (unsigned short int)(two - 1 + n);
        }
        two <<= 1;
        one <<= 1;
    }
}

void huffman_code(unsigned char* codes, unsigned char* values, bitstring* HT)
{
    unsigned char k, j;
    unsigned char pos = 0;
    unsigned short int codevalue = 0;
    for (k = 1; k <= 16; ++k)
    {
        for (j = 1; j <= codes[k]; ++j)
        {
            HT[values[pos]].value = codevalue; //编码值
            HT[values[pos]].length = k;     //长度
            pos++;
            codevalue++;
        }
        codevalue *= 2;
    }
}

void code_all()
{
    //huffman编码表
    bitstring YDC[12];
    bitstring CbDC[12];
    bitstring YAC[256];
    bitstring CbAC[256];

    //计算各项的huffman表
    huffman_code(dc_y_codes, dc_y_values, YDC);
    huffman_code(dc_cb_codes, dc_cb_values, CbDC);
    huffman_code(ac_y_codes, ac_y_values, YAC);
    huffman_code(ac_cb_codes, ac_cb_values, CbAC);

    //二进制长度以及编码
    leng_and_numbercode();

    bitstring fillbit;
    signed short int DCY = 0, DCCb = 0, DCCr = 0;//直流系数
    unsigned short int x, y;
    //8*8一组进行处理
    for (y = 0; y < yimage; y += 8)
        for (x = 0; x < ximage; x += 8)
        {
            //printf("1"); //测试
            RGBtoYCbCr(x, y);//RGB->YCbCr
            fdct_and_quan(YDU, DQTinfo.Ytable);//离散余弦和量化,z型编码
            code_and_write(&DCY, YDC, YAC);//编码并写入
            fdct_and_quan(CbDU, DQTinfo.Cbtable);
            code_and_write(&DCCb, CbDC, CbAC);
            fdct_and_quan(CrDU, DQTinfo.Cbtable);
            code_and_write(&DCCr, CbDC, CbAC);
            //printf("2");
        }
    //尾部填充0并写入尾部
    if (bytepos > 0)
    {
        fillbit.length = bytepos;
        fillbit.value = 0;
        writefile(fillbit);
    }
    writeword(0xffd9);//EOI

    //释放空间
    free(RGB_buf);
    free(RGBa_buf);
    fclose(fp_jpg);

}

void writetop()
{
    unsigned char i;
    //1.SOI
    writeword(0xFFD8)
        //2.APP0
        writeword(APP0info.marker);
    writeword(APP0info.length);
    writebyte('J');
    writebyte('F');
    writebyte('I');
    writebyte('F');
    writebyte(0);
    writebyte(APP0info.versionhi);
    writebyte(APP0info.versionlo);
    writebyte(APP0info.xyunits);
    writeword(APP0info.xdensity);
    writeword(APP0info.ydensity);
    writebyte(APP0info.thumbnwidth);
    writebyte(APP0info.thumbnheight);
    //3.DQT
    writeword(DQTinfo.marker);
    writeword(DQTinfo.length);
    writebyte(DQTinfo.QTYinfo);
    for (i = 0; i < 64; i++)
        writebyte(DQTinfo.Ytable[i]);
    writebyte(DQTinfo.QTCbinfo);
    for (i = 0; i < 64; i++)
        writebyte(DQTinfo.Cbtable[i]);
    //4.SOF0
    writeword(SOF0info.marker);
    writeword(SOF0info.length);
    writebyte(SOF0info.precision);
    writeword(SOF0info.height);
    writeword(SOF0info.width);
    writebyte(SOF0info.nrofcomponents);
    writebyte(SOF0info.IdY);
    writebyte(SOF0info.HVY);
    writebyte(SOF0info.QTY);
    writebyte(SOF0info.IdCb);
    writebyte(SOF0info.HVCb);
    writebyte(SOF0info.QTCb);
    writebyte(SOF0info.IdCr);
    writebyte(SOF0info.HVCr);
    writebyte(SOF0info.QTCr);
    //5.DHT
    writeword(DHTinfo.marker);
    writeword(DHTinfo.length);
    writebyte(DHTinfo.HTYDCinfo);
    for (i = 0; i < 16; i++)
        writebyte(DHTinfo.YDC_codes[i]);
    for (i = 0; i <= 11; i++)
        writebyte(DHTinfo.YDC_values[i]);
    writebyte(DHTinfo.HTYACinfo);
    for (i = 0; i < 16; i++)
        writebyte(DHTinfo.YAC_codes[i]);
    for (i = 0; i <= 161; i++)
        writebyte(DHTinfo.YAC_values[i]);
    writebyte(DHTinfo.HTCbDCinfo);
    for (i = 0; i < 16; i++)
        writebyte(DHTinfo.CbDC_codes[i]);
    for (i = 0; i <= 11; i++)
        writebyte(DHTinfo.CbDC_values[i]);
    writebyte(DHTinfo.HTCbACinfo);
    for (i = 0; i < 16; i++)
        writebyte(DHTinfo.CbAC_codes[i]);
    for (i = 0; i <= 161; i++)
        writebyte(DHTinfo.CbAC_values[i]);
    //6.SOS
    writeword(SOSinfo.marker);
    writeword(SOSinfo.length);
    writebyte(SOSinfo.nrofcomponents);
    writebyte(SOSinfo.IdY);
    writebyte(SOSinfo.HTY);
    writebyte(SOSinfo.IdCb);
    writebyte(SOSinfo.HTCb);
    writebyte(SOSinfo.IdCr);
    writebyte(SOSinfo.HTCr);
    writebyte(SOSinfo.Ss);
    writebyte(SOSinfo.Se);
    writebyte(SOSinfo.Bf);
}


void init_JPG_and_writ(char* JPG_filename)
{
    fp_jpg = fopen(JPG_filename, "wb");//打开jpg文件
    int i;
    //初始化量化表
    DQTinfo.marker = 0xFFDB;
    DQTinfo.length = 132;
    DQTinfo.QTYinfo = 0;
    DQTinfo.QTCbinfo = 1;
    for (i = 0; i < 64; ++i)
    {
        DQTinfo.Ytable[i] = DQT_Y[i];
        DQTinfo.Cbtable[i] = DQT_C[i];
    }
    //初始化huffman表
    DHTinfo.marker = 0xFFC4;
    DHTinfo.length = 0x01A2;
    DHTinfo.HTYDCinfo = 0; //0号直流表
    for (i = 0; i < 16; i++)
        DHTinfo.YDC_codes[i] = dc_y_codes[i + 1];
    for (i = 0; i <= 11; i++)
        DHTinfo.YDC_values[i] = dc_y_values[i];

    DHTinfo.HTYACinfo = 0x10; //0号交流表
    for (i = 0; i < 16; i++)
        DHTinfo.YAC_codes[i] = ac_y_codes[i + 1];
    for (i = 0; i <= 161; i++)
        DHTinfo.YAC_values[i] = ac_y_values[i];
    DHTinfo.HTCbDCinfo = 1; //1号直流表

    for (i = 0; i < 16; i++)
        DHTinfo.CbDC_codes[i] = dc_cb_codes[i + 1];
    for (i = 0; i <= 11; i++)
        DHTinfo.CbDC_values[i] = dc_cb_values[i];
    DHTinfo.HTCbACinfo = 0x11; //1号交流表

    for (i = 0; i < 16; i++)
        DHTinfo.CbAC_codes[i] = ac_cb_codes[i + 1];
    for (i = 0; i <= 161; i++)
        DHTinfo.CbAC_values[i] = ac_cb_values[i];

    writetop(); //写入文件头
}

void bmp(char* bmp_name)
{
    unsigned short int x8, y8; //拓展长度
    signed short int y2, a = 0; //用于处理倒序
    unsigned char fillbytes; //可被4整除
    colorRGB lastcolor;
    unsigned short int column, nrline, line_up, line_down;
    unsigned char TOPBUF[256]; //存取头部信息
    colorRGB* tmpline; //用于交换

    FILE* fp_bmp = fopen(bmp_name, "rb");//打开文件
    if (fp_bmp == NULL)
    {
        printf("文件打开失败!");
        exit(0);
    }

    //读取文件头部信息
    fread(TOPBUF, 1, 54, fp_bmp);
    if ((TOPBUF[0] != 'B') || (TOPBUF[1] != 'M'))
    {
        printf("文件不是BMP格式!");
        exit(0);
    }

    //图片长和宽
    ximage = (unsigned short int)TOPBUF[19] * 256 + TOPBUF[18];//图片长度和宽度
    y2 = (short int)TOPBUF[23] * 256 + TOPBUF[22];
    yimage = y2;
    //长度负值处理
    if (y2 <= 0)
    {
        a = 1;
        yimage = -y2;
    }
    SOF0info.width = ximage;
    SOF0info.height = yimage;
    if (ximage % 8 != 0)
        x8 = (ximage / 8) * 8 + 8;
    else
        x8 = ximage;
    if (yimage % 8 != 0)
        y8 = (yimage / 8) * 8 + 8;
    else
        y8 = yimage;
    //建立并存储,填充每一行,转换为RGB
    RGB_buf = (colorRGB*)(malloc(3 * x8 * y8));
    if (RGB_buf == NULL)
    {
        printf("存储创建失败!");
        exit(0);
    }
    //处理32位
    if (TOPBUF[28] == 32)
    {
        RGBa_buf = (colorRGBa*)(malloc(4 * x8 * y8));
        if (RGBa_buf == NULL)
        {
            printf("存储创建失败!");
            exit(0);
        }
        for (nrline = 0; nrline < yimage; nrline++)
        {
            fread(RGBa_buf + nrline * x8, 1, ximage * 4, fp_bmp);
            memcpy(&lastcolor, RGBa_buf + nrline * x8 + ximage - 1, 4);
            for (column = ximage; column < x8; column++)
                memcpy(RGBa_buf + nrline * x8 + column, &lastcolor, 4);
        }

        for (unsigned long int n = 0; n < x8 * yimage; ++n)
        {
            //转换为RGB
            RGB_buf[n].B = RGBa_buf[n].B;
            RGB_buf[n].G = RGBa_buf[n].G;
            RGB_buf[n].R = RGBa_buf[n].R;
        }
    }
    //处理24位
    else if (TOPBUF[28] == 24)
    {
        //判断有无填充
        if (ximage % 4 != 0)
            fillbytes = 4 - (ximage % 4);
        else
            fillbytes = 0;

        for (nrline = 0; nrline < yimage; nrline++)
        {
            fread(RGB_buf + nrline * x8, 1, ximage * 3, fp_bmp);
            fread(TOPBUF, 1, fillbytes, fp_bmp);
            memcpy(&lastcolor, RGB_buf + nrline * x8 + ximage - 1, 3);
            for (column = ximage; column < x8; column++)
                memcpy(RGB_buf + nrline * x8 + column, &lastcolor, 3);
        }
    }
    else
    {
        printf("信息错误!");
        exit(0);
    }
    ximage = x8;
    tmpline = (colorRGB*)malloc(ximage * 8);
    if (tmpline == NULL)
    {
        printf("存储创建失败!");
        exit(0);
    }
    //是否需要逆序处理
    if (a == 0)
    {
        for (line_up = yimage - 1, line_down = 0; line_up > line_down; line_up--, line_down++)
        {
            memcpy(tmpline, RGB_buf + line_up * ximage, ximage * 3);
            memcpy(RGB_buf + line_up * ximage, RGB_buf + line_down * ximage, ximage * 3);
            memcpy(RGB_buf + line_down * ximage, tmpline, ximage * 3);
        }
    }
    //填充行
    memcpy(tmpline, RGB_buf + (yimage - 1) * ximage, ximage * 3);
    for (nrline = yimage; nrline < y8; nrline++)
        memcpy(RGB_buf + nrline * ximage, tmpline, ximage * 3);
    yimage = y8;
    free(tmpline);
    fclose(fp_bmp);

}

int main()
{
    int mm = 2;
    printf("                =========功能:将BMP格式图片转换为JPG格式=========\n");
    while (mm != 1)
    {
        printf("\n");
        //输入文件名称
        char BMP_filename[64];
        char JPG_filename[64];
        printf("输入要压缩的BMP格式的图片名称:");
        scanf("%s", BMP_filename);
        printf("输入压缩完成后JPG格式的图片名称:");
        scanf("%s", JPG_filename);

        bmp(BMP_filename);//读入bmp信息
        init_JPG_and_writ(JPG_filename);//初始化JPG格式并写入
        code_all(); //综合变换并写入

        printf("\n");
        printf("输入'1'退出,输入任意数字继续:");
        scanf("%d", &mm);
    }
    return 0;
}

        执行时输入文件的具体路径和替换的图片名称即可。整个过程相当于制作不同格式的图片并相互转化。图片格式转化来源于其它博客,属于转载,其余为修改和原创。

       无论如何,这是属于文件操作,主要的痛点在于熟悉文件格式,比如bmp,jpg以及PNG等等,颜色的操作和识别也是一门功课,所以整理集合两份代码,利于大家研究与学习,谢谢阅读。

你可能感兴趣的:(C/C++)