BMP图片转JPEG图片
本文最后更新于 159 天前,其中的信息可能已经有所发展或是发生改变。
#include <stdio.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include </home/gec/software/installed/jepg/include/jpeglib.h>


// ...(保持你的结构体定义不变)...
#pragma pack(push, 1) // 禁用内存对齐

typedef struct

{
    uint16_t bfType;      // 文件标识,必须为 "BM"(0x4D42)
    uint32_t bfSize;      // 文件总大小(字节)
    uint16_t bfReserved1; // 保留字段(必须为0)
    uint16_t bfReserved2; // 保留字段(必须为0)
    uint32_t bfOffBits;   // 像素数据偏移量(从文件头到像素数据的字节数)
} BITMAPFILEHEADER;

#pragma pack(pop)

typedef struct

{

    uint32_t biSize;         // 本结构体大小(通常为40)
    int32_t biWidth;         // 图像宽度(像素)
    int32_t biHeight;        // 图像高度(像素),正数表示从下到上存储
    uint16_t biPlanes;       // 颜色平面数(必须为1)
    uint16_t biBitCount;     // 每像素位数(1/4/8/16/24/32)
    uint32_t biCompression;  // 压缩方式(0表示不压缩)
    uint32_t biSizeImage;    // 像素数据大小(字节),压缩时需填写
    int32_t biXPelsPerMeter; // 水平分辨率(像素/米)
    int32_t biYPelsPerMeter; // 垂直分辨率(像素/米)
    uint32_t biClrUsed;      // 实际使用的调色板颜色数(0表示全部)
    uint32_t biClrImportant; // 重要颜色数(0表示所有颜色均重要)

} BITMAPINFOHEADER;

/*
 * Sample routine for JPEG compression.  We assume that the target file name
 * and a compression quality factor are passed in.
 */

GLOBAL(void)
write_JPEG_file (char * filename, int quality, unsigned char *image_buffer, int image_width, int image_height)
{
  /* This struct contains the JPEG compression parameters and pointers to
   * working space (which is allocated as needed by the JPEG library).
   * It is possible to have several such structures, representing multiple
   * compression/decompression processes, in existence at once.  We refer
   * to any one struct (and its associated working data) as a "JPEG object".
   */
  struct jpeg_compress_struct cinfo;
  /* This struct represents a JPEG error handler.  It is declared separately
   * because applications often want to supply a specialized error handler
   * (see the second half of this file for an example).  But here we just
   * take the easy way out and use the standard error handler, which will
   * print a message on stderr and call exit() if compression fails.
   * Note that this struct must live as long as the main JPEG parameter
   * struct, to avoid dangling-pointer problems.
   */
  struct jpeg_error_mgr jerr;
  /* More stuff */
  FILE * outfile;		/* target file */
  JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
  int row_stride;		/* physical row width in image buffer */

  /* Step 1: allocate and initialize JPEG compression object */

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error(&jerr);
  /* Now we can initialize the JPEG compression object. */
  jpeg_create_compress(&cinfo);

  /* Step 2: specify data destination (eg, a file) */
  /* Note: steps 2 and 3 can be done in either order. */

  /* Here we use the library-supplied code to send compressed data to a
   * stdio stream.  You can also write your own code to do something else.
   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
   * requires it in order to write binary files.
   */
  if ((outfile = fopen(filename, "wb")) == NULL) {
    fprintf(stderr, "can't open %s\n", filename);
    exit(1);
  }
  jpeg_stdio_dest(&cinfo, outfile);

  /* Step 3: set parameters for compression */

  /* First we supply a description of the input image.
   * Four fields of the cinfo struct must be filled in:
   */
  cinfo.image_width = image_width; 	/* image width and height, in pixels */
  cinfo.image_height = image_height;
  cinfo.input_components = 3;		/* # of color components per pixel */
  cinfo.in_color_space = JCS_RGB; 	/* colorspace of input image */
  /* Now use the library's routine to set default compression parameters.
   * (You must set at least cinfo.in_color_space before calling this,
   * since the defaults depend on the source color space.)
   */
  jpeg_set_defaults(&cinfo);
  /* Now you can set any non-default parameters you wish to.
   * Here we just illustrate the use of quality (quantization table) scaling:
   */
  jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);

  /* Step 4: Start compressor */

  /* TRUE ensures that we will write a complete interchange-JPEG file.
   * Pass TRUE unless you are very sure of what you're doing.
   */
  jpeg_start_compress(&cinfo, TRUE);

  /* Step 5: while (scan lines remain to be written) */
  /*           jpeg_write_scanlines(...); */

  /* Here we use the library's state variable cinfo.next_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   * To keep things simple, we pass one scanline per call; you can pass
   * more if you wish, though.
   */
  row_stride = image_width * 3;	/* JSAMPLEs per row in image_buffer */

  while (cinfo.next_scanline < cinfo.image_height) {
    /* jpeg_write_scanlines expects an array of pointers to scanlines.
     * Here the array is only one element long, but you could pass
     * more than one scanline at a time if that's more convenient.
     */
    row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
  }


  jpeg_finish_compress(&cinfo);
  fclose(outfile);
  jpeg_destroy_compress(&cinfo);
}

