about summary refs log tree commit diff
path: root/converter/ppm/sldtoppm.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/ppm/sldtoppm.c')
-rw-r--r--converter/ppm/sldtoppm.c650
1 files changed, 650 insertions, 0 deletions
diff --git a/converter/ppm/sldtoppm.c b/converter/ppm/sldtoppm.c
new file mode 100644
index 00000000..7da6d592
--- /dev/null
+++ b/converter/ppm/sldtoppm.c
@@ -0,0 +1,650 @@
+/*
+
+      Convert an AutoCAD slide (.sld) file to PPM format
+
+    An AutoCAD slide is a compressed sequence of  vectors  and  filled
+    polygons.   The  ppmdraw  package  is  used  to scan convert these
+    geometrical objects into a portable pixmap.
+
+    Author:
+        John Walker
+        Autodesk SA
+        Avenue des Champs-Montants 14b
+        CH-2074 MARIN
+        Switzerland
+        Usenet: kelvin@Autodesk.com
+        Fax:    038/33 88 15
+        Voice:  038/33 76 33
+
+    Permission  to  use, copy, modify, and distribute this software and
+    its documentation  for  any  purpose  and  without  fee  is  hereby
+    granted,  without any conditions or restrictions.  This software is
+    provided "as is" without express or implied warranty.
+
+*/
+
+#include <string.h>
+#include <math.h>
+
+#include "ppm.h"
+#include "ppmdraw.h"
+#include "nstring.h"
+#ifdef DEBUG
+#include <assert.h>
+#else
+#define assert(x)
+#endif
+
+/*  Define a variable type accepting numbers -127 <= n <= 127.  But note
+    that we still expect it to act UNSIGNED. */
+
+#define smallint unsigned char        /* Small integers */
+
+#define TRUE     1
+#define FALSE    0
+
+#define EOS     '\0'
+
+/* Screen point */
+
+struct spoint {
+    int x, y;
+};
+
+/* Screen polygon */
+
+struct spolygon { 
+    int npoints,              /* Number of points in polygon */
+          fill;           /* Fill type */
+    struct spoint pt[11];         /* Actual points */
+};
+
+/* Screen vector */
+
+struct svector {
+    struct spoint f;          /* From point */
+    struct spoint t;          /* To point */
+};
+
+static int extend ARGS((smallint ch));
+static int sli ARGS((void));
+static int slib ARGS((void));
+static void vscale ARGS((int *px, int *py));
+static void slider ARGS((void (*slvec) ARGS((struct svector *vec, int color)),
+                    void (*slflood) ARGS((struct spolygon *poly, int color)) ));
+static void slidefind ARGS((char *sname, int dironly, int ucasen));
+static void draw ARGS((struct svector *vec, int color));
+static void flood ARGS((struct spolygon *poly, int color));
+
+static int ixdots, iydots;        /* Screen size in dots */
+static FILE *slfile;              /* Slide file descriptor */
+static int blither = FALSE;       /* Dump slide file information ? */
+static int info = FALSE;          /* Print header information */
+static pixel **pixels;            /* Pixel map */
+static int pixcols, pixrows;          /* Pixel map size */
+#define pixmaxval 255             /* Largest pixel value */
+static double uscale = -1;        /* Uniform scale factor */
+static int sxsize = -1, sysize = -1;  /* Scale to X, Y size ? */
+
+#include "autocad.h"                  /* AutoCAD standard color assignments */
+
+/*  Local variables  */
+
+struct slhead {
+    char slh[17];             /* Primate-readable header */
+    char sntype;              /* Machine type (for number compat) */
+    char slevel;              /* Format type */
+    short sxdots, sydots;         /* Display X, Y dots */
+    double sdsar;             /* Display aspect ratio */
+    short shwfill;            /* Display hardware fill type */
+    char spad;                /* Pad to even byte length */
+};
+
+static int adjust = FALSE;        /* Adjust to correct aspect ratio ? */
+static struct slhead slfrof;          /* Slide file header */
+static long xfac, yfac;           /* Aspect ratio scale factors */
+
+static int sdrawkcab;             /* Slide drawing kinematic conversion of
+                     ass-backwards data flag */
+
+/*  EXTEND  --  Turn a smallint into an int with sign extension, whether
+        or not that happens automatically.  */
+
+static int extend(smallint ch)
+{
+    return ((int) ((ch & 0x80) ? (ch | ~0xFF) : ch));
+}
+
+/*  SLI  --  Input word from slide file  */
+
+static int sli()
+{
+    short wd;
+
+    if (fread(&wd, sizeof wd, 1, slfile) != 1) {
+        pm_error("error reading slide file");
+    } else {
+    if (sdrawkcab) {
+        wd = ((wd >> 8) & 0xFF) | (wd << 8);
+    }
+    }
+    return wd;
+}
+
+/*  SLIB  --  Input byte from slide file  */
+
+static int slib()
+{
+    smallint ch = 0;
+
+    if (fread(&ch, sizeof ch, 1, slfile) != 1) {
+        pm_error("error reading slide file");
+    }
+    return extend(ch);
+}
+
+/*  VSCALE -- scale screen coordinates for mismatched display.  */
+
+static void vscale(px, py)
+  int *px, *py;
+{
+    *px = (((unsigned) *px) * xfac) >> 16;
+    *py = (((unsigned) *py) * yfac) >> 16;
+}
+
+/*  SLIDER  --  Read slide file.  This is called with the name of the
+        file to be read and function pointers to the routines
+        which process vectors and polygon fill requests
+        respectively.
+*/
+
+static void slider(slvec, slflood)
+  void (*slvec) ARGS((struct svector *vec, int color));
+  void (*slflood) ARGS((struct spolygon *poly, int color));
+{
+    int i, rescale;
+    unsigned char ubfr[4];        /* Utility character buffer */
+    int lx, ly;               /* Last x and y point */
+    int slx, sly;             /* Last x and y scaled screen point */
+    struct svector vec;           /* Screen vector */
+    struct spolygon poly;         /* Screen polygon */
+    unsigned short cw;            /* Control word */
+    double dsar;              /* Screen aspect ratio */
+    long ldsar;               /* Scaled long DSAR */
+    short rtest;              /* Value to test byte reversal */
+    short btest = 0x1234;         /* Value to test byte-reversal */
+    static struct slhead slhi =       /* Master slide header sample */
+        {"AutoCAD Slide\r\n\32", 86,2, 0,0, 0.0, 0};
+    int curcolor = 7;             /* Current vector color */
+    pixel rgbcolor;           /* Pixel used to clear pixmap */
+
+    lx = ly = 32000;
+
+    /* Process the header of the slide file.  */
+
+    sdrawkcab = FALSE;            /* Initially guess byte order is OK */
+    fread(slfrof.slh, 17, 1, slfile);
+    fread(&slfrof.sntype, sizeof(char), 1, slfile);
+    fread(&slfrof.slevel, sizeof(char), 1, slfile);
+    fread(&slfrof.sxdots, sizeof(short), 1, slfile);
+    fread(&slfrof.sydots, sizeof(short), 1, slfile);
+    fread(ubfr, 4, 1, slfile);
+    fread(&slfrof.shwfill, sizeof(short), 1, slfile);
+    fread(&rtest, sizeof rtest, 1, slfile);
+
+    /* Verify that slide format is compatible with this program. */
+
+    if (STREQ(slfrof.slh, slhi.slh)) {
+        pm_error("this is not an AutoCAD slide file.");
+    }
+
+    /* Verify that the number format and file level in the header  are
+       compatible.  All slides written by versions of AutoCAD released
+       since September of 1987 are compatible with this format.  */
+
+    if ((slfrof.sntype != slhi.sntype) || (slfrof.slevel != slhi.slevel)) {
+        pm_error("incompatible slide file format");
+    }
+
+    /* Build SDSAR value from long scaled version. */
+
+    ldsar = 0L;
+    for (i = 3; i >= 0; i--) {
+    ldsar = (ldsar << 8) | ubfr[i];
+    }
+    slfrof.sdsar = ((double) ldsar) / 1E7;
+
+    /* Examine the byte order test value.   If it's backwards, set the
+       byte-reversal flag and correct all of the values we've read  in
+       so far. */
+
+    if (btest != rtest) {
+    sdrawkcab = TRUE;
+#define rshort(x) x = ((x >> 8) & 0xFF) | (x << 8)
+    rshort(slfrof.sxdots);
+    rshort(slfrof.sydots);
+    rshort(slfrof.shwfill);
+#undef rshort
+    }
+
+    /* Dump the header if we're blithering. */
+
+    if (blither || info) {
+        pm_message("Slide file type %d, level %d, hwfill type %d.",
+        slfrof.sntype, slfrof.slevel, slfrof.shwfill);
+        pm_message("Original screen size %dx%d, aspect ratio %.3f.",
+        slfrof.sxdots + 1, slfrof.sydots + 1, slfrof.sdsar);
+        pm_message("Byte order is %s.",
+            sdrawkcab ? "being reversed" : "the same");
+    }
+
+    /* If the display aspect ratio indicates that the  pixels  on  the
+       sending  screen  were  not  square,  adjust  the  size  of  the
+       generated bitmap to correct the  aspect  ratio  to  square  the
+       pixels.
+
+       We  always  correct  the aspect ratio by adjusting the width of
+       the image.  This guarantees that output from the SHADE command,
+       which  is  essentially  scan-line  data written in vector form,
+       will not be corrupted. */
+
+    dsar = ((double) slfrof.sxdots) / slfrof.sydots;
+    if (fabs(slfrof.sdsar - dsar) > 0.0001) {
+    if (adjust) {
+        ixdots = slfrof.sxdots * (slfrof.sdsar / dsar) + 0.5;
+        iydots = slfrof.sydots;
+        dsar = ((double) ixdots) / iydots;
+    } else {
+            pm_message("Warning - pixels on source screen were non-square.");
+            pm_message("          Specifying -adjust will correct image width to compensate.");
+        ixdots = slfrof.sxdots;
+        iydots = slfrof.sydots;
+        dsar = slfrof.sdsar;
+    }
+    } else {
+    /* Source pixels were square. */
+    ixdots = slfrof.sxdots;
+    iydots = slfrof.sydots;
+    dsar = slfrof.sdsar;
+    adjust = FALSE;           /* Mark no adjustment needed */
+    }
+
+    /* If there's a uniform scale factor specified, apply it. */
+
+    if (uscale > 0) {
+    ixdots = (ixdots * uscale) + 0.5;
+    iydots = (iydots * uscale) + 0.5;
+    }
+
+    /* If the image is to be stretched  to  a  given  width,  set  the
+       output  image  sizes accordingly.  If only a height or width is
+       given, scale the other direction proportionally to preserve the
+       aspect ratio. */
+
+    if (sxsize > 0) {
+    if (sysize > 0) {
+        iydots = sysize - 1;
+    } else {
+        iydots = ((((long) iydots) * (sxsize - 1)) +
+              (iydots / 2)) / ixdots;
+    }
+    ixdots = sxsize - 1;
+    } else if (sysize > 0) {
+    if (sxsize > 0) {
+        ixdots = sxsize - 1;
+    } else {
+        ixdots = ((((long) ixdots) * (sysize - 1)) +
+              (ixdots / 2)) / iydots;
+    }
+    iydots = sysize - 1;
+    }
+
+    if (adjust) {
+    pm_message(
+            "Resized from %dx%d to %dx%d to correct pixel aspect ratio.",
+        slfrof.sxdots + 1, slfrof.sydots + 1, ixdots + 1, iydots + 1);
+    }
+
+    /* Allocate image buffer and clear it to black. */
+
+    pixels = ppm_allocarray(pixcols = ixdots + 1, pixrows = iydots + 1);
+    PPM_ASSIGN(rgbcolor, 0, 0, 0);
+    ppmd_filledrectangle(pixels, pixcols, pixrows, pixmaxval, 0, 0,
+                         pixcols, pixrows, PPMD_NULLDRAWPROC,
+                         (char *) &rgbcolor);
+
+    if ((rescale = slfrof.sxdots != ixdots ||
+    slfrof.sydots != iydots ||
+    slfrof.sdsar != dsar) != 0) {
+
+        /* Rescale all coords. so they'll look (more or less)
+       right on this display.  */
+
+    xfac = (ixdots + 1) * 0x10000L;
+    xfac /= (long) (slfrof.sxdots + 1);
+    yfac = (iydots + 1) * 0x10000L;
+    yfac /= (long) (slfrof.sydots + 1);
+    if (dsar < slfrof.sdsar) {
+        yfac = yfac * dsar / slfrof.sdsar;
+       } else {
+        xfac = xfac * slfrof.sdsar / dsar;
+    }
+    }
+
+    poly.npoints = 0;             /* No flood in progress. */
+
+    while ((cw = sli()) != 0xFC00) {
+    switch (cw & 0xFF00) {
+        case 0xFB00:          /*  Short vector compressed  */
+        vec.f.x = lx + extend(cw & 0xFF);
+        vec.f.y = ly + slib();
+        vec.t.x = lx + slib();
+        vec.t.y = ly + slib();
+        lx = vec.f.x;
+        ly = vec.f.y;
+        if (rescale) {
+            vscale(&vec.f.x, &vec.f.y);
+            vscale(&vec.t.x, &vec.t.y);
+        }
+        (*slvec)(&vec, curcolor);/* Draw vector on screen */
+        slx = vec.f.x;        /* Save scaled point */
+        sly = vec.f.y;
+        break;
+
+        case 0xFC00:          /*  End of file  */
+        break;
+
+        case 0xFD00:          /*  Flood command  */
+        vec.f.x = sli();
+        vec.f.y = sli();
+        if ((int) vec.f.y < 0) { /* start or end */
+            if (poly.npoints != 0) { /* end?  */
+            if (poly.npoints > 2 && poly.npoints < 11) {
+                (*slflood)(&poly, curcolor);
+            } else {
+                            pm_error("Bad polygon vertex count (%d)",
+                   poly.npoints);
+            }
+            poly.npoints = 0;
+            } else {
+            poly.fill = -vec.f.y;  /* Start */
+            }
+        } else {          /* Polygon vertex */
+            if (poly.npoints < 10) {
+            if (rescale) {
+                vscale(&vec.f.x, &vec.f.y);
+            }
+            poly.pt[poly.npoints].x = vec.f.x;
+            poly.pt[poly.npoints].y = vec.f.y;
+            }
+            poly.npoints++;
+        }
+        break;
+
+        case 0xFE00:          /*  Common endpoint compressed  */
+        vec.f.x = lx + extend(cw & 0xFF);
+        vec.f.y = ly + slib();
+        lx = vec.f.x;
+        ly = vec.f.y;
+        vec.t.x = slx;
+        vec.t.y = sly;
+        if (rescale) {
+            vscale(&vec.f.x, &vec.f.y);
+        }
+        (*slvec)(&vec, curcolor);/* Draw vector */
+        slx = vec.f.x;        /* Save scaled point */
+        sly = vec.f.y;
+        break;
+
+        case 0xFF00:          /*  Change color  */
+        curcolor = cw & 0xFF;
+        break;
+
+        default:              /*  Co-ordinates  */
+        lx = vec.f.x = cw;
+        ly = vec.f.y = sli();
+        vec.t.x = sli();
+        vec.t.y = sli();
+        if (rescale) {
+           vscale(&vec.f.x, &vec.f.y);
+           vscale(&vec.t.x, &vec.t.y);
+        }
+        (*slvec)(&vec, curcolor);
+        slx = vec.f.x;        /* Save scaled point */
+        sly = vec.f.y;
+        break;
+    }
+    }
+}
+
+/*  SLIDEFIND  --  Find  a  slide  in  a  library  or,  if  DIRONLY is
+           nonzero, print a directory listing of the  library.
+           If  UCASEN  is nonzero, the requested slide name is
+           converted to upper case. */
+
+static void slidefind(sname, dironly, ucasen)
+  char *sname;
+  int dironly, ucasen;
+{
+    char uname[32];
+    unsigned char libent[36];
+    long pos;
+
+    if (dironly) {
+        pm_message("Slides in library:");
+    } else {
+    int i;
+    char *ip = sname;
+
+    for (i = 0; i < 31; i++) {
+        char ch = *ip++;
+        if (ch == EOS) {
+        break;
+        }
+        if (ucasen && ISLOWER(ch)) {
+        ch = TOUPPER(ch);
+        }
+        uname[i] = ch;
+    }
+    uname[i] = EOS;
+    }
+
+    /* Read slide library header and verify. */
+
+    if ((fread(libent, 32, 1, slfile) != 1) ||
+        (!STREQ((char *)libent, "AutoCAD Slide Library 1.0\015\012\32"))) {
+        pm_error("not an AutoCAD slide library file.");
+    }
+    pos = 32;
+
+    /* Search for a slide with the requested name. */
+
+    while (TRUE) {
+    if ((fread(libent, 36, 1, slfile) != 1) ||
+        (strlen((char *)libent) == 0)) {
+        if (dironly) {
+        return;
+        }
+            pm_error("slide %s not in library.", sname);
+    }
+    pos += 36;
+    if (dironly) {
+            pm_message("  %s", libent);
+    } else if (STREQ((char *)libent, uname)) {
+        long dpos = (((((libent[35] << 8) | libent[34]) << 8) |
+                 libent[33]) << 8) | libent[32];
+        if ((slfile == stdin) || (fseek(slfile, dpos, 0) == -1)) {
+        dpos -= pos;
+
+        while (dpos-- > 0) {
+            (void) getc(slfile);
+        }
+        }
+        break;
+    }
+    }
+}
+
+/*  DRAW  --  Draw a vector in the given AutoCAD color.  */
+
+static void draw(vec, color)
+  struct svector *vec;
+  int color;
+{
+    pixel rgbcolor;
+
+    if (blither) {
+        pm_message("Vector (%d, %d) - (%d, %d)  Color %d",
+           vec->f.x, vec->f.y, vec->t.x, vec->t.y, color);
+    }
+    assert(vec->f.x >= 0 && vec->f.x < pixcols);
+    assert(vec->f.y >= 0 && vec->f.y < pixrows);
+    assert(vec->t.x >= 0 && vec->t.x < pixcols);
+    assert(vec->t.y >= 0 && vec->t.y < pixrows);
+    PPM_ASSIGN(rgbcolor,
+           acadcol[color][0], acadcol[color][1], acadcol[color][2]);
+    ppmd_line(pixels, pixcols, pixrows, pixmaxval,
+          vec->f.x, iydots - vec->f.y, vec->t.x, iydots - vec->t.y,
+          PPMD_NULLDRAWPROC,
+          (char *) &rgbcolor);
+}
+
+/*  FLOOD  --  Draw a filled polygon.  */
+
+static void
+flood(struct spolygon * const poly,
+      int               const color) {
+
+    int i;
+    struct fillobj * handle;
+    pixel rgbcolor;
+
+    handle = ppmd_fill_create();
+
+    if (blither) {
+        pm_message("Polygon: %d points, fill type %d, color %d",
+                   poly->npoints, poly->fill, color);
+        for (i = 0; i < poly->npoints; i++) {
+            pm_message("   Point %d:  (%d, %d)", i + 1,
+                       poly->pt[i].x, poly->pt[i].y);
+        }
+    }
+
+    PPM_ASSIGN(rgbcolor,
+               acadcol[color][0], acadcol[color][1], acadcol[color][2]);
+    for (i = 0; i < poly->npoints; i++) {
+        assert(poly->pt[i].x >= 0 && poly->pt[i].x < pixcols);
+        assert(poly->pt[i].y >= 0 && poly->pt[i].y < pixrows);
+        ppmd_line(pixels, pixcols, pixrows, pixmaxval,
+                  poly->pt[i].x, iydots - poly->pt[i].y, 
+                  poly->pt[(i + 1) % poly->npoints].x,
+                  iydots - poly->pt[(i + 1) % poly->npoints].y,
+                  ppmd_fill_drawproc, handle);
+    }
+    ppmd_fill(pixels, pixcols, pixrows, pixmaxval,
+              handle, PPMD_NULLDRAWPROC, (char *) &rgbcolor);
+
+    ppmd_fill_destroy(handle);
+}
+
+/*  Main program. */
+
+int main(argc, argv)
+  int argc;
+  char *argv[];
+{
+    int argn;
+    const char * const usage = "[-verbose] [-info] [-adjust] [-scale <s>]\n\
+                 [-dir] [-lib|-Lib <name>]\n\
+                 [-xsize|-width <x>] [-ysize|-height <y>] [sldfile]";
+    int scalespec = FALSE, widspec = FALSE, hgtspec = FALSE, dironly = FALSE,
+    ucasen;
+    char *slobber = (char *) 0;       /* Slide library item */
+
+
+    ppm_init(&argc, argv);
+    argn = 1;
+
+    while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
+        if (pm_keymatch(argv[argn], "-verbose", 2)) {
+        blither = TRUE;
+        } else if (pm_keymatch(argv[argn], "-adjust", 2)) {
+        adjust = TRUE;
+        } else if (pm_keymatch(argv[argn], "-dir", 2)) {
+        dironly = TRUE;
+        } else if (pm_keymatch(argv[argn], "-info", 2)) {
+        info = TRUE;
+        } else if (pm_keymatch(argv[argn], "-lib", 2)) {
+        if (slobber != (char *) 0) {
+                pm_error("already specified a library item");
+        }
+            ucasen = argv[argn][1] != 'L';
+        argn++;
+        if (argn == argc) {
+        pm_usage(usage);
+        }
+        slobber = argv[argn];
+        } else if (pm_keymatch(argv[argn], "-scale", 2)) {
+        if (scalespec) {
+                pm_error("already specified a scale factor");
+        }
+        argn++;
+            if ((argn == argc) || (sscanf(argv[argn], "%lf", &uscale) != 1))
+        pm_usage(usage);
+        if (uscale <= 0.0) {
+                pm_error("scale factor must be greater than 0");
+        }
+        scalespec = TRUE;
+        } else if (pm_keymatch(argv[argn], "-xsize", 2) ||
+                   pm_keymatch(argv[argn], "-width", 2)) {
+        if (widspec) {
+                pm_error("already specified a width/xsize");
+        }
+        argn++;
+            if ((argn == argc) || (sscanf(argv[argn], "%d", &sxsize) != 1))
+        pm_usage(usage);
+        widspec = TRUE;
+        } else if (pm_keymatch(argv[argn], "-ysize", 2) ||
+                   pm_keymatch(argv[argn], "-height", 2)) {
+        if (hgtspec) {
+                pm_error("already specified a height/ysize");
+        }
+        argn++;
+            if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
+        pm_usage(usage);
+        hgtspec = TRUE;
+    } else {
+        pm_usage(usage);
+    }
+    argn++;
+    }
+
+    /* If a file name is specified, open it.  Otherwise read from
+       standard input. */
+
+    if (argn < argc) {
+    slfile = pm_openr(argv[argn]);
+    argn++;
+    } else {
+    slfile = stdin;
+    }
+
+    if (argn != argc) {           /* Extra bogus arguments ? */
+    pm_usage(usage);
+    }
+
+    /* If we're extracting an item from a slide library, position the
+       input stream to the start of the chosen slide. */
+
+    if (dironly || (slobber != (char *) 0)) {
+    slidefind(slobber, dironly, ucasen);
+    }
+
+    if (!dironly) {
+    slider(draw, flood);
+    ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, FALSE);
+    }
+    pm_close(slfile);
+    pm_close(stdout);
+    exit(0);
+}