📄 ppm_util.cpp
字号:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include "ppm_util.hpp"
/*+----------------------------------------------------------------------------
consume_PPM_comment
Consume the bytes from the FILE* until a '\r' a '\n'
is read.
No return value. It just returns when a '\r', '\n'
or EOF is read.
*/
void consume_PPM_comment (FILE* file)
{
assert(file != NULL);
char data;
size_t num_objects_read;
bool done = false;
while (!done)
{
num_objects_read = fread(&data, 1, 1, file);
if ((num_objects_read < 1) ||
data == '\r' ||
data == '\n')
{
done = true; // Not needed, this is for debugging.
break;
}
}
}
/*+----------------------------------------------------------------------------
read_PPM_integer
*/
int read_PPM_integer (FILE* file)
{
assert(file != NULL);
size_t num_objects_read = 0;
char data;
bool done = false;
int state = 0;
//
// state = 0 is the number is not yet started
// state = 1 is that we're currently reading the
// number.
// state = 2 is the number is over.
//
// large enum to hold the decimal representation
// of an unsigned 32 bit integer.
//
const int num_digits = 11;
char num_buffer[num_digits + 1];
int num_pos = 0;
memset(num_buffer, 0, num_digits + 1);
while (!done)
{
num_objects_read = fread(&data, 1, 1, file);
if (isdigit(data))
{
if (num_pos <= num_digits)
{
num_buffer[num_pos++] = data;
state = 1;
}
}
else if (isspace(data))
{
if (state != 0)
{
done = true;
state = 2;
}
// If the state is 0, then just keep
//going
}
else if (data == '#')
{
consume_PPM_comment(file);
}
else
{
// Put the character back , and we're done.
fputc(data, file);
done = true;
state = 2;
}
}
return atoi(num_buffer);
}
/*+----------------------------------------------------------------------------
read_PPM_image_data
*/
bool read_PPM_image_data (FILE* file,
unsigned char** ppData,
unsigned int width,
unsigned int height,
unsigned int colorDepth
)
{
assert(file != NULL);
assert(ppData != NULL);
bool success = false;
//int current_pos = 0;
char data; // data for red, green or blue channel
size_t num_read = 0;
// FIXME - Take color depth into account
int max_size = 3 * width * height;
*ppData = new unsigned char[max_size];
unsigned char* image_data = *ppData;
int pos = -1;
for (pos = 0; pos < max_size; pos++)
{
num_read = fread(&data, 1, 1, file);
if (num_read < 1)
{
break;
}
image_data[pos] = data;
}
if (pos == max_size) // read the number of bytes expected.
success = true;
return success;
}
void flip_PPM_image (unsigned char* pData,
unsigned int width,
unsigned int height,
unsigned int colorDepth)
{
unsigned char* pScanLine = new unsigned char [3 * width];
int last_scanline = (height / 2) - 1;
int src_offset = 0;
int dst_offset = 0;
// FIXME - Use color depth
int bytes_per_row = 3 * width;
for (int i = 0; i <= last_scanline; i++)
{
src_offset = bytes_per_row * i;
dst_offset = bytes_per_row * (height - i - 1);
memcpy(pScanLine, &(pData[src_offset]), bytes_per_row);
memcpy(&(pData[src_offset]), &(pData[dst_offset]), bytes_per_row);
memcpy(&(pData[dst_offset]), pScanLine, bytes_per_row);
}
if (pScanLine)
{
delete [] pScanLine;
}
}
/*+----------------------------------------------------------------------------
read_PPM_File
Read a PPM (Portable Pixmap) file.
Place the dimensions of the file in the global variables
g_image_width and g_image_height. Place the image data itself
in g_image_data;
Returns true if the PPM file was read successfully, and false
otherwise.
0 is looking for the magic number
1 is looking for the width
2 is looking for the height
3 is looking for the color depth
4 is looking for the image data
*/
bool read_PPM_file (FILE* file,
unsigned char** ppData,
unsigned int* width,
unsigned int* height,
unsigned int* colorDepth
)
{
assert(ppData != NULL);
bool done = false;
bool success = false;
int state = 0;
char data;
size_t result;
// States.
// Does comment count as a state?
//
while (!done)
{
// If there is an error, just break w/o setting
// the success flag.
switch(state)
{
case 0: // looking for header
result = fread(&data, 1, 1, file);
if (data != 'P')
{
// bail out, maybe I need an exception or a
// (gasp) goto.
break;
}
result = fread(&data, 1, 1, file);
if ((data == '6') && (result == 1))
{
state = 1;
}
break;
case 1:
*width = read_PPM_integer(file);
state = 2;
break;
case 2:
*height = read_PPM_integer(file);
state = 3;
break;
case 3:
*colorDepth = read_PPM_integer(file);
state = 4;
break;
case 4:
success = read_PPM_image_data(file, ppData, *width, *height, *colorDepth);
state = 5;
done = true;
break;
}
}
// The PPM image is top down, OpenGL likes
// pixel data to be bottom up. Maybe I'll figure out
// how to use glPixelZoom and glRasterPos2i
flip_PPM_image(*ppData, *width, *height, *colorDepth);
// Check to see
if (!success)
{
// spit out an error message.
}
return true;
}
/*+-----------------------------------------------------------------------------
save_PPM_file
*/
bool save_PPM_file (FILE* file,
unsigned char* pData,
unsigned int width,
unsigned int height,
unsigned int maxChannelValue
)
{
if (file == NULL)
return false;
if (pData == NULL)
return false;
flip_PPM_image(pData, width, height, maxChannelValue);
fprintf(file, "P6\n");
fprintf(file, "%d %d\n", width, height);
assert (maxChannelValue == 255);
fprintf(file, "%d\n", maxChannelValue); // should be 255
size_t data_size = 3 * width * height;
unsigned char* ptr = pData;
for (unsigned int i = 0; i < data_size; i++, ptr++)
{
fputc(*ptr, file);
}
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -