home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 13 / AACD13.ISO / AACD / Graphics / PPT / pluginsrc / ppm / ppm.c next >
C/C++ Source or Header  |  2000-01-04  |  12KB  |  543 lines

  1. /*
  2.     PROJECT: ppt
  3.     MODULE : Loaders/ppm
  4.  
  5.     PPT and this file are (C) Janne Jalkanen 1998.
  6.  
  7.     $Id: ppm.c,v 3.0 2000/01/04 21:36:32 jj Exp jj $
  8. */
  9.  
  10.  
  11. #include <exec/memory.h>
  12.  
  13. #include "ppm.h"
  14.  
  15. #include <stdlib.h>
  16. #include <string.h>
  17.  
  18. /*------------------------------------------------------------------*/
  19.  
  20. #define MYNAME          "PPM"
  21.  
  22. /*------------------------------------------------------------------*/
  23.  
  24. /*------------------------------------------------------------------*/
  25.  
  26. const char infoblurb[] = "Loads PPM/PGM images (P2,P3,P5 and P6)\n"
  27.                          "Saves PPM/PGM images of type P5 and P6\n";
  28.  
  29. #pragma msg 186 ignore
  30.  
  31. const struct TagItem MyTagArray[] = {
  32.     PPTX_Load,              TRUE,
  33.     PPTX_ColorSpaces,       CSF_RGB|CSF_GRAYLEVEL,
  34.  
  35.     PPTX_Name,              MYNAME,
  36.     PPTX_Author,            "Janne Jalkanen, 1995-1998",
  37.     PPTX_InfoTxt,           infoblurb,
  38.     PPTX_ReqPPTVersion,     3,
  39.  
  40.     PPTX_RexxTemplate,      "",
  41.  
  42.     PPTX_PreferredPostFix,  ".ppm",
  43.     PPTX_PostFixPattern,    "#?.(ppm|pgm|pnm)",
  44.  
  45.     PPTX_SupportsGetArgs,   TRUE,
  46.  
  47.     TAG_DONE
  48. };
  49.  
  50. #if defined( __GNUC__ )
  51. const BYTE LibName[]="ppm.iomod";
  52. const BYTE LibIdString[]="ppm.iomod 1.0";
  53. const UWORD LibVersion=1;
  54. const UWORD LibRevision=0;
  55. ADD2LIST(LIBIOInquire,__FuncTable__,22);
  56. ADD2LIST(LIBIOCheck,__FuncTable__,22);
  57. ADD2LIST(LIBIOLoad,__FuncTable__,22);
  58. ADD2LIST(LIBIOSave,__FuncTable__,22);
  59. /* The following two definitions are only required
  60.    if you link with libinitr */
  61. ADD2LIST(LIBIOInquire,__LibTable__,22);
  62. ADD2LIST(LIBIOCheck,__LibTable__,22);
  63. ADD2LIST(LIBIOLoad,__LibTable__,22);
  64. ADD2LIST(LIBIOSave,__LibTable__,22);
  65.  
  66. /* Make GNU C specific declarations. __UtilityBase is
  67.    required for the libnix integer multiplication */
  68. struct ExecBase *SysBase = NULL;
  69. struct Library *__UtilityBase = NULL;
  70. #endif
  71.  
  72. /*------------------------------------------------------------------*/
  73.  
  74. #ifdef __SASC
  75. /* Disable SAS/C control-c handling. */
  76. void __regargs __chkabort(void) {}
  77. void __regargs _CXBRK(void) {}
  78. #endif
  79.  
  80. LIBINIT
  81. {
  82. #if defined(__GNUC__)
  83.     SysBase = SYSBASE();
  84.  
  85.     if( NULL == (__UtilityBase = OpenLibrary("utility.library",37L))) {
  86.         return 1L;
  87.     }
  88.  
  89. #endif
  90.     return 0;
  91. }
  92.  
  93.  
  94. LIBCLEANUP
  95. {
  96. #if defined(__GNUC__)
  97.     if( __UtilityBase ) CloseLibrary(__UtilityBase);
  98. #endif
  99. }
  100.  
  101.  
  102. /*
  103.     Eats away all whitespaces, returning the beginning of the next string
  104. */
  105. UBYTE *NextChar( UBYTE *string )
  106. {
  107.     UBYTE *s = string;
  108.  
  109.     while(*s == ' ' || *s == '\t') s++;
  110.  
  111.     return s;
  112. }
  113.  
  114. UBYTE *NextEmpty( UBYTE *string )
  115. {
  116.     UBYTE *s = string;
  117.  
  118.     while( *s != ' ' && *s != '\t') s++;
  119.  
  120.     return s;
  121. }
  122.  
  123. UBYTE *NextItem( UBYTE *string )
  124. {
  125.     UBYTE *s = string;
  126.  
  127.     s = NextEmpty( s );
  128.     s = NextChar( s );
  129.  
  130.     return s;
  131. }
  132.  
  133.  
  134.  
  135. /*
  136.     Read one number, ignoring comments and whitespaces.
  137.  
  138.     Returns -1 on EOF, -2 on error.
  139. */
  140. LONG ReadNextNumber( struct PPTBase *PPTBase, BPTR fh )
  141. {
  142.     LONG ch, val;
  143.     APTR DOSBase = PPTBase->lb_DOS;
  144.  
  145.     /*
  146.      *  Skip whitespaces & newlines
  147.      */
  148.     do {
  149.         ch = FGetC( fh );
  150.     } while( ch == ' ' || ch == '\t' || ch == '\n' );
  151.  
  152.     /*
  153.      *  If comment, read until the end of line.
  154.      */
  155.  
  156.     if( ch == '#' ) {
  157.         do {
  158.             ch = FGetC( fh );
  159.         } while (ch != '\n' && ch != -1);
  160.     }
  161.  
  162.     /*
  163.      *  Is this EOF?
  164.      */
  165.  
  166.     if( ch == EOF )
  167.         return -1;
  168.  
  169.     /*
  170.      *  Read the number.
  171.      */
  172.  
  173.     if( ch < '0' || ch > '9' ) return -2; /* File read error */
  174.  
  175.     val = ch - '0';
  176.  
  177.     while( (ch = FGetC( fh )) >= '0' && ch <= '9' ) {
  178.         val *= 10;
  179.         val += ch - '0';
  180.     }
  181.  
  182.     return val;
  183. }
  184.  
  185. /* Read ASCII RGB data */
  186. PERROR Read_P3_Row( struct PPTBase *PPTBase, ROWPTR dest, UBYTE *scale, UWORD width, BPTR fh )
  187. {
  188.     ROWPTR ds = dest;
  189.     UWORD ccol = 0;
  190.  
  191.     width *= 3;
  192.  
  193.     while( ccol < width ) {
  194.         LONG val;
  195.  
  196.         val = ReadNextNumber( PPTBase, fh );
  197.         if( val < 0 ) return PERR_FILEREAD;
  198.         *ds++ = (UBYTE) val;
  199.         ccol++;
  200.     }
  201.  
  202.     return PERR_OK;
  203. }
  204.  
  205. /* Read ASCII GRAY data */
  206. PERROR Read_P2_Row( struct PPTBase *PPTBase, ROWPTR dest, UBYTE *scale, UWORD width, BPTR fh )
  207. {
  208.     ROWPTR ds = dest;
  209.     UWORD ccol = 0;
  210.  
  211.     while( ccol < width ) {
  212.         LONG val;
  213.  
  214.         val = ReadNextNumber( PPTBase, fh );
  215.         if( val < 0 ) return PERR_FILEREAD;
  216.         *ds++ = (UBYTE) val;
  217.         ccol++;
  218.     }
  219.  
  220.     return PERR_OK;
  221. }
  222.  
  223.  
  224. /*
  225.     RAW RGB data
  226. */
  227. PERROR Read_P6_Row( struct PPTBase *PPTBase, ROWPTR dest, UBYTE *scale, UWORD width, BPTR fh )
  228. {
  229.     APTR DOSBase = PPTBase->lb_DOS;
  230.     UWORD ccol = 0;
  231.     ROWPTR ds = dest;
  232.  
  233.     width *= 3; /* Make it in bytes */
  234.  
  235.     while( ccol < width ) {
  236.         LONG val;
  237.  
  238.         val = FGetC( fh );
  239.         if( val == -1 )
  240.             return PERR_FILEREAD;
  241.         *ds++ = (UBYTE) val;
  242.         ccol++;
  243.     }
  244.     return PERR_OK;
  245. }
  246.  
  247. /*
  248.     RAW GRAY data
  249. */
  250. PERROR Read_P5_Row( struct PPTBase *PPTBase, ROWPTR dest, UBYTE *scale, UWORD width, BPTR fh )
  251. {
  252.     APTR DOSBase = PPTBase->lb_DOS;
  253.     UWORD ccol = 0;
  254.     ROWPTR ds = dest;
  255.  
  256.     while( ccol < width ) {
  257.         LONG val;
  258.  
  259.         val = FGetC( fh );
  260.         if( val == -1 )
  261.             return PERR_FILEREAD;
  262.         *ds++ = (UBYTE) val;
  263.         ccol++;
  264.     }
  265.     return PERR_OK;
  266. }
  267.  
  268. UBYTE *MakeScaleTable( LONG maxval, struct PPTBase *PPTBase )
  269. {
  270.     UBYTE *buffer;
  271.     APTR SysBase = PPTBase->lb_Sys;
  272.     LONG i, mv2 = maxval >> 1;
  273.  
  274.     buffer = AllocVec( maxval+1, MEMF_CLEAR );
  275.     if(!buffer) return NULL;
  276.  
  277.     for( i = 0; i <= maxval; i++ ) {
  278.         buffer[i] = (i * 255 + mv2) / maxval;
  279.     }
  280.  
  281.     return buffer;
  282. }
  283.  
  284. VOID FreeScaleTable( UBYTE *st, struct PPTBase *PPTBase )
  285. {
  286.     APTR SysBase = PPTBase->lb_Sys;
  287.  
  288.     FreeVec( st );
  289. }
  290.  
  291. IOINQUIRE(attr,PPTBase,IOModuleBase)
  292. {
  293.     return TagData( attr, MyTagArray );
  294. }
  295.  
  296. IOLOAD(fh,frame,tags,PPTBase,IOModuleBase)
  297. {
  298.     struct Library *DOSBase = PPTBase->lb_DOS;
  299.     UWORD height, width, crow = 0;
  300.     UBYTE msg[80], type, buf[BUFFERSIZE+1], *s;
  301.     ULONG maxval;
  302.     PERROR res = PERR_OK;
  303.     UBYTE *typestr, id, *scaletable = NULL;
  304.     PERROR (*ReadRow)( struct PPTBase *, ROWPTR, UBYTE *, UWORD, BPTR );
  305.  
  306.  
  307.     // PDebug(MYNAME" : Load()\n");
  308.  
  309.     /*
  310.      *  Recognize file type
  311.      */
  312.  
  313.     FGets( fh, buf, BUFFERSIZE );
  314.  
  315.     // PDebug(" ID: %s\n",buf );
  316.  
  317.     if( buf[0] != 'P' ) {
  318.         SetErrorMsg( frame, "This is not a PPM file!" );
  319.         return PERR_FAILED;
  320.     }
  321.  
  322.     id = buf[1];
  323.  
  324.     /*
  325.      *  Get picture size
  326.      */
  327.  
  328.     FGets( fh, buf, BUFFERSIZE );
  329.  
  330.     s = NextChar( buf );
  331.     width = atol(s);
  332.     s = NextItem( s );
  333.     height = atol(s);
  334.  
  335.     /*
  336.      *  Maximum value
  337.      */
  338.  
  339.     FGets( fh, buf, BUFFERSIZE );
  340.     s = NextChar( buf );
  341.     maxval = atol(s);
  342.  
  343.     /*
  344.      *  Initialize frame
  345.      */
  346.  
  347.     frame->pix->height = height;
  348.     frame->pix->width = width;
  349.  
  350.     switch( id ) {
  351.         case '6': /* P6 = RAW RGB data */
  352.             frame->pix->components = 3;
  353.             frame->pix->origdepth = 24;
  354.             frame->pix->colorspace = CS_RGB;
  355.             type = PPM_P6;
  356.             typestr = "P6";
  357.             ReadRow = Read_P6_Row;
  358.             break;
  359.  
  360.         case '3': /* P3 = ASCII RGB data */
  361.             frame->pix->components = 3;
  362.             frame->pix->origdepth = 24;
  363.             frame->pix->colorspace = CS_RGB;
  364.             type = PPM_P3;
  365.             typestr = "P3";
  366.             ReadRow = Read_P3_Row;
  367.             scaletable = MakeScaleTable( maxval, PPTBase );
  368.             if(!scaletable) {
  369.                 SetErrorCode( frame, PERR_OUTOFMEMORY );
  370.                 return PERR_ERROR;
  371.             }
  372.             break;
  373.  
  374.         case '5': /* P5 = RAW GRAY data */
  375.             frame->pix->components = 1;
  376.             frame->pix->origdepth = 8;
  377.             frame->pix->colorspace = CS_GRAYLEVEL;
  378.             type = PPM_P5;
  379.             typestr = "P5";
  380.             ReadRow = Read_P5_Row;
  381.             break;
  382.  
  383.         case '2': /* P2 = ASCII GRAY data */
  384.             frame->pix->components = 1;
  385.             frame->pix->origdepth = 8;
  386.             frame->pix->colorspace = CS_GRAYLEVEL;
  387.             type = PPM_P2;
  388.             typestr = "P2";
  389.             ReadRow = Read_P2_Row;
  390.             scaletable = MakeScaleTable( maxval, PPTBase );
  391.             if(!scaletable) {
  392.                 SetErrorCode( frame, PERR_OUTOFMEMORY );
  393.                 return PERR_ERROR;
  394.             }
  395.             break;
  396.  
  397.         default:
  398.             SetErrorCode( frame, PERR_UNKNOWNTYPE );
  399.             return PERR_FAILED;
  400.     }
  401.  
  402.     if( maxval > 255  && (type == PPM_P6 || type == PPM_P5)  ) {
  403.         SetErrorMsg( frame, "Illegal P5/P6 maximum value" );
  404.         return PERR_FAILED;
  405.     }
  406.  
  407.     // PDebug(" Height=%d, Width=%d, Maxval = %d\n",height,width,maxval );
  408.  
  409.     sprintf(msg,"Loading PPM (%s) picture...", typestr );
  410.  
  411.     InitProgress( frame, msg, 0, height );
  412.  
  413.     if(InitFrame( frame ) != PERR_OK) {
  414.         /* Do clean up */
  415.         return PERR_FAILED;
  416.     }
  417.  
  418.     while( crow < height ) {
  419.         ROWPTR cp;
  420.  
  421.         if(Progress(frame, (ULONG)crow)) {
  422.             SetErrorCode( frame, PERR_BREAK );
  423.             res = PERR_FAILED;
  424.             break;
  425.         }
  426.  
  427.         cp = GetPixelRow( frame, crow );
  428.  
  429.         /*
  430.          *  Get the actual row of pixels, then decompress it into cp
  431.          */
  432.  
  433.         res = (*ReadRow)( PPTBase, cp, NULL, width, fh );
  434.  
  435.         if(res != PERR_OK) {
  436.             SetErrorCode( frame, res );
  437.             res = PERR_FAILED;
  438.             goto errorexit;
  439.         }
  440.  
  441.         PutPixelRow( frame, crow, cp );
  442.  
  443.         crow++;
  444.  
  445.     } /* while */
  446.  
  447.     FinishProgress( frame );
  448.  
  449. errorexit:
  450.     /*
  451.      *  Release allocated resources
  452.      */
  453.  
  454.     if( scaletable ) FreeScaleTable( scaletable, PPTBase );
  455.  
  456.     return res;
  457. }
  458.  
  459. /*
  460.     The save routine is actually quite easy. All we currently do is decide whether
  461.     to write GRAY or RGB data, since we don't know how to deal with ASCII files yet.
  462. */
  463. IOSAVE(fh,format,frame,tags,PPTBase,IOModuleBase)
  464. {
  465.     UWORD height = frame->pix->height, width = frame->pix->width;
  466.     UBYTE buf[80];
  467.     APTR DOSBase = PPTBase->lb_DOS;
  468.     UWORD crow = 0;
  469.     LONG bpr = frame->pix->bytes_per_row;
  470.     PERROR res = PERR_OK;
  471.  
  472.     if( format & (CSF_LUT|CSF_ARGB) )
  473.         return PERR_UNKNOWNTYPE;
  474.  
  475.     InitProgress( frame, "Saving PPM/PGM image...", 0, height );
  476.  
  477.     /*
  478.      *  Write header info.
  479.      */
  480.  
  481.     sprintf(buf, "%s\n%lu %lu\n%lu\n",
  482.                  (frame->pix->colorspace == CS_RGB) ? "P6" : "P5",
  483.                  width, height,
  484.                  255 ); /* Default maxval. BUG: Might fail on future versions of ppt */
  485.  
  486.     FPuts( fh, buf );
  487.  
  488.     /*
  489.      *  Write the actual data.
  490.      */
  491.  
  492.     while( crow < height ) {
  493.         ROWPTR cp;
  494.         UWORD ccol;
  495.  
  496.         if(Progress( frame, (ULONG)crow )) {
  497.             SetErrorCode( frame, PERR_BREAK );
  498.             res = PERR_FAILED;
  499.             goto errorexit;
  500.         }
  501.  
  502.         cp = GetPixelRow( frame, crow );
  503.  
  504.         for( ccol = 0; ccol < bpr; ccol++ ) {
  505.             if(FPutC( fh, (LONG) *cp++ ) == EOF) {
  506.                 SetErrorCode( frame, PERR_FILEWRITE );
  507.                 res = PERR_FAILED;
  508.                 goto errorexit;
  509.             }
  510.         }
  511.         crow++;
  512.     }
  513.     FinishProgress( frame );
  514.  
  515. errorexit:
  516.  
  517.     return res;
  518. }
  519.  
  520. IOCHECK(fh,len,buf,PPTBase,IOModuleBase)
  521. {
  522.     // PDebug(MYNAME": Check()\n");
  523.  
  524.     /*
  525.      *  Read bytes from file, then return TRUE if we can handle this
  526.      *  type of file. If two first bytes from the file are P3, P2, P5 or P6
  527.      *  this is a PPM/PGM file.
  528.      */
  529.  
  530.     if( buf[0] == 'P' && ( buf[1] == '5' || buf[1] == '6' || buf[1] == '3' || buf[1] == '2' ) )
  531.         return TRUE;
  532.  
  533.     return FALSE;
  534. }
  535.  
  536. IOGETARGS(format,frame,tags,PPTBase,IOModuleBase)
  537. {
  538.     return PERR_OK;
  539. }
  540.  
  541.  
  542.  
  543.