(edit by king)由于性能测试需要,需要准备大量不相同的图片(图片md5值不同),为了方便的创建这些图片,写了个小程序来完成这个工作。
这个程序最初的算法是生成一张指定长和宽的图片,然后一个个像素置成特定的颜色。因为最终要生成jpg文件,这样的做法,会导致生成的图片普遍比较小,最终确定为从参数中获得一个种子文件,然后对每个像素进行反色处理。
主要的计算方法如下:
jpgInFile = fopen(param_p->fileName, "rb"); if(jpgInFile == NULL) { perror("open seed file"); return NULL; } im = gdImageCreateFromJpeg(jpgInFile); fclose(jpgInFile); width = gdImageSX(im); height = gdImageSY(im); pch = strrchr(param_p->fileName, '.'); strncpy(fileBase, param_p->fileName, pch - param_p->fileName); for(n = param_p->start; n < param_p->end; ++n) { color = gdImageGetPixel(im, n % width, (n / width) % height); revertColor = gdImageColorAllocate(im, 0xFF - gdImageRed(im, color), 0xFF - gdImageGreen(im, color), 0xFF - gdImageBlue(im, color)); gdImageSetPixel(im, n % width, (n / width) % height, revertColor); sprintf(fileName, "%s%d.jpg", fileBase, n); jpgOutFile = fopen(fileName, "wb"); gdImageJpeg(im, jpgOutFile, 60); fclose(jpgOutFile); }
反色的方法很简单,分别用0xFF减去像素点的RGB分色就可以了。这里使用了gd库来操作图片,具体gd库的API,可以看http://www.libgd.org/Reference 。
还有个问题,就是“大量”。刚开始还在纠结于用多线程还是多进程,看了下发现多进程非常不便于任务分派,最后还是决定是用多线程来加快图片的创建。
先定义一个结构来保存传递给线程函数的参数:
typedef struct { char *fileName; int start; int end; }param;
分别代表种子图片文件名、开始像素点和结束像素点。
for(n = 0; n < threadCount; ++n) { paramArray[n].fileName = fileName; paramArray[n].start = createPerThread * n; paramArray[n].end = createPerThread * (n + 1); ret = pthread_create(&threads[n], &attr, &do_create_image, ¶mArray[n]); if(ret != 0) { perror("thread create"); exit(EXIT_FAILURE); } } for(n = 0; n < threadCount; ++n) { ret = pthread_join(threads[n], NULL); if(ret != 0) { perror("thread join"); exit(EXIT_FAILURE); } }
是用pthread_create和pthread_join进行线程的创建和等待结束,是用多线程的方式大大增加了图片创建的速度,采用O2优化程度编译的代码,可以在13分钟创建1万张图片。
最后,还是用了getopt函数来获得从命令行传入的参数。while((ret = getopt(argc, argv, "s:t:f:")) != -1)
while((ret = getopt(argc, argv, "s:t:f:")) != -1) { switch(ret) { case 's': totalCount = atoi(optarg); break; case 't': threadCount = atoi(optarg); break; case 'f': strncpy(fileName, optarg, 256); break; default: fprintf(stderr, "usage: %s [-s SUM] [-t THREAD_COUNT] [-f SEED_FILE]\n", argv[0]); exit(EXIT_FAILURE); } }
因为这个小程序使用了gd库、pthread库,因此在编译的时候,需要连接着两个库。
CC = gcc FLAGS = -O2 LIBS = -lpthread -lgd EXE = jpg all: $(EXE) jpg: jpg_creator.c $(CC) $(FLAGS) -o $@ $? $(LIBS) clean: rm $(EXE)