kehuadong

[十万个为什么] ppm图片转png图片

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"


struct ppm
{
	int type;
	
	int depth;
	
	// 像素字节数
	int step;
	
	int width;
	
	int height;
	
	uint8_t *buffer;
};

#define LINEMAX 128

// 读入ppm文件的一行 (例如第一行P6 type=6, 第二行1024 1024 width=1024 height=1024,第三行255代表depth=255)
// ---------------------------------------------------------------------------
static char *readline(FILE *f, char *buffer)
{
	for (;;)
	{
		char *ret = fgets(buffer, LINEMAX, f);
		if (ret == NULL)
		{
			return NULL;
		}
		if (ret[0] != '#')
		{
			return ret;
		}
	}
}

// ppm和pgm都是相同头格式
// ---------------------------------------------------------------------------
static int ppm_header(FILE *f, struct ppm *ppm)
{
	char tmp[LINEMAX];
	char *line = readline(f, tmp);
	if (line == NULL)
		return 0;
	
	char c = 0;
	sscanf(line, "P%c", &c);
	ppm->type = c;

	line = readline(f, tmp);
	if (line == NULL)
		return 0;
	sscanf(line, "%d %d", &(ppm->width), &(ppm->height));
	
	line = readline(f, tmp);
	if (line == NULL)
		return 0;
	sscanf(line, "%d", &(ppm->depth));
	
	return 1;
}

// id '3' ASCII RGB, '6' binary RGB,  '2' ASCII Alpha, '5' binary Alpha
// ---------------------------------------------------------------------------
static int ppm_data(struct ppm *ppm, FILE *f, int id, int skip)
{
	int i;
	
	int n = ppm->width * ppm->height;
	
	uint8_t *buffer = ppm->buffer + skip;
	
	uint8_t *tmp;
	
	int step = ppm->step;
	
	switch (id)
	{
		case '3': // RGB text
			for (i = 0; i < n; i++)
			{
				int r, g, b;
				fscanf(f, "%d %d %d", &r, &g, &b);
				buffer[i * step + 0] = (uint8_t)r;
				buffer[i * step + 1] = (uint8_t)g;
				buffer[i * step + 2] = (uint8_t)b;
			}
			break;

		case '2': // ALPHA text
			for (i = 0; i < n; i++)
			{
				int alpha;
				fscanf(f, "%d", &alpha);
				buffer[i * step] = (uint8_t)alpha;
			}
			break;

		case '6': // RGB binary
			tmp = (uint8_t *)malloc(n * 3);
			if (fread(tmp, n * 3, 1, f) == 0)
			{
				free(tmp);
				return 0;
			}
			for (i = 0; i < n; i++)
			{
				buffer[i * step + 0] = tmp[i * 3 + 0];
				buffer[i * step + 1] = tmp[i * 3 + 1];
				buffer[i * step + 2] = tmp[i * 3 + 2];
			}
			free(tmp);
			break;

		case '5': // ALPHA binary
			tmp = (uint8_t *)malloc(n);
			if (fread(tmp, n, 1, f) == 0)
			{
				free(tmp);
				return 0;
			}
			for (i = 0; i < n; i++)
			{
				buffer[i * step] = tmp[i];
			}
			free(tmp);
			break;

		default:
			return 0;
	}
	return 1;
}

// ---------------------------------------------------------------------------
static int loadppm_from_file(FILE *rgb, FILE *alpha, struct ppm *ppm)
{
	ppm->buffer = NULL;
	ppm->step = 0;
	int rgb_id = 0;
	int alpha_id = 0;

	if (rgb)
	{
		if (!ppm_header(rgb, ppm))
		{
			return 0;
		}
		rgb_id = ppm->type;
		ppm->step += 3;
	}
	
	if (alpha)
	{
		if (rgb == NULL)
		{
			if (!ppm_header(alpha, ppm))
			{
				return 0;
			}
			alpha_id = ppm->type;
		}
		else
		{
			struct ppm pgm;
			if (!ppm_header(alpha, &pgm))
			{
				return 0;
			}
			if (ppm->depth != pgm.depth || ppm->width != pgm.width || ppm->height != pgm.height)
			{
				return 0;
			}
			alpha_id = pgm.type;
		}
		ppm->step += 1;
	}

	ppm->buffer = (uint8_t *)malloc(ppm->height * ppm->width * ppm->step);

	if (rgb)
	{
		if (!ppm_data(ppm, rgb, rgb_id, 0))
			return 0;
	}

	if (alpha)
	{
		int skip = 0;
		if (rgb)
		{
			skip = 3;
		}

		if (!ppm_data(ppm, alpha, alpha_id, skip))
			return 0;
	}

	return 1;
}

int main(int argc, char* argv[])
{
	if (argc < 2)
	{
		printf("use ppn_to_png file_name\n");
		return -1;
	}
	
	const char *file_name = argv[1];
	int sz = strlen(file_name);
	
	char tmp[sz+5];
	
	sprintf(tmp, "%s.ppm", file_name);
	
	FILE *rgb = fopen(tmp, "rb");
	
	sprintf(tmp, "%s.pgm", file_name);
	
	FILE *alpha = fopen(tmp, "rb");

	if (rgb == NULL && alpha == NULL)
	{
		printf("Can't open %s(.ppm/.pgm)\n", file_name);
		return -1;
	}

	struct ppm ppm;

	int ok = loadppm_from_file(rgb, alpha, &ppm);

	if (rgb)
	{
		fclose(rgb);
	}
	
	if (alpha)
	{
		fclose(alpha);
	}
	
	sprintf(tmp, "%s.png", file_name);
	
	stbi_write_png(tmp, ppm.width, ppm.height, ppm.step, ppm.buffer, ppm.width*ppm.step);
	
	free(ppm.buffer);
	
	return 0;
}

用到的库 

stb/stb_image_write.h at master · nothings/stb · GitHub

 

posted on   kehuadong  阅读(13)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示