/* * The Npic library * * Copyright (C) 2003 Edouard Thiel * * This library is free software under the terms of the * GNU Lesser General Public License (LGPL) version 2.1. */ /* DO NOT EDIT !!! Generated by npic-templa from "files_pnm.ct" */ /* * files_pnm.c - 22/11/2010 * * PNM - Portable aNyMap file format (PBM/PGM/PPM extensions) * * See man pnm/pgm/pbm/ppm for specifications. */ #include #define MAXBUF 65536 #define FBUF_INT8 8192 #define FBUF_INT16 4096 /*--------------------- P U B L I C - I N T E R F A C E ----------------------*/ /* * Save image in a file in PNM format. * If comp != NPIC_COMPRESS_NONE, the file is directly compressed using * the appropriate command (see files_hints.h for available formats). * Do nothing if image is not ok. * * Return NPIC_SUCCESS, else error code. Verbose. * * USAGE : * Npic_image *np; int err; * ... * err = NpicWritePNM (&np, "example.pnm", NPIC_COMPRESS_NONE, * NPIC_PNM_AUTO_DETECT, * NPIC_PNM_ALLOW_16_BIT | NPIC_PNM_LITTLE_ENDIAN); * or err = NpicWritePNM (&np, "example.pnm.gz", NPIC_COMPRESS_GZ, ...); * if (err < 0) return err; * .... * NpicDestroyImage (np); */ int NpicWritePNM (Npic_image *np, const char *filename, Npic_file_compress comp, Npic_pnm_format format, Npic_pnm_option option) { Npic_file_gz fgz; if (NpicImageIsOK (np, __func__) != NPIC_SUCCESS) return NPIC_ERR_NOT_OK; NpicWriteGZ_Open (&fgz, filename, __func__, 0, comp); if (fgz.res == NPIC_SUCCESS) fgz.res = NpicPNMWriteFile (np, fgz.f2, filename, __func__, format, option); NpicWriteGZ_Close (&fgz); return fgz.res; } /* * Read image file in PNM format and create Npic_image of corresponding type. * If comp != NPIC_COMPRESS_NONE, the file is uncompressed in memory using * the appropriate command (but stay compressed on disk). * Return image on success, else return NULL. Verbose. * * USAGE : * Npic_image *np; * np = NpicReadPNM ("example.pnm" , NPIC_COMPRESS_NONE, NPIC_PNM_OPTION_NONE); * or np = NpicReadPNM ("example.pnm.gz", NPIC_COMPRESS_GZ, NPIC_PNM_OPTION_NONE); * if (np == NULL) return; * .... * NpicDestroyImage (np); */ Npic_image *NpicReadPNM (const char *filename, Npic_file_compress comp, Npic_pnm_option option) { Npic_image *np = NULL; Npic_file_gz fgz; NpicReadGZ_Open (&fgz, filename, __func__, 0, comp); if (fgz.res == NPIC_SUCCESS) np = NpicPNMReadFile (fgz.f2, filename, __func__, option); NpicReadGZ_Close (&fgz); return np; } /* * Print infos of a file in PNM format * * Return NPIC_SUCCESS, else error code. Verbose. */ int NpicInfoPNM (const char *filename, Npic_file_compress comp) { Npic_file_gz fgz; Npic_pnm_info info; NpicReadGZ_Open (&fgz, filename, __func__, 0, comp); if (fgz.res == NPIC_SUCCESS) { fgz.res = NPicPNMReadInfo (fgz.f2, &info); if (fgz.res == NPIC_SUCCESS) fgz.res = NpicPNMPrintInfo (filename, &info); NpicError (__func__, fgz.res, ": file \"%s\"", filename); } NpicReadGZ_Close (&fgz); return fgz.res; } /*-------------------- P R I V A T E - F U N C T I O N S ---------------------*/ /* * Save an image in a file, according to hints. * Return NPIC_SUCCESS, else error code. Verbose. */ int NpicWritePNMwithHints (Npic_image *np, Npic_file_hints *h) { int pnm_format, pnm_options, ascii; const char *allowed_hints[] = { "help", "bitmap", "ascii", "16-bit", "little-endian", NULL}; if (h == NULL) return NPIC_ERR_NULL_PTR; /* Check for bad hints */ if (NpicFileCheckHints (h, allowed_hints) < 0) { return NpicError ("", NPIC_ERROR, ": bad hint in \"%s\".\n" "try with filename \"%s:help\" to get allowed hints\n", h->filename, h->realname); } /* Self-documentation */ if (NpicFileHint (h, "help") >= 0) { fprintf (stderr, "Available hints when writing pnm/pbm/pgm/ppm files:\n" " bitmap (default is greymap or pixmap)\n" " ascii (default is binary)\n" " 16-bit (default is 8-bit)\n" " little-endian (default is big-endian)\n"); return NpicError ("", NPIC_ERROR, ": write aborted"); } pnm_options = (NpicFileHint (h, "bitmap" ) >= 0 ? NPIC_PNM_BITMAP : 0) | (NpicFileHint (h, "ascii" ) >= 0 ? NPIC_PNM_ASCII : 0) | (NpicFileHint (h, "16-bit" ) >= 0 ? NPIC_PNM_ALLOW_16_BIT : 0) | (NpicFileHint (h, "little-endian") >= 0 ? NPIC_PNM_LITTLE_ENDIAN : 0); ascii = pnm_options & NPIC_PNM_ASCII ? 1 : 0; if (strcmp (h->extension, ".pbm") == 0) pnm_format = ascii ? NPIC_PNM_BITMAP_ASCII : NPIC_PNM_BITMAP_BINARY; else if (strcmp (h->extension, ".pgm") == 0) pnm_format = ascii ? NPIC_PNM_GREYMAP_ASCII : NPIC_PNM_GREYMAP_BINARY; else if (strcmp (h->extension, ".ppm") == 0) pnm_format = ascii ? NPIC_PNM_PIXMAP_ASCII : NPIC_PNM_PIXMAP_BINARY; else pnm_format = NPIC_PNM_AUTO_DETECT; return NpicWritePNM (np, h->realname, h->comp, pnm_format, pnm_options); } /* * Load an image from a file, according to hints. * Return image on success, else return NULL. Verbose. */ Npic_image *NpicReadPNMwithHints (Npic_file_hints *h) { int pnm_options; const char *allowed_hints[] = { "help", "little-endian", NULL}; if (h == NULL) return NULL; /* Check for bad hints */ if (NpicFileCheckHints (h, allowed_hints) < 0) { NpicError ("", NPIC_ERROR, ": bad hint in \"%s\".\n" "try with filename \"%s:help\" to get allowed hints\n", h->filename, h->realname); return NULL; } /* Self-documentation */ if (NpicFileHint (h, "help") >= 0) { fprintf (stderr, "Available hints when reading pnm/pbm/pgm/ppm files:\n" " little-endian (default is big-endian)\n"); NpicError ("", NPIC_ERROR, ": read aborted"); return NULL; } pnm_options = (NpicFileHint (h, "little-endian") >= 0 ? NPIC_PNM_LITTLE_ENDIAN : 0); return NpicReadPNM (h->realname, h->comp, pnm_options); } /* * Save Npic_image image in a file in PNM format. * The file is already fopen. * If format is NPIC_PNM_AUTO_DETECT, the format is guessed from the options. * Return NPIC_SUCCESS, else error code. Verbose. */ int NpicPNMWriteFile (Npic_image *np, FILE *f1, const char *filename, const char *funcname, Npic_pnm_format format, Npic_pnm_option option) { int bit16, bswap, bdest; if (NpicImageIsOK (np, funcname) != NPIC_SUCCESS) return NPIC_ERR_NOT_OK; if (format == NPIC_PNM_AUTO_DETECT) { int opt_ascii = option & NPIC_PNM_ASCII ? 1 : 0, opt_bitmap = option & NPIC_PNM_BITMAP ? 1 : 0; switch (np->type) { case NPIC_IMAGE_2C: case NPIC_IMAGE_2L: format = opt_bitmap ? opt_ascii ? NPIC_PNM_BITMAP_ASCII : NPIC_PNM_BITMAP_BINARY : opt_ascii ? NPIC_PNM_GREYMAP_ASCII : NPIC_PNM_GREYMAP_BINARY ; break; case NPIC_IMAGE_2Q: format = opt_ascii ? NPIC_PNM_PIXMAP_ASCII : NPIC_PNM_PIXMAP_BINARY; break; default: return NpicError (funcname, NPIC_ERR_UNEX_NPIC, ""); } } NpicPNMWriteHeader (np, f1, filename, funcname, format, option); bit16 = option & NPIC_PNM_ALLOW_16_BIT ? 1 : 0; bdest = option & NPIC_PNM_LITTLE_ENDIAN ? __LITTLE_ENDIAN : __BIG_ENDIAN; bswap = bdest == __BYTE_ORDER ? 0 : 1; switch (format) { case NPIC_PNM_BITMAP_ASCII : return NpicPNMWriteBitmapAscii (np, f1); case NPIC_PNM_GREYMAP_ASCII : return NpicPNMWriteGreymapAscii (np, f1, bit16); case NPIC_PNM_PIXMAP_ASCII : return NpicPNMWritePixmapAscii (np, f1, bit16); case NPIC_PNM_BITMAP_BINARY : return NpicPNMWriteBitmapBin (np, f1); case NPIC_PNM_GREYMAP_BINARY : return NpicPNMWriteGreymapBin (np, f1, bit16, bswap); case NPIC_PNM_PIXMAP_BINARY : return NpicPNMWritePixmapBin (np, f1, bit16, bswap); default: return NpicError (funcname, NPIC_ERR_UNAV_FORMAT, ""); } } /* * Write pnm file header, according to image np and format. * The file is already fopen. Verbose. */ void NpicPNMWriteHeader (Npic_image *np, FILE *f1, const char *filename, const char *funcname, Npic_pnm_format format, Npic_pnm_option option) { time_t tm; char *s = NULL; switch (format) { case NPIC_PNM_BITMAP_ASCII : s = "P1"; break; case NPIC_PNM_GREYMAP_ASCII : s = "P2"; break; case NPIC_PNM_PIXMAP_ASCII : s = "P3"; break; case NPIC_PNM_BITMAP_BINARY : s = "P4"; break; case NPIC_PNM_GREYMAP_BINARY : s = "P5"; break; case NPIC_PNM_PIXMAP_BINARY : s = "P6"; break; default: NpicError (funcname, NPIC_ERR_UNAV_FORMAT, ""); return; } fprintf (f1, "%s\n", s); time(&tm); fprintf (f1, "# Image file generated by libNpic - %s", ctime(&tm)); fprintf (f1, "# width height\n"); fprintf (f1, "%d %d\n", np->gen.xmax, np->gen.ymax); if (format == NPIC_PNM_GREYMAP_ASCII || format == NPIC_PNM_PIXMAP_ASCII || format == NPIC_PNM_GREYMAP_BINARY || format == NPIC_PNM_PIXMAP_BINARY) { fprintf (f1, "# maxgrey\n"); fprintf (f1, "%d\n", option & NPIC_PNM_ALLOW_16_BIT ? 65535 : 255); } /* The header should finish with exactly one char after Maxgrey ; this is the case for '\n' since the file is open in binary mode */ } /* * Write pixel values as a Bitmap in ascii format (P1). * Only interior pixels are saved. * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMWriteBitmapAscii (Npic_image *np, FILE *f) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; /* 1 for black, 0 for white. */ switch (np->type) { case NPIC_IMAGE_2C : { int y, x; Npic_image_2c *I = NpicCastImage(np); for (y = 0; y < I->ymax; y++) { for (x = 0; x < I->xmax; x++) fprintf (f, "%1d ", I->pix[y][x] == 0 ? 1 : 0); fprintf (f, "\n"); } } break; case NPIC_IMAGE_2L : { int y, x; Npic_image_2l *I = NpicCastImage(np); for (y = 0; y < I->ymax; y++) { for (x = 0; x < I->xmax; x++) fprintf (f, "%1d ", I->pix[y][x] == 0 ? 1 : 0); fprintf (f, "\n"); } } break; default : return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Write pixel values as a Greymap in ascii format (P2). * Only interior pixels are saved. * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMWriteGreymapAscii (Npic_image *np, FILE *f, int bit16) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; switch (np->type) { case NPIC_IMAGE_2C : { int y, x; Npic_image_2c *I = NpicCastImage(np); for (y = 0; y < I->ymax; y++) { for (x = 0; x < I->xmax; x++) { Npic_l a = I->pix[y][x]; if (bit16) fprintf (f, "%5" NPIC_PL " ", a | (a << 8)); else fprintf (f, "%3" NPIC_PL " ", a); } fprintf (f, "\n"); } } break; case NPIC_IMAGE_2L : { int y, x; Npic_image_2l *I = NpicCastImage(np); for (y = 0; y < I->ymax; y++) { for (x = 0; x < I->xmax; x++) { Npic_l a = I->pix[y][x]; if (bit16) fprintf (f, "%5" NPIC_PL " ", a % 65536); else fprintf (f, "%3" NPIC_PL " ", a % 256); } fprintf (f, "\n"); } } break; default : return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Write pixel values as a Pixmap in ascii format (P3). * Only interior pixels are saved. * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMWritePixmapAscii (Npic_image *np, FILE *f, int bit16) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; switch (np->type) { case NPIC_IMAGE_2Q : { int y, x; Npic_image_2q *I = NpicCastImage(np); for (y = 0; y < I->ymax; y++) { for (x = 0; x < I->xmax; x++) { if (bit16) fprintf (f, "%5d %5d %5d ", I->pix[y][x].a, I->pix[y][x].b, I->pix[y][x].c); else fprintf (f, "%3d %3d %3d ", I->pix[y][x].a >> 8, I->pix[y][x].b >> 8, I->pix[y][x].c >> 8); } fprintf (f, "\n"); } } break; default : return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Write pixel values as a Bitmap in binary format (P4). * Only interior pixels are saved. * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMWriteBitmapBin (Npic_image *np, FILE *f) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; /* 1 for black, 0 for white. In each row, the last byte is filled with 0's. In a byte, the order is most significant to least significant bit. */ switch (np->type) { case NPIC_IMAGE_2C : { int y, x, i, j, k; Npic_image_2c *I = NpicCastImage(np); Npic_uint8 buf[FBUF_INT8]; for (j = 0, y = 0; y < I->ymax; y++) for (i = 0, x = 0; x < I->xmax; x++) { if (i == 0) buf[j] = 0; buf[j] |= (I->pix[y][x] == 0 ? 1 : 0) << (7-i); if (++i >= 8 || x+1 >= I->xmax) { i = 0; j++; if (j >= FBUF_INT8) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; j = 0; } } } /* Flush buf */ if (j > 0) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; } } break; case NPIC_IMAGE_2L : { int y, x, i, j, k; Npic_image_2l *I = NpicCastImage(np); Npic_uint8 buf[FBUF_INT8]; for (j = 0, y = 0; y < I->ymax; y++) for (i = 0, x = 0; x < I->xmax; x++) { if (i == 0) buf[j] = 0; buf[j] |= (I->pix[y][x] == 0 ? 1 : 0) << (7-i); if (++i >= 8 || x+1 >= I->xmax) { i = 0; j++; if (j >= FBUF_INT8) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; j = 0; } } } /* Flush buf */ if (j > 0) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; } } break; default : return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Write pixel values as a Greymap in binary format (P5). * Only interior pixels are saved. * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMWriteGreymapBin (Npic_image *np, FILE *f, int bit16, int bswap) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; switch (np->type) { case NPIC_IMAGE_2C : { int y, x, j, k; Npic_image_2c *I = NpicCastImage(np); if (bit16) { /* 16-bit */ Npic_uint16 buf[FBUF_INT16]; j = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { Npic_l a = I->pix[y][x]; a = a | (a << 8); buf[j++] = bswap ? NPIC_BSWAP16 (a) : a; if (j >= FBUF_INT16) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; j = 0; } } /* Flush buf */ if (j > 0) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; } } else { /* 8-bit ; bswap is ignored */ Npic_uint8 buf[FBUF_INT8]; j = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { buf[j++] = I->pix[y][x]; if (j >= FBUF_INT8) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; j = 0; } } /* Flush buf */ if (j > 0) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; } } } break; case NPIC_IMAGE_2L : { int y, x, j, k; Npic_image_2l *I = NpicCastImage(np); if (bit16) { /* 16-bit */ Npic_uint16 buf[FBUF_INT16]; j = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { Npic_l a = I->pix[y][x]; a = a % 65536; buf[j++] = bswap ? NPIC_BSWAP16 (a) : a; if (j >= FBUF_INT16) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; j = 0; } } /* Flush buf */ if (j > 0) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; } } else { /* 8-bit ; bswap is ignored */ Npic_uint8 buf[FBUF_INT8]; j = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { Npic_l a = I->pix[y][x]; buf[j++] = a % 256; if (j >= FBUF_INT8) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; j = 0; } } /* Flush buf */ if (j > 0) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; } } } break; default : return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Write pixel values as a Pixmap in binary format (P6). * Only interior pixels are saved. * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMWritePixmapBin (Npic_image *np, FILE *f, int bit16, int bswap) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; if (np->type != NPIC_IMAGE_2Q) return NPIC_ERR_UNEX_NPIC; if (bit16) { /* 16 bit */ int y, x, j, k; Npic_uint16 buf[FBUF_INT16+4]; Npic_image_2q *I = NpicCastImage(np); j = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (bswap) { /* swap bytes */ buf[j++] = NPIC_BSWAP16 (I->pix[y][x].a); buf[j++] = NPIC_BSWAP16 (I->pix[y][x].b); buf[j++] = NPIC_BSWAP16 (I->pix[y][x].c); } else { buf[j++] = I->pix[y][x].a; buf[j++] = I->pix[y][x].b; buf[j++] = I->pix[y][x].c; } if (j >= FBUF_INT16) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; j = 0; } } /* Flush buf */ if (j > 0) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; } } else { /* 8 bit */ int y, x, j, k; Npic_uint8 buf[FBUF_INT8+4]; Npic_image_2q *I = NpicCastImage(np); j = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { buf[j++] = I->pix[y][x].a >> 8; buf[j++] = I->pix[y][x].b >> 8; buf[j++] = I->pix[y][x].c >> 8; if (j >= FBUF_INT8) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; j = 0; } } /* Flush buf */ if (j > 0) { k = fwrite (buf, sizeof(buf[0])*j, 1, f); if (k != 1) return NPIC_ERR_WRITE; } } return NPIC_SUCCESS; } /* * Read image file in PNM format and create Npic_image image of corresponding * type. The file is already fopen. * Return image on success, else return NULL. Verbose. */ Npic_image *NpicPNMReadFile (FILE *f1, const char *filename, const char *funcname, Npic_pnm_option option) { Npic_image *np = NULL; Npic_pnm_info info; Npic_vec vsize; int k, bswap, bit16, bsrc; k = NPicPNMReadInfo (f1, &info); if (k != NPIC_SUCCESS) { NpicError (funcname, k, ": file \"%s\"", filename); return NULL; } /* Allocate Image */ vsize.x = info.xmax; vsize.y = info.ymax; np = NpicCreateImageNS (info.npic_type, &vsize); if (np == NULL) { NpicError (funcname, NPIC_ERROR, ": file \"%s\"", filename); return NULL; } bit16 = info.maxgrey > 255; bsrc = option & NPIC_PNM_LITTLE_ENDIAN ? __LITTLE_ENDIAN : __BIG_ENDIAN; bswap = bsrc == __BYTE_ORDER ? 0 : 1; switch (info.format) { case NPIC_PNM_BITMAP_ASCII : k = NpicPNMReadBitmapAscii (np, f1); break; case NPIC_PNM_GREYMAP_ASCII : k = NpicPNMReadGreymapAscii (np, f1, info.maxgrey); break; case NPIC_PNM_PIXMAP_ASCII : k = NpicPNMReadPixmapAscii (np, f1, info.maxgrey); break; case NPIC_PNM_BITMAP_BINARY : k = NpicPNMReadBitmapBin (np, f1); break; case NPIC_PNM_GREYMAP_BINARY : k = NpicPNMReadGreymapBin (np, f1, bit16, bswap); break; case NPIC_PNM_PIXMAP_BINARY : k = NpicPNMReadPixmapBin (np, f1, bit16, bswap); break; default : k = NPIC_ERR_UNAV_FORMAT; } if (k != NPIC_SUCCESS) { NpicDestroyImage (np); np = NULL; NpicError (funcname, k, ": file \"%s\"", filename); } return np; } /* * Read infos (i.e text header) in a PNM file, * then store results in struct info. * The file is already fopen. * Return NPIC_SUCCESS, else error code. Silent. */ int NPicPNMReadInfo (FILE *f1, Npic_pnm_info *info) { int k; if (f1 == NULL) return NPIC_ERR_BAD_FD; if (info == NULL) return NPIC_ERR_NULL_PTR; memset (info, 0, sizeof(Npic_pnm_info)); /* Read MagicValue */ k = fread (info->magic, 2, 1, f1); if (k != 1) return NPIC_ERR_READ; if (info->magic[0] != 'P') return NPIC_ERR_MAGIC; switch (info->magic[1]) { case '1' : info->format = NPIC_PNM_BITMAP_ASCII; info->npic_type = NPIC_IMAGE_2C; break; case '2' : info->format = NPIC_PNM_GREYMAP_ASCII; info->npic_type = NPIC_IMAGE_2C; break; case '3' : info->format = NPIC_PNM_PIXMAP_ASCII; info->npic_type = NPIC_IMAGE_2Q; break; case '4' : info->format = NPIC_PNM_BITMAP_BINARY; info->npic_type = NPIC_IMAGE_2C; break; case '5' : info->format = NPIC_PNM_GREYMAP_BINARY; info->npic_type = NPIC_IMAGE_2C; break; case '6' : info->format = NPIC_PNM_PIXMAP_BINARY; info->npic_type = NPIC_IMAGE_2Q; break; default : return NPIC_ERR_MAGIC; } info->npic_dim = 2; /* Read Width Height in file header */ k = NpicPNMReadInt (f1, &info->xmax); if (k < 0) return k; k = NpicPNMReadInt (f1, &info->ymax); if (k < 0) return k; /* Read MaxGrey if necessary */ if (info->format == NPIC_PNM_BITMAP_ASCII || info->format == NPIC_PNM_BITMAP_BINARY) info->maxgrey = 1; else { k = NpicPNMReadInt (f1, &info->maxgrey); if (k < 0) return k; } /* Check Maxgrey */ if (info->maxgrey < 1) return NPIC_ERR_HEADER; if (info->maxgrey > 255 && info->npic_type == NPIC_IMAGE_2C) info->npic_type = NPIC_IMAGE_2L; if ((info->format == NPIC_PNM_GREYMAP_BINARY || info->format == NPIC_PNM_PIXMAP_BINARY) && (info->maxgrey != 255 && info->maxgrey != 65535)) return NPIC_ERR_HEADER; /* After the header there is exactly one char to read before binary datas. The '*' in fscanf suppresses the assignment */ k = fscanf (f1, "%*c"); return NPIC_SUCCESS; } /* * Print infos on file. * Return NPIC_SUCCESS, else error code. Verbose. */ int NpicPNMPrintInfo (const char *filename, Npic_pnm_info *info) { printf ("FILENAME \"%s\"\n", filename); if (info == NULL) return NPIC_ERR_NULL_PTR; printf ("MAGIC %s\n", info->magic); printf ("XMAX %d\n", info->xmax); printf ("YMAX %d\n", info->ymax); printf ("MAXGREY %d\n", info->maxgrey); printf ("TYPE %s\n", NpicImageTypeName(info->npic_type)); printf ("DIM %d\n", info->npic_dim); return NPIC_SUCCESS; } /* * Read the next integer in the header of f, and store it in val. * The comments are ignored. * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMReadInt (FILE *f, int *val) { char tok[32]; while (1) { /* Ignore a comment, defined by : ' ' a serie of separators (space, \n, \t) '%1[#]' a serie of 1 '#' ; assignment is counted. '%*[^\n]' a serie of char different from \n ; suppressed with * and not counted. '\n' char \n */ if (fscanf (f, " %1[#]%*[^\n]\n", tok) > 0) continue; /* Previous version was : if (fscanf (f, " #%*[^\n]\n") == 1) continue; does not work because * suppress assignement and thus is not counted in return value. Bugfix 22 nov 2005. */ /* Read one integer */ if (fscanf (f, "%d", val) == 1) return NPIC_SUCCESS; /* Bad header */ return NPIC_ERR_HEADER; } } /* * Read pixel values for a Bitmap in ascii format (P1). * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMReadBitmapAscii (Npic_image *np, FILE *f) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; /* 1 for black, 0 for white. */ switch (np->type) { case NPIC_IMAGE_2C : { Npic_image_2c *I = NpicCastImage(np); int x, y, a; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (fscanf (f, "%d", &a) != 1) return NPIC_ERR_READ; I->pix[y][x] = a == 1 ? 0 : 255; } } break; return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Read pixel values for a Greymap in ascii format (P2). * Values are interpolated over maxgrey. * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMReadGreymapAscii (Npic_image *np, FILE *f, int maxgrey) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; if (maxgrey < 1) return NPIC_ERR_HEADER; switch (np->type) { case NPIC_IMAGE_2C : { Npic_image_2c *I = NpicCastImage(np); int x, y; Npic_l a; double r = 255.0 / maxgrey; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (fscanf (f, "%" NPIC_PL, &a) != 1) return NPIC_ERR_READ; I->pix[y][x] = r * (a % (maxgrey+1)); } } break; case NPIC_IMAGE_2L : { Npic_image_2l *I = NpicCastImage(np); int x, y; Npic_l a; double r = 65535.0 / maxgrey; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (fscanf (f, "%" NPIC_PL, &a) != 1) return NPIC_ERR_READ; I->pix[y][x] = r * (a % (maxgrey+1)); } } break; return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Read pixel values for a Pixmap in ascii format (P3). * Values are interpolated over maxgrey. * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMReadPixmapAscii (Npic_image *np, FILE *f, int maxgrey) { if (maxgrey < 1) return NPIC_ERR_HEADER; if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; switch (np->type) { case NPIC_IMAGE_2Q : { Npic_image_2q *I = NpicCastImage (np); int x, y, a, b, c; double r = 65535.0 / maxgrey; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (fscanf (f, "%d %d %d", &a, &b, &c) != 3) return NPIC_ERR_READ; I->pix[y][x].a = r * (a % (maxgrey+1)); I->pix[y][x].b = r * (b % (maxgrey+1)); I->pix[y][x].c = r * (c % (maxgrey+1)); } } break; return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Read pixel values for a Bitmap in binary format (P4). * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMReadBitmapBin (Npic_image *np, FILE *f) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; switch (np->type) { case NPIC_IMAGE_2C : { int y, x, i, j, k; Npic_image_2c *I = NpicCastImage(np); Npic_c buf[FBUF_INT8]; k = 0; for (j = 0, y = 0; y < I->ymax; y++) for (i = 0, x = 0; x < I->xmax; x++) { if (j == k) { j = 0; k = fread (buf, sizeof(buf[0]), FBUF_INT8, f); if (k <= 0) return NPIC_ERR_READ; } I->pix[y][x] = buf[j] & 1 << (7-i) ? 0 : 255; if (++i >= 8 || x+1 >= I->xmax) { i = 0; j++; } } } break; return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Read pixel values for a Greymap in binary format (P5). * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMReadGreymapBin (Npic_image *np, FILE *f, int bit16, int bswap) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; switch (np->type) { case NPIC_IMAGE_2C : { int y, x, j, k; Npic_image_2c *I = NpicCastImage(np); if (bit16) { Npic_uint16 buf[FBUF_INT16]; j = k = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (j == k) { j = 0; k = fread (buf, sizeof(buf[0]), FBUF_INT16, f); if (k <= 0) return NPIC_ERR_READ; } I->pix[y][x] = buf[j] >> 8; j++; } } else { /* 8-bit */ Npic_c buf[FBUF_INT8]; j = k = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (j == k) { j = 0; k = fread (buf, sizeof(buf[0]), FBUF_INT8, f); if (k <= 0) return NPIC_ERR_READ; } I->pix[y][x] = buf[j]; j++; } } } break; case NPIC_IMAGE_2L : { int y, x, j, k; Npic_image_2l *I = NpicCastImage(np); if (bit16) { Npic_uint16 buf[FBUF_INT16]; j = k = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (j == k) { j = 0; k = fread (buf, sizeof(buf[0]), FBUF_INT16, f); if (k <= 0) return NPIC_ERR_READ; } I->pix[y][x] = bswap ? NPIC_BSWAP16 (buf[j]) : buf[j]; j++; } } else { /* 8-bit */ Npic_c buf[FBUF_INT8]; j = k = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (j == k) { j = 0; k = fread (buf, sizeof(buf[0]), FBUF_INT8, f); if (k <= 0) return NPIC_ERR_READ; } I->pix[y][x] = buf[j] | (buf[j] << 8); j++; } } } break; return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; } /* * Read pixel values for a Pixmap in binary format (P6). * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPNMReadPixmapBin (Npic_image *np, FILE *f, int bit16, int bswap) { if (np == NULL) return NPIC_ERR_NULL_PTR; if (f == NULL) return NPIC_ERR_BAD_FD; switch (np->type) { case NPIC_IMAGE_2Q : { int y, x, j, k; Npic_image_2q *I = NpicCastImage(np); if (bit16) { Npic_uint16 buf[FBUF_INT16]; j = k = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (j >= k) { j = 0; k = fread (buf, sizeof(buf[0])*3, FBUF_INT16/4, f)*3; if (k <= 0) return NPIC_ERR_READ; } if (bswap) { I->pix[y][x].a = NPIC_BSWAP16 (buf[j]); j++; I->pix[y][x].b = NPIC_BSWAP16 (buf[j]); j++; I->pix[y][x].c = NPIC_BSWAP16 (buf[j]); j++; I->pix[y][x].d = 65535; } else { I->pix[y][x].a = buf[j++]; I->pix[y][x].b = buf[j++]; I->pix[y][x].c = buf[j++]; I->pix[y][x].d = 65535; } } } else { /* 8-bit */ Npic_c buf[FBUF_INT8]; j = k = 0; for (y = 0; y < I->ymax; y++) for (x = 0; x < I->xmax; x++) { if (j >= k) { j = 0; k = fread (buf, sizeof(buf[0])*3, FBUF_INT8/4, f)*3; if (k <= 0) return NPIC_ERR_READ; } I->pix[y][x].a = buf[j] | (buf[j] << 8); j++; I->pix[y][x].b = buf[j] | (buf[j] << 8); j++; I->pix[y][x].c = buf[j] | (buf[j] << 8); j++; I->pix[y][x].d = 65535; } } } break; return NPIC_ERR_UNEX_NPIC; } return NPIC_SUCCESS; }