如何在Linux C中剪切图片 [英] how to cut a picture in linux c

查看:68
本文介绍了如何在Linux C中剪切图片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如何复制图片,但是我不知道如何像gimp一样剪切图片的一部分?当然,我知道图像的类型是differnet.所以我只知道如何处理.bmp类型. (crop_x0,crop_y0)是原始图片上剪裁的左上角坐标,(crop_x1,crop_y1)是裁剪的右下角坐标.请注意,结果图片中不包含crop_y1寻址的行和crop_x1寻址的列.
无需RLE压缩即可处理8、16、24和32位bmp图像.也处理原始的V4和V5标头.您可能想注释掉LITTLE_ENDIAN定义,如果您的处理器是big endian.

 #define LITTLE_ENDIAN

#ifdef _WIN32
#定义_CRT_SECURE_NO_WARNINGS
 typedef   __ int8  int8_t;
 typedef   __ int16  int16_t;
 typedef   __ int32  int32_t;
 typedef   __ int64  int64_t;
 typedef   unsigned   __ int8  uint8_t;
 typedef   unsigned   __ int16  uint16_t;
 typedef   unsigned   __ int32  uint32_t;
 typedef   unsigned   __ int64  uint64_t;
#else
#include< stdint.h>
#endif

#ifndef BI_RGB
#define BI_RGB  0 
#endif
 #ifndef BI_BITFIELDS
#define BI_BITFIELDS  3 
#endif

#include   ><  > 
 #include   <   stdlib.h  > 
 #include   <  内存.h > 


// 将结构对齐方式设置为1个字节,您可能必须在linux上使用其他功能才能做到这一点... 
// 较新的gcc版本支持编译指示包.参见:http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html 
#pragma pack(push,1)
  typedef   struct  tagBITMAPFILEHEADER {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} BITMAPFILEHEADER;

 typedef  结构 tagBITMAPINFOHEADER {
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
} BITMAPINFOHEADER;
#pragma pack(pop)


 int 最大值( int  a, int  b )
{
返回 a> b吗? a:b;
}
 int 最小值( int  a, int  b )
{
返回 a< b吗? a:b;
}

#ifdef LITTLE_ENDIAN

#define GET_INT16_LE(var)\
 var
#define SET_INT16_LE(var,value)\
 var = 
#define GET_INT32_LE(var)\
 var
#define SET_INT32_LE(var,value)\
 var = 

#else

