home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / MacPNG Library 1.02 / pngMacSrc 1.02 / png.1 / ptot / ptot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-08  |  16.5 KB  |  686 lines  |  [TEXT/CWIE]

  1. /*
  2.  * ptot.c
  3.  *
  4.  * Convert PNG (Portable Network Graphic) file to TGA (Truevision
  5.  * TGA File Format). Takes a filename argument on the command line.
  6.  *
  7.  **********
  8.  *
  9.  * HISTORY
  10.  *
  11.  * 95-03-10 Created by Lee Daniel Crocker <lee@piclab.com>
  12.  *          http://www.piclab.com/piclab/index.html
  13.  */
  14.  
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <stdarg.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <math.h>
  21.  
  22. #include "ptot.h"
  23.  
  24. #if defined(MACOS)    /* RMF needed to set file type and creator */
  25. #include <files.h>
  26. int _Main(int argc, char *argv[]);
  27. #define main _Main
  28. #endif
  29.  
  30. #define DEFINE_ENUMS
  31. #include "errors.h"
  32. #define DEFINE_STRINGS
  33. #include "errors.h"
  34.  
  35. PNG_STATE ps = {0}; /* Referenced by tempfile.c, etc. */
  36.  
  37. char *keyword_table[N_KEYWORDS] = {
  38.     "Author", "Copyright", "Software", "Source", "Title"
  39. };
  40.  
  41. /*
  42.  * Local definitions and statics
  43.  */
  44.  
  45. static int decode_chunk(void);
  46. static int decode_IHDR(void);
  47. static int decode_PLTE(void);
  48. static int decode_gAMA(void);
  49. static int decode_tRNS(void);
  50. static int decode_cHRM(void);
  51. static int decode_pHYs(void);
  52. static int decode_oFFs(void);
  53. static int decode_sCAL(void);
  54. static int skip_chunk_data(void);
  55. static int validate_image(IMG_INFO *);
  56.  
  57. /*
  58.  * Main for PTOT.  Get filename from command line, massage the
  59.  * extensions as necessary, and call the read/write routines.
  60.  */
  61.  
  62. int
  63. main(
  64.     int argc,
  65.     char *argv[])
  66. {
  67.     int err;
  68.     FILE *fp;
  69.     char *cp, infname[FILENAME_MAX], outfname[FILENAME_MAX];
  70.     IMG_INFO *image;
  71.  
  72.     image = (IMG_INFO *)malloc((size_t)IMG_SIZE);
  73.     if (NULL == image) error_exit(ERR_MEMORY);
  74.  
  75.     if (argc < 2) error_exit(ERR_USAGE);
  76.     strcpy(infname, argv[1]);
  77.     strcpy(outfname, argv[1]);
  78.  
  79.     if (NULL == (cp = strrchr(outfname, '.'))) {
  80.         strcat(infname, ".png");
  81.     } else (*cp = '\0');
  82.     strcat(outfname, ".tif");
  83.  
  84.     if (NULL == (fp = fopen(infname, "rb")))
  85.       error_exit(ERR_READ);
  86.     err = read_PNG(fp, image);
  87.     fclose(fp);
  88.     if (0 != err) error_exit(err);
  89.  
  90.     if (NULL == (fp = fopen(outfname, "wb")))
  91.       error_exit(ERR_WRITE);
  92.     err = write_TIFF(fp, image);
  93.     fclose(fp);
  94.         
  95. #if defined(MACOS)    /* RMF needed to set file type and creator */
  96. {        FSSpec spec;
  97.         FInfo        ioFlFndrInfo;
  98.         OSErr err;
  99.         
  100.         c2pstr((char*)outfname);
  101.         FSMakeFSSpec(0, 0, (ConstStr255Param) outfname, &spec);
  102.         err = FSpGetFInfo(&spec, &ioFlFndrInfo);
  103.         if (err == noErr) {
  104.             ioFlFndrInfo.fdCreator = 'JVWR';        // Set the creator or type...
  105.             ioFlFndrInfo.fdType = 'TIFF';
  106.             
  107.             err = FSpSetFInfo(&spec, &ioFlFndrInfo);
  108.             }
  109.         p2cstr((unsigned char *) outfname);
  110.         
  111. }
  112. #endif      
  113.     if (0 != err) error_exit(err);
  114.     return 0;
  115. }
  116.  
  117. /*
  118.  * Print warning, but continue.  A bad code should never be
  119.  * passed here, so that causes an assertion failure and exit.
  120.  */
  121.  
  122. void
  123. print_warning(
  124.     int code)
  125. {
  126.     ASSERT(PTOT_NMESSAGES > 0);
  127.     ASSERT(code >= 0 && code < PTOT_NMESSAGES);
  128.  
  129.     fprintf(stderr, "WARNING: %s.\n", ptot_error_messages[code]);
  130.     fflush(stderr);
  131. }
  132.  
  133. /*
  134.  * Print fatal error and exit.
  135.  */
  136.  
  137. void
  138. error_exit(
  139.     int code)
  140. {
  141.     int msgindex;
  142.  
  143.     ASSERT(PTOT_NMESSAGES > 0);
  144.  
  145.     if (code < 0 || code >= PTOT_NMESSAGES) msgindex = 0;
  146.     else msgindex = code;
  147.  
  148.     fprintf(stderr, "ERROR: %s.\n",
  149.       ptot_error_messages[msgindex]);
  150.     fflush(stderr);
  151.  
  152.     if (0 == code) exit(1);
  153.     else exit(code);
  154. }
  155.  
  156. void
  157. Assert(
  158.     char *filename,
  159.     int lineno)
  160. {
  161.     fprintf(stderr, "ASSERTION FAILURE: "
  162.       "Line %d of file \"%s\".\n", lineno, filename);
  163.     fflush(stderr);
  164.     exit(2);
  165. }
  166.  
  167. /*
  168.  * PNG-specific code begins here.
  169.  *
  170.  * read_PNG() reads the PNG file into the passed IMG_INFO struct.
  171.  * Returns 0 on success.
  172.  */
  173.  
  174. int
  175. read_PNG(
  176.     FILE *inf,
  177.     IMG_INFO *image)
  178. {
  179.     int err;
  180.  
  181.     ASSERT(NULL != inf);
  182.     ASSERT(NULL != image);
  183.  
  184.     memset(image, 0, IMG_SIZE);
  185.     memset(&ps, 0, sizeof ps);
  186.  
  187.     ps.inf = inf;
  188.     ps.image = image;
  189.     if (NULL == (ps.buf = (U8 *)malloc(IOBUF_SIZE)))
  190.       return ERR_MEMORY;
  191.     /*
  192.      * Skip signature and possible MacBinary header, and
  193.      * verify signature. A more robust implementation might
  194.      * search for the file signature anywhere in the first
  195.      * 1k bytes or so, but in practice, the method shown
  196.      * is adequate or file I/O applications.
  197.      */
  198.     fread(ps.buf, 1, 8, inf);
  199.     ps.buf[8] = '\0';
  200.     if (0 != memcmp(ps.buf, PNG_Signature, 8)) {
  201.         fread(ps.buf, 1, 128, inf);
  202.         ps.buf[128] = '\0';
  203.         if (0 != memcmp(ps.buf+120, PNG_Signature, 8)) {
  204.             err = ERR_BAD_PNG;
  205.             goto err_out;
  206.         }
  207.     }
  208.  
  209.     ps.got_first_chunk = ps.got_first_idat = FALSE;
  210.     do {
  211.         if (0 != (err = get_chunk_header())) goto err_out;
  212.         if (0 != (err = decode_chunk())) goto err_out;
  213.         /*
  214.          * IHDR must be the first chunk.
  215.          */
  216.         if (!ps.got_first_chunk &&
  217.           (PNG_CN_IHDR != ps.current_chunk_name))
  218.           print_warning(WARN_BAD_PNG);
  219.         ps.got_first_chunk = TRUE;
  220.         /*
  221.          * Extra unused bytes in chunk?
  222.          */
  223.         if (0 != ps.bytes_remaining) {
  224.             print_warning(WARN_EXTRA_BYTES);
  225.             if (0 != (err = skip_chunk_data())) goto err_out;
  226.         }
  227.         if (0 != (err = verify_chunk_crc())) goto err_out;
  228.  
  229.     } while (PNG_CN_IEND != ps.current_chunk_name);
  230.  
  231.     if (!ps.got_first_idat) {
  232.         err = ERR_NO_IDAT;
  233.         goto err_out;
  234.     }
  235.     if (0 != (err = validate_image(image))) goto err_out;
  236.  
  237.     ASSERT(0 == ps.bytes_remaining);
  238.     if (EOF != getc(inf)) print_warning(WARN_EXTRA_BYTES);
  239.  
  240.     err = 0;
  241. err_out:
  242.     ASSERT(NULL != ps.buf);
  243.     free(ps.buf);
  244.     return err;
  245. }
  246.  
  247. /*
  248.  * decode_chunk() is just a dispatcher, shunting the work of
  249.  * decoding the incoming chunk (whose header we have just read)
  250.  * to the appropriate handler.
  251.  */
  252.  
  253. static int
  254. decode_chunk(
  255.     void)
  256. {
  257.     /*
  258.      * Every case in the switch below should set err. We set it
  259.      * here to gurantee that we hear about it if we don't.
  260.      */
  261.     int err = ERR_ASSERT;
  262.  
  263.     switch (ps.current_chunk_name) {
  264.  
  265.     case PNG_CN_IHDR:   err = decode_IHDR();    break;
  266.     case PNG_CN_gAMA:   err = decode_gAMA();    break;
  267.     case PNG_CN_IDAT:   err = decode_IDAT();    break;
  268.     /*
  269.      * PNG allows a suggested colormap for 24-bit images. TIFF
  270.      * does not, and PLTE is not copy-safe, so we discard it.
  271.      */
  272.     case PNG_CN_PLTE:
  273.         if (ps.image->is_palette) err = decode_PLTE();
  274.         else err = skip_chunk_data();
  275.         break;
  276.  
  277.     case PNG_CN_tRNS:   err = decode_tRNS();    break;
  278.     case PNG_CN_cHRM:   err = decode_cHRM();    break;
  279.     case PNG_CN_pHYs:   err = decode_pHYs();    break;
  280.     case PNG_CN_oFFs:   err = decode_oFFs();    break;
  281.     case PNG_CN_sCAL:   err = decode_sCAL();    break;
  282.  
  283.     case PNG_CN_tEXt:   err = decode_text();    break;
  284.     case PNG_CN_zTXt:   err = decode_text();    break;
  285.  
  286.     case PNG_CN_tIME:   /* Will be recreated */
  287.     case PNG_CN_hIST:   /* Not safe to copy */
  288.     case PNG_CN_bKGD:
  289.         err = skip_chunk_data();
  290.         break;
  291.     case PNG_CN_IEND:   /* We're done */
  292.         err = 0;
  293.         break;
  294.     /*
  295.      * Note: sBIT does not have the "copy-safe" bit set, but that
  296.      * really only applies to unknown chunks. We know what it is
  297.      * just like PLTE, and that it's probably safe to put in the
  298.      * output file. hIST and bKGD are not (modifications to the
  299.      * output file might invalidate them), so we leave them out.
  300.      */
  301.     case PNG_CN_sBIT:
  302.         err = copy_unknown_chunk_data();
  303.         break;
  304.     default:
  305.         if (0 == (ps.current_chunk_name & PNG_CF_CopySafe))
  306.           err = skip_chunk_data();
  307.         else err = copy_unknown_chunk_data();
  308.         break;
  309.     }
  310.     return err;
  311. }
  312.  
  313. /*
  314.  * get_chunk_header() reads the first 8 bytes of each chunk, which
  315.  * include the length and ID fields.  It returns 0 on success.
  316.  * The crc argument is preconditioned and then updated with the
  317.  * chunk name read.
  318.  */
  319.  
  320. int
  321. get_chunk_header(
  322.     void)
  323. {
  324.     int byte;
  325.  
  326.     ASSERT(NULL != ps.inf);
  327.     ASSERT(NULL != ps.buf);
  328.  
  329.     if (8 != fread(ps.buf, 1, 8, ps.inf)) return ERR_READ;
  330.  
  331.     ps.bytes_remaining = BE_GET32(ps.buf);
  332.     ps.current_chunk_name= BE_GET32(ps.buf+4);
  333.     ps.bytes_in_buf = 0;
  334.  
  335.     if (ps.bytes_remaining > PNG_MaxChunkLength)
  336.       print_warning(WARN_BAD_PNG);
  337.  
  338.     for (byte = 4; byte < 8; ++byte)
  339.       if (!isalpha(ps.buf[byte])) return ERR_BAD_PNG;
  340.  
  341.     ps.crc = update_crc(0xFFFFFFFFL, ps.buf+4, 4);
  342.     return 0;
  343. }
  344.  
  345. /*
  346.  * get_chunk_data() reads chunk data into the buffer,
  347.  * returning the number of bytes actually read.  Do not
  348.  * use this for IDAT chunks; they are dealt with specially
  349.  * by the fill_buf() function.
  350.  */
  351.  
  352. U32
  353. get_chunk_data(
  354.     U32 bytes_requested)
  355. {
  356.     ASSERT(NULL != ps.inf);
  357.     ASSERT(NULL != ps.buf);
  358.  
  359.     ps.bytes_in_buf = (U32)fread(ps.buf, 1,
  360.       (size_t)min(IOBUF_SIZE, bytes_requested), ps.inf);
  361.  
  362.     ASSERT((S32)(ps.bytes_remaining) >= ps.bytes_in_buf);
  363.     ps.bytes_remaining -= ps.bytes_in_buf;
  364.  
  365.     ps.crc = update_crc(ps.crc, ps.buf, ps.bytes_in_buf);
  366.     return ps.bytes_in_buf;
  367. }
  368.  
  369. /*
  370.  * Assuming we have read a chunk header and all the chunk data,
  371.  * we now check to see that the CRC stored at the end of the
  372.  * chunk matches the one we've calculated.
  373.  */
  374.  
  375. int
  376. verify_chunk_crc(
  377.     void)
  378. {
  379.     ASSERT(NULL != ps.inf);
  380.     ASSERT(NULL != ps.buf);
  381.  
  382.     if (4 != fread(ps.buf, 1, 4, ps.inf)) return ERR_READ;
  383.  
  384.     if ((ps.crc ^ 0xFFFFFFFFL) != BE_GET32(ps.buf)) {
  385.         print_warning(WARN_BAD_CRC);
  386.     }
  387.     return 0;
  388. }
  389.  
  390. /*
  391.  * Read and decode IHDR. Errors that would probably cause the
  392.  * IDAT reader to fail are returned as errors; less serious
  393.  * errors generate a warning but continue anyway.
  394.  */
  395.  
  396. static int
  397. decode_IHDR(
  398.     void)
  399. {
  400.     ASSERT(NULL != ps.inf);
  401.     ASSERT(NULL != ps.buf);
  402.     ASSERT(NULL != ps.image);
  403.  
  404.     if (ps.bytes_remaining < 13) return ERR_BAD_PNG;
  405.     if (13 != get_chunk_data(13)) return ERR_READ;
  406.  
  407.     ps.image->width = BE_GET32(ps.buf);
  408.     ps.image->height = BE_GET32(ps.buf+4);
  409.  
  410.     if (0 != ps.buf[10] || 0 != ps.buf[11])
  411.       return ERR_BAD_PNG;   /* Compression & filter type */
  412.  
  413.     ps.image->is_interlaced = ps.buf[12];
  414.     if (!(0 == ps.image->is_interlaced ||
  415.       1 == ps.image->is_interlaced)) return ERR_BAD_PNG;
  416.  
  417.     ps.image->is_color = (0 != (ps.buf[9] & PNG_CB_Color));
  418.     ps.image->is_palette = (0 != (ps.buf[9] & PNG_CB_Palette));
  419.     ps.image->has_alpha = (0 != (ps.buf[9] & PNG_CB_Alpha));
  420.  
  421.     ps.image->samples_per_pixel = 1;
  422.     if (ps.image->is_color && !ps.image->is_palette)
  423.       ps.image->samples_per_pixel = 3;
  424.     if (ps.image->has_alpha) ++ps.image->samples_per_pixel;
  425.  
  426.     if (ps.image->is_palette && ps.image->has_alpha)
  427.       print_warning(WARN_BAD_PNG);
  428.     /*
  429.      * Check for invalid bit depths.  If a bitdepth is
  430.      * not one we can read, abort processing.  If we can
  431.      * read it, but it is illegal, issue a warning and
  432.      * continue anyway.
  433.      */
  434.     ps.image->bits_per_sample = ps.buf[8];
  435.  
  436.     if (!(1 == ps.buf[8] || 2 == ps.buf[8] || 4 == ps.buf[8] ||
  437.       8 == ps.buf[8] || 16 == ps.buf[8])) return ERR_BAD_PNG;
  438.  
  439.     if ((ps.buf[8] > 8) && ps.image->is_palette)
  440.       print_warning(WARN_BAD_PNG);
  441.  
  442.     if ((ps.buf[8] < 8) && (2 == ps.buf[9] || 4 == ps.buf[9] ||
  443.       6 == ps.buf[9])) return ERR_BAD_PNG;
  444.  
  445.     return 0;
  446. }
  447.  
  448. /*
  449.  * Decode gAMA chunk.
  450.  */
  451.  
  452. static int
  453. decode_gAMA(
  454.     void)
  455. {
  456.     ASSERT(NULL != ps.inf);
  457.     ASSERT(NULL != ps.buf);
  458.     ASSERT(NULL != ps.image);
  459.  
  460.     if (0 != ps.image->palette_size)
  461.       print_warning(WARN_LATE_GAMA);
  462.  
  463.     if (ps.bytes_remaining < 4) return ERR_BAD_PNG;
  464.     if (4 != get_chunk_data(4)) return ERR_READ;
  465.  
  466.     ps.image->source_gamma = (double)BE_GET32(ps.buf) / 100000.0;
  467.     return 0;
  468. }
  469.  
  470. /*
  471.  * Decode PLTE chunk. Number of entries is determined by
  472.  * chunk length. A non-multiple of 3 is technically an error;
  473.  * we just issue a warning in that case. IOBUF_SIZE must be
  474.  * 768 or greater, so we check that at compile time here.
  475.  */
  476.  
  477. #if (IOBUF_SIZE < 768)
  478. #  error "IOBUF_SIZE must be >= 768"
  479. #endif
  480.  
  481. static int
  482. decode_PLTE(
  483.     void)
  484. {
  485.     U32 bytes_read;
  486.  
  487.     ASSERT(NULL != ps.inf);
  488.     ASSERT(NULL != ps.buf);
  489.     ASSERT(NULL != ps.image);
  490.  
  491.     if (!ps.image->is_color) print_warning(WARN_PLTE_GRAY);
  492.     if (0 != ps.image->palette_size) {
  493.         print_warning(WARN_MULTI_PLTE);
  494.         return skip_chunk_data();
  495.     }
  496.     ps.image->palette_size =
  497.       min(256, (int)(ps.bytes_remaining / 3));
  498.     if (0 == ps.image->palette_size) return ERR_BAD_PNG;
  499.  
  500.     bytes_read = get_chunk_data(3 * ps.image->palette_size);
  501.     if (bytes_read < (U32)(3 * ps.image->palette_size))
  502.       return ERR_READ;
  503.  
  504.     memcpy(ps.image->palette, ps.buf, 3 * ps.image->palette_size);
  505.  
  506.     ASSERT(0 != ps.image->palette_size);
  507.     return 0;
  508. }
  509.  
  510. /*
  511.  * Copy transparency data into structure. We will later expand the
  512.  * TIFF data into full alpha to account for its lack of this data.
  513.  */
  514.  
  515. static int
  516. decode_tRNS(
  517.     void)
  518. {
  519.     int i;
  520.     U32 bytes_read;
  521.  
  522.     ASSERT(NULL != ps.inf);
  523.     ASSERT(NULL != ps.buf);
  524.     ASSERT(NULL != ps.image);
  525.  
  526.     if (ps.image->has_trns) print_warning(WARN_MULTI_TRNS);
  527.     ps.image->has_trns = TRUE;
  528.  
  529.     if (ps.image->is_palette) {
  530.         if (0 == ps.image->palette_size) {
  531.             print_warning(WARN_LATE_TRNS);
  532.         }
  533.         bytes_read = get_chunk_data(ps.bytes_remaining);
  534.         memcpy(ps.image->palette_trans_bytes,
  535.           ps.buf, (size_t)bytes_read);
  536.  
  537.         for (i = bytes_read; i < ps.image->palette_size; ++i)
  538.           ps.image->palette_trans_bytes[i] = 255;
  539.  
  540.     } else if (ps.image->is_color) {
  541.         if (ps.bytes_remaining < 6) return ERR_BAD_PNG;
  542.         bytes_read = get_chunk_data(6);
  543.         for (i = 0; i < 3; ++i)
  544.           ps.image->trans_values[i] = BE_GET16(ps.buf + 2 * i);
  545.     } else {
  546.         if (ps.bytes_remaining < 2) return ERR_BAD_PNG;
  547.         ps.image->trans_values[0] = BE_GET16(ps.buf);
  548.     }
  549.     return 0;
  550. }
  551.  
  552. static int
  553. decode_cHRM(
  554.     void)
  555. {
  556.     int i;
  557.  
  558.     ASSERT(NULL != ps.inf);
  559.     ASSERT(NULL != ps.buf);
  560.     ASSERT(NULL != ps.image);
  561.  
  562.     if (ps.bytes_remaining < 32) return ERR_BAD_PNG;
  563.     if (32 != get_chunk_data(32)) return ERR_READ;
  564.  
  565.     for (i = 0; i < 8; ++i)
  566.       ps.image->chromaticities[i] = BE_GET32(ps.buf + 4 * i);
  567.  
  568.     return 0;
  569. }
  570.  
  571. static int
  572. decode_pHYs(
  573.     void)
  574. {
  575.     ASSERT(NULL != ps.inf);
  576.     ASSERT(NULL != ps.buf);
  577.     ASSERT(NULL != ps.image);
  578.  
  579.     if (ps.bytes_remaining < 9) return ERR_BAD_PNG;
  580.     if (9 != get_chunk_data(9)) return ERR_READ;
  581.  
  582.     ps.image->resolution_unit = ps.buf[8];
  583.     if (ps.buf[8] > PNG_MU_Meter) print_warning(WARN_BAD_VAL);
  584.  
  585.     ps.image->xres = BE_GET32(ps.buf);
  586.     ps.image->yres = BE_GET32(ps.buf + 4);
  587.  
  588.     return 0;
  589. }
  590.  
  591. static int
  592. decode_oFFs(
  593.     void)
  594. {
  595.     ASSERT(NULL != ps.inf);
  596.     ASSERT(NULL != ps.buf);
  597.     ASSERT(NULL != ps.image);
  598.  
  599.     if (ps.bytes_remaining < 9) return ERR_BAD_PNG;
  600.     if (9 != get_chunk_data(9)) return ERR_READ;
  601.  
  602.     ps.image->offset_unit = ps.buf[8];
  603.     if (ps.buf[8] > PNG_MU_Micrometer) print_warning(WARN_BAD_VAL);
  604.  
  605.     ps.image->xoffset = BE_GET32(ps.buf);
  606.     ps.image->yoffset = BE_GET32(ps.buf + 4);
  607.  
  608.     return 0;
  609. }
  610.  
  611. /*
  612.  * Decode sCAL chunk. Note: as of this writing, this is not
  613.  * an official PNG chunk. It probably will be by the time
  614.  * you read this, but it might possibly change in some way.
  615.  * You have been warned. It also has no TIFF equivalent, so
  616.  * this only gets read into the structure.
  617.  */
  618.  
  619. static int
  620. decode_sCAL(
  621.     void)
  622. {
  623.     ASSERT(NULL != ps.inf);
  624.     ASSERT(NULL != ps.buf);
  625.     ASSERT(NULL != ps.image);
  626.  
  627.     get_chunk_data(ps.bytes_remaining);
  628.     if (ps.bytes_in_buf == IOBUF_SIZE) {
  629.         --ps.bytes_in_buf;
  630.         print_warning(WARN_BAD_PNG);
  631.     }
  632.     ps.buf[ps.bytes_in_buf] = '\0';
  633.  
  634.     ps.image->scale_unit = ps.buf[0];
  635.     if (ps.buf[0] < PNG_MU_Meter || ps.buf[0] > PNG_MU_Radian)
  636.       print_warning(WARN_BAD_VAL);
  637.  
  638.     ps.image->xscale = atof((char *)ps.buf+1);
  639.     ps.image->yscale = atof((char *)ps.buf + (strlen((char *)ps.buf+1)) + 2);
  640.  
  641.     return 0;
  642. }
  643.  
  644. /*
  645.  * Skip all remaining data in current chunk.
  646.  */
  647.  
  648. static int
  649. skip_chunk_data(
  650.     void)
  651. {
  652.     U32 bytes_read;
  653.  
  654.     do {
  655.         bytes_read = get_chunk_data(ps.bytes_remaining);
  656.     } while (0 != bytes_read);
  657.  
  658.     return 0;
  659. }
  660.  
  661. /*
  662.  * Ensure that the image structure we have created by reading
  663.  * the input PNG is compatible with whatever we intend to do
  664.  * with it. In this case, TIFF can handle anything, so we just
  665.  * use this as a sanity check on some basic assumptions.
  666.  */
  667.  
  668. static int
  669. validate_image(
  670.     IMG_INFO *image)
  671. {
  672.     if (0 == image->width || 0 == image->height)
  673.       return ERR_BAD_IMAGE;
  674.     if (image->samples_per_pixel < 1 ||
  675.       image->samples_per_pixel > 4) return ERR_BAD_IMAGE;
  676.     if (image->is_palette && (image->palette_size < 1 ||
  677.       image->palette_size > 256)) return ERR_BAD_IMAGE;
  678.     if (NULL == image->pixel_data_file) return ERR_BAD_IMAGE;
  679.  
  680.     return 0;
  681. }
  682.  
  683. /*
  684.  * End of ptot.c.
  685.  */
  686.