我知道C语言的能力很强,但是对于图形图像类的C语言实现很是好奇,觉得很难。我读书的时候,用C语言画过BMP格式的图像,因为没有任何的压缩,所以图像的数据量比较大,基本上就是RGB 字节流。今天看了Banu blog中的博文 Drawing circles,想起了以前用C语言进行BMP图像的处理。 写这篇博客,是给自己枯燥的学习带来一些乐趣,C语言也可以干些比较有有趣的事情。代码基本上是照搬Banu,只是,文章画的图像是灰度图像,不够靓丽,我将代码改成了生成彩色图像。不管怎么说,光荣属于Banu,我只是仰望前辈的学习者。
生成一个文件,后缀为ppm,Linux下的GIMP自然可以解析这种格式。ppm格式和BMP很像,基本属于傻瓜型图像格式,每个像素就是RGB三个字节表示,当然为了声明文件类型,会有文件头。看下WIKI中的介绍。
Magic Number | Type | Encoding |
---|
P1 | Portable bitmap | ASCII |
P2 | Portable graymap | ASCII |
P3 | Portable pixmap | ASCII |
P4 | Portable bitmap | Binary |
P5 | Portable graymap | Binary |
P6 | Portable pixmap | Binary
|
P3 # The P3 means colors are in ASCII, then 3 columns and 2 rows,
# then 255 for max color, then RGB triplets
3 2
255
255 0 0 0 255 0 0 0 255
255 255 0 255 255 255 0 0 0
我们看到了上面虚框中的文件内容,画出来就是下面这个彩色图像。当然,下面的图用一个比较大的正方形来表示一个像素点(255,0,0)表示红色,所以代表第一个像素点的正方形是红色的,依次类推。
OK,下面看下代码:
- static void
-
image_save (const Image *image,
-
const char *filename)
-
{
-
FILE *out;
-
-
out = fopen (filename, "wb");
-
if (!out)
-
return;
-
-
fprintf (out, "P6\n");
-
fprintf (out, "%zu %zu\n", image->width, image->height);
-
fprintf (out, "255\n");
-
-
fwrite (image->data, 1, image->width * image->height*3, out);
-
-
fclose (out);
-
}
P6告诉文件解析程序(如GIMP)我是PPM格式的文件(Portable pixmap)。
第二行告诉文件的长和高。
下面是完整的代码,再次强调,荣耀和版权都属于Banu,我只是仰望Banu的学习者。
- #include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <math.h>
-
-
typedef struct {
-
size_t width;
-
size_t height;
-
unsigned char *data;
-
} Image;
-
-
static Image *
-
image_new (size_t width,
-
size_t height)
-
{
-
Image *image;
-
-
image = malloc (sizeof *image);
-
image->width = width;
-
image->height = height;
-
image->data = malloc (width * height*3);
-
-
return image;
-
}
-
-
static void
-
image_free (Image *image)
-
{
-
free (image->data);
-
free (image);
-
}
-
-
static void
-
image_fill (Image *image,
-
unsigned char value)
-
{
-
memset (image->data, value, image->width * image->height*3);
-
}
-
-
/**
-
* image_set_pixel:
-
*
-
* Sets a pixel passed in signed (x, y) coordinates, where (0,0) is at
-
* the center of the image.
-
**/
-
static void
-
image_set_pixel (Image *image,
-
ssize_t x,
-
ssize_t y,
-
unsigned char Rvalue,
- unsigned char Gvalue,
- unsigned char Bvalue)
-
{
-
size_t tx, ty;
-
unsigned char *p;
-
-
tx = (image->width / 2) + x;
-
ty = (image->height / 2) + y;
-
-
p = image->data + (ty * image->width*3) + tx*3;
-
-
*p = Rvalue;
-
*(p+1) = Gvalue;
-
*(p+2) = Bvalue;
-
}
-
-
static void
-
image_save (const Image *image,
-
const char *filename)
-
{
-
FILE *out;
-
-
out = fopen (filename, "wb");
-
if (!out)
-
return;
-
-
fprintf (out, "P6\n");
-
fprintf (out, "%zu %zu\n", image->width, image->height);
-
fprintf (out, "255\n");
-
-
fwrite (image->data, 1, image->width * image->height*3, out);
-
-
fclose (out);
-
}
-
-
static void
-
draw_circle (Image *image,
-
int radius,
-
unsigned char Rvalue,
-
unsigned char Gvalue,
-
unsigned char Bvalue)
-
{
-
int x, y;
-
-
for (y = -radius; y <= radius; y++)
-
for (x = -radius; x <= radius; x++)
-
if ((x * x) + (y * y) <= (radius * radius))
-
image_set_pixel (image, x, y, Rvalue,Gvalue,Bvalue);
-
}
-
-
int
-
main (int argc, char *argv[])
-
{
-
Image *image;
-
-
image = image_new (600, 600);
-
-
image_fill (image, 0xff);
-
draw_circle (image, 200, 0x00,0x00,0xff);
-
image_save (image, "circle.ppm");
-
-
image_free (image);
-
-
return 0;
-
}
就可以在本地查看一个蓝色的圆图像。下图格式是jpg格式的,我用QQ截图工具生成的。
由于CU不支持ppm格式的图像,所以只能传jpg了。
参考文献:
1 Banu 博文 Drawing Circles
2 Wiki
阅读(23706) | 评论(4) | 转发(5) |