home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / ppm / ppmtotga.c < prev    next >
C/C++ Source or Header  |  1993-10-04  |  11KB  |  454 lines

  1. /* ppmtotga.c - read a portable pixmap and produce a TrueVision Targa file
  2. **
  3. ** Copyright (C) 1989, 1991 by Mark Shand and Jef Poskanzer
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include "ppm.h"
  14. #include "ppmcmap.h"
  15. #include "tga.h"
  16.  
  17. /* Max number of colors allowed for colormapped output. */
  18. #define MAXCOLORS 256
  19.  
  20. /* Forward routines. */
  21. static void writetga ARGS(( struct ImageHeader* tgaP, char* id ));
  22. static void put_map_entry ARGS(( pixel* valueP, int size, pixval maxval ));
  23. static void compute_runlengths ARGS(( int cols, pixel* pixelrow, int* runlength ));
  24. static void put_pixel ARGS(( pixel* pP, int imgtype, pixval maxval, colorhash_table cht ));
  25. static void put_mono ARGS(( pixel* pP, pixval maxval ));
  26. static void put_map ARGS(( pixel* pP, colorhash_table cht ));
  27. static void put_rgb ARGS(( pixel* pP, pixval maxval ));
  28.  
  29. /* Routines. */
  30.  
  31. int
  32. main( argc, argv )
  33.     int argc;
  34.     char* argv[];
  35.     {
  36.     FILE* ifp;
  37.     pixel** pixels;
  38.     register pixel* pP;
  39.     pixel p;
  40.     int argn, rle_flag, rows, cols, ncolors, row, col, i, format, realrow;
  41.     pixval maxval;
  42.     colorhist_vector chv;
  43.     colorhash_table cht;
  44.     char out_name[100];
  45.     char* cp;
  46.     int* runlength;
  47.     char* usage = "[-name <tganame>] [-mono|-cmap|-rgb] [-norle] [ppmfile]";
  48.     struct ImageHeader tgaHeader;
  49.  
  50.  
  51.     ppm_init( &argc, argv );
  52.     out_name[0] = '\0';
  53.  
  54.     /* Check for command line options. */
  55.     argn = 1;
  56.     tgaHeader.ImgType = TGA_Null;
  57.     rle_flag = 1;
  58.     /* Check for command line options. */
  59.     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
  60.         {
  61.         if ( pm_keymatch( argv[argn], "-name", 2 ) )
  62.             {
  63.             ++argn;
  64.             if ( argn == argc )
  65.             pm_usage( usage );
  66.             (void) strcpy( out_name, argv[argn] );
  67.             }
  68.         else if ( pm_keymatch( argv[argn], "-cmap", 2 ) )
  69.             tgaHeader.ImgType = TGA_Map;
  70.         else if ( pm_keymatch( argv[argn], "-mono", 2 ) )
  71.             tgaHeader.ImgType = TGA_Mono;
  72.         else if ( pm_keymatch( argv[argn], "-rgb", 2 ) )
  73.             tgaHeader.ImgType = TGA_RGB;
  74.         else if ( pm_keymatch( argv[argn], "-norle", 2 ) )
  75.             rle_flag = 0;
  76.         else
  77.             pm_usage( usage );
  78.         ++argn;
  79.         }
  80.  
  81.     if ( argn != argc )
  82.         {
  83.         /* Open the input file. */
  84.         ifp = pm_openr( argv[argn] );
  85.  
  86.         /* If output filename not specified, use input filename as default. */
  87.         if ( out_name[0] == '\0' )
  88.             {
  89.             (void) strcpy( out_name, argv[argn] );
  90.             cp = index( out_name, '.' );
  91.             if ( cp != 0 )
  92.             *cp = '\0';    /* remove extension */
  93.             if ( strcmp( out_name, "-" ) == 0 )
  94.             (void) strcpy( out_name, "noname" );
  95.             }
  96.  
  97.         ++argn;
  98.         }
  99.     else
  100.         {
  101.         /* No input file specified. */
  102.         ifp = stdin;
  103.         if ( out_name[0] == '\0' )
  104.             (void) strcpy( out_name, "noname" );
  105.         }
  106.  
  107.     if ( argn != argc )
  108.         pm_usage( usage );
  109.  
  110.     /* Read in the ppm file. */
  111.     ppm_readppminit( ifp, &cols, &rows, &maxval, &format);
  112.     pixels = ppm_allocarray( cols, rows );
  113.     for ( row = 0; row < rows; ++row )
  114.     ppm_readppmrow( ifp, pixels[row], cols, maxval, format );
  115.     pm_close( ifp );
  116.  
  117.     /* Figure out the colormap. */
  118.     switch ( PPM_FORMAT_TYPE( format ) )
  119.     {
  120.         case PPM_TYPE:
  121.     if ( tgaHeader.ImgType == TGA_Mono )
  122.         pm_error( "input is not a graymap, filter through ppmtopgm first" );
  123.     if ( tgaHeader.ImgType == TGA_Null || tgaHeader.ImgType == TGA_Map )
  124.         {
  125.         pm_message( "computing colormap..." );
  126.         chv = ppm_computecolorhist(
  127.         pixels, cols, rows, MAXCOLORS, &ncolors );
  128.         if ( chv == (colorhist_vector) 0 )
  129.         {
  130.         if ( tgaHeader.ImgType == TGA_Map )
  131.             pm_error(
  132.             "too many colors - try doing a 'ppmquant %d'",
  133.             MAXCOLORS );
  134.         else
  135.             tgaHeader.ImgType = TGA_RGB;
  136.         }
  137.         else
  138.         {
  139.         pm_message( "%d colors found", ncolors );
  140.         if ( tgaHeader.ImgType == TGA_Null )
  141.             tgaHeader.ImgType = TGA_Map;
  142.         }
  143.         }
  144.     break;
  145.  
  146.         case PGM_TYPE:
  147.         case PBM_TYPE:
  148.     if ( tgaHeader.ImgType == TGA_Null )
  149.         tgaHeader.ImgType = TGA_Mono;
  150.     else if ( tgaHeader.ImgType == TGA_Map )
  151.         {
  152.         pm_message( "computing colormap..." );
  153.         chv = ppm_computecolorhist(
  154.         pixels, cols, rows, MAXCOLORS, &ncolors );
  155.         if ( chv == (colorhist_vector) 0 )
  156.         pm_error( "can't happen" );
  157.         pm_message( "%d colors found", ncolors );
  158.         }
  159.     break;
  160.  
  161.         default:
  162.     pm_error( "can't happen" );
  163.     }
  164.  
  165.     if ( rle_flag )
  166.     {
  167.     switch ( tgaHeader.ImgType )
  168.         {
  169.         case TGA_Mono:
  170.         tgaHeader.ImgType = TGA_RLEMono;
  171.         break;
  172.         case TGA_Map:
  173.         tgaHeader.ImgType = TGA_RLEMap;
  174.         break;
  175.         case TGA_RGB:
  176.         tgaHeader.ImgType = TGA_RLERGB;
  177.         break;
  178.         default:
  179.         pm_error( "can't happen" );
  180.         }
  181.     runlength = (int*) pm_allocrow( cols, sizeof(int) );
  182.     }
  183.     
  184.     tgaHeader.IDLength = 0;
  185.     tgaHeader.Index_lo = 0;
  186.     tgaHeader.Index_hi = 0;
  187.     if ( tgaHeader.ImgType == TGA_Map || tgaHeader.ImgType == TGA_RLEMap )
  188.     {
  189.         /* Make a hash table for fast color lookup. */
  190.         cht = ppm_colorhisttocolorhash( chv, ncolors );
  191.  
  192.         tgaHeader.CoMapType = 1;
  193.         tgaHeader.Length_lo = ncolors % 256;
  194.         tgaHeader.Length_hi = ncolors / 256;
  195.         tgaHeader.CoSize = 24;
  196.     }
  197.     else
  198.     {
  199.         tgaHeader.CoMapType = 0;
  200.         tgaHeader.Length_lo = 0;
  201.         tgaHeader.Length_hi = 0;
  202.         tgaHeader.CoSize = 0;
  203.     }
  204.     if ( tgaHeader.ImgType == TGA_RGB || tgaHeader.ImgType == TGA_RLERGB )
  205.     tgaHeader.PixelSize = 24;
  206.     else
  207.     tgaHeader.PixelSize = 8;
  208.     tgaHeader.X_org_lo = tgaHeader.X_org_hi = 0;
  209.     tgaHeader.Y_org_lo = tgaHeader.Y_org_hi = 0;
  210.     tgaHeader.Width_lo = cols % 256;
  211.     tgaHeader.Width_hi = cols / 256;
  212.     tgaHeader.Height_lo = rows % 256;
  213.     tgaHeader.Height_hi = rows / 256;
  214.     tgaHeader.AttBits = 0;
  215.     tgaHeader.Rsrvd = 0;
  216.     tgaHeader.IntrLve = 0;
  217.     tgaHeader.OrgBit = 0;
  218.  
  219.     /* Write out the Targa header. */
  220.     writetga( &tgaHeader, (char*) 0 );
  221.  
  222.     if ( tgaHeader.ImgType == TGA_Map || tgaHeader.ImgType == TGA_RLEMap )
  223.     {
  224.         /* Write out the Targa colormap. */
  225.         for ( i = 0; i < ncolors; ++i )
  226.             put_map_entry( &chv[i].color, tgaHeader.CoSize, maxval );
  227.     }
  228.  
  229.     /* Write out the pixels */
  230.     for ( row = 0; row < rows; ++row )
  231.     {
  232.     realrow = row;
  233.     if ( tgaHeader.OrgBit == 0 )
  234.         realrow = rows - realrow - 1;
  235.     if ( rle_flag )
  236.         {
  237.         compute_runlengths( cols, pixels[realrow], runlength );
  238.         for ( col = 0; col < cols; )
  239.         {
  240.         if ( runlength[col] > 0 )
  241.             {
  242.             putchar( 0x80 + runlength[col] - 1 );
  243.             put_pixel(
  244.             &(pixels[realrow][col]),
  245.             tgaHeader.ImgType, maxval, cht );
  246.             col += runlength[col];
  247.             }
  248.         else if ( runlength[col] < 0 )
  249.             {
  250.             putchar( -runlength[col] - 1 );
  251.             for ( i = 0; i < -runlength[col]; ++i )
  252.             put_pixel(
  253.                 &(pixels[realrow][col + i]),
  254.                 tgaHeader.ImgType, maxval, cht );
  255.             col += -runlength[col];
  256.             }
  257.         else
  258.             pm_error( "can't happen" );
  259.         }
  260.         }
  261.     else
  262.         {
  263.         for ( col = 0, pP = pixels[realrow]; col < cols; ++col, ++pP )
  264.         put_pixel( pP, tgaHeader.ImgType, maxval, cht );
  265.         }
  266.     }
  267.  
  268.     exit( 0 );
  269.     }
  270.  
  271. static void
  272. writetga( tgaP, id )
  273.     struct ImageHeader* tgaP;
  274.     char* id;
  275.     {
  276.     unsigned char flags;
  277.  
  278.     putchar( tgaP->IDLength );
  279.     putchar( tgaP->CoMapType );
  280.     putchar( tgaP->ImgType );
  281.     putchar( tgaP->Index_lo );
  282.     putchar( tgaP->Index_hi );
  283.     putchar( tgaP->Length_lo );
  284.     putchar( tgaP->Length_hi );
  285.     putchar( tgaP->CoSize );
  286.     putchar( tgaP->X_org_lo );
  287.     putchar( tgaP->X_org_hi );
  288.     putchar( tgaP->Y_org_lo );
  289.     putchar( tgaP->Y_org_hi );
  290.     putchar( tgaP->Width_lo );
  291.     putchar( tgaP->Width_hi );
  292.     putchar( tgaP->Height_lo );
  293.     putchar( tgaP->Height_hi );
  294.     putchar( tgaP->PixelSize );
  295.     flags = ( tgaP->AttBits & 0xf ) | ( ( tgaP->Rsrvd & 0x1 ) << 4 ) |
  296.         ( ( tgaP->OrgBit & 0x1 ) << 5 ) | ( ( tgaP->OrgBit & 0x3 ) << 6 );
  297.     putchar( flags );
  298.     if ( tgaP->IDLength )
  299.         fwrite( id, 1, (int) tgaP->IDLength, stdout );
  300.     }
  301.     
  302. #if __STDC__
  303. static void
  304. put_map_entry( pixel* valueP, int size, pixval maxval )
  305. #else /*__STDC__*/
  306. static void
  307. put_map_entry( valueP, size, maxval )
  308.     pixel* valueP;
  309.     int size;
  310.     pixval maxval;
  311. #endif /*__STDC__*/
  312.     {
  313.     int j;
  314.     pixel p;
  315.     
  316.     switch ( size )
  317.     {
  318.     case 8:                /* Grey scale. */
  319.     put_mono( valueP, maxval );
  320.     break;
  321.  
  322.     case 16:            /* 5 bits each of red green and blue. */
  323.     case 15:            /* Watch for byte order. */
  324.     PPM_DEPTH( p, *valueP, maxval, 31 );
  325.     j = (int) PPM_GETB( p ) | ( (int) PPM_GETG( p ) << 5 ) |
  326.         ( (int) PPM_GETR( p ) << 10 );
  327.     putchar( j % 256 );
  328.     putchar( j / 256 );
  329.     break;
  330.  
  331.     case 32:
  332.     case 24:            /* 8 bits each of blue green and red. */
  333.     put_rgb( valueP, maxval );
  334.     break;
  335.  
  336.     default:
  337.     pm_error( "unknown colormap pixel size (#2) - %d", size );
  338.     }
  339.     }
  340.  
  341. static void
  342. compute_runlengths( cols, pixelrow, runlength )
  343.     int cols;
  344.     pixel* pixelrow;
  345.     int* runlength;
  346.     {
  347.     int col, start;
  348.  
  349.     /* Initialize all run lengths to 0.  (This is just an error check.) */
  350.     for ( col = 0; col < cols; ++col )
  351.     runlength[col] = 0;
  352.     
  353.     /* Find runs of identical pixels. */
  354.     for ( col = 0; col < cols; )
  355.     {
  356.     start = col;
  357.     do {
  358.         ++col;
  359.         }
  360.     while ( col < cols &&
  361.         col - start < 128 &&
  362.         PPM_EQUAL( pixelrow[col], pixelrow[start] ) );
  363.     runlength[start] = col - start;
  364.     }
  365.     
  366.     /* Now look for runs of length-1 runs, and turn them into negative runs. */
  367.     for ( col = 0; col < cols; )
  368.     {
  369.     if ( runlength[col] == 1 )
  370.         {
  371.         start = col;
  372.         while ( col < cols &&
  373.             col - start < 128 &&
  374.             runlength[col] == 1 )
  375.         {
  376.         runlength[col] = 0;
  377.         ++col;
  378.         }
  379.         runlength[start] = - ( col - start );
  380.         }
  381.     else
  382.         col += runlength[col];
  383.     }
  384.     }
  385.  
  386. #if __STDC__
  387. static void
  388. put_pixel( pixel* pP, int imgtype, pixval maxval, colorhash_table cht )
  389. #else /*__STDC__*/
  390. static void
  391. put_pixel( pP, imgtype, maxval, cht )
  392.     pixel* pP;
  393.     int imgtype;
  394.     pixval maxval;
  395.     colorhash_table cht;
  396. #endif /*__STDC__*/
  397.     {
  398.     switch ( imgtype )
  399.     {
  400.     case TGA_Mono:
  401.     case TGA_RLEMono:
  402.     put_mono( pP, maxval );
  403.     break;
  404.     case TGA_Map:
  405.     case TGA_RLEMap:
  406.     put_map( pP, cht );
  407.     break;
  408.     case TGA_RGB:
  409.     case TGA_RLERGB:
  410.     put_rgb( pP, maxval );
  411.     break;
  412.     default:
  413.     pm_error( "can't happen" );
  414.     }
  415.     }
  416.  
  417. #if __STDC__
  418. static void
  419. put_mono( pixel* pP, pixval maxval )
  420. #else /*__STDC__*/
  421. static void
  422. put_mono( pP, maxval )
  423.     pixel* pP;
  424.     pixval maxval;
  425. #endif /*__STDC__*/
  426.     {
  427.     PPM_DEPTH( *pP, *pP, maxval, (pixval) 255 );
  428.     putchar( PPM_GETR( *pP ) );
  429.     }
  430.  
  431. static void
  432. put_map( pP, cht )
  433.     pixel* pP;
  434.     colorhash_table cht;
  435.     {
  436.     putchar( ppm_lookupcolor( cht, pP ) );
  437.     }
  438.  
  439. #if __STDC__
  440. static void
  441. put_rgb( pixel* pP, pixval maxval )
  442. #else /*__STDC__*/
  443. static void
  444. put_rgb( pP, maxval )
  445.     pixel* pP;
  446.     pixval maxval;
  447. #endif /*__STDC__*/
  448.     {
  449.     PPM_DEPTH( *pP, *pP, maxval, (pixval) 255 );
  450.     putchar( PPM_GETB( *pP ) );
  451.     putchar( PPM_GETG( *pP ) );
  452.     putchar( PPM_GETR( *pP ) );
  453.     }
  454.