Javier Luis Lopez Ответов: 1

Чтение и запись файлов PPM


Я сделал следующий код для быстрого чтения и записи ppm с помощью смарт-кода.
К сожалению, мне приходится использовать функцию leelin (), чтобы посмотреть, будет ли прочитан текст, начинающийся с#, Прежде чем читать xmax и ymax.
Можно ли искать " # " (следующий с текстом) в указателе файла перед чтением?

Вот заголовок файла PPM:
P6
# CREATOR: GIMP PNM Filter Version 1.1
1280 720
255
(binary data)


Что я уже пробовал:

#include <iostream>
#pragma warning(disable:4996) //disable deprecateds
using namespace std;
typedef unsigned char uchar;

//Lee de ficheros:
void leelin(FILE *strin, char *linea);

bool read_image_ppm(char *filename, uchar  *&data, int &xmax1,int &ymax1);
bool save_image_ppm(char *filename, uchar  *data,int xmax,int ymax);

void main()
{
	uchar *data=NULL;
	int xmax,ymax;
	read_image_ppm("2944_1.ppm",data,xmax,ymax);
	save_image_ppm("out.ppm",data,xmax,ymax);
	delete data;
	cout<<"===END==="<<endl;getchar();
}


bool read_image_ppm(char *filename, uchar  *&data, int &xmax1,int &ymax1)
{
	xmax1=ymax1=0;
	FILE *str = fopen(filename, "rb");
	if (str == NULL) 	{ 		printf("Couldn't open %s for reading!\n", filename);getchar(); 		return false; 	}
	char linea[1024];
	leelin(str,linea);if(linea[0]!='P'||linea[1]!='6')  { 		printf("%s PPM file not type P6, so couldn't read! \n", filename);getchar();		return false; 	}
	leelin(str,linea);if(linea[0]=='#') leelin(str,linea);
	char *ptr=linea;xmax1=strtol(ptr,&ptr,10);ymax1=strtol(ptr+1,&ptr,10);leelin(str,linea);
	if (xmax1<1||xmax1>90000||ymax1<1||ymax1>90000) { 		printf("%s PPM file xmax or ymax is wrong= %i %i, so couldn't read! \n", filename,xmax1,ymax1);getchar();		return false; 	}
	data=new uchar[xmax1*ymax1*3];
	for (int j = 0; j < ymax1; j++) 
		fread(&data[3*j*xmax1], 1, 3*xmax1, str);
	fclose(str);
	return true;
}



bool save_image_ppm(char *filename, uchar  *data,int xmax1,int ymax1)
{
	FILE *output = fopen(filename, "wb");
	if (output == NULL)
	{
		printf("Couldn't open %s for writing!\n", filename);
		return false;
	}
	fprintf(output, "P6\n%d %d\n%d\n", xmax1, ymax1, 255);
	for (int j = 0; j < ymax1; j++) 
		fwrite(&data[3*j*xmax1], 1, 3*xmax1, output);
	fclose(output);
	return true;
}


void leelin(FILE *strin,char *linea)
{
	//removes 0x0D and 0x0A
	int i;
	linea[0]='\0';
	char *ptr=linea;
	for (i=0;(i<1024 && !feof(strin)); i++)
	{
		*ptr++ = fgetc(strin);
		//fscanf(strin, "%c", ptr++);  //OLD!!
		if (ptr[-1] == 10)
			break;
	}
	if (i>=1)
		ptr[-1]='\0';
	else
		linea[0]='\0';
	if (i>2 && ptr[-2]==0x0D)
		ptr[-2]='\0';
}

1 Ответов

Рейтинг:
8

Jochen Arndt

Ваш leelin() функция уже считывает строку из файла в буфер. Таким образом, не должно быть никакой необходимости в дополнительной проверке комментариев перед чтением. Просто проигнорируйте эту строку (что вы уже делаете в своем коде, читая следующую строку).

Чтобы пропустить строки комментариев, Вы можете использовать что-то вроде

do
    leelin(str,linea);
while (linea[0] == '#');

Однако вы также можете прочитать вперед, сохранив указатель файла перед чтением и восстановив его после чтения (см. ссылка на ftell - C++ [^], ссылка на fseek - C++ [^] или fgetpos, fsetpos).

Чтобы прочитать только один символ вперед, вы также можете использовать ссылка ungetc - C++ [^]:
int readAhead = fgetc(str);
// Next read from stream will contain readAhead as first character
ungetc(readAhead, str);
if (readAhead == '#')
{
    // do something
}