/* See frgb_image.h */ /* Last edited on 2006-03-25 23:38:35 by stolfi */ #include "frgb_image.h" #include #include #include #include #include #include #include #include #include /* Color images */ frgb_image_t frgb_image_new (nat_t NX, nat_t NY) { frgb_image_t im; int y; im.NX = NX; im.NY = NY; im.pix = (frgb_t **) malloc(NY * sizeof(frgb_t *)); for (y = 0; y < NY; y++) { im.pix[y] = (frgb_t *) malloc(NX * sizeof(frgb_t)); affirm(im.pix[y] != NULL, "frgb_image_new: out of memory"); } return(im); } frgb_image_t frgb_image_read_ppm (FILE *f, float gamma) { nat_t NX, NY, maxval, y; bool_t raw; frgb_image_t im; frgb_image_read_ppm_header(f, &NX, &NY, &maxval, &raw); im = frgb_image_new(NX, NY); for (y = 0; y < NY; y++) { if (raw) frgb_image_read_ppm_raw_pixels(f, maxval, gamma, im.NX, im.pix[y]); else frgb_image_read_ppm_ascii_pixels(f, maxval, gamma, im.NX, im.pix[y]); } fclose(f); return(im); } void frgb_image_normalize (frgb_image_t im) { float max_RGB, min_RGB, a, b; int x, y; max_RGB = -MAXFLOAT; min_RGB = MAXFLOAT; for (y = 0; y < im.NY; y++) for (x = 0; x < im.NX; x++) { frgb_t *pix = &(im.pix[y][x]); if (pix->c[0] > max_RGB) max_RGB = pix->c[0]; if (pix->c[1] > max_RGB) max_RGB = pix->c[1]; if (pix->c[2] > max_RGB) max_RGB = pix->c[2]; if (pix->c[0] < min_RGB) min_RGB = pix->c[0]; if (pix->c[1] < min_RGB) min_RGB = pix->c[1]; if (pix->c[2] < min_RGB) min_RGB = pix->c[2]; } a = (1.0/(max_RGB - min_RGB)); b = - a * min_RGB; for (y = 0; y < im.NY; y++) for (x = 0; x < im.NX; x++) { frgb_t *pix = &(im.pix[y][x]); pix->c[0] = a * pix->c[0] + b; pix->c[1] = a * pix->c[1] + b; pix->c[2] = a * pix->c[2] + b; } } void frgb_image_write_ppm (FILE *f, float gamma, frgb_image_t im) { int y; frgb_image_write_ppm_header(f, im.NX, im.NY, 255, TRUE); for (y = 0; y < im.NY; y++) { frgb_image_write_ppm_raw_pixels(f, 255, gamma, im.NX, im.pix[y]); } } void frgb_image_read_ppm_header (FILE *f, nat_t *NX, nat_t *NY, nat_t *maxval, bool_t *raw) { char magicnumber[3]; fgets(magicnumber, 3, f); magicnumber[2] = '\000'; if (strcmp(magicnumber, "P6") == 0) *raw = TRUE; else if (strcmp(magicnumber, "P3") == 0) *raw = FALSE; else fatalerror("unrecognized format"); fscanf(f, " %d %d %d", NX, NY, maxval); if (*raw) affirm(getc(f) == '\n', "bad format" ); } void frgb_image_read_ppm_raw_pixels (FILE *f, nat_t maxval, float gamma, nat_t NX, frgb_t pix[]) { nat_t x, R, G, B; for (x = 0; x < NX; x++) { if (maxval < 256) { R = getc(f); G = getc(f); B = getc(f); } else { R = (getc(f)<< 8) + getc(f); G = (getc(f)<< 8) + getc(f); B = (getc(f)<< 8) + getc(f); } pix[x].c[0] = frgb_image_undo_gamma(R, maxval, gamma); pix[x].c[1] = frgb_image_undo_gamma(G, maxval, gamma); pix[x].c[2] = frgb_image_undo_gamma(B, maxval, gamma); } } void frgb_image_read_ppm_ascii_pixels (FILE *f, nat_t maxval, float gamma, nat_t NX, frgb_t pix[]) { nat_t x; int R, G, B; for (x = 0; x < NX; x++) { fscanf(f, "%d %d %d", &R, &G, &B); pix[x].c[0] = frgb_image_undo_gamma(R, maxval, gamma); pix[x].c[1] = frgb_image_undo_gamma(G, maxval, gamma); pix[x].c[2] = frgb_image_undo_gamma(B, maxval, gamma); } } void frgb_image_write_ppm_header (FILE *f, nat_t NX, nat_t NY, nat_t maxval, bool_t raw) { if (raw) fprintf(f, "P6\n"); else fprintf(f, "P3\n"); fprintf(f, "%d %d\n%d\n", NX, NY, maxval); fflush(f); } void frgb_image_write_ppm_raw_pixels (FILE *f, nat_t maxval, float gamma, nat_t NX, frgb_t pix[]) { int x; unsigned char R, G, B; for (x = 0; x < NX; x++) { R = frgb_image_apply_gamma(pix[x].c[0], maxval, gamma); G = frgb_image_apply_gamma(pix[x].c[1], maxval, gamma); B = frgb_image_apply_gamma(pix[x].c[2], maxval, gamma); if (maxval < 256) { fputc(R & 255, f); fputc(G & 255, f); fputc(B & 255, f); } else { fputc((R & 65535) >> 8, f); fputc(R & 255, f); fputc((G & 65535) >> 8, f); fputc(G & 255, f); fputc((B & 65535) >> 8, f); fputc(B & 255, f); } } fflush(f); } void frgb_image_write_ppm_ascii_pixels (FILE *f, nat_t maxval, float gamma, nat_t NX, frgb_t pix[]) { int x; nat_t R, G, B; for (x = 0; x < NX; x++) { if (x>0) fputc(' ', f); R = frgb_image_apply_gamma(pix[x].c[0], maxval, gamma); G = frgb_image_apply_gamma(pix[x].c[1], maxval, gamma); B = frgb_image_apply_gamma(pix[x].c[2], maxval, gamma); fprintf(f, "%d %d %d", R, G, B); } fputc('\n', f); fflush(f); } int frgb_image_apply_gamma (float intensity, nat_t maxval, float gamma) { double y; /* Clip to 0-1 range */ y = (double)intensity; if (y > 1.0) y = 1.0; if (y < 0.0) y = 0.0; /* Do gamma correction */ if ((y > 0.0) && (y < 1.0)) y = pow(y, 1.0/(double)gamma); /* Convert to integer, range [0..maxval]: */ return((int)(y*(double)maxval + 0.5)); } float frgb_image_undo_gamma (int pixel, nat_t maxval, float gamma) { double y; if ((pixel < 0) || (pixel > maxval)) { fatalerror("frgb_image_undo_gamma: invalid pixel value"); } /* Convert to [0..1] double: */ y = (double)pixel / (double)maxval; /* Undo gamma correction */ if ((y > 0.0) && (y < 1.0)) y = pow(y, gamma); return((float)y); }