home *** CD-ROM | disk | FTP | other *** search
/ swCHIP 1991 January / swCHIP_95-1.bin / utility / gsview13 / src / gvceps.c < prev    next >
C/C++ Source or Header  |  1995-12-09  |  30KB  |  1,125 lines

  1. /* Copyright (C) 1993, 1994, Russell Lang.  All rights reserved.
  2.   
  3.   This file is part of GSview.
  4.   
  5.   This program is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the GSview Free Public Licence 
  9.   (the "Licence") for full details.
  10.   
  11.   Every copy of GSview must include a copy of the Licence, normally in a 
  12.   plain ASCII text file named LICENCE.  The Licence grants you the right 
  13.   to copy, modify and redistribute GSview, but only under certain conditions 
  14.   described in the Licence.  Among other things, the Licence requires that 
  15.   the copyright notice and this notice be preserved on all copies.
  16. */
  17.  
  18. /* gvceps.c */
  19. /* EPS file manipulation module of PM and Windows GSview */
  20.  
  21. #ifdef EPSTOOL
  22. #include "epstool.h"
  23. #else    /* GSview */
  24. #ifdef _Windows
  25. #include "gvwin.h"
  26. #else
  27. #include "gvpm.h"
  28. #endif
  29. #include "gvceps.h"
  30. #endif
  31.  
  32. PSBBOX bbox;
  33.  
  34. #ifndef EPSTOOL
  35. /* At present only allows bounding box to be specified */
  36. void
  37. ps_to_eps(void)
  38. {
  39. char output[MAXSTR];
  40. FILE *f;
  41. char *buffer;
  42. UINT count;
  43. FILE *infile;
  44. time_t t;
  45. char *now;
  46. char text[PSLINELENGTH];
  47. char *comment;
  48. long here;
  49.  
  50.     load_string(IDS_EPSREAD, output, sizeof(output));
  51.     if (message_box(output, MB_YESNO | MB_ICONQUESTION)
  52.         != IDYES) {
  53.         load_string(IDS_TOPICPSTOEPS, szHelpTopic, sizeof(szHelpTopic));
  54.         get_help();
  55.         return;
  56.     }
  57.  
  58.     if (!(display.page || display.sync)) {
  59.         gserror(IDS_EPSNOBBOX, NULL, MB_ICONEXCLAMATION, SOUND_ERROR);
  60.         return;
  61.     }
  62.  
  63.     if ((doc != (PSDOC *)NULL) && (doc->numpages > 1)) {
  64.         gserror(IDS_EPSONEPAGE, NULL, MB_ICONEXCLAMATION, SOUND_ERROR);
  65.         return;
  66.     }
  67.     if (doc == (PSDOC *)NULL) {
  68.         char mess[MAXSTR];
  69.         load_string(IDS_EPSQPAGES, mess, sizeof(mess));
  70.         if (message_box(mess, MB_YESNO | MB_ICONQUESTION) != IDYES)
  71.         return;
  72.     }
  73.  
  74.     if (!get_bbox()) {
  75.         play_sound(SOUND_ERROR);
  76.         return;
  77.     }
  78.  
  79.     output[0] = '\0';
  80.     if (!get_filename(output, TRUE, FILTER_PS, 0, IDS_TOPICPSTOEPS))
  81.         return;
  82.  
  83.     if ((f = fopen(output, "wb")) == (FILE *)NULL) {
  84.         play_sound(SOUND_ERROR);
  85.         return;
  86.     }
  87.  
  88.     if (doc == (PSDOC *)NULL) {
  89.         load_string(IDS_WAITWRITE, szWait, sizeof(szWait));
  90.         info_wait(TRUE);
  91.         fputs("%!PS-Adobe-3.0 EPSF-3.0\r\n",f);
  92.         /* if this is not a single page document then gsview has just lied */
  93.         fprintf(f, "%%%%BoundingBox: %u %u %u %u\r\n",
  94.         bbox.llx,bbox.lly,bbox.urx,bbox.ury);
  95.         fprintf(f,"%%%%Title: %s\r\n",psfile.name);
  96.         fprintf(f,"%%%%Creator: %s from %s\r\n",szAppName,psfile.name);
  97.         t = time(NULL);
  98.         now = ctime(&t);
  99.         now[strlen(now)-1] = '\0';    /* remove trailing \n */
  100.         fprintf(f,"%%%%CreationDate: %s\r\n",now);
  101.         fputs("%%Pages: 1\r\n",f);
  102.         fputs("%%EndComments\r\n",f);
  103.  
  104.         fputs("%%Page: 1 1\r\n",f);
  105.         fprintf(f,"%%BeginDocument: %s\r\n",psfile.name);
  106.  
  107.         /* create buffer for PS file copy */
  108.         buffer = malloc(COPY_BUF_SIZE);
  109.         if (buffer == (char *)NULL) {
  110.             play_sound(SOUND_ERROR);
  111.             fclose(f);
  112.         unlink(output);
  113.             return;
  114.         }
  115.  
  116.         infile = fopen(psfile.name, "rb");
  117.         if (infile == (FILE *)NULL) {
  118.             play_sound(SOUND_ERROR);
  119.             fclose(f);
  120.         unlink(output);
  121.             return;
  122.         }
  123.  
  124.             while ( (count = fread(buffer, 1, COPY_BUF_SIZE, infile)) != 0 ) {
  125.             fwrite(buffer, 1, count, f);
  126.         }
  127.         free(buffer);
  128.         fclose(infile);
  129.  
  130.         fputs("%%EndDocument\r\n",f);
  131.         fputs("%%Trailer\r\n",f);
  132.         fclose(f);
  133.         info_wait(FALSE);
  134.     }
  135.     else {
  136.         /* document already has DSC comments */
  137.         load_string(IDS_WAITWRITE, szWait, sizeof(szWait));
  138.         info_wait(TRUE);
  139.         dfreopen();
  140.         fseek(psfile.file, doc->beginheader, SEEK_SET);
  141.         fgets(text, PSLINELENGTH, psfile.file);
  142.         if (doc->epsf)
  143.             fputs(text,f);
  144.         else
  145.             fputs("%!PS-Adobe-3.0 EPSF-3.0\r\n",f);
  146.         if (!( (doc->boundingbox[LLX]==0) &&  (doc->boundingbox[LLY]==0) 
  147.              &&  (doc->boundingbox[URX]==0) &&  (doc->boundingbox[URY]==0) )) {
  148.             if ( (comment = pscopyuntil(psfile.file, f, -1,
  149.                doc->endheader, "%%BoundingBox:")) != (char *)NULL ) {
  150.             free(comment);
  151.             }
  152.         }
  153.         fprintf(f, "%%%%BoundingBox: %d %d %d %d\r\n",
  154.         bbox.llx, bbox.lly, bbox.urx, bbox.ury);
  155.         here = ftell(psfile.file);
  156.         pscopyuntil(psfile.file, f, here, doc->endtrailer, NULL);
  157.         dfclose();
  158.         fclose(f);
  159.         info_wait(FALSE);
  160.     }
  161. }
  162. #endif
  163.  
  164. typedef struct tagWINRECT {
  165.     WORD    left;
  166.     WORD    top;
  167.     WORD    right;
  168.     WORD    bottom;
  169. } WINRECT;
  170.  
  171. typedef struct {
  172.     DWORD    key;
  173.     WORD     hmf;
  174.     WINRECT     bbox;
  175.     WORD    inch;
  176.     DWORD    reserved;
  177.     WORD    checksum;
  178. } METAFILEHEADER;
  179.  
  180.  
  181. /* extract EPS or TIFF or WMF file from DOS EPS file */
  182. void 
  183. extract_doseps(int command)
  184. {
  185. unsigned long pos;
  186. unsigned long len;
  187. unsigned int count;
  188. char *buffer;
  189. FILE* epsfile;
  190. BOOL is_meta = TRUE;
  191. char outname[MAXSTR];
  192. FILE *outfile;
  193. unsigned int filter;
  194.     if ((doc == (PSDOC *)NULL) || (doc->doseps == (DOSEPS *)NULL)) {
  195.         gserror(IDS_NOPREVIEW, NULL, MB_ICONEXCLAMATION, SOUND_ERROR);
  196.         return;
  197.     }
  198.     epsfile = fopen(psfile.name,"rb");
  199.     pos = doc->doseps->ps_begin;
  200.     len = doc->doseps->ps_length;
  201.     if (command == IDM_EXTRACTPRE) {
  202.         pos = doc->doseps->mf_begin;
  203.         len = doc->doseps->mf_length;
  204.         if (pos == 0L) {
  205.             pos = doc->doseps->tiff_begin;
  206.             len = doc->doseps->tiff_length;
  207.             is_meta = FALSE;
  208.         }
  209.     }
  210.     if (pos == 0L) {
  211.         fclose(epsfile);
  212.         gserror(IDS_NOPREVIEW, NULL, MB_ICONEXCLAMATION, SOUND_ERROR);
  213.         return;
  214.     }
  215.     fseek(epsfile, pos, SEEK_SET);    /* seek to section to extract */
  216.  
  217.  
  218. #ifdef EPSTOOL
  219.     /* assume outname already exists */
  220.     strcpy(outname, oname);
  221.     if (*outname!='\0')
  222.         outfile = fopen(outname,"wb");
  223.     else
  224.         outfile = stdout;
  225. #else
  226.     /* create postscript or preview file */
  227.     outname[0] = '\0';
  228.     if (command == IDM_EXTRACTPRE) {
  229.         if (is_meta)
  230.             filter = FILTER_WMF;
  231.         else
  232.             filter = FILTER_TIFF;
  233.     }
  234.     else
  235.         filter = FILTER_PS;
  236.     if (!get_filename(outname, TRUE, filter, 0, IDS_TOPICEDIT)) {
  237.         fclose(epsfile);
  238.         return;
  239.     }
  240.     outfile = fopen(outname, "wb");
  241. #endif
  242.     if (outfile == (FILE *)NULL) {
  243.         play_sound(SOUND_ERROR);
  244.         fclose(epsfile);
  245.         return;
  246.     }
  247.     
  248.     /* create buffer for file copy */
  249.     buffer = malloc(COPY_BUF_SIZE);
  250.     if (buffer == (char *)NULL) {
  251.         play_sound(SOUND_ERROR);
  252.         fclose(epsfile);
  253.         if (*outname!='\0')
  254.             fclose(outfile);
  255.         return;
  256.     }
  257.  
  258.     if ((command == IDM_EXTRACTPRE) && is_meta) {
  259.         /* write placeable Windows Metafile header */
  260.         METAFILEHEADER mfh;
  261.         int i;
  262.         unsigned short *pw;
  263.         mfh.key = reorder_dword(0x9ac6cdd7L);
  264.         mfh.hmf = 0;
  265.         mfh.bbox.left = 0;
  266.         mfh.bbox.right = reorder_word((WORD)(doc->boundingbox[URX] - doc->boundingbox[LLX]));
  267.         mfh.bbox.top = 0;
  268.         mfh.bbox.bottom = reorder_word((WORD)(doc->boundingbox[URY] - doc->boundingbox[LLY]));
  269.         mfh.inch = reorder_word(72);    /* PostScript points */
  270.         mfh.reserved = 0L;
  271.         mfh.checksum =  0;
  272.         pw = (WORD *)&mfh;
  273.         for (i=0; i<10; i++) {
  274.             mfh.checksum ^= *pw++;
  275.         }
  276.         fwrite(&mfh, sizeof(mfh), 1, outfile);
  277.     }
  278.  
  279.         while ( (count = (unsigned int)min(len,COPY_BUF_SIZE)) != 0 ) {
  280.         count = fread(buffer, 1, count, epsfile);
  281.         fwrite(buffer, 1, count, outfile);
  282.         len -= count;
  283.     }
  284.     free(buffer);
  285.     fclose(epsfile);
  286.     if (*outname!='\0')
  287.         fclose(outfile);
  288. }
  289.  
  290.  
  291. /* These routines deal with a PBM bitmap under Unix */
  292. /* and a BMP under OS/2 or MS-DOS */
  293.  
  294. /* a structure for holding details of a bitmap used for constructing */
  295. /* an EPS preview */
  296. typedef struct tagPREBMAP {
  297.     int  width;
  298.     int  height;
  299.     int  depth;
  300.     int  bytewidth;    /* length of each scan line in bytes */
  301.     BYTE GVHUGE* bits;
  302.     BOOL topleft;
  303. } PREBMAP;
  304.  
  305. void scan_bbox(PREBMAP *pprebmap, PSBBOX *psbbox);
  306. void shift_preview(unsigned char *preview, int bwidth, int offset);
  307.  
  308.  
  309. char isblack[256];    /* each byte is non-zero if that colour is black */
  310.  
  311. BOOL
  312. iswhitespace(char c)
  313. {
  314.     return (c==' ' || c=='\t' || c=='\r' || c=='\n');
  315. }
  316.  
  317. /* this doesn't do a good job of scanning pbm format */
  318. /* instead it makes assumptions about the way Ghostscript writes pbm files */
  319. void
  320. scan_pbmplus(PREBMAP *ppbmap, LPBITMAP2 pbm)
  321. {
  322. char *pbitmap;
  323. char *p;
  324. int i;
  325.     pbitmap = (char *)pbm;
  326.     if (pbitmap[0] == 'P' && (pbitmap[1] == '4' || pbitmap[1] == '5')) {
  327.     /* pbmraw */
  328.     p = pbitmap+3;
  329.     while (*p!='\n')
  330.         p++;    /* skip comment line */
  331.     p++;
  332.     ppbmap->width = atoi(p);
  333.     while (isdigit(*p))
  334.         p++;
  335.     while (iswhitespace(*p))
  336.         p++;
  337.     ppbmap->height = atoi(p);
  338.     while (isdigit(*p))
  339.         p++;
  340.     if (pbitmap[1] == '4') {    /* pbmraw */
  341.         ppbmap->depth = 1;
  342.         isblack[0] = 0;
  343.         isblack[1] = 1;
  344.     }
  345.     else {                /* pgmraw */
  346.         while (iswhitespace(*p))
  347.             p++;
  348.         ppbmap->depth = atoi(p);
  349.         while (isdigit(*p))
  350.             p++;
  351.         for (i=0; i<ppbmap->depth; i++)
  352.         isblack[i] = (char)(i!=0);
  353.     }
  354.     ppbmap->bits = ((BYTE GVHUGE *)p) +1;
  355.         ppbmap->bytewidth = (( ppbmap->width * ppbmap->depth + 7) & ~7) >> 3;
  356.     ppbmap->topleft = TRUE;
  357.     }
  358.     else {
  359.     gserror(0, "Unknown bitmap format", MB_ICONEXCLAMATION, SOUND_ERROR);
  360.     }
  361. }
  362.  
  363. #ifdef UNIX
  364. void
  365. scan_dib(PREBMAP *ppbmap, LPBITMAP2 pbm)
  366. {
  367.     fprintf(stderr, "Can't handle BMP format under Unix");
  368. }
  369.  
  370. #else
  371. void scan_colors(PREBMAP *ppbmap, LPBITMAP2 pbm);
  372.  
  373. void
  374. scan_dib(PREBMAP *ppbmap, LPBITMAP2 pbm)
  375. {
  376.     if (pbm->biSize == sizeof(BITMAP1)) {
  377.     ppbmap->width = ((LPBITMAP1)pbm)->bcWidth;
  378.     ppbmap->height = ((LPBITMAP1)pbm)->bcHeight;
  379.     ppbmap->depth = ((LPBITMAP1)pbm)->bcBitCount;
  380.         ppbmap->bytewidth = (( ppbmap->width * ppbmap->depth + 31) & ~31) >> 3;
  381.     ppbmap->bits =  (((BYTE GVHUGE *)pbm) + pbm->biSize)
  382.             + dib_pal_colors(pbm) * sizeof(RGB3); 
  383.     ppbmap->topleft = FALSE;
  384.     }
  385.     else {
  386.     ppbmap->width = (int)pbm->biWidth;
  387.     ppbmap->height = (int)pbm->biHeight;
  388.     ppbmap->depth = pbm->biBitCount;
  389.         ppbmap->bytewidth = (int)(((pbm->biWidth * pbm->biBitCount + 31) & ~31) >> 3);
  390.     ppbmap->bits =  (((BYTE GVHUGE *)pbm) + pbm->biSize)
  391.             + dib_pal_colors(pbm) * sizeof(RGB4); 
  392.     ppbmap->topleft = FALSE;
  393.     }
  394.     scan_colors(ppbmap, pbm);
  395. }
  396.  
  397. /* return number of bytes per line, rounded up to multiple of 4 bytes */
  398. unsigned long
  399. dib_bytewidth(LPBITMAP2 pbm)
  400. {
  401. unsigned long l;
  402.     if (pbm->biSize == sizeof(BITMAP1)) {
  403.         l = ((( ((LPBITMAP1)pbm)->bcWidth * ((LPBITMAP1)pbm)->bcBitCount + 31) & ~31) >> 3);
  404.     }
  405.     else
  406.         l = (((pbm->biWidth * pbm->biBitCount + 31) & ~31) >> 3);
  407.     return l;
  408. }
  409.  
  410. /* return number of colors in color table */
  411. unsigned int
  412. dib_pal_colors(LPBITMAP2 pbm)
  413. {
  414.     if (pbm->biSize == sizeof(BITMAP1)) {
  415.     LPBITMAP1 pbm1 = (LPBITMAP1)pbm;
  416.     if (pbm1->bcBitCount != 24)
  417.         return 1<<(pbm1->bcBitCount * pbm1->bcPlanes);
  418.     }
  419.     else {
  420.     if (pbm->biBitCount != 24)
  421.         return (pbm->biClrUsed) ? (unsigned int)(pbm->biClrUsed) :
  422.         1<<(pbm->biBitCount * pbm->biPlanes);
  423.     }
  424.     return 0;
  425. }
  426.  
  427.  
  428. void
  429. scan_colors(PREBMAP *ppbmap, LPBITMAP2 pbm)
  430. {
  431.     LPRGB4 prgbquad;
  432.     LPRGB3 prgbtriple;
  433.     unsigned char rr;
  434.     unsigned char gg;
  435.     unsigned char bb;
  436.     int type_one = FALSE;
  437.     int clrtablesize;
  438.     int i;
  439.  
  440.     prgbquad   = (LPRGB4)(((BYTE GVHUGE *)pbm) + pbm->biSize);
  441.     prgbtriple = (LPRGB3)prgbquad;
  442.     if (pbm->biSize == sizeof(BITMAP1))
  443.         type_one = TRUE;
  444.     /* read in the color table */
  445.     clrtablesize = dib_pal_colors(pbm);
  446.     for (i = 0; i < clrtablesize; i++) {
  447.         if (type_one) {
  448.             bb = prgbtriple[i].rgbtBlue;
  449.             gg = prgbtriple[i].rgbtGreen;
  450.             rr = prgbtriple[i].rgbtRed;
  451.         }
  452.         else {
  453.             bb = prgbquad[i].rgbBlue;
  454.             gg = prgbquad[i].rgbGreen;
  455.             rr = prgbquad[i].rgbRed;
  456.         }
  457.         isblack[i] = (unsigned char)((rr < 0xff) || (gg < 0xff) || (bb < 0xff));
  458.     }
  459. }
  460.  
  461. /* return pointer to bitmap bits */
  462. BYTE GVHUGE *
  463. get_dib_bits(LPBITMAP2 pbm)
  464. {
  465. BYTE GVHUGE *lpDibBits;
  466.     lpDibBits = (((BYTE GVHUGE *)pbm) + pbm->biSize);
  467.     if (pbm->biSize == sizeof(BITMAP1))
  468.         lpDibBits += dib_pal_colors(pbm) * sizeof(RGB3); 
  469.     else
  470.         lpDibBits += dib_pal_colors(pbm) * sizeof(RGB4); 
  471.     return lpDibBits;
  472. }
  473. #endif /* !UNIX */
  474.  
  475. /* get line from DIB and store as 1 bit/pixel in preview */
  476. /* also works for PBM bitmap */
  477. /* preview has 0=black, 1=white */
  478. void
  479. get_dib_line(BYTE GVHUGE *line, unsigned char *preview, int width, int bitcount)
  480. {
  481. int bwidth = ((width + 7) & ~7) >> 3; /* byte width with 1 bit/pixel */
  482. unsigned char omask;
  483. int oroll;
  484. unsigned char c = 0;
  485. int j;
  486.     memset(preview,0xff,bwidth);
  487.     omask = 0x80;
  488.     oroll = 7;
  489.     if (bitcount == 1) {
  490.         if (isblack[0])
  491.         for (j = 0; j < bwidth ; j++)
  492.             preview[j] = line[j];
  493.         else
  494.         for (j = 0; j < bwidth ; j++)
  495.             preview[j] = (unsigned char)~line[j];
  496.         preview[bwidth-1] |= (unsigned char)(width & 7 ? (1<<(8-(width&7)))-1 : 0);    /* mask for edge of bitmap */
  497.     }
  498.     else {
  499.         for (j = 0; j < width; j++) {
  500.         switch (bitcount) {
  501.             case 4:
  502.                 c = line[j>>1];
  503.                 if (!(j&1))
  504.                     c >>= 4;
  505.                 c = isblack[ c & 0x0f ];
  506.                 break;
  507.             case 8:
  508.                 c = isblack[ (int)(line[j]) ];
  509.                 break;
  510.             case 24:
  511.                 c = (unsigned char)(
  512.                     (line[j*3] < 0xff) || 
  513.                     (line[j*3+1] < 0xff) || 
  514.                     (line[j*3+2] < 0xff) );
  515.                 break;
  516.         }
  517.         if (c) 
  518.             preview[j/8] &= (unsigned char)(~omask);
  519.         else
  520.             preview[j/8] |= omask;
  521.         oroll--;
  522.         omask >>= 1;
  523.         if (oroll < 0) {
  524.             omask = 0x80;
  525.             oroll = 7;
  526.         }
  527.         }
  528.     }
  529. }
  530.  
  531. #define TIFF_BYTE 1
  532. #define TIFF_ASCII 2
  533. #define TIFF_SHORT 3
  534. #define TIFF_LONG 4
  535. #define TIFF_RATIONAL 5
  536.  
  537. struct rational_s {
  538.     DWORD numerator;
  539.     DWORD denominator;
  540. };
  541.  
  542. struct ifd_entry_s {
  543.     WORD tag;
  544.     WORD type;
  545.     DWORD length;
  546.     DWORD value;
  547. };
  548.  
  549. struct tiff_head_s {
  550.     WORD order;
  551.     WORD version;
  552.     DWORD ifd_offset;
  553. };
  554.  
  555. /* write tiff file from DIB bitmap */
  556. void
  557. write_tiff(FILE *f, LPBITMAP2 pbm, BOOL tiff4)
  558. {
  559. char *now;
  560. DWORD *strip;
  561. #define IFD_MAX_ENTRY 12
  562. struct tiff_head_s tiff_head;
  563. WORD ifd_length;
  564. DWORD ifd_next;
  565. struct ifd_entry_s ifd_entry[IFD_MAX_ENTRY];
  566. struct ifd_entry_s *pifd_entry;
  567. struct rational_s rational;
  568. DWORD tiff_end, end;
  569. time_t t;
  570. int i;
  571. unsigned char *preview;
  572. BYTE GVHUGE *line;
  573. int bwidth;
  574. BOOL soft_extra = FALSE;
  575. BOOL date_extra = FALSE;
  576. PREBMAP prebmap;
  577.     
  578.     if (*(char *)pbm == 'P')
  579.         scan_pbmplus(&prebmap, pbm);
  580.     else
  581.         scan_dib(&prebmap, pbm);
  582.  
  583.     /* byte width with 1 bit/pixel, rounded up even word */
  584.     bwidth = ((prebmap.width + 15) & ~15) >> 3;
  585.  
  586.     tiff_end = sizeof(tiff_head);
  587.     if (reorder_word(1) == 1)
  588.         tiff_head.order = 0x4949;    /* Intel = little endian */
  589.     else
  590.         tiff_head.order = 0x4d4d;    /* Motorola = big endian */
  591.     tiff_head.version = 42;
  592.     tiff_head.ifd_offset = tiff_end;
  593.  
  594.     tiff_end += sizeof(ifd_length);
  595.  
  596.     if (tiff4)
  597.         ifd_length = 10;
  598.     else
  599.         ifd_length = 12;
  600.  
  601.     tiff_end += ifd_length * sizeof(struct ifd_entry_s) + sizeof(ifd_next);
  602.     ifd_next = 0;
  603.     pifd_entry = &ifd_entry[0];
  604.     if (tiff4) {
  605.         pifd_entry->tag = 0xff;    /* SubfileType */
  606.         pifd_entry->type = TIFF_SHORT;
  607.     }
  608.     else {
  609.         pifd_entry->tag = 0xfe;    /* NewSubfileType */
  610.         pifd_entry->type = TIFF_LONG;
  611.     }
  612.     pifd_entry->length = 1;
  613.     pifd_entry->value = 0;
  614.  
  615.     pifd_entry = &ifd_entry[1];
  616.     pifd_entry->tag = 0x100;    /* ImageWidth */
  617.     if (tiff4)
  618.         pifd_entry->type = TIFF_SHORT;
  619.     else
  620.         pifd_entry->type = TIFF_LONG;
  621.     pifd_entry->length = 1;
  622.     pifd_entry->value = prebmap.width;
  623.  
  624.     pifd_entry = &ifd_entry[2];
  625.     pifd_entry->tag = 0x101;    /* ImageLength */
  626.     if (tiff4)
  627.         pifd_entry->type = TIFF_SHORT;
  628.     else
  629.         pifd_entry->type = TIFF_LONG;
  630.     pifd_entry->length = 1;
  631.     pifd_entry->value = prebmap.height;
  632.  
  633.     pifd_entry = &ifd_entry[3];
  634.     pifd_entry->tag = 0x103;    /* Compression */
  635.     pifd_entry->type = TIFF_SHORT;
  636.     pifd_entry->length = 1;
  637.     pifd_entry->value = 1;        /* no compression */
  638.  
  639.     pifd_entry = &ifd_entry[4];
  640.     pifd_entry->tag = 0x106;    /* PhotometricInterpretation */
  641.     pifd_entry->type = TIFF_SHORT;
  642.     pifd_entry->length = 1;
  643.     pifd_entry->value = 1;        /* black is zero */
  644.  
  645.     pifd_entry = &ifd_entry[5];
  646.     pifd_entry->tag = 0x111;    /* StripOffsets */
  647.     pifd_entry->type = TIFF_LONG;
  648.     pifd_entry->length = prebmap.height;
  649.     pifd_entry->value = tiff_end;
  650.     tiff_end += (pifd_entry->length * sizeof(DWORD));
  651.  
  652.     pifd_entry = &ifd_entry[6];
  653.     pifd_entry->tag = 0x116;    /* RowsPerStrip */
  654.     pifd_entry->type = TIFF_LONG;
  655.     pifd_entry->length = 1;
  656.     pifd_entry->value = 1;
  657.  
  658.     pifd_entry = &ifd_entry[7];
  659.     pifd_entry->tag = 0x117;    /* StripByteCounts */
  660.     pifd_entry->type = TIFF_LONG;
  661.     pifd_entry->length = prebmap.height;
  662.     pifd_entry->value = tiff_end;
  663.     tiff_end += (pifd_entry->length * sizeof(DWORD));
  664.  
  665.     pifd_entry = &ifd_entry[8];
  666.     pifd_entry->tag = 0x11a;    /* XResolution */
  667.     pifd_entry->type = TIFF_RATIONAL;
  668.     pifd_entry->length = 1;
  669.     pifd_entry->value = tiff_end;
  670.     tiff_end += sizeof(struct rational_s);
  671.  
  672.     pifd_entry = &ifd_entry[9];
  673.     pifd_entry->tag = 0x11b;    /* YResolution */
  674.     pifd_entry->type = TIFF_RATIONAL;
  675.     pifd_entry->length = 1;
  676.     pifd_entry->value = tiff_end;
  677.     tiff_end += sizeof(struct rational_s);
  678.  
  679.     if (!tiff4) {
  680.         pifd_entry = &ifd_entry[10];
  681.         pifd_entry->tag = 0x131;    /* Software */
  682.         pifd_entry->type = TIFF_ASCII;
  683.         pifd_entry->length = strlen(szAppName) + 1;
  684.         pifd_entry->value = tiff_end;
  685.         tiff_end += pifd_entry->length;
  686.         if (tiff_end & 1) { /* pad to word boundary */
  687.             soft_extra = TRUE;
  688.             tiff_end++;
  689.         }
  690.  
  691.         pifd_entry = &ifd_entry[11];
  692.         pifd_entry->tag = 0x132;    /* DateTime */
  693.         pifd_entry->type = TIFF_ASCII;
  694.         t = time(NULL);
  695.         now = ctime(&t);
  696.         now[strlen(now)-1] = '\0';    /* remove trailing \n */
  697.         pifd_entry->length = strlen(now)+1;
  698.         pifd_entry->value = tiff_end;
  699.         tiff_end += pifd_entry->length;
  700.         if (tiff_end & 1) { /* pad to word boundary */
  701.             date_extra = TRUE;
  702.             tiff_end++;
  703.         }
  704.     }
  705.  
  706.     fwrite(&tiff_head, sizeof(tiff_head), 1, f);
  707.     fwrite(&ifd_length, sizeof(ifd_length), 1, f);
  708.     fwrite(ifd_entry, ifd_length * sizeof(struct ifd_entry_s), 1, f);
  709.     fwrite(&ifd_next, sizeof(ifd_next), 1, f);
  710.     strip = (DWORD *)malloc(prebmap.height * sizeof(DWORD));
  711.     end = tiff_end;
  712.     for (i=0; i<prebmap.height; i++) {
  713.         strip[i] = end;        /* strip offsets */
  714.         end += bwidth;
  715.     }
  716.     fwrite(strip, 1, prebmap.height * sizeof(DWORD), f);
  717.     for (i=0; i<prebmap.height; i++)
  718.         strip[i] = bwidth;    /* strip byte counts */
  719.     fwrite(strip, 1, prebmap.height * sizeof(DWORD), f);
  720.     free((void *)strip);
  721.     rational.numerator = (int)option.xdpi;
  722.     rational.denominator = 1;
  723.     fwrite(&rational, sizeof(rational), 1, f);
  724.     rational.numerator = (int)option.ydpi;
  725.     rational.denominator = 1;
  726.     fwrite(&rational, sizeof(rational), 1, f);
  727.     if (!tiff4) {
  728.         fwrite(szAppName, 1, strlen(szAppName)+1, f);
  729.         if (soft_extra)
  730.             fputc('\0',f);
  731.         fwrite(now, 1, strlen(now)+1, f);
  732.         if (date_extra)
  733.             fputc('\0',f);
  734.     }
  735.  
  736.     preview = (unsigned char *) malloc(bwidth);
  737.     memset(preview,0xff,bwidth);
  738.  
  739.     if (prebmap.topleft)
  740.         line = (BYTE GVHUGE *)prebmap.bits;
  741.     else
  742.         line = (BYTE GVHUGE *)prebmap.bits + ((long)prebmap.bytewidth * (prebmap.height-1));
  743.         /* process each line of bitmap */
  744.     for (i = 0; i < prebmap.height; i++) {
  745.         get_dib_line(line, preview, prebmap.width, prebmap.depth);
  746.         fwrite(preview, 1, bwidth, f);
  747.         if (prebmap.topleft)
  748.         line += prebmap.bytewidth;
  749.         else
  750.         line -= prebmap.bytewidth;
  751.     }
  752.     free(preview);
  753. }
  754.  
  755.  
  756. /* make a PC EPS file with a TIFF Preview */
  757. /* from a PS file and a bitmap */
  758. void
  759. make_eps_tiff(int type)
  760. {
  761. char epsname[MAXSTR];
  762. LPBITMAP2 pbm;
  763. char *buffer;
  764. unsigned int count;
  765. FILE *epsfile;
  766. FILE *tiff_file;
  767. char tiffname[MAXSTR];
  768. #ifdef __EMX__
  769. #pragma pack(1)
  770. #endif
  771. struct eps_header_s eps_header;
  772. #ifdef __EMX__
  773. #pragma pack()
  774. #endif
  775.  
  776.     
  777.     if ( (pbm = get_bitmap()) == (LPBITMAP2)NULL) {
  778.         play_sound(SOUND_ERROR);
  779.         return;
  780.     }
  781.  
  782.     if ( (tiff_file = gp_open_scratch_file(szScratch, tiffname, "wb")) == (FILE *)NULL) {
  783.         play_sound(SOUND_ERROR);
  784.         release_bitmap();
  785.         return;
  786.     }
  787.     write_tiff(tiff_file, pbm, (type == IDM_MAKEEPST4));
  788.     fclose(tiff_file);
  789.     release_bitmap();
  790.  
  791. #ifdef EPSTOOL
  792.     strcpy(epsname, oname);
  793.     if (*epsname!='\0')
  794.         epsfile = fopen(epsname,"wb");
  795.     else
  796.         epsfile = stdout;
  797. #else
  798.     /* create EPS file */
  799.     epsname[0] = '\0';
  800.     if (!get_filename(epsname, TRUE, FILTER_EPS, 0, IDS_TOPICEDIT)) {
  801.         unlink(tiffname);
  802.         return;
  803.     }
  804.     epsfile = fopen(epsname,"wb");
  805. #endif
  806.     if (epsfile == (FILE *)NULL) {
  807.         play_sound(SOUND_ERROR);
  808.         release_bitmap();
  809.         return;
  810.     }
  811.  
  812.     /* write DOS EPS binary header */
  813.     eps_header.id[0] = 0xc5;
  814.     eps_header.id[1] = 0xd0;
  815.     eps_header.id[2] = 0xd3;
  816.     eps_header.id[3] = 0xc6;
  817.     eps_header.ps_begin = sizeof(eps_header);
  818.     fseek(psfile.file, 0, SEEK_END);
  819.     eps_header.ps_length = ftell(psfile.file);
  820.     eps_header.mf_begin = 0;
  821.     eps_header.mf_length = 0;
  822.     eps_header.tiff_begin = eps_header.ps_begin + eps_header.ps_length;
  823.     tiff_file = fopen(tiffname,"rb");
  824.     fseek(tiff_file, 0, SEEK_END);
  825.     eps_header.tiff_length = ftell(tiff_file);
  826.     eps_header.checksum = -1;
  827.     /* reverse byte order if big endian machine */
  828.     eps_header.ps_begin = reorder_dword(eps_header.ps_begin);
  829.     eps_header.ps_length = reorder_dword(eps_header.ps_length);
  830.     eps_header.tiff_begin = reorder_dword(eps_header.tiff_begin);
  831.     eps_header.tiff_length = reorder_dword(eps_header.tiff_length);
  832.     fwrite(&eps_header, sizeof(eps_header), 1, epsfile);
  833.     rewind(psfile.file);
  834.     pscopyuntil(psfile.file, epsfile, doc->beginheader, doc->endtrailer, NULL);
  835.     
  836.     /* copy tiff file */
  837.     rewind(tiff_file);
  838.     buffer = malloc(COPY_BUF_SIZE);
  839.     if (buffer == (char *)NULL) {
  840.         play_sound(SOUND_ERROR);
  841.         fclose(epsfile);
  842.         unlink(epsname);
  843.         fclose(tiff_file);
  844.         unlink(tiffname);
  845.         return;
  846.     }
  847.         while ( (count = fread(buffer, 1, COPY_BUF_SIZE, tiff_file)) != 0 )
  848.         fwrite(buffer, 1, count, epsfile);
  849.     free(buffer);
  850.     fclose(tiff_file);
  851.     unlink(tiffname);
  852.     if (*epsname!='\0')
  853.        fclose(epsfile);
  854. }
  855.  
  856. static char hex[16] = "0123456789ABCDEF";
  857.  
  858. /* write interchange preview to file f */
  859. void
  860. write_interchange(FILE *f, LPBITMAP2 pbm, BOOL calc_bbox)
  861. {
  862.     int i, j;
  863.     unsigned char *preview;
  864.     BYTE GVHUGE *line;
  865.     int preview_width, bwidth;
  866.     int lines_per_scan;
  867.     PREBMAP prebmap;
  868.     PSBBOX devbbox;    /* in pixel units */
  869.     
  870.     if (*(char *)pbm == 'P')
  871.         scan_pbmplus(&prebmap, pbm);
  872.     else
  873.         scan_dib(&prebmap, pbm);
  874.     
  875.     if (calc_bbox) {
  876.         scan_bbox(&prebmap, &devbbox);
  877.         if (devbbox.valid) {
  878.             /* copy to global bbox as if obtained by PS to EPS */
  879.             bbox.llx = devbbox.llx * 72.0 / option.xdpi;
  880.             bbox.lly = devbbox.lly * 72.0 / option.ydpi;
  881.             bbox.urx = devbbox.urx * 72.0 / option.xdpi;
  882.             bbox.ury = devbbox.ury * 72.0 / option.ydpi;
  883.             bbox.valid = TRUE;
  884.         }
  885.         copy_bbox_header(f); /* adjust %%BoundingBox: comment */
  886.     }
  887.     else {
  888.         devbbox.urx = prebmap.width;
  889.         devbbox.ury = prebmap.height;
  890.         devbbox.llx = devbbox.lly = 0;
  891.         pscopyuntil(psfile.file, f, doc->beginheader, doc->endheader, NULL);
  892.     }
  893.  
  894.     bwidth = (((devbbox.urx-devbbox.llx) + 7) & ~7) >> 3; /* byte width with 1 bit/pixel */
  895.     preview_width = ((prebmap.width + 7) & ~7) >> 3; /* byte width with 1 bit/pixel */
  896.  
  897.     preview = (unsigned char *) malloc(preview_width);
  898.  
  899.     lines_per_scan = ((bwidth-1) / 32) + 1;
  900.     fprintf(f,"%%%%BeginPreview: %u %u 1 %u",(devbbox.urx-devbbox.llx), (devbbox.ury-devbbox.lly), 
  901.         (devbbox.ury-devbbox.lly)*lines_per_scan);
  902.     fputs(EOLSTR, f);
  903.  
  904.     if (prebmap.topleft)
  905.         line = (BYTE GVHUGE *)prebmap.bits + ((long)prebmap.bytewidth * (prebmap.height - devbbox.ury));
  906.     else
  907.         line = (BYTE GVHUGE *)prebmap.bits + ((long)prebmap.bytewidth * (devbbox.ury-1));
  908.     /* process each line of bitmap */
  909.     for (i = 0; i < (devbbox.ury-devbbox.lly); i++) {
  910.         get_dib_line(line, preview, prebmap.width, prebmap.depth);
  911.         if (devbbox.llx)
  912.             shift_preview(preview, preview_width, devbbox.llx);
  913.         fputs("% ",f);
  914.         for (j=0; j<bwidth; j++) {
  915.             if (j && ((j & 31) == 0)) {
  916.             fputs(EOLSTR, f);
  917.                 fputs("% ",f);
  918.             }
  919.             fputc(hex[15-((preview[j]>>4)&15)],f);
  920.             fputc(hex[15-((preview[j])&15)],f);
  921.         }
  922.         fputs(EOLSTR, f);
  923.         if (prebmap.topleft)
  924.             line += prebmap.bytewidth;
  925.         else 
  926.             line -= prebmap.bytewidth;
  927.     }
  928.  
  929.     fputs("%%EndPreview",f);
  930.     fputs(EOLSTR, f);
  931.     free(preview);
  932.     pscopyuntil(psfile.file, f, doc->endpreview, doc->endtrailer, NULL);
  933. }
  934.  
  935. /* make an EPSI file with an Interchange Preview */
  936. /* from a PS file and a bitmap */
  937. void
  938. make_eps_interchange(BOOL calc_bbox)
  939. {
  940. char epiname[MAXSTR];
  941. FILE *epifile;
  942. LPBITMAP2 pbm;
  943.  
  944.     if ( (pbm = get_bitmap()) == (LPBITMAP2)NULL) {
  945.         play_sound(SOUND_ERROR);
  946.         return;
  947.     }
  948.  
  949. #ifdef EPSTOOL
  950.     strcpy(epiname, oname);
  951.     if (*epiname!='\0')
  952.         epifile = fopen(epiname,"wb");
  953.     else
  954.         epifile = stdout;
  955. #else
  956.     /* create EPI file */
  957.     epiname[0] = '\0';
  958.     if (!get_filename(epiname, TRUE, FILTER_EPI, 0, IDS_TOPICEDIT)) {
  959.         play_sound(SOUND_ERROR);
  960.         release_bitmap();
  961.         return;
  962.     }
  963.     epifile = fopen(epiname,"wb");
  964. #endif
  965.  
  966.     if (epifile == (FILE *)NULL) {
  967.         play_sound(SOUND_ERROR);
  968.         release_bitmap();
  969.         return;
  970.     }
  971.  
  972.     rewind(psfile.file);
  973.     write_interchange(epifile, pbm, calc_bbox);
  974.     if (*epiname!='\0')
  975.         fclose(epifile);
  976.     release_bitmap();
  977. }
  978.  
  979.  
  980. /* scan bitmap and return bbox measured in pixels */
  981. void
  982. scan_bbox(PREBMAP *pprebmap, PSBBOX *devbbox)
  983. {
  984.     unsigned char *preview;
  985.     BYTE GVHUGE *line;
  986.     int bwidth = ((pprebmap->width + 7) & ~7) >> 3; /* byte width with 1 bit/pixel */
  987.     int i, j, k, l;
  988.     int x;
  989.     BYTE ch;
  990.     BYTE GVHUGE *chline;
  991.     unsigned char omask;
  992.  
  993.     devbbox->llx = pprebmap->width;
  994.     devbbox->lly = pprebmap->height;
  995.     devbbox->urx = devbbox->ury = 0;
  996.     devbbox->valid = FALSE;
  997.  
  998.     preview = (unsigned char *) malloc(bwidth);
  999.     memset(preview,0xff,bwidth);
  1000.  
  1001.     if (pprebmap->topleft)
  1002.         line = (BYTE GVHUGE *)pprebmap->bits + ((long)pprebmap->bytewidth * (pprebmap->height-1));
  1003.     else
  1004.         line = (BYTE GVHUGE *)pprebmap->bits;
  1005.         /* process each line of bitmap */
  1006.     for (i = 0; i < pprebmap->height; i++) {
  1007.         /* get 1bit/pixel line, 0=black, 1=white */
  1008.         get_dib_line(line, preview, pprebmap->width, pprebmap->depth);
  1009.         chline = preview;
  1010.         ch = 0;
  1011.         for (j=0; j<bwidth; j++)
  1012.             ch |= (BYTE)(~(*chline++));    /* check for black pixels */
  1013.         if (ch) {
  1014.         /* adjust y coordinates of bounding box */
  1015.         if (i < devbbox->lly)
  1016.             devbbox->lly = i;
  1017.         if (i+1 > devbbox->ury)
  1018.             devbbox->ury = i+1;
  1019.         /* scan for x coordinates of black pixels */
  1020.             chline = preview;
  1021.         for (k=0; k<bwidth; k++) {
  1022.             if (~(*chline)) { /* a pixel is black */
  1023.             omask = 0x80;
  1024.             for (l=0; l<8; l++) {
  1025.                 if ( ~*chline & omask ) {
  1026.                     x = k*8 + l;
  1027.                     if (x < devbbox->llx)
  1028.                         devbbox->llx = x;
  1029.                     if (x+1 > devbbox->urx)
  1030.                         devbbox->urx = x+1;
  1031.                 }
  1032.                     omask >>= 1;
  1033.             }
  1034.             }
  1035.             chline++;
  1036.         }
  1037.         }
  1038.         if (pprebmap->topleft)
  1039.         line -= pprebmap->bytewidth;
  1040.         else
  1041.         line += pprebmap->bytewidth;
  1042.     }
  1043.     free(preview);
  1044.     if ( (devbbox->lly < devbbox->ury) && (devbbox->llx < devbbox->urx) )
  1045.         devbbox->valid = TRUE;
  1046.     
  1047. #ifdef EPSTOOL
  1048.     {   char buf[256];
  1049.         sprintf(buf, "bbox=%d %d %d %d\n", devbbox->llx, devbbox->lly, devbbox->urx, devbbox->ury);
  1050.         pserror(buf);
  1051.     }
  1052. #endif
  1053. }
  1054.  
  1055. /* shift preview by offset bits to the left */
  1056. /* width is in bytes */
  1057. /* fill exposed bits with 1's */
  1058. void
  1059. shift_preview(unsigned char *preview, int bwidth, int offset)
  1060. {
  1061. int bitoffset;
  1062. int byteoffset;
  1063. int newwidth;
  1064. int shifter;
  1065. int i;
  1066.     if (offset == 0)
  1067.         return;
  1068.     byteoffset = offset / 8;
  1069.     newwidth = bwidth - byteoffset;
  1070.     /* first remove byte offset */
  1071.     memmove(preview, preview+byteoffset, newwidth);
  1072.     memset(preview+newwidth, 0xff, bwidth-newwidth);
  1073.     /* next remove bit offset */
  1074.     bitoffset = offset - byteoffset*8;
  1075.     if (bitoffset==0)
  1076.         return;
  1077.     bitoffset = 8 - bitoffset;
  1078.     for (i=0; i<newwidth; i++) {
  1079.        shifter = preview[i] << 8;
  1080.        if (i==newwidth-1)
  1081.            shifter += 0xff;    /* can't access preview[bwidth] */
  1082.        else
  1083.            shifter += preview[i+1];  
  1084.        preview[i] = (unsigned char)(shifter>>bitoffset);
  1085.     }
  1086. }
  1087.  
  1088. /* Copy the header to file f */
  1089. /* change bbox line if present, or add bbox line */
  1090. void
  1091. copy_bbox_header(FILE *f)
  1092. {
  1093.     char text[PSLINELENGTH];
  1094.     char *comment;
  1095.     BOOL bbox_written = FALSE;
  1096.     long position;
  1097.  
  1098.     fseek(psfile.file, doc->beginheader, SEEK_SET);
  1099.       if (!( (doc->boundingbox[LLX]==0) &&  (doc->boundingbox[LLY]==0) 
  1100.           && (doc->boundingbox[URX]==0) &&  (doc->boundingbox[URY]==0) )) {
  1101.       position = ftell(psfile.file);
  1102.       while ( (comment = pscopyuntil(psfile.file, f, position,
  1103.                doc->endheader, "%%BoundingBox:")) != (char *)NULL ) {
  1104.     position = ftell(psfile.file);
  1105.     if (bbox_written) {
  1106.         free(comment);
  1107.         continue;
  1108.     }
  1109.     fprintf(f, "%%%%BoundingBox: %d %d %d %d\r\n",
  1110.         bbox.llx, bbox.lly, bbox.urx, bbox.ury);
  1111.     bbox_written = TRUE;
  1112.     free(comment);
  1113.       }
  1114.     }
  1115.     else {
  1116.       fgets(text, PSLINELENGTH, psfile.file);
  1117.       fputs(text,f);
  1118.       fprintf(f, "%%%%BoundingBox: %d %d %d %d\r\n",
  1119.         bbox.llx, bbox.lly, bbox.urx, bbox.ury);
  1120.       position = ftell(psfile.file);
  1121.       comment = pscopyuntil(psfile.file, f, position, doc->endheader, NULL);
  1122.     }
  1123. }
  1124.  
  1125.