http://blog.chinaunix.net/uid-24774106-id-3047520.html
我知道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 |
# 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