#define GET_INT16_LE(var)\
((var>>  8 )& 0xFF)| ((var<<  8 )& 0xFF00)
#define SET_INT16_LE(var,value)\
 var =((>>  8 )& 0xFF)| (((<<  8 )& 0xFF00)
#define GET_INT32_LE(var)\
((((var>>  24 )& 0xFF)|(((var>>  8 )& 0xFF00)|((var<<  8 )& 0xFF0000)|((var<<  24 和0xFF000000))
#define SET_INT32_LE(var,value)\
 var =((((>>  24 )& 0xFF)|( (>>  8 )& 0xFF00)|((关键字>值<<  <<  24 )& 0xFF000000))

#endif

// 出错时返回零
 int  CropBmpData( const   char  *数据,  int  data_size, int  crop_x0, int  crop_y0 , int  crop_x1, int  crop_y1, char  ** out_data, int  * out_size)
{
 const  BITMAPFILEHEADER *标头=(BITMAPFILEHEADER *)data;
 const  BITMAPINFOHEADER * bmih =(BITMAPINFOHEADER *)(header +  1 );
 int 宽度,高度,top_down,bpp,步幅,bytes_per_pixel,bytes_to_copy_per_row;
 int  width2,height2,stride2,head_size;
 int  y,padding_bytes;
BITMAPFILEHEADER * header2;
BITMAPINFOHEADER * bmih2;
 const   char  * src;
字符 * dest;
uint16_t magic = GET_INT16_LE(header-> bfType);

如果(不可思议!= 0x4D42)
返回  0 ;
// 我们使用的事实是,我们使用的第一个字段在中是相同的
//  BITMAPINFOHEADER和BITMAPV4HEADER和BITMAPV5HEADER.
如果(GET_INT32_LE(bmih-> biSize)< sizeof(BITMAPINFOHEADER))
返回  0 ;

// 每像素位数
bpp = GET_INT16_LE(bmih-> biBitCount);
如果(bpp!=  8 && bpp!=  16 && bpp!=  24 && bpp!=  32  )
返回  0 ;

// 我们不处理RLE压缩的BMP文件.
如果(GET_INT32_LE(bmih-> biCompression)!= BI_RGB)
{
// 我们仅允许BI_BITFIELDS用于16位bmp文件.
如果(bpp!=  16  || GET_INT32_LE(bmih-> biCompression)!= BI_BITFIELDS)
返回  0 ;
}
// 在这里从未见过具有其他值的bmp ... 
如果(GET_INT16_LE(bmih-> biPlanes)!=  1 )
返回  0 ;

宽度= GET_INT32_LE(bmih-> biWidth);
高度= GET_INT32_LE(bmih-> biHeight);

如果(宽度< =  0  || height ==  0 )
返回  0 ;

top_down =高度<  0 ;
如果(top_down)
高度=-高度;

crop_x0 =最大值(crop_x0, 0 );
crop_y0 =最大值(crop_y0, 0 );
crop_x1 =最小值(crop_x1,宽度);
crop_y1 = Min(crop_y1,height);

// 如果生成的图片的宽度或高度为零,则将导致致命错误
// ,因为.bmp文件中的零不是有效大小!
如果(crop_x0> = crop_x1)
返回  0 ;
如果(crop_y0> = crop_y1)
返回  0 ;

// 步幅(每行像素的数据字节)在.bmp文件中始终是4的倍数.
步幅=((bpp *宽度+  31 )/ 8 )& 〜3;

head_size = GET_INT32_LE(header-> bfOffBits);

// 根据位图标头和bmp尺寸,文件大小应该更大... 
如果(data_size< head_size + stride * height)
返回  0 ;

src =数据+ head_size;
如果(!top_down)
{
src + =(height-  1 )*大步;
步幅=-步幅;
}
bytes_per_pixel = bpp/ 8 ;
src + = crop_x0 * bytes_per_pixel + crop_y0 *步幅;

宽度2 = crop_x1 -crop_x0;
高度2 = crop_y1 -crop_y0;
stride2 =((bpp * width2 +  31 )/ 8 )& 〜3;

* out_size = head_size + stride2 * height2;
* out_data =( char  *)malloc(* out_size);
如果(!* out_data)
返回  0 ;
memcpy(* out_data,data,head_size);
header2 =(BITMAPFILEHEADER *)* out_data;
bmih2 =(BITMAPINFOHEADER *)(标题2 + 1);
SET_INT32_LE(bmih2-> biWidth,width2);
SET_INT32_LE(bmih2-> biHeight,top_down?-height2:height2);
SET_INT32_LE(bmih2-> biSizeImage, 0 );

dest = * out_data + head_size;
如果(!top_down)
{
dest + =(height2-  1 )* stride2;
stride2 = -stride2;
}

bytes_to_copy_per_row = width2 * bytes_per_pixel;
padding_bytes = stride2-bytes_to_copy_per_row;

 for (y =  0 ; y 如果(padding_bytes>  0 )
memset(dest + bytes_to_copy_per_row, 0 ,padding_bytes);
src + =大步;
dest + = stride2;
}

返回  1 ;
}

// 出错时返回零
 int  CropBmpFile( const   char  * input_file,  const   char  * output_file, int  crop_x0,  int  crop_y0, int  crop_x1, int  crop_y1 )
{
文件* f;
文件大小;
 char  *数据;
 size_t 字节读取,字节写入;
字符 * new_data;
 int  new_size;
 int 成功;

f = fopen(input_file," );
如果(!f)
返回  0 ;
fseek(f, 0 ,SEEK_END);
文件大小= ftell(f);
如果(文件大小< =  sizeof (BITMAPFILEHEADER)+ sizeof(BITMAPINFOHEADER))
{
fclose(f);
返回  0 ;
}

数据=( char  *)malloc(filesize);
如果(!数据)
{
fclose(f);
返回  0 ;
}

倒带(f);
bytes_read = fread(data, 1 ,( size_t )filesize,f);
fclose(f);
如果(bytes_read!=( size_t )文件大小)
{
免费(数据);
返回  0 ;
}

new_data = NULL;
new_size =  0 ;
成功= CropBmpData(数据,文件大小,crop_x0,crop_y0,crop_x1,crop_y1,& new_data和& new_size);
免费(数据);
如果(成功)
{
f = fopen(输出文件," );
如果(f)
{
bytes_write = fwrite(new_data, 1 ,( size_t )new_size,f);
fclose(f);
成功=字节写入==( size_t )new_size;
}
其他
{
成功=  0 ;
}
}

如果(新数据)
免费(新数据);
返回成功;
}


 int  main( int  argc, char  * argv [])
{
printf(" ,CropBmpFile(" "  e:\\ w-mode-1_03_cropped.bmp" 10  50  20 )));
printf(" ,CropBmpFile(" "  e:\\ w-mode-1_03_8_cropped.bmp" 10  50  20 )));
printf(" ,CropBmpFile(" "  e:\\ w-mode-1_03_16_cropped.bmp" 10  50  20 )));
返回  0 ;
} 


I know how to copy a picture ,but I don''t know how to cut a part of a picture like gimp? Of couse I know the type of image is differnet.So i just know how to handle a type of .bmp.

解决方案

Here you go! (crop_x0, crop_y0) is the topleft coordinate and (crop_x1, crop_y1) is the bottomright coordinate of the cut on the original picture. Note that the row addressed by crop_y1 and the column addressed by crop_x1 aren''t included in the resulting picture.
Works with 8, 16, 24, and 32 bit bmp images without RLE compression. Handles original V4 and V5 headers as well. You might want to comment out the LITTLE_ENDIAN define if your processor is big endian.

#define LITTLE_ENDIAN

#ifdef _WIN32
# define _CRT_SECURE_NO_WARNINGS
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#else
# include <stdint.h>
#endif

#ifndef BI_RGB
# define BI_RGB 0
#endif
#ifndef BI_BITFIELDS
# define BI_BITFIELDS 3
#endif

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>


// Setting struct alignment to 1 byte, you might have to use something else on linux to do this...
// Newer gcc version support pragma pack. see: http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html
#pragma pack(push, 1)
typedef struct tagBITMAPFILEHEADER {
	uint16_t	bfType;
	uint32_t	bfSize;
	uint16_t	bfReserved1;
	uint16_t	bfReserved2;
	uint32_t	bfOffBits;
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
	uint32_t	biSize;
	int32_t		biWidth;
	int32_t		biHeight;
	uint16_t	biPlanes;
	uint16_t	biBitCount;
	uint32_t	biCompression;
	uint32_t	biSizeImage;
	int32_t		biXPelsPerMeter;
	int32_t		biYPelsPerMeter;
	uint32_t	biClrUsed;
	uint32_t	biClrImportant;
} BITMAPINFOHEADER;
#pragma pack(pop)


int Max(int a, int b)
{
	return a>b ? a : b;
}
int Min(int a, int b)
{
	return a<b ? a : b;
}

#ifdef LITTLE_ENDIAN

#define GET_INT16_LE(var) \
	var
#define SET_INT16_LE(var, value) \
	var = value
#define GET_INT32_LE(var) \
	var
#define SET_INT32_LE(var, value) \
	var = value

#else

#define GET_INT16_LE(var) \
	((var >> 8) & 0xFF) | ((var << 8) & 0xFF00)
#define SET_INT16_LE(var, value) \
	var = ((value >> 8) & 0xFF) | ((value << 8) & 0xFF00)
#define GET_INT32_LE(var) \
	(((var >> 24) & 0xFF) | ((var >> 8) & 0xFF00) | ((var << 8) & 0xFF0000) | ((var << 24) & 0xFF000000))
#define SET_INT32_LE(var, value) \
	var = (((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000))

#endif

// returns zero on error
int CropBmpData(const char* data, int data_size, int crop_x0, int crop_y0, int crop_x1, int crop_y1, char** out_data, int* out_size)
{
	const BITMAPFILEHEADER* header = (BITMAPFILEHEADER*)data;
	const BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)(header + 1);
	int width, height, top_down, bpp, stride, bytes_per_pixel, bytes_to_copy_per_row;
	int width2, height2, stride2, head_size;
	int y, padding_bytes;
	BITMAPFILEHEADER* header2;
	BITMAPINFOHEADER* bmih2;
	const char* src;
	char* dest;
	uint16_t magic = GET_INT16_LE(header->bfType);

	if (magic != 0x4D42)
		return 0;
	// We use the fact that the first fields we use are the same in
	// BITMAPINFOHEADER and BITMAPV4HEADER and BITMAPV5HEADER.
	if (GET_INT32_LE(bmih->biSize)<sizeof(BITMAPINFOHEADER))
		return 0;

	// bits per pixel
	bpp = GET_INT16_LE(bmih->biBitCount);
	if (bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
		return 0;

	// We don't handle RLE compressed BMP files.
	if (GET_INT32_LE(bmih->biCompression) != BI_RGB)
	{
		// We allow BI_BITFIELDS only for 16 bit bmp files.
		if (bpp != 16 || GET_INT32_LE(bmih->biCompression) != BI_BITFIELDS)
			return 0;
	}
	// Never seen a bmp with other value here...
	if (GET_INT16_LE(bmih->biPlanes) != 1)
		return 0;

	width = GET_INT32_LE(bmih->biWidth);
	height = GET_INT32_LE(bmih->biHeight);

	if (width <= 0 || height == 0)
		return 0;

	top_down = height < 0;
	if (top_down)
		height = -height;

	crop_x0 = Max(crop_x0, 0);
	crop_y0 = Max(crop_y0, 0);
	crop_x1 = Min(crop_x1, width);
	crop_y1 = Min(crop_y1, height);

	// If the resulting picture has zero width or height its a fatal error
	// because zero is not a valid size in .bmp files!
	if (crop_x0 >= crop_x1)
		return 0;
	if (crop_y0 >= crop_y1)
		return 0;

	// stride (data bytes per row of pixels) is always a multiple of 4 in .bmp files.
	stride = ((bpp * width + 31) / 8) & ~3;

	head_size = GET_INT32_LE(header->bfOffBits);

	// According to the bitmap header and bmp dimensions the file size should be bigger...
	if (data_size < head_size+stride*height)
		return 0;

	src = data + head_size;
	if (!top_down)
	{
		src += (height-1) * stride;
		stride = -stride;
	}
	bytes_per_pixel = bpp / 8;
	src += crop_x0 * bytes_per_pixel + crop_y0 * stride;

	width2 = crop_x1 - crop_x0;
	height2 = crop_y1 - crop_y0;
	stride2 = ((bpp * width2 + 31) / 8) & ~3;

	*out_size = head_size + stride2*height2;
	*out_data = (char*)malloc(*out_size);
	if (!*out_data)
		return 0;
	memcpy(*out_data, data, head_size);
	header2 = (BITMAPFILEHEADER*)*out_data;
	bmih2 = (BITMAPINFOHEADER*)(header2+1);
	SET_INT32_LE(bmih2->biWidth, width2);
	SET_INT32_LE(bmih2->biHeight, top_down ? -height2 : height2);
	SET_INT32_LE(bmih2->biSizeImage, 0);

	dest = *out_data + head_size;
	if (!top_down)
	{
		dest += (height2-1) * stride2;
		stride2 = -stride2;
	}

	bytes_to_copy_per_row = width2 * bytes_per_pixel;
	padding_bytes = stride2 - bytes_to_copy_per_row;

	for (y=0; y<height2; y++)
	{
		memcpy(dest, src, bytes_to_copy_per_row);
		if (padding_bytes > 0)
			memset(dest+bytes_to_copy_per_row, 0, padding_bytes);
		src += stride;
		dest += stride2;
	}

	return 1;
}

// returns zero on error
int CropBmpFile(const char* input_file, const char* output_file, int crop_x0, int crop_y0, int crop_x1, int crop_y1)
{
	FILE* f;
	long filesize;
	char* data;
	size_t bytes_read, bytes_written;
	char* new_data;
	int new_size;
	int success;

	f = fopen(input_file, "rb");
	if (!f)
		return 0;
	fseek(f, 0, SEEK_END);
	filesize = ftell(f);
	if (filesize <= sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER))
	{
		fclose(f);
		return 0;
	}

	data = (char*)malloc(filesize);
	if (!data)
	{
		fclose(f);
		return 0;
	}

	rewind(f);
	bytes_read = fread(data, 1, (size_t)filesize, f);
	fclose(f);
	if (bytes_read != (size_t)filesize)
	{
		free(data);
		return 0;
	}

	new_data = NULL;
	new_size = 0;
	success = CropBmpData(data, filesize, crop_x0, crop_y0, crop_x1, crop_y1, &new_data, &new_size);
	free(data);
	if (success)
	{
		f = fopen(output_file, "wb");
		if (f)
		{
			bytes_written = fwrite(new_data, 1, (size_t)new_size, f);
			fclose(f);
			success = bytes_written == (size_t)new_size;
		}
		else
		{
			success = 0;
		}
	}

	if (new_data)
		free(new_data);
	return success;
}


int main(int argc, char* argv[])
{
	printf("result: %d\n", CropBmpFile("e:\\w-mode-1_03.bmp", "e:\\w-mode-1_03_cropped.bmp", 5, 10, 50, 20));
	printf("result: %d\n", CropBmpFile("e:\\w-mode-1_03_8.bmp", "e:\\w-mode-1_03_8_cropped.bmp", 5, 10, 50, 20));
	printf("result: %d\n", CropBmpFile("e:\\w-mode-1_03_16.bmp", "e:\\w-mode-1_03_16_cropped.bmp", 5, 10, 50, 20));
	return 0;
}


这篇关于如何在Linux C中剪切图片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