int main(int argc, const char* argv[])
{   
    if(argc != 2)
    {
        printf("用法: %s <bmp图片路径> \n", argv[0]);
        return 0;
    }

    FILE* bmp = fopen(argv[1], "rb");
    if(bmp == NULL)
    {
        printf("bmp图片加载失败!\n");
        return 0;
    }

    BITMAPFILEHEADER fileheader;
    BITMAPINFOHEADER infoheader;
    fread(&fileheader, 14, 1, bmp);
    fread(&infoheader, 40, 1, bmp);

    int width = infoheader.biWidth;
    int height = infoheader.biHeight;
    // 有些少见的BMP是从上到下的,高度为负数,做个绝对值保护
    if (height < 0) height = -height; 

    // 1. 计算 BMP 每行带补齐的实际字节数
    int bmp_row_stride = ((width * 3 + 3) / 4) * 4;
    // 2. JPEG 需要的纯净行字节数(无补齐)
    int jpeg_row_stride = width * 3;

    // 申请两块内存
    unsigned char* bmp_raw_buf = (unsigned char*)malloc(bmp_row_stride * height);
    unsigned char* jpeg_rgb_buf = (unsigned char*)malloc(jpeg_row_stride * height);

    if(!bmp_raw_buf || !jpeg_rgb_buf) {
        printf("内存申请失败!\n");
        return 0;
    }

    // 严谨点:跳过可能的调色板,直接从像素偏移量开始读
    fseek(bmp, fileheader.bfOffBits, SEEK_SET);
    // 一口气把包含废字节的所有BMP数据读进 raw_buf
    fread(bmp_raw_buf, 1, bmp_row_stride * height, bmp);

    // ================= 开始“清洗”数据 =================
    for (int y = 0; y < height; y++) 
    {
        // JPEG 的行:从上到下 (0 到 height-1)
        int jpeg_y = y;
        // BMP 的行:从下到上 (height-1 到 0)
        int bmp_y = height - 1 - y;

        // 算出这两行在各自内存里的起始地址
        unsigned char* jpeg_row = jpeg_rgb_buf + (jpeg_y * jpeg_row_stride);
        unsigned char* bmp_row  = bmp_raw_buf + (bmp_y * bmp_row_stride);

        // 遍历这一行的每一个像素,做 BGR -> RGB 的转换
        for (int x = 0; x < width; x++) 
        {
            // jpeg_row 是目标,bmp_row 是源
            jpeg_row[x * 3 + 0] = bmp_row[x * 3 + 2]; // Red   <- 提取源的 R
            jpeg_row[x * 3 + 1] = bmp_row[x * 3 + 1]; // Green <- 提取源的 G
            jpeg_row[x * 3 + 2] = bmp_row[x * 3 + 0]; // Blue  <- 提取源的 B
        }
    }
    // ================= 洗完收工 =================

    // 把纯净的 RGB 数据喂给 libjpeg
    write_JPEG_file("destjpeg.jpeg", 90, jpeg_rgb_buf, width, height);

    // 释放资源
    fclose(bmp);
    free(bmp_raw_buf);
    free(jpeg_rgb_buf);
    
    printf("BMP转JPEG成功!\n");

    return 0;
}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