home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_C / OPTICN15.ZIP / OPTICON.C < prev    next >
C/C++ Source or Header  |  1994-02-03  |  19KB  |  631 lines

  1. /*
  2.  *  OPTICON.C
  3.  */
  4.  
  5. #define VERSION "1.5"
  6. static char versiontag[] = "$VER: $Id: opticon.c,v 1.5 1994/02/03 04:03:02 tf Exp $";
  7.  
  8. /****** OptIcon ******************************************
  9. *
  10. *   NAME
  11. *    OptIcon -- Optimize icon images for size and speed (V36)
  12. *
  13. *   SYNOPSIS
  14. *    OptIcon NAME/A/M,DEPTH=PLANES/N,NOEXPAND/S,CRITICAL/S,VERBOSE/S
  15. *
  16. *   FUNCTION
  17. *    OptIcon reads in given ".info" files and scans the icon image
  18. *    in order to optimize the PlanePick and PlaneOnOff fields in the
  19. *    icon Image structure.  This is a space-saving mechanism for image
  20. *    data.
  21. *    Rather than defining the image data for every plane of the RastPort,
  22. *    you need define data only for the planes that are not entirely zero
  23. *    or one.  As you define your Imagery, you will often find that most
  24. *    of the planes ARE just as color selectors.  For instance, if you're
  25. *    designing a two-color icon to use colors one and three, and the icon
  26. *    will reside in a five-plane display, bit plane zero of your
  27. *    imagery would be all ones, bit plane one would have data that
  28. *    describes the imagery, and bit planes two through four would be
  29. *    all zeroes.  Using these flags avoids wasting all that memory in
  30. *    this way:  first, you specify which planes you want your data to
  31. *    appear in using the PlanePick variable.  For each bit set in the
  32. *    variable, the next "plane" of your image data is blitted to the
  33. *    display.  For each bit clear in this variable, the corresponding bit
  34. *    in PlaneOnOff is examined.  If that bit is clear, a "plane" of zeroes
  35. *    will be used.  If the bit is set, ones will go out instead.
  36. *    Note that if you want an Image that is only a filled rectangle, you
  37. *    can get this by setting PlanePick to zero (pick no planes of data)
  38. *    and set PlaneOnOff to describe the pen color of the rectangle.
  39. *
  40. *   INPUTS
  41. *    NAME          - name of the icon image file.  A trailing ".info"
  42. *            is optional but not required.
  43. *    DEPTH         - maximum number of bitplanes to be saved.
  44. *    VERBOSE       - display input and output information for each icon.
  45. *
  46. *   EXAMPLE
  47. *    ;Remove all but the first 3 planes of the icon image for the
  48. *    ;disk in drive DF0: but don't add any planes
  49. *    opticon df0:disk planes=3 noexpand
  50. *
  51. *   NOTES
  52. *    Since the IconEdit from Commodore will always save 8 bitplane icons
  53. *    the above example might be of great use to you.  (Note that 3 plane
  54. *    images are not only smaller but also faster!)
  55. *    Coming with OptIcon is the script PatchIcons which will recursively
  56. *    descend all subdirectories of a given path deleting all but the first
  57. *    3 planes of all icon images in that path.
  58. *
  59. *    OptIcon now also allows you to expand your 8 or more color icons
  60. *    for the use on a 16 or more color Workbench.  This is important due
  61. *    to the new color system under OS3.x which always shifts the second
  62. *    four colors to the end of the system palette.  Therefore you might
  63. *    want to adapt an icon's color depth to the actual screenmode it is
  64. *    used on.
  65. *
  66. *   EXAMPLE
  67. *    ;Remap the last 4 of at least 8 colors of the RAM DISK icon
  68. *    ;to the last 4 colors in a 16 or more colors Workbench palette
  69. *    opticon ram:disk planes=4
  70. *
  71. *   BUGS
  72. *    Commodore's PutDiskObject() currently [icon.library 40.1 (15.2.93)]
  73. *    re-expands icon images using the PlanePick/PlaneOnOff mechanism and
  74. *    in fact PutDiskObject() has quite a lot of problems doing so!
  75. *    For this reason OptIcon will perform the PlanePick/PlaneOnOff
  76. *    optimization only if the keyword CRITICAL is given in the command
  77. *    line.
  78. *
  79. *   DISCLAIMER
  80. *    This file is part of the Icon2C and OptIcon distribution.
  81. *
  82. *    Icon2C and OptIcon are free software; you can redistribute them
  83. *    and/or modify them under the terms of the GNU General Public License
  84. *    as published by the Free Software Foundation; either version 1 of
  85. *    the License, or (at your option) any later version.
  86. *
  87. *    Icon2C and Opticon are distributed in the hope that they will be
  88. *    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  89. *    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  90. *    GNU General Public License for more details.
  91. *
  92. *    You should have received a copy of the GNU General Public License
  93. *    along with these programs; see the file COPYING.  If not, write to
  94. *    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  95. *
  96. *   SEE ALSO
  97. *    PatchIcons, Icon2C
  98. *
  99. ******************************************************************************
  100. *
  101. *    Compile w/ -DDEBUG to output more information at runtime
  102. */
  103.  
  104. #include <ctype.h>
  105. #include <stdlib.h>
  106. #include <string.h>
  107. #include <stdio.h>
  108.  
  109. #include <exec/types.h>
  110. #include <exec/memory.h>
  111.  
  112. #include <dos/dos.h>
  113. #include <dos/rdargs.h>
  114.  
  115. #include <intuition/intuition.h>
  116. #include <intuition/intuitionbase.h>
  117.  
  118. #include <workbench/workbench.h>
  119. #include <workbench/startup.h>
  120. #include <workbench/icon.h>
  121.  
  122. #ifdef __GNUC__
  123. /* suggest parentheses around assignment used as truth value */
  124. #define if(assignment) if( (assignment) )
  125. #endif /* __GNUC__ */
  126.  
  127. extern struct Library *OpenLibrary(STRPTR, ULONG);
  128. extern void CloseLibrary(struct Library *);
  129. extern void CopyMem(APTR, APTR, ULONG);
  130. extern void *AllocMem(ULONG, ULONG);
  131. extern void FreeMem(void *, ULONG);
  132. extern ULONG TypeOfMem(void *);
  133. extern struct RDArgs *ReadArgs(STRPTR, LONG *, struct RDArgs *);
  134. extern LONG IoErr(void);
  135. extern BOOL PrintFault(LONG, STRPTR);
  136. extern void FreeArgs(struct RDArgs *);
  137. extern struct DiskObject *GetDiskObject(char *);
  138. extern BOOL PutDiskObject(char *, struct DiskObject *);
  139. extern void FreeDiskObject(struct DiskObject *);
  140.  
  141. struct IconBase *IconBase;
  142.  
  143. /*#define CopyMem(a,b,c) printf("CopyMem( 0x%lx, 0x%lx, %ld )\n", a,b,c);*/
  144.  
  145. void display_version_information(void)
  146. {
  147.   static char license[]=
  148.     "OptIcon is free software; you can redistribute it and/or modify\n"
  149.     "it under the terms of the GNU General Public License as published\n"
  150.     "by the Free Software Foundation; either version 1 of the License,\n"
  151.     "or (at your option) any later version.\n"
  152.     "\n"
  153.     "OptIcon is distributed in the hope that it will be useful,\n"
  154.     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  155.     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
  156.     "GNU General Public License for more details.\n"
  157.     "\n"
  158.     "You should have received a copy of the GNU General Public License\n"
  159.     "along with OptIcon; see the file COPYING.  If not, write to the\n"
  160.     "Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
  161.     ;
  162.  
  163.   puts("OptIcon Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
  164.        "(c)Copyright 1994 by Tobias Ferber, ukjg@dkauni2.bitnet\n");
  165.  
  166.   puts(license);
  167. }
  168.  
  169.  
  170. struct Image *free_image(struct Image *i)
  171. {
  172.   if(i)
  173.   {
  174.     long size= i->Depth * i->Height * ((i->Width + 15) / 16) * sizeof(UWORD);
  175.  
  176.     if(i->ImageData && size > 0)
  177.       FreeMem( i->ImageData, size );
  178.  
  179.     FreeMem( i, sizeof(struct Image) );
  180.   }
  181.  
  182.   return (struct Image *)0L;
  183. }
  184.  
  185.  
  186. #define OPT_NOEXPAND  (1<<0)
  187. #define OPT_CRITICAL  (1<<1)
  188. #define OPT_VERBOSE   (1<<2)
  189.  
  190. struct Image *optimize_image(struct Image *i, WORD planes, int optimode)
  191. {
  192.   UWORD p16= i->Height * ((i->Width + 15) / 16); /* #of words per plane */
  193.   UWORD *idata= i->ImageData;
  194.   WORD d, dmax, D, P;
  195.   UBYTE pp= 0;    /* plane pick */
  196.   UBYTE p10= 0;   /* plane on/off */
  197.  
  198.   struct Image *o= i;  /* optimized image */
  199.  
  200.   /* prevent silly args from being harmful */
  201.  
  202.   if(!i)
  203.     return i;
  204.  
  205.   if(planes > 8)
  206.     planes= 8;
  207.  
  208.   if(optimode & OPT_VERBOSE)
  209.   {
  210.     printf("(depth=%d, pick=%d, onoff=%d)", i->Depth,
  211.                                             i->PlanePick,
  212.                                             i->PlaneOnOff);
  213.     fflush(stdout);
  214.   }
  215.  
  216.   /*
  217.       PRESCAN:  Examine dmax planes of i and compute
  218.  
  219.         D   = the real depth (without trailing 0 planes)
  220.         pp  = the new PlanePick value
  221.         p10 = the new PlaneOnOff value
  222.   */
  223.  
  224.   dmax= (0 < planes && planes < i->Depth) ? planes : i->Depth;
  225.  
  226.   for(d= D= 0; d<dmax; d++)
  227.   {
  228.     /* check if we have some image data for plane d */
  229.     if(i->PlanePick & (1<<d))
  230.     {
  231.       UWORD n, *p, v;
  232.  
  233.       /* scan the image data of plane d */
  234.       for(n=0, p=idata, v=*p; n < p16; n++, p++)
  235.         if(*p != v)
  236.           break;
  237.  
  238.       if(n==p16 && v==0xFFFF) /* plane d is entirely 1 */
  239.         p10 |= (1<<d);  /* pp bit is already 0 */
  240.  
  241.       if( n!=p16 || (n==p16 && v!=0x0000 && v!=0xFFFF) )
  242.         pp |= (1<<d);
  243.  
  244.       if( n!=p16 || (n==p16 && v!=0x0000) )
  245.         D= d;
  246.  
  247.       idata= &idata[p16];
  248.     }
  249.     else if(i->PlaneOnOff & (1<<d))
  250.     {
  251.       p10 |= (1<<d);
  252.       D=d;
  253.     }
  254.   }
  255.  
  256.   ++D;
  257.  
  258.   if( (optimode & OPT_VERBOSE) && (D != dmax || pp != i->PlanePick || p10 != i->PlaneOnOff) )
  259.   {
  260.     printf(" -> (%d,%d,%d)", D,pp,p10);
  261.     fflush(stdout);
  262.   }
  263.  
  264.   /* compute the #of planes in the output image */
  265.   P= ( planes>D && !(optimode & OPT_NOEXPAND) ) ? planes : D;
  266.  
  267.   if(P != i->Depth || pp != i->PlanePick || p10 != i->PlaneOnOff)
  268.   {
  269.     UWORD p8= p16 * sizeof(UWORD);
  270.     UWORD *odata;
  271.     ULONG osize= P * p8;
  272.  
  273.     if( o= (struct Image *)AllocMem(sizeof(struct Image),MEMF_CLEAR) )
  274.     {
  275.       if( odata= (UWORD *)AllocMem(osize,TypeOfMem(i->ImageData)|MEMF_CLEAR) )
  276.       {
  277.         CopyMem( (APTR)i, (APTR)o, sizeof(struct Image) );
  278.         o->ImageData= odata;
  279.  
  280.         idata= i->ImageData;
  281.  
  282.         for(d=0; d<D; d++)
  283.         {
  284.           if( pp & (1<<d) )
  285.           {
  286.             if(i->PlanePick & (1<<d))
  287.             {
  288.               CopyMem( (APTR)idata, (APTR)odata, p8 );
  289.               idata= &idata[p16];
  290.               odata= &odata[p16];
  291.             }
  292.             else /* !PlanePick bit (should not happen) */
  293.             {
  294.               memset( (char *)odata, (i->PlaneOnOff & (1<<d)) ? 0xFF : 0x00, p8 );
  295.               odata= &odata[p16];
  296.             }
  297.           }
  298.           else /* !pp bit */
  299.           {
  300.             if(i->PlanePick & (1<<d))
  301.               idata= &idata[p16];
  302.  
  303.             if( !(optimode & OPT_CRITICAL) )
  304.             {
  305.               memset( (char *)odata, (p10 & (1<<d)) ? 0xFF : 0x00, p8 );
  306.               odata= &odata[p16];
  307.               pp |= (1<<d);
  308.               p10 &= ~(1<<d);
  309.             }
  310.           }
  311.         }
  312.  
  313.         if(D>=3 && D<P) /* no need to check OPT_NOEXPAND sice P is < D if set */
  314.         {
  315.           UWORD *p;
  316.  
  317.           if( p= (UWORD *)malloc(p8) )
  318.           {
  319.  
  320. #ifdef OBSOLETE
  321.             if( (optimode & OPT_OBSOLETE) && p10<=7 )
  322.             {
  323.  
  324.               /*
  325.                   REMAP:  Make colors 4-7 become the last 4 in the palette
  326.  
  327.                   Algo: (1) OR together all planes > 2,
  328.                         (2) invert the result,
  329.                         (3) AND it with plane 2 and
  330.                         (4) OR the result with all planes > 2
  331.  
  332.                   Note: There is no need to expamd the image data if p10 &~ %111 != 0
  333.               */
  334.  
  335.               /* move to plane 2 */
  336.  
  337.               idata= i->ImageData;
  338.  
  339.               for(d=0; d<2; d++)
  340.                 if(i->PlanePick & (1<<d))
  341.                   idata= &idata[p16];
  342.  
  343.               if(i->PlanePick & (1<<2))
  344.               {
  345.                 memcpy((char *)p, (char *)idata, p8);
  346.                 idata= &idata[p16];
  347.               }
  348.               else memset( (char *)p, (p10 & (1L<<2)) ? 0xFF : 0x00, p8 );
  349.  
  350.               /* or planes 3..D, invert them, AND the result with plane 2 */
  351.  
  352.               for(d=3; d<D; d++)
  353.               {
  354.                 if(i->PlanePick & (1<<d))
  355.                 {
  356.                   memandnot( (char *)p, (char *)idata, p8 );
  357.                   idata= &idata[p16];
  358.                 }
  359.                 /* else bit d of i->PlaneOnOff is 0 --> no-op */
  360.               }
  361.  
  362.               /* move to plane 3 */
  363.  
  364.               odata= o->ImageData;
  365.  
  366.               for(d=0; d<3; d++)
  367.                 if(pp & (1<<d))
  368.                   odata= &odata[p16];
  369.  
  370.               for(d=3; d<P; d++)
  371.               {
  372.                 if( d>=D || pp & (1<<d) )
  373.                 {
  374.                   memor( (char *)odata, (char *)p, p8 );
  375.                   odata= &odata[p16];
  376.                   pp |= (1<<d);
  377.                 }
  378.               }
  379.             }
  380. #endif /* OBSOLETE */
  381.  
  382.             /*
  383.                 EXPAND:  Remap the last 4 colors of i to the last 4 colors of o
  384.  
  385.                 Algo: (1) OR together all planes but the last
  386.                       (2) AND the result with the last plane
  387.                       (3) set the result in all new planes
  388.  
  389.                 Note: if any plane of i but the last is entirely 1 then we can
  390.                       simply copy the last plane of i to all new planes in o
  391.             */
  392.  
  393.             idata= i->ImageData;
  394.  
  395.             if( p10 &~ (1<<(D-1)) == 0)
  396.             {
  397.               memset( (char *)p, 0x00, p8 );
  398.  
  399.               for(d=0; d<D-1; d++)
  400.               {
  401.                 if(i->PlanePick & (1<<d))
  402.                 {
  403.                   memor( (char *)p, (char *)idata, p8 );
  404.                   idata= &idata[p16];
  405.                 }
  406.               }
  407.               /* else plane d is entirely 0 */
  408.  
  409.               if( i->PlanePick & (1<<(D-1)) )
  410.                 memand( (char *)p, (char *)idata, p8 );
  411.               /* else the last plane is entirely 1 */
  412.             }
  413.             else /* move to the last plane */
  414.             {
  415.               for(d=0; d<D-1; d++)
  416.                 if(i->PlanePick & (1<<d))
  417.                   idata= &idata[p16];
  418.  
  419.               if( i->PlanePick & (1<<(D-1)) )
  420.                 memcpy( (char *)p, (char *)idata, p8 );
  421.               else
  422.                 memset( (char *)p, 0xFF, p8 );
  423.             }
  424.  
  425.             /* move to plane D */
  426.  
  427.             odata= o->ImageData;
  428.  
  429.             for(d=0; d<D; d++)
  430.               if(pp & (1<<d))
  431.                 odata= &odata[p16];
  432.  
  433.             for(d=D; d<P; d++)
  434.             {
  435.               memcpy( (char *)odata, (char *)p, p8 );
  436.               odata= &odata[p16];
  437.               pp |= (1<<d);
  438.             }
  439.  
  440.             free(p);
  441.           }
  442.           else /* !p --> panic! */
  443.           {
  444.             FreeMem(o->ImageData,osize);
  445.             FreeMem(o,sizeof(struct Image));
  446.             o= (struct Image *)0L;
  447.           }
  448.         }
  449.  
  450.         o->Depth= P;
  451.         o->PlanePick= pp;
  452.         o->PlaneOnOff= p10;
  453.  
  454.       }
  455.       else /* !odata */
  456.       {
  457.         FreeMem(o,sizeof(struct Image));
  458.         o= (struct Image *)0L;
  459.       }
  460.     }
  461.   }
  462.  
  463.   if(optimode & OPT_VERBOSE)
  464.   {
  465.     if(o && o!=i)
  466.       printf(" -> (%d,%d,%d)", o->Depth, o->PlanePick, o->PlaneOnOff);
  467.     putchar('\n');
  468.   }
  469.  
  470.   return o;
  471. }
  472.  
  473.  
  474. int main(int argc, char **argv)
  475. {
  476.   struct RDArgs *a;
  477.   LONG args[5] = { 0,0,0,0,0 };
  478.  
  479.   WORD numplanes= 0;
  480.   char *whoami= *argv;
  481.   int rc= RETURN_OK;
  482.  
  483.   if( a= ReadArgs("NAME/A/M,DEPTH=PLANES/N,NOEXPAND/S,CRITICAL/S,VERBOSE/S", args, NULL) )
  484.   {
  485.     char **flist= (char **)args[0];
  486.  
  487.     if(args[1])
  488.     {
  489.       if( (numplanes= (WORD)*(LONG *)(args[1])) < 1 )
  490.       {
  491.         fprintf(stderr,"%s: Illegal maximum depth %d\n",whoami,numplanes);
  492.         rc= RETURN_FAIL;
  493.       }
  494.     }
  495.  
  496.     if(flist && rc == RETURN_OK)
  497.     {
  498.       if( IconBase= (struct IconBase *)OpenLibrary(ICONNAME,36) )
  499.       {
  500.         while(*flist && rc == RETURN_OK)
  501.         {
  502.           char *iname= (char *)malloc( strlen(*flist) + 1 );
  503.  
  504.           if(iname)
  505.           {
  506.             struct DiskObject *icon;
  507.             strcpy(iname, *flist);
  508.  
  509.             if( (icon= GetDiskObject(iname)) == NULL )
  510.             {
  511.               int x= strlen(iname) - 5;
  512.               if(x>0 && !stricmp(&(iname[x]),".info"))
  513.               {
  514.                 iname[x]= '\0';
  515.                 icon= GetDiskObject(iname);
  516.               }
  517.             }
  518.  
  519.             if(icon)
  520.             {
  521.               struct Gadget *g= &icon->do_Gadget;
  522.  
  523.               struct Image *ogr, *osr;
  524.               int modified= 0;
  525.               int flags= 0;
  526.  
  527.               ogr= osr= (struct Image *)0L;
  528.  
  529.               if(args[2]) flags |= OPT_NOEXPAND;
  530.               if(args[3]) flags |= OPT_CRITICAL;
  531.               if(args[4]) flags |= OPT_VERBOSE;
  532.  
  533.               if(g->GadgetRender && (g->Flags & GFLG_GADGIMAGE))
  534.               {
  535.                 struct Image *i= (struct Image *)g->GadgetRender;
  536.  
  537.                 if(flags & OPT_VERBOSE)
  538.                   printf("Normal   ");
  539.  
  540.                 if( ogr= optimize_image(i,numplanes,flags) )
  541.                 {
  542.                   if(ogr != i)
  543.                   {
  544.                     g->GadgetRender= (APTR)ogr;
  545.                     ++modified;
  546.                   }
  547.                   else ogr= (struct Image *)0L; /* don't free ogr */
  548.  
  549.                   if(g->SelectRender && (g->Flags & GFLG_GADGHIMAGE))
  550.                   {
  551.                     i= (struct Image *)g->SelectRender;
  552.  
  553.                     if(flags & OPT_VERBOSE)
  554.                       printf("Selected ");
  555.  
  556.                     if( osr= optimize_image(i,numplanes, flags) )
  557.                     {
  558.                       if(osr != i)
  559.                       {
  560.                         g->SelectRender= (APTR)osr;
  561.                         ++modified;
  562.                       }
  563.                       else osr= (struct Image *)0L; /* don't free osr */
  564.                     }
  565.                     else
  566.                     {
  567.                       fprintf(stderr,"%s: %s.info: not enough free memory to optimize the selected image\n",whoami,iname);
  568.                       rc= RETURN_ERROR;
  569.                     }
  570.                   }
  571.                 }
  572.                 else
  573.                 {
  574.                   fprintf(stderr,"%s: %s.info: not enough free memory to optimize the normal image\n",whoami,iname);
  575.                   rc= RETURN_ERROR;
  576.                 }
  577.               }
  578.  
  579.               if( modified && rc == RETURN_OK )
  580.               {
  581.                 if( !PutDiskObject(iname,icon) )
  582.                   PrintFault(rc= IoErr(), iname);
  583.               }
  584.  
  585.               if(ogr) ogr= free_image(ogr);
  586.               if(osr) osr= free_image(osr);
  587.  
  588.               FreeDiskObject(icon);
  589.             }
  590.             else /* !icon */
  591.             {
  592.               fprintf(stderr,"%s: GetDiskObject() failed for %s[.info]\n",whoami,iname);
  593.               rc= IoErr();
  594.             }
  595.  
  596.             free(iname);
  597.           }
  598.           else /* !iname */
  599.           {
  600.             fprintf(stderr,"%s: out of memory... aaaiiiiiieeeeeeeee!\n",whoami);
  601.             rc= RETURN_ERROR;
  602.           }
  603.  
  604.           ++flist;
  605.         }
  606.         CloseLibrary((struct Library *)IconBase);
  607.       }
  608.       else
  609.       {
  610.         fprintf(stderr,"%s: You need %s V36+",whoami,ICONNAME);
  611.         rc= RETURN_ERROR;
  612.       }
  613.     }
  614.     FreeArgs(a);
  615.   }
  616.   else /* !ReadArgs */
  617.   {
  618.     if(argc == 1)
  619.       display_version_information();
  620.  
  621.     if(argc <= 4)
  622.       printf("%s: required argument missing\n",whoami);
  623.     else
  624.       printf("%s: wrong number of arguments\n",whoami);
  625.  
  626.     rc= RETURN_FAIL;
  627.   }
  628.  
  629.   exit(rc);
  630. }
  631.