(root)/
libredwg-0.13/
programs/
dwg2ps.c
       1  /*****************************************************************************/
       2  /*  LibreDWG - free implementation of the DWG file format                    */
       3  /*                                                                           */
       4  /*  Copyright (C) 2009-2023 Free Software Foundation, Inc.                   */
       5  /*  Copyright (C) 2010 Thien-Thi Nguyen                                      */
       6  /*                                                                           */
       7  /*  This library is free software, licensed under the terms of the GNU       */
       8  /*  General Public License as published by the Free Software Foundation,     */
       9  /*  either version 3 of the License, or (at your option) any later version.  */
      10  /*  You should have received a copy of the GNU General Public License        */
      11  /*  along with this program.  If not, see <http://www.gnu.org/licenses/>.    */
      12  /*****************************************************************************/
      13  
      14  /*
      15   * dwg2ps.c: create a PostScript file of lines from a DWG
      16   * TODO: more 2D elements, see dwg2SVG
      17   * written by Felipe Castro
      18   * modified by Felipe CorrĂȘa da Silva Sances
      19   * modified by Rodrigo Rodrigues da Silva
      20   * modified by Thien-Thi Nguyen
      21   * modified by Reini Urban
      22   */
      23  
      24  #include "../src/config.h"
      25  #include <stdio.h>
      26  #include <stdlib.h>
      27  #include <string.h>
      28  #include <libps/pslib.h>
      29  #include "my_getopt.h"
      30  
      31  #include <dwg.h>
      32  #include <dwg_api.h>
      33  #include "common.h"
      34  #include "../src/bits.h" //bit_convert_TU
      35  #include "suffix.inc"
      36  #include "geom.h"
      37  
      38  static int opts = 0;
      39  
      40  static int
      41  usage (void)
      42  {
      43    printf ("\nUsage: dwg2ps [-v[0-9]] DWGFILE [PSFILE]\n");
      44    return 1;
      45  }
      46  static int
      47  opt_version (void)
      48  {
      49    printf ("dwg2ps %s\n", PACKAGE_VERSION);
      50    return 0;
      51  }
      52  static int
      53  help (void)
      54  {
      55    printf ("\nUsage: dwg2ps [OPTION]... DWGFILE [PSFILE]\n");
      56    printf ("Converts some 2D elements of the DWG to a Postscript file.\n"
      57            "\n");
      58  #ifdef HAVE_GETOPT_LONG
      59    printf ("  -v[0-9], --verbose [0-9]  verbosity\n");
      60    printf ("           --help           display this help and exit\n");
      61    printf ("           --version        output version information and exit\n"
      62            "\n");
      63  #else
      64    printf ("  -v[0-9]     verbosity\n");
      65    printf ("  -h          display this help and exit\n");
      66    printf ("  -i          output version information and exit\n"
      67            "\n");
      68  #endif
      69    printf ("GNU LibreDWG online manual: "
      70            "<https://www.gnu.org/software/libredwg/>\n");
      71    return 0;
      72  }
      73  
      74  /* handles r2007 wide chars (=> utf8) */
      75  static int
      76  set_info (PSDoc *restrict ps, Dwg_Data *restrict dwg, const char *restrict key,
      77            BITCODE_T16 restrict text)
      78  {
      79    int ret = 0;
      80    if (!text)
      81      return 0;
      82    if (dwg->header.from_version < R_2007)
      83      {
      84        PS_set_info (ps, key, text);
      85        ret = 1;
      86      }
      87    else
      88      {
      89        char *u8 = bit_convert_TU ((BITCODE_TU)text);
      90        if (u8 && strlen (u8))
      91          {
      92            PS_set_info (ps, key, u8);
      93            ret = 1;
      94          }
      95        if (u8)
      96          free (u8);
      97      }
      98    return ret;
      99  }
     100  
     101  static void
     102  create_postscript (Dwg_Data *dwg, char *output)
     103  {
     104    double dx;
     105    double dy;
     106    double scale_x;
     107    double scale_y;
     108    double scale;
     109    BITCODE_BL i;
     110    // FILE *fh;
     111    PSDoc *ps;
     112  
     113    /* Initialization
     114     */
     115    PS_boot ();
     116    ps = PS_new ();
     117    if (PS_open_file (ps, output) < 0)
     118      {
     119        puts ("Cannot write PostScript file");
     120        return;
     121      }
     122  
     123    PS_set_info (ps, "Creator", "dwg2ps " PACKAGE_VERSION);
     124    (void)set_info (ps, dwg, "Subject", dwg->summaryinfo.SUBJECT);
     125    (void)set_info (ps, dwg, "Author", dwg->summaryinfo.LASTSAVEDBY);
     126    if (set_info (ps, dwg, "Title", dwg->summaryinfo.TITLE))
     127      (void)set_info (ps, dwg, "Keywords", dwg->summaryinfo.KEYWORDS);
     128    else
     129      {
     130        PS_set_info (ps, "Title", output);
     131        PS_set_info (ps, "Keywords", "dwg, postscript, conversion, CAD, plot");
     132      }
     133  
     134    /* First page: Model Space (?)
     135     */
     136    dx = (dwg_model_x_max (dwg) - dwg_model_x_min (dwg));
     137    dy = (dwg_model_y_max (dwg) - dwg_model_y_min (dwg));
     138    scale_x = dx / (dwg_model_x_max (dwg) - dwg_model_x_min (dwg));
     139    scale_y = dy / (dwg_model_y_max (dwg) - dwg_model_y_min (dwg));
     140    scale = 25.4 / 72; // pt:mm
     141    PS_begin_page (ps, dx / scale, dy / scale);
     142    scale *= (scale_x > scale_y ? scale_x : scale_y);
     143    PS_scale (ps, (float)scale, (float)scale);
     144    PS_translate (ps, (float)-dwg_model_x_min (dwg),
     145                  (float)-dwg_model_y_min (dwg));
     146    if (dwg->opts & DWG_OPTS_LOGLEVEL)
     147      {
     148        fprintf (stderr, "Limits: %f, %f\n", dx, dy);
     149        fprintf (stderr, "Scale: %f (%f, %f)\n", scale, scale_x, scale_y);
     150      }
     151  
     152      /* Mark the origin with a crossed circle
     153       */
     154  #define H 1
     155    PS_circle (ps, 0, 0, H);
     156    PS_moveto (ps, 0, H);
     157    PS_lineto (ps, 0, -H);
     158    PS_moveto (ps, -H, 0);
     159    PS_lineto (ps, H, 0);
     160    PS_stroke (ps);
     161  
     162    /* Iterate all entities
     163     */
     164    for (i = 0; i < dwg->num_objects; i++)
     165      {
     166        Dwg_Object *obj = &dwg->object[i];
     167        if (obj->supertype == DWG_SUPERTYPE_OBJECT) // no entity
     168          continue;
     169        // if (obj->tio.entity->entity_mode == 0) // belongs to block
     170        //  continue;
     171        if (obj->fixedtype == DWG_TYPE_LINE)
     172          {
     173            Dwg_Entity_LINE *line = obj->tio.entity->tio.LINE;
     174            BITCODE_3DPOINT start, end;
     175  
     176            transform_OCS (&start, line->start, line->extrusion);
     177            transform_OCS (&end, line->end, line->extrusion);
     178            PS_moveto (ps, (float)start.x, (float)start.y);
     179            PS_lineto (ps, (float)end.x, (float)end.y);
     180            PS_stroke (ps);
     181          }
     182        else if (obj->fixedtype == DWG_TYPE_POLYLINE_2D)
     183          {
     184            int error;
     185            BITCODE_RL j,
     186                numpts = dwg_object_polyline_2d_get_numpoints (obj, &error);
     187            dwg_point_2d *pts = dwg_object_polyline_2d_get_points (obj, &error);
     188            Dwg_Entity_POLYLINE_2D *pline = obj->tio.entity->tio.POLYLINE_2D;
     189            if (numpts && !error)
     190              {
     191                BITCODE_2DPOINT pt0, ptin;
     192                ptin.x = pts[0].x;
     193                ptin.y = pts[0].y;
     194                transform_OCS_2d (&pt0, ptin, pline->extrusion);
     195                PS_moveto (ps, (float)pt0.x, (float)pt0.y);
     196                for (j = 1; j < numpts; j++)
     197                  {
     198                    BITCODE_2DPOINT pt;
     199                    ptin.x = pts[j].x;
     200                    ptin.y = pts[j].y;
     201                    transform_OCS_2d (&pt, ptin, pline->extrusion);
     202                    PS_lineto (ps, (float)pt.x, (float)pt.y);
     203                    PS_stroke (ps);
     204                  }
     205                if (pline->flag & 1) // closed
     206                  {
     207                    PS_lineto (ps, (float)pt0.x, (float)pt0.y);
     208                    PS_stroke (ps);
     209                  }
     210                free (pts);
     211              }
     212          }
     213        else if (obj->fixedtype == DWG_TYPE_LWPOLYLINE)
     214          {
     215            int error;
     216            Dwg_Entity_LWPOLYLINE *pline = obj->tio.entity->tio.LWPOLYLINE;
     217            BITCODE_RL numpts = dwg_ent_lwpline_get_numpoints (pline, &error);
     218            if (numpts && !error)
     219              {
     220                BITCODE_2DPOINT pt0, ptin;
     221                dwg_point_2d *pts = dwg_ent_lwpline_get_points (pline, &error);
     222                BITCODE_RL j;
     223                ptin.x = pts[0].x;
     224                ptin.y = pts[0].y;
     225                transform_OCS_2d (&pt0, ptin, pline->extrusion);
     226                PS_moveto (ps, (float)pt0.x, (float)pt0.y);
     227                for (j = 1; j < numpts; j++)
     228                  {
     229                    BITCODE_2DPOINT pt;
     230                    ptin.x = pts[j].x;
     231                    ptin.y = pts[j].y;
     232                    transform_OCS_2d (&pt, ptin, pline->extrusion);
     233                    PS_lineto (ps, (float)pt.x, (float)pt.y);
     234                    PS_stroke (ps);
     235                  }
     236                if (pline->flag & 512) // closed
     237                  {
     238                    PS_lineto (ps, (float)pt0.x, (float)pt0.y);
     239                    PS_stroke (ps);
     240                  }
     241  
     242                free (pts);
     243              }
     244          }
     245        else if (obj->fixedtype == DWG_TYPE_ARC)
     246          {
     247            Dwg_Entity_ARC *arc = obj->tio.entity->tio.ARC;
     248            BITCODE_3DPOINT center;
     249            transform_OCS (&center, arc->center, arc->extrusion);
     250            PS_arc (ps, (float)center.x, (float)center.y, (float)arc->radius,
     251                    (float)arc->start_angle, (float)arc->end_angle);
     252          }
     253        else if (obj->fixedtype == DWG_TYPE_CIRCLE)
     254          {
     255            Dwg_Entity_CIRCLE *circle = obj->tio.entity->tio.CIRCLE;
     256            BITCODE_3DPOINT center;
     257            transform_OCS (&center, circle->center, circle->extrusion);
     258            PS_circle (ps, (float)center.x, (float)center.y,
     259                       (float)circle->radius);
     260          }
     261      }
     262  
     263    /* End Model Space */
     264    PS_end_page (ps);
     265  
     266    PS_close (ps);
     267    PS_delete (ps);
     268    PS_shutdown ();
     269  }
     270  
     271  int
     272  main (int argc, char *argv[])
     273  {
     274    int error;
     275    char *outfile;
     276    int i = 1;
     277    Dwg_Data dwg;
     278  
     279    int c;
     280  #ifdef HAVE_GETOPT_LONG
     281    int option_index = 0;
     282    static struct option long_options[]
     283        = { { "verbose", 1, &opts, 1 }, // optional
     284            { "help", 0, 0, 0 },
     285            { "version", 0, 0, 0 },
     286            { NULL, 0, NULL, 0 } };
     287  #endif
     288  
     289    if (argc < 2)
     290      return usage ();
     291  
     292    while
     293  #ifdef HAVE_GETOPT_LONG
     294        ((c = getopt_long (argc, argv, ":v::h", long_options, &option_index))
     295         != -1)
     296  #else
     297        ((c = getopt (argc, argv, ":v::hi")) != -1)
     298  #endif
     299      {
     300        if (c == -1)
     301          break;
     302        switch (c)
     303          {
     304          case ':': // missing arg
     305            if (optarg && !strcmp (optarg, "v"))
     306              {
     307                opts = 1;
     308                break;
     309              }
     310            fprintf (stderr, "%s: option '-%c' requires an argument\n", argv[0],
     311                     optopt);
     312            break;
     313  #ifdef HAVE_GETOPT_LONG
     314          case 0:
     315            /* This option sets a flag */
     316            if (!strcmp (long_options[option_index].name, "verbose"))
     317              {
     318                if (opts < 0 || opts > 9)
     319                  return usage ();
     320  #  if defined(USE_TRACING) && defined(HAVE_SETENV)
     321                {
     322                  char v[2];
     323                  *v = opts + '0';
     324                  *(v + 1) = 0;
     325                  setenv ("LIBREDWG_TRACE", v, 1);
     326                }
     327  #  endif
     328                break;
     329              }
     330            if (!strcmp (long_options[option_index].name, "version"))
     331              return opt_version ();
     332            if (!strcmp (long_options[option_index].name, "help"))
     333              return help ();
     334            break;
     335  #else
     336          case 'i':
     337            return opt_version ();
     338  #endif
     339          case 'v': // support -v3 and -v
     340            i = (optind > 0 && optind < argc) ? optind - 1 : 1;
     341            if (!memcmp (argv[i], "-v", 2))
     342              {
     343                opts = argv[i][2] ? argv[i][2] - '0' : 1;
     344              }
     345            if (opts < 0 || opts > 9)
     346              return usage ();
     347  #if defined(USE_TRACING) && defined(HAVE_SETENV)
     348            {
     349              char v[2];
     350              *v = opts + '0';
     351              *(v + 1) = 0;
     352              setenv ("LIBREDWG_TRACE", v, 1);
     353            }
     354  #endif
     355            break;
     356          case 'h':
     357            return help ();
     358          case '?':
     359            fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0],
     360                     optopt);
     361            break;
     362          default:
     363            return usage ();
     364          }
     365      }
     366    i = optind;
     367    if (i >= argc)
     368      return usage ();
     369  
     370    memset (&dwg, 0, sizeof (Dwg_Data));
     371    dwg.opts = opts;
     372    error = dwg_read_file (argv[i], &dwg);
     373    if (error >= DWG_ERR_CRITICAL)
     374      {
     375        fprintf (stderr, "READ ERROR 0x%x\n", error);
     376        dwg_free (&dwg);
     377        return 1;
     378      }
     379  
     380    outfile = suffix (argv[i], "ps");
     381    create_postscript (&dwg, outfile);
     382  
     383    printf ("Success! See the file '%s'\n", outfile);
     384    free (outfile);
     385    dwg_free (&dwg);
     386    return 0;
     387  }