This is ppmread.c in view mode; [Download] [Up]
#include <stdio.h>
#include <stdlib.h>
#include <libc.h>
#include "ppm.h"
#include "strfunc.h"
/* PPM Format
Px : Header
Width Height
MAX : pbm does not have this field
Bitmap : in ASCII / Binary
*/
#define PXOF 0xff
#define PAOF 0xfe
#define UnknownHD 0
/* PX original Format
PX : Header
Width Height Colors : Colors := Number of colors in palette - 1
Count : if Trans is there Count=1, otherwise Count=0.
Trans : Transparent + 256
[Palette] : Binary
[Bitmap] : Binary
*/
/* PA original Format
PA : Header
Width Height MAX
Planes : Planes = 1,2,3 or 4. (planes 2 and 4 have ALPHA)
[Bitmap] : Binary
*/
static int ppmkind = 0, ppmmax = 0;
static int pxtrans = 0;
static char ppmcomm[MAX_COMMENT];
static void ppm_skip(FILE *fp)
{
int c;
while ((c = getc(fp)) != EOF) {
if (c == '\n') {
c = getc(fp);
while (c == '#') {
while ((c = getc(fp)) != '\n')
if (c == EOF)
return;
c = getc(fp);
}
}
if (c > ' ') {
ungetc(c, fp);
return;
}
}
}
static int ppm_head(FILE *fp)
{
int c, i, kind = UnknownHD;
if ((c = getc(fp)) != 'P')
return UnknownHD;
c = getc(fp);
if (c >= '0' && c <= '9')
kind = c - '0';
else if (c == 'X')
kind = PXOF;
else if (c == 'A')
kind = PAOF;
ppmcomm[0] = 0;
while ((c = getc(fp)) <= ' ') ;
if (c == '#') {
for (i = 0; (c = getc(fp)) != '\n'; i++)
if (i < MAX_COMMENT-1)
ppmcomm[i] = c;
else {
while (getc(fp) != '\n') ;
break;
}
ppmcomm[i] = 0;
ungetc('\n', fp);
ppm_skip(fp);
}else
ungetc(c, fp);
return kind;
}
static int ppm_getint(FILE *fp)
{
int c;
int v = 0;
c = getc(fp);
while (c < '0' || c > '9') {
if (c == EOF) return -1;
c = getc(fp);
}
while (c >= '0' && c <= '9') {
v = (v * 10) + c - '0';
c = getc(fp);
}
if (c != EOF && c < ' ')
ungetc(c, fp);
return v;
}
commonInfo *loadPpmHeader(FILE *fp, int *errcode)
{
int w, err;
commonInfo *cinf;
*errcode = err = 0;
ppmkind = ppm_head(fp);
if (ppmkind == UnknownHD) {
*errcode = Err_FORMAT;
return NULL;
}
if ((w = ppm_getint(fp)) >= MAXWidth) {
*errcode = Err_IMPLEMENT;
return NULL;
}
if ((cinf = (commonInfo *)malloc(sizeof(commonInfo))) == NULL) {
*errcode = Err_MEMORY;
return NULL;
}
cinf->width = w;
cinf->alpha = NO;
cinf->type = Type_ppm;
cinf->isplanar = YES;
cinf->palsteps = 0;
cinf->palette = NULL;
cinf->memo[0] = 0;
ppm_skip(fp);
cinf->height = ppm_getint(fp);
if (ppmkind == PBMa || ppmkind == PBMb) {
ppmmax = 2;
cinf->numcolors = 1;
cinf->cspace = NX_OneIsBlackColorSpace;
cinf->bits = 1;
cinf->xbytes = byte_length(1, cinf->width);
(void)getc(fp); /* feed last CR */
return cinf;
}
ppm_skip(fp);
ppmmax = ppm_getint(fp) + 1;
if (ppmkind == PAOF) {
int pn;
ppm_skip(fp);
pn = ppm_getint(fp);
if (pn < 1 || pn > 4) { /* PAOF must have alpha */
*errcode = Err_FORMAT;
return NULL;
}
if (pn >= 3) {
cinf->numcolors = 3;
cinf->cspace = NX_RGBColorSpace;
}else {
cinf->numcolors = 1;
cinf->cspace = NX_OneIsWhiteColorSpace;
}
(void)getc(fp); /* feed last CR */
cinf->alpha = (pn == 2 || pn == 4);
}else if (ppmkind == PXOF) {
int cnt;
pxtrans = -1;
ppm_skip(fp);
cnt = ppm_getint(fp);
if (cnt-- > 0) {
ppm_skip(fp);
pxtrans = ppm_getint(fp);
}
while (cnt-- > 0) { /* skip unknown parameters */
ppm_skip(fp);
(void) ppm_getint(fp);
}
(void)getc(fp); /* feed last CR */
if (pxtrans >= 256) {
cinf->alpha = YES;
pxtrans -= 256;
}else
pxtrans = -1;
cinf->numcolors = 3;
cinf->cspace = NX_RGBColorSpace;
cinf->bits = 8;
cinf->xbytes = cinf->width;
return cinf;
}else {
(void)getc(fp); /* feed last CR */
if (ppmkind == PPMa || ppmkind == PPMb) {
cinf->numcolors = 3;
cinf->cspace = NX_RGBColorSpace;
}else {
cinf->numcolors = 1;
cinf->cspace = NX_OneIsWhiteColorSpace;
}
}
cinf->bits = (ppmmax > 16) ? 8
: ((ppmmax > 4) ? 4 : ((ppmmax > 2) ? 2 : 1));
cinf->xbytes = byte_length(cinf->bits, cinf->width);
return cinf;
}
static int isGrayPPM(unsigned char **planes, int length)
{
int i;
unsigned char *rr, *gg, *bb;
rr = planes[0];
gg = planes[1];
bb = planes[2];
for (i = 0; i < length; i++) {
if (rr[i] != gg[i] || gg[i] != bb[i]) return 0;
}
return 1;
}
static int bitsOfPPM(unsigned char **planes, commonInfo *cinf)
{
unsigned char *p, buf[256];
int i, pn, pnmx, w, num;
w = cinf->width * cinf->height;
for (i = 0; i < 256; i++) buf[i] = 0;
num = 0;
pnmx = cinf->numcolors;
if (cinf->alpha) pnmx++;
for (pn = 0; pn < pnmx; pn++) {
p = planes[pn];
for (i = 0; i < w; i++)
if (buf[p[i]] == 0) {
buf[p[i]] = 1;
if (++num > 16) return 8;
}
}
return optimalBits(buf, num);
}
static int getPXOF(FILE *fp, commonInfo *cinf,
unsigned char **planes, int *aflag)
{
int i, x, y;
unsigned char *p, *rr, *gg, *bb;
cinf->palette = (paltype *)malloc(sizeof(paltype) * ppmmax);
if (cinf->palette == NULL)
return Err_MEMORY;
cinf->palsteps = ppmmax;
for (i = 0; i < ppmmax; i++) {
p = cinf->palette[i];
for (x = 0; x < 3; x++)
p[x] = getc(fp);
}
rr = planes[0];
gg = planes[1];
bb = planes[2];
if (! cinf->alpha) {
for (y = 0; y < cinf->height; y++) {
for (x = 0; x < cinf->width; x++) {
p = cinf->palette[getc(fp)];
*rr++ = p[RED];
*gg++ = p[GREEN];
*bb++ = p[BLUE];
}
}
}else {
unsigned char *aa = planes[3];
int cc;
for (y = 0; y < cinf->height; y++) {
for (x = 0; x < cinf->width; x++) {
if ((cc = getc(fp)) == pxtrans) {
*rr++ = *gg++ = *bb++ = 255;
*aa++ = AlphaTransp;
*aflag = YES;
}else {
p = cinf->palette[cc];
*rr++ = p[RED];
*gg++ = p[GREEN];
*bb++ = p[BLUE];
*aa++ = AlphaOpaque;
}
}
}
if (pxtrans != ppmmax - 1) {
unsigned char *q;
p = cinf->palette[ppmmax-1];
q = cinf->palette[pxtrans];
for (i = 0; i < 3; i++)
q[i] = p[i];
cinf->palsteps = pxtrans = ppmmax - 1;
p = cinf->palette[pxtrans];
for (i = 0; i < 3; i++)
p[i] = 255;
}
}
return 0;
}
static int PPMplanes(FILE *fp,
commonInfo *cinf, int pn, unsigned char **planes, int *hasalpha)
{
int i, r, x, y;
unsigned char work[MAXPLANE][MAXWidth];
unsigned char *pp;
int width = cinf->width;
int rdmax = ppmmax - 1;
int aflag = NO;
for (y = 0; y < cinf->height; y++) {
if (feof(fp))
return Err_SHORT;
if (isPPMascii(ppmkind)) {
for (x = 0; x < width; x++)
for (i = 0; i < pn; i++) {
ppm_skip(fp);
work[i][x] = ((r = ppm_getint(fp)) >= rdmax)
? 255 : ((r << 8) / ppmmax);
}
}else if (ppmkind == PBMb) {
int mask, cc;
for (x = 0; x < width; ) {
cc = getc(fp);
for (mask = 0x80; mask; mask >>= 1) {
work[0][x] = (cc & mask) ? 0xff : 0;
if (++x >= width) break;
}
}
}else {
for (x = 0; x < width; x++) {
for (i = 0; i < pn; i++)
work[i][x] = ((r = getc(fp)) >= rdmax)
? 255 : ((r << 8) / ppmmax);
}
}
for (i = 0; i < pn; i++) {
pp = planes[i] + y * cinf->xbytes;
packImage(pp, work[i], width, cinf->bits);
}
if (cinf->alpha && aflag == NO) {
pp = work[pn - 1];
for (i = 0; i < width; i++) {
if (*pp++ != AlphaOpaque) {
aflag = YES;
break;
}
}
}
}
*hasalpha = aflag;
return 0;
}
int ppmGetImage(FILE *fp,
commonInfo *cinf, unsigned char **planes, const char *fkind)
{
int i, y, pn, bits, err;
int width, xbyte;
const char *kp;
int aflag = NO;
width = cinf->width;
pn = cinf->numcolors;
if (cinf->alpha) pn++;
err = allocImage(planes, width, cinf->height, cinf->bits, pn);
if (err) return err;
if (ppmkind == PXOF)
err = getPXOF(fp, cinf, planes, &aflag);
else
err = PPMplanes(fp, cinf, pn, planes, &aflag);
if (err) return err;
/* ALPHA image ? */
if (cinf->alpha && aflag == NO) {
cinf->alpha = NO;
--pn;
}
/* Is this image Gray ? */
if (pn == 3 && isGrayPPM(planes, cinf->xbytes * cinf->height)) {
size_t newsize = planes[1] - planes[0];
planes[0] = (unsigned char *)realloc(planes[0], newsize);
planes[1] = planes[2] = NULL;
pn = cinf->numcolors = 1;
cinf->cspace = NX_OneIsWhiteColorSpace;
}
/* How many bits are needed ? */
if (cinf->bits == 8 && (bits = bitsOfPPM(planes, cinf)) < 8) {
unsigned char *src, *dst, *newmap[MAXPLANE];
err = allocImage(newmap, width, cinf->height, bits, pn);
if (err) return 0; /* Error */
xbyte = byte_length(bits, width);
for (i = 0; i < pn; i++) {
src = planes[i];
dst = newmap[i];
for (y = 0; y < cinf->height; y++) {
packImage(dst, src, width, bits);
src += width;
dst += xbyte;
}
}
free((void *)planes[0]);
for (i = 0; i < pn; i++)
planes[i] = newmap[i];
cinf->xbytes = xbyte;
cinf->bits = bits;
}
sprintf(cinf->memo, "%d x %d ", cinf->width, cinf->height);
if (fkind) kp = fkind;
else if (ppmkind == PXOF) kp = "PXOF";
else if (ppmkind == PAOF) kp = "PAOF";
else kp = PPMname(ppmkind);
strcat(cinf->memo, kp);
if ((bits = cinf->bits) == 1)
strcat(cinf->memo, " 1bit");
else {
i = strlen(cinf->memo);
sprintf(cinf->memo + i, " %dbits%s", bits,
(pn > 2 ? "" : " gray"));
}
if (pn == 2 || pn == 4)
strcat(cinf->memo, " Alpha");
if (ppmcomm[0]) {
const char *p = ppmcomm;
while (*p == ' ') p++;
if (*p != 0) {
strcat(cinf->memo, " ");
comm_cat(cinf->memo, p);
}
}
return 0;
}
#ifdef _TEST
main()
{
printf("kind=P%d\n", ppm_head(stdin));
while (!feof(stdin)) {
ppm_skip(stdin);
printf("%d\n", ppm_getint(stdin));
}
}
#endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.