在C中加载和操作位图

时间:2015-11-07 03:11:08

标签: c bitmap

我有两个文件,我需要使用它。 bmplib.h ...

#ifndef BMPLIB_H
#define BMPLIB_H

typedef struct {
  unsigned short padding;
  unsigned short bfType;
  unsigned int bfSize;
  unsigned short bfReserved1;
  unsigned short bfReserved2;
  unsigned int bfOffBits;
} BITMAPFILEHEADER;

typedef struct {
  unsigned int biSize;
  int biWidth;
  int biHeight;
  unsigned short biPlanes;
  unsigned short biBitCount;
  unsigned int biCompression;
  unsigned int biSizeImage;
  unsigned int biXPelsPerMeter;
  unsigned int biYPelsPerMeter;
  unsigned int biClrUsed;
  unsigned int biClrImportant;
} BITMAPINFOHEADER;

typedef struct {
  unsigned char r;
  unsigned char g;
  unsigned char b;
} PIXEL;

#define DEFAULT_BITMAP_OFFSET 1078

/* Read an uncompressed 24-bit bmp from a file named 'filename' (if
   null, it's standard input); return the number of 'rows', the number
   of 'cols', and the 'bitmap' as an array of PIXELs. The function
   return 0 if successful. */
int readFile (char* filename, int* rows, int* cols, PIXEL** bitmap);


/* Write an uncompressed 24-bit bmp to a file named 'filename' (if
   null, it's standard output); the dimension of the bmp is the number
   of 'rows' by the number of 'cols', and the 'bitmap' contains an
   array of PIXELs.  The function return 0 if successful. */
int writeFile (char* filename, int rows, int cols, PIXEL* bitmap);

/* Read bmp file header from file 'fd', return the number of 'rows',
   the number of 'cols', and the 'start' position of the bitmap. The
   function returns 0 if successful. */
int readHeader(int fd, int *rows, int *cols, unsigned int *start);

/* Write bmp file header to file 'fd'; the dimention of the bitmap is
   the number of 'rows' by the number of 'cols', and it starts at the
   'start' position. The function returns 0 if successful. */
int writeHeader(int fd, int rows, int cols, unsigned int start);

/* Read the 'bitmap' from file 'fd'; the dimention of the bitmap is
   the number of 'rows' by the number of 'cols', and it starts at the
   'start' position. The function returns 0 if successful. */
int readBits(int fd, PIXEL* bitmap, int rows, int cols, unsigned int start);

/* Write the 'bitmap' to file 'fd'; the dimention of the bitmap is the
   number of 'rows' by the number of 'cols', and it starts at the
   'start' position. The function returns 0 if successful. */
int writeBits(int fd, int rows, int cols, PIXEL* bitmap, unsigned int start);

#endif /*BMPLIB_H*/

bmplib.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include "bmplib.h"

static int myread(int fd, char* buf, unsigned int size)
{
  int r = 0;
  while(r < size) {
    int x = read(fd, &buf[r], size-r);
    if(x < 0) return x;
    else r += x;
  }
  return size;
}

static int mywrite(int fd, char* buf, unsigned int size)
{
  int w = 0;
  while(w < size) {
    int x = write(fd, &buf[w], size-w);
    if(x < 0) return x;
    else w += x;
  }
  return size;
}

int readFile (char *filename, int *rows, int *cols, PIXEL** bitmap) 
{
  int fd, ret;
  unsigned int start;

  if(filename) {
    if((fd = open(filename, O_RDONLY)) < 0) {
      perror("Can't open bmp file to read");
      return -1;
    }
  } else fd = STDIN_FILENO;

  ret = readHeader (fd, rows, cols, &start);
  if(ret) return ret;

  *bitmap = (PIXEL*)malloc(sizeof(PIXEL)*(*rows)*(*cols));
  ret = readBits (fd, *bitmap, *rows, *cols, start);
  if(ret) return ret;

  if(filename) close(fd);

  return 0;
}

int writeFile (char* filename, int rows, int cols, PIXEL* bitmap) 
{
  int fd, ret;
  unsigned int start = DEFAULT_BITMAP_OFFSET;

  if(filename) {
    if((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) {
      perror("Can't open bmp file to write");
      return -1;
    }
  } else fd = STDOUT_FILENO;

  ret = writeHeader (fd, rows, cols, start);
  if(ret) return ret;

  ret = writeBits(fd, rows, cols, bitmap, start);
  if(ret) return ret;

  if(filename) close(fd);

  return 0;
}

int readHeader(int fd, int *rows, int *cols, unsigned int *start) 
{
  BITMAPFILEHEADER bmfh;
  BITMAPINFOHEADER bmih;

  if(myread(fd, ((char*)&bmfh)+2, sizeof(bmfh)-2) <= 0) {
    perror("Can't read BITMAPFILEHEADER");
    return -2;
  }
  if(myread(fd, (char*)&bmih, sizeof(bmih)) <= 0) {
    perror("Can't read BITMAPINFOHEADER");
    return -3;
  }

  if(bmih.biCompression != 0) {
    fprintf(stderr, "Can't read compressed bmp");
    return -4;
  }
  if(bmih.biBitCount != 24) {
    fprintf(stderr, "Can't handle bmp other than 24-bit");
    return -5;
  }

  *rows = bmih.biHeight;
  *cols = bmih.biWidth;
  *start = bmfh.bfOffBits;

  return 0;
}

int writeHeader(int fd, int rows, int cols, unsigned int start)
{
  unsigned int fileSize;
  unsigned int headerSize;
  unsigned int paddedCols;
  BITMAPFILEHEADER bmfh;
  BITMAPINFOHEADER bmih;

  memset (&bmfh, 0, sizeof(bmfh));
  memset (&bmih, 0, sizeof(bmih));

  paddedCols = ((cols/4)*4 !=cols ? ((cols+4)/4)*4 : cols);
  headerSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
  fileSize = rows*paddedCols*sizeof(PIXEL)+headerSize;

  bmfh.bfType = 0x4D42;
  bmfh.bfSize = fileSize;
  bmfh.bfReserved1 = 0;
  bmfh.bfReserved2 = 0;
  bmfh.bfOffBits = start;

  bmih.biSize = 40;
  bmih.biWidth  = cols;
  bmih.biHeight = rows;
  bmih.biPlanes = 1;
  bmih.biBitCount = 24;
  bmih.biCompression = 0;
  bmih.biSizeImage = 0;
  bmih.biXPelsPerMeter  = 0;
  bmih.biYPelsPerMeter = 0;
  bmih.biClrUsed = 0;
  bmih.biClrImportant = 0;

  if(mywrite(fd, ((char*)&bmfh)+2, sizeof(bmfh)-2) < 0) {
    perror("Can't write BITMAPFILEHEADER");
    return -2;
  }
  if(mywrite(fd, (char*)&bmih, sizeof(bmih)) < 0) {
    perror("Can't write BITMAPINFOHEADER");
    return -3;
  }

  return 0;
}

int readBits(int fd, PIXEL* bitmap, int rows, int cols, unsigned int start) 
{
  int row;
  char padding[3];
  int padAmount;
  char useless[DEFAULT_BITMAP_OFFSET];

  padAmount = ((cols * sizeof(PIXEL)) % 4) ? (4 - ((cols * sizeof(PIXEL)) % 4)) : 0;

  start -= sizeof(BITMAPFILEHEADER)-2+sizeof(BITMAPINFOHEADER);
  if(start > 0 && myread(fd, useless, start) < 0) { 
    perror("Can't lseek to bitmap");
    return -6;
  }
  /*
  if(lseek (fd, start, SEEK_SET) < 0) {
    perror("Can't lseek to bitmap");
    return -6;
  }
  */

  for (row=0; row < rows; row++) {
    if(myread(fd, (char*)(bitmap+(row*cols)), cols*sizeof(PIXEL)) < 0) {
      perror("Can't read bitmap");
      return -7;
    }
    if(padAmount > 0) { 
      if(myread(fd, padding, padAmount) < 0) {
    perror("Can't read bitmap");
    return -8;
      }
    }
  }

  return 0;
}

int writeBits(int fd, int rows, int cols, PIXEL* bitmap, unsigned int start) 
{
  int row;
  char padding[3];
  int padAmount;
  char useless[DEFAULT_BITMAP_OFFSET];

  padAmount = ((cols * sizeof(PIXEL)) % 4) ? (4 - ((cols * sizeof(PIXEL)) % 4)) : 0;
  memset(padding, 0, 3);

  start -= sizeof(BITMAPFILEHEADER)-2+sizeof(BITMAPINFOHEADER);
  if(start > 0) {
    memset(useless, 0, start);
    if(mywrite(fd, useless, start) < 0) { 
      perror("Can't lseek to bitmap");
      return -6;
    }
  }
  /*
  if(lseek (fd, start, SEEK_SET) < 0) {
    perror("Can't lseek to bitmap");
    return -6;
  }
  */

  for (row=0; row < rows; row++) {
    if(mywrite(fd, (char*)(bitmap+(row*cols)), cols*sizeof(PIXEL)) < 0) {
      perror("Can't write bitmap");
      return -7;
    }
    if(padAmount > 0) { 
      if(mywrite(fd, padding, padAmount) < 0) {
    perror("Can't write bitmap");
    return -8;
      }
    }
  }

  return 0;
}

我试图理解如何使用readInput函数加载位图图像,但我完全不知道我需要为行,列和PIXEL数组传递什么参数。此外,我不太明白我是如何使用这个库来操作位图的;放大或翻转90度。有人可以解释这段代码是如何工作的,特别是如何使用下面的函数成功加载位图图像,然后放大或翻转它。

0 个答案:

没有答案