/* See jspnm_image.h */ /* Last edited on 2012-06-09 19:28:40 by stolfilocal */ #include #include #include #include #include #include #include #include pnm_image_t *pnm_image_new(int cols, int rows, int chns) { /* Allocate header: */ pnm_image_t *img = pnm_image_new_header(cols, rows, chns); /* Allocate pixels: */ if ((cols != 0) && (rows != 0)) { img->smp = pnm_image_alloc_pixel_array(cols, rows, chns); } return(img); } void pnm_image_free(pnm_image_t *img) { if (img == NULL) return; if (img->smp != NULL) { pnm_image_free_pixel_array(img->smp, img->cols, img->rows, img->chns); } free(img); } pnm_image_t *pnm_image_new_header(int cols, int rows, int chns) { /* Allocate header: */ pnm_image_t *img = (pnm_image_t *)pnm_malloc(sizeof(pnm_image_t)); assert(img != NULL); /* Initialize fields: */ img->cols = cols; img->rows = rows; img->chns = chns; /* Leave sample arrays as NULL: */ img->smp = (pnm_sample_t**)NULL; /* Initialize the {maxval} field as 0 (invalid): */ img->maxval = 0; return(img); } pnm_sample_t** pnm_image_alloc_pixel_array(int cols, int rows, int chns) { int row; pnm_sample_t **smp = (pnm_sample_t **)pnm_malloc(rows*sizeof(pnm_sample_t *)); for (row = 0; row < rows; row++) { smp[row] = pnm_image_alloc_pixel_row(cols, chns); } return smp; } void pnm_image_free_pixel_array(pnm_sample_t **smp, int cols, int rows, int chns) { int row; if (smp == NULL) { return; } for (row = 0; row < rows; row++) { pnm_image_free_pixel_row(smp[row], cols, chns); } free(smp); } pnm_sample_t* pnm_image_alloc_pixel_row(int cols, int chns) { if (cols == 0) { return (pnm_sample_t *)NULL; } else { return (pnm_sample_t *)pnm_malloc(cols*chns*sizeof(pnm_sample_t)); } } void pnm_image_free_pixel_row(pnm_sample_t *row, int cols, int chns) { if (row != NULL) { free(row); } } pnm_sample_t pnm_image_get_sample(pnm_image_t *img, int c, int x, int y) { if ((c < 0) || (c >= img->chns)) { return 0; } if ((x < 0) || (x >= img->cols)) { return 0; } if ((y < 0) || (y >= img->rows)) { return 0; } return img->smp[y][x*img->chns + c]; } void pnm_image_set_sample(pnm_image_t *img, int c, int x, int y, pnm_sample_t pv) { if ((c < 0) || (c >= img->chns)) { pnm_error("invalid channel"); } if ((x < 0) || (x >= img->cols)) { pnm_error("invalid column"); } if ((y < 0) || (y >= img->rows)) { pnm_error("invalid row"); } if (pv > img->maxval) { pnm_error("invalid sample value"); } img->smp[y][x*img->chns + c] = pv; } pnm_image_t *pnm_image_crop(pnm_image_t *img, int ic, int nc, int ix, int nx, int iy, int ny) { demand((ic >= 0) && (ic+nc <= img->chns), "invalid channel range"); demand((ix >= 0) && (ix+nx <= img->cols), "invalid column range"); demand((iy >= 0) && (iy+ny <= img->rows), "invalid row range"); pnm_image_t *omg = pnm_image_new(nx, ny, nc); omg->maxval = img->maxval; int chn, col, row; for (row = 0; row < ny; row++) { for (col = 0; col < nx; col++) { pnm_sample_t *pi = &(img->smp[iy + row][(ix + col)*img->chns + ic]); pnm_sample_t *po = &(omg->smp[row][col*nc]); for (chn = 0; chn < nc; chn++) { (*po) = (*pi); po++; pi++; } } } return omg; } pnm_image_t *pnm_image_read(char *name, bool_t verbose) { FILE *rd = open_read(name, verbose); pnm_image_t *img = pnm_image_fread(rd); if (rd != stdin) { fclose(rd); } return img; } pnm_image_t *pnm_image_fread(FILE *rd) { /* We cannot rely on {pnm_readpnm} because PBMPLUS has different pixel layout. */ /* Read file header: */ int cols, rows, chns; pnm_sample_t maxval; bool_t raw, bits; pnm_format_t format; pnm_read_header(rd, &cols, &rows, &chns, &maxval, &raw, &bits, &format); /* Allocate image and set maxval: */ pnm_image_t *img = pnm_image_new(cols, rows, chns); img->maxval = maxval; /* Read pixels: */ int row; for (row = 0; row < rows; row++) { pnm_read_pixels(rd, img->smp[row], cols, chns, maxval, raw, bits); } return(img); } void pnm_image_write(char *name, pnm_image_t *img, bool_t forceplain, bool_t verbose) { FILE *wr = open_write(name, verbose); pnm_image_fwrite(wr, img, forceplain); if (wr != stdout) { fclose(wr); } } void pnm_image_fwrite(FILE *wr, pnm_image_t *img, bool_t forceplain) { /* We cannot rely on {pnm_writepnm} because PBMPLUS has different pixel layout. */ if (img->maxval <= 0){ pnm_error("invalid maxval (%u)", img->maxval); } pnm_format_t format; bool_t raw; bool_t bits; pnm_choose_output_format(img->maxval, img->chns, forceplain, &format, &raw, &bits); pnm_write_header(wr, img->cols, img->rows, img->maxval, format); int row; for (row = 0; row < img->rows; row++) { pnm_write_pixels(wr, img->smp[row], img->cols, img->chns, img->maxval, raw, bits); } fflush(wr); } void pnm_image_describe(FILE *wr, char *name, pnm_image_t *img) { fprintf(stderr, "image %s\n", name); fprintf(stderr, "\n"); fprintf(stderr, "cols = %5d\n", img->cols); fprintf(stderr, "rows = %5d\n", img->rows); fprintf(stderr, "chns = %5d\n", img->chns); fprintf(stderr, "maxval = %5d\n", img->maxval); /* Determine min and max pixel value: */ pnm_sample_t minsmp = img->maxval; pnm_sample_t maxsmp = 0; int x, y, c; for (y = 0; y < img->rows; y++) { pnm_sample_t *ip = img->smp[y]; for (x = 0; x < img->cols; x++) { for (c = 0; c < img->chns; c++) { pnm_sample_t smp = (*ip); assert(smp <= img->maxval); if (smp < minsmp) { minsmp = smp; } if (smp > maxsmp) { maxsmp = smp; } ip++; } } } fprintf(wr, "minsmp = %5d\n", minsmp); fprintf(wr, "maxsmp = %5d\n", maxsmp); }