/* * Written 2003 Lukas Kunc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include "xmalloc.h" #include "image.h" #define LINE_LEN_BORDER_PPM 56 #define LINE_LEN_BORDER_PGM 64 //++pac #define EINVAL 1 typedef enum { PBM_ASCII = 1, PGM_ASCII = 2, PPM_ASCII = 3, PBM_BINARY = 4, PGM_BINARY = 5, PPM_BINARY = 6, PNM_UNKNOWN } PNMType; image_t* image_create(image_t* image, int x, int y) { image->x = x; image->y = y; image->data = (real_t*)xmalloc(sizeof(real_t) * x * y); return image; } image_t* image_create_copyparam(image_t* image, image_t* src) { image->x = src->x; image->y = src->y; image->data = (real_t*)xmalloc(sizeof(real_t) * image->x * image->y); return image; } void image_init(image_t* image) { image->data = NULL; } void image_destroy(image_t* image) { xfree(image->data); } image_t* image_convolve_mirror(image_t* dst, image_t* src, convmask_t* filter) { int i, j, k, l, r; real_t value; r = filter->radius; for (i = 0; i < src->x; i++) { for (j = 0; j < src->y; j++) { value = R(0.0); for (k = -r; k <= r; k++) { for (l = -r; l <= r; l++) { value += convmask_get(filter, k,l) * image_get_mirror(src, i-k, j-l); } } image_set(dst, i, j, value); } } return dst; } image_t* image_convolve_period(image_t* dst, image_t* src, convmask_t* filter) { int i, j, k, l, r; real_t value; r = filter->radius; for (i = 0; i < src->x; i++) { for (j = 0; j < src->y; j++) { value = R(0.0); for (k = -r; k <= r; k++) { for (l = -r; l <= r; l++) { value += convmask_get(filter, k,l) * image_get_period(src, i-k, j-l); } } image_set(dst, i, j, value); } } return dst; } int image_load_pnm_file(image_t* imageR, image_t* imageG, image_t* imageB, int* bpp, FILE* file) { char buff[2]; unsigned char bytesRGB[3]; int c; int i, x, y, Y, valueR, valueG, valueB; unsigned char byte; PNMType type; real_t scale; if (imageR) image_init(imageR); if (imageG) image_init(imageG); if (imageB) image_init(imageB); if (fread(buff, sizeof(buff), 1, file) != 1) { return -1; } if (buff[0] != 'P') { errno = EINVAL; return -1; } switch (buff[1]) { case '1': /* PBM, ascii */ type = PBM_ASCII; break; case '2': /* PGM, ascii */ type = PGM_ASCII; break; case '3': /* PPM, ascii */ type = PPM_ASCII; break; case '4': /* PBM, binary */ type = PBM_BINARY; break; case '5': /* PGM binary */ type = PGM_BINARY; break; case '6': /* PPM, binary */ type = PPM_BINARY; break; default: /* Unsupported */ type = PNM_UNKNOWN; break; } if (type == PNM_UNKNOWN) { errno = EINVAL; return -1; } do { c = getc(file); } while (c == '\t' || c == ' '); if (c == '\r') c = getc(file); if (c != '\n') { errno = EINVAL; return -1; } c = getc(file); while (c == '#') { while (((c = getc(file)) != '\n') && (c != EOF)); if (c != EOF) c = getc(file); } if (c == EOF) { errno = EINVAL; return -1; } ungetc(c, file); if (fscanf(file, "%d %d %d", &x, &y, &c) != 3) { errno = EINVAL; return -1; } scale = R(255.0) / (real_t)c; c = getc(file); if (c == '\r') c = getc(file); if (c != '\n') { errno = EINVAL; return -1; } Y = y; switch (type) { case PGM_ASCII: if (bpp) *bpp = 1; image_create(imageR, x, y); y = 0; i = 0; while (y < Y && fscanf(file, "%d", &valueR) == 1) { image_set(imageR, i, y, scale * (real_t)valueR); i++; if (i >= x) { i = 0; y++; } } break; case PGM_BINARY: if (bpp) *bpp = 1; image_create(imageR, x, y); y = 0; i = 0; while (y < Y && fread(&byte, sizeof(byte), 1, file) == 1) { image_set(imageR, i, y, scale * (real_t)byte); i++; if (i >= x) { i = 0; y++; } } break; case PPM_ASCII: if (bpp) *bpp = 3; image_create(imageR, x, y); if (!imageG || !imageR) { errno = EINVAL; return -1; } image_create(imageG, x, y); image_create(imageB, x, y); y = 0; i = 0; while (y < Y && fscanf(file, "%d %d %d", &valueR, &valueG, &valueB) == 3) { image_set(imageR, i, y, scale * (real_t)valueR); image_set(imageG, i, y, scale * (real_t)valueG); image_set(imageB, i, y, scale * (real_t)valueB); i++; if (i >= x) { i = 0; y++; } } break; case PPM_BINARY: if (bpp) *bpp = 3; image_create(imageR, x, y); if (!imageG || !imageR) { errno = EINVAL; return -1; } image_create(imageG, x, y); image_create(imageB, x, y); y = 0; i = 0; while (y < Y && fread(&bytesRGB, sizeof(bytesRGB), 1, file) == 1) { image_set(imageR, i, y, scale * (real_t)bytesRGB[0]); image_set(imageG, i, y, scale * (real_t)bytesRGB[1]); image_set(imageB, i, y, scale * (real_t)bytesRGB[2]); i++; if (i >= x) { i = 0; y++; } } break; default: errno = EINVAL; return -1; } return 0; } int image_save_pnm_file(image_t* imageR, image_t* imageG, image_t* imageB, int binary, FILE* file) { int type; int i, j, rv, R, G, B; unsigned char c; int chars_cnt; if (imageG && imageG->data && imageB && imageB->data) type = 3; else type = 2; if (binary) type+=3; if (fprintf(file, "P%d\n# Deblur output\n%d %d\n255", type, imageR->x, imageR->y) < 0) return -1; switch (type) { case PGM_ASCII: chars_cnt = LINE_LEN_BORDER_PGM + 1; for (j = 0; j < imageR->y; j++) { for (i = 0; i < imageR->x; i++) { R = (int)(image_get(imageR, i, j) + R(0.5)); if (chars_cnt > LINE_LEN_BORDER_PGM) { if (fprintf(file, "\n") < 0) return -1; chars_cnt = 0; rv = fprintf(file, "%d", R); } else { rv = fprintf(file, " %d", R); } if (rv < 0) return -1; chars_cnt += rv; } } break; case PGM_BINARY: if (fprintf(file, "\n") < 0) return -1; for (j = 0; j < imageR->y; j++) { for (i = 0; i < imageR->x; i++) { c = (unsigned char)(image_get(imageR, i, j) + R(0.5)); if (fwrite(&c, sizeof(c), 1, file) != 1) return -1; } } break; case PPM_ASCII: chars_cnt = LINE_LEN_BORDER_PPM + 1; for (j = 0; j < imageR->y; j++) { for (i = 0; i < imageR->x; i++) { R = (int)(image_get(imageR, i, j) + R(0.5)); G = (int)(image_get(imageG, i, j) + R(0.5)); B = (int)(image_get(imageB, i, j) + R(0.5)); if (chars_cnt > LINE_LEN_BORDER_PPM) { if (fprintf(file, "\n") < 0) return -1; chars_cnt = 0; rv = fprintf(file, "%d %d %d", R, G, B); } else { rv = fprintf(file, " %d %d %d", R, G, B); } if (rv < 0) return -1; chars_cnt += rv; } } break; case PPM_BINARY: if (fprintf(file, "\n") < 0) return -1; for (j = 0; j < imageR->y; j++) { for (i = 0; i < imageR->x; i++) { c = (unsigned char)(image_get(imageR, i, j) + R(0.5)); if (fwrite(&c, sizeof(c), 1, file) != 1) return -1; c = (unsigned char)(image_get(imageG, i, j) + R(0.5)); if (fwrite(&c, sizeof(c), 1, file) != 1) return -1; c = (unsigned char)(image_get(imageB, i, j) + R(0.5)); if (fwrite(&c, sizeof(c), 1, file) != 1) return -1; } } break; default: errno = EINVAL; return -1; } return 0; } int image_save_pnm(image_t* imageR, image_t* imageG, image_t* imageB, int binary, const char* name) { int retval; FILE *file; file = fopen(name, "wb"); if (file) { retval = image_save_pnm_file(imageR, imageG, imageB, binary, file); fclose(file); } else { retval = -1; } return retval; } int image_load_pnm(image_t* imageR, image_t* imageG, image_t* imageB, int* bpp, const char* name) { FILE *file; int retval; file = fopen(name, "rb"); if (file) { retval = image_load_pnm_file(imageR, imageG, imageB, bpp, file); fclose(file); } else { retval = -1; } return retval; } void image_load_bytes_gray(image_t* image, unsigned char* src) { int size, i; real_t *dst; size = image->x * image->y; dst = image->data; for (i = 0; i < size; i++) { *dst = *src; src++; dst++; } } void image_load_bytes_rgb(image_t* image, unsigned char* bytes, unsigned int channel) { int size, i; unsigned char *src; real_t *dst; size = image->x * image->y; dst = image->data; src = bytes + channel; for (i = 0; i < size; i++) { *dst = *src; src += 3; dst++; } } /* * GET / SET */ #if !defined(INLINE) && !defined(INLINE_MACRO) real_t image_get_mirror(image_t* image, int x, int y) { return MACRO_IMAGE_GET_MIRROR(image, x, y); } real_t image_get_period(image_t* image, int x, int y) { return MACRO_IMAGE_GET_PERIOD(image, x, y); } void image_set(image_t* image, int x, int y, real_t value) { MACRO_IMAGE_SET(image, x, y, value); } real_t image_get(image_t* image, int x, int y) { return MACRO_IMAGE_GET(image, x, y); } #endif