1 /*****************************************************************************/
2 /*  LibreDWG - free implementation of the DWG file format                    */
3 /*                                                                           */
4 /*  Copyright (C) 2009-2019 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 <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
usage(void)41 usage (void)
42 {
43   printf ("\nUsage: dwg2ps [-v[0-9]] DWGFILE [PSFILE]\n");
44   return 1;
45 }
46 static int
opt_version(void)47 opt_version (void)
48 {
49   printf ("dwg2ps %s\n", PACKAGE_VERSION);
50   return 0;
51 }
52 static int
help(void)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
set_info(PSDoc * restrict ps,Dwg_Data * restrict dwg,const char * restrict key,BITCODE_TU restrict text)76 set_info (PSDoc *restrict ps, Dwg_Data *restrict dwg, const char *restrict key,
77           BITCODE_TU restrict text)
78 {
79   int ret = 0;
80   if (text)
81     {
82       char *u8 = bit_convert_TU (text);
83       if (u8 && strlen (u8))
84         {
85           PS_set_info (ps, key, u8);
86           ret = 1;
87         }
88       if (u8)
89         free (u8);
90     }
91   return ret;
92 }
93 
94 static void
create_postscript(Dwg_Data * dwg,char * output)95 create_postscript (Dwg_Data *dwg, char *output)
96 {
97   double dx;
98   double dy;
99   double scale_x;
100   double scale_y;
101   double scale;
102   BITCODE_BL i;
103   // FILE *fh;
104   PSDoc *ps;
105 
106   /* Initialization
107    */
108   PS_boot ();
109   ps = PS_new ();
110   if (PS_open_file (ps, output) < 0)
111     {
112       puts ("Cannot write PostScript file");
113       return;
114     }
115 
116   PS_set_info (ps, "Creator", "dwg2ps " PACKAGE_VERSION);
117   (void)set_info (ps, dwg, "Author", dwg->summaryinfo.LASTSAVEDBY);
118   if (set_info (ps, dwg, "Title", dwg->summaryinfo.TITLE))
119     set_info (ps, dwg, "Keywords", dwg->summaryinfo.KEYWORDS);
120   else
121     {
122       PS_set_info (ps, "Title", output);
123       PS_set_info (ps, "Keywords", "dwg, postscript, conversion, CAD, plot");
124     }
125 
126   /* First page: Model Space (?)
127    */
128   dx = (dwg_model_x_max (dwg) - dwg_model_x_min (dwg));
129   dy = (dwg_model_y_max (dwg) - dwg_model_y_min (dwg));
130   scale_x = dx / (dwg_model_x_max (dwg) - dwg_model_x_min (dwg));
131   scale_y = dy / (dwg_model_y_max (dwg) - dwg_model_y_min (dwg));
132   scale = 25.4 / 72; // pt:mm
133   PS_begin_page (ps, dx / scale, dy / scale);
134   scale *= (scale_x > scale_y ? scale_x : scale_y);
135   PS_scale (ps, (float)scale, (float)scale);
136   PS_translate (ps, (float)-dwg_model_x_min (dwg),
137                 (float)-dwg_model_y_min (dwg));
138   if (dwg->opts & DWG_OPTS_LOGLEVEL)
139     {
140       fprintf (stderr, "Limits: %f, %f\n", dx, dy);
141       fprintf (stderr, "Scale: %f (%f, %f)\n", scale, scale_x, scale_y);
142     }
143 
144     /* Mark the origin with a crossed circle
145      */
146 #define H 1
147   PS_circle (ps, 0, 0, H);
148   PS_moveto (ps, 0, H);
149   PS_lineto (ps, 0, -H);
150   PS_moveto (ps, -H, 0);
151   PS_lineto (ps, H, 0);
152   PS_stroke (ps);
153 
154   /* Iterate all entities
155    */
156   for (i = 0; i < dwg->num_objects; i++)
157     {
158       Dwg_Object *obj = &dwg->object[i];
159       if (obj->type == DWG_SUPERTYPE_OBJECT) // no entity
160         continue;
161       // if (obj->tio.entity->entity_mode == 0) // belongs to block
162       //  continue;
163       if (obj->type == DWG_TYPE_LINE)
164         {
165           Dwg_Entity_LINE *line = obj->tio.entity->tio.LINE;
166           BITCODE_3DPOINT start, end;
167 
168           transform_OCS (&start, line->start, line->extrusion);
169           transform_OCS (&end, line->end, line->extrusion);
170           PS_moveto (ps, (float)start.x, (float)start.y);
171           PS_lineto (ps, (float)end.x, (float)end.y);
172           PS_stroke (ps);
173         }
174       else if (obj->type == DWG_TYPE_POLYLINE_2D)
175         {
176           int error;
177           BITCODE_RL j,
178             numpts = dwg_object_polyline_2d_get_numpoints (obj, &error);
179           dwg_point_2d *pts = dwg_object_polyline_2d_get_points (obj, &error);
180           Dwg_Entity_POLYLINE_2D *pline = obj->tio.entity->tio.POLYLINE_2D;
181           if (numpts && !error)
182             {
183               BITCODE_2DPOINT pt0, ptin;
184               ptin.x = pts[0].x;
185               ptin.y = pts[0].y;
186               transform_OCS_2d (&pt0, ptin, pline->extrusion);
187               PS_moveto (ps, (float)pt0.x, (float)pt0.y);
188               for (j = 1; j < numpts; j++)
189                 {
190                   BITCODE_2DPOINT pt;
191                   ptin.x = pts[j].x;
192                   ptin.y = pts[j].y;
193                   transform_OCS_2d (&pt, ptin, pline->extrusion);
194                   PS_lineto (ps, (float)pt.x, (float)pt.y);
195                   PS_stroke (ps);
196                 }
197               if (pline->flag & 1) // closed
198                 {
199                   PS_lineto (ps, (float)pt0.x, (float)pt0.y);
200                   PS_stroke (ps);
201                 }
202               free (pts);
203             }
204         }
205       else if (obj->type == DWG_TYPE_LWPOLYLINE)
206         {
207           int error;
208           Dwg_Entity_LWPOLYLINE *pline = obj->tio.entity->tio.LWPOLYLINE;
209           BITCODE_RL numpts = dwg_ent_lwpline_get_numpoints (pline, &error);
210           if (numpts && !error)
211             {
212               BITCODE_2DPOINT pt0, ptin;
213               dwg_point_2d *pts = dwg_ent_lwpline_get_points (pline, &error);
214               BITCODE_RL j;
215               ptin.x = pts[0].x;
216               ptin.y = pts[0].y;
217               transform_OCS_2d (&pt0, ptin, pline->extrusion);
218               PS_moveto (ps, (float)pt0.x, (float)pt0.y);
219               for (j = 1; j < numpts; j++)
220                 {
221                   BITCODE_2DPOINT pt;
222                   ptin.x = pts[j].x;
223                   ptin.y = pts[j].y;
224                   transform_OCS_2d (&pt, ptin, pline->extrusion);
225                   PS_lineto (ps, (float)pt.x, (float)pt.y);
226                   PS_stroke (ps);
227                 }
228               if (pline->flag & 512) // closed
229                 {
230                   PS_lineto (ps, (float)pt0.x, (float)pt0.y);
231                   PS_stroke (ps);
232                 }
233 
234               free (pts);
235             }
236         }
237       else if (obj->type == DWG_TYPE_ARC)
238         {
239           Dwg_Entity_ARC *arc = obj->tio.entity->tio.ARC;
240           BITCODE_3DPOINT center;
241           transform_OCS (&center, arc->center, arc->extrusion);
242           PS_arc (ps, (float)center.x, (float)center.y,
243                   (float)arc->radius, (float)arc->start_angle,
244                   (float)arc->end_angle);
245         }
246       else if (obj->type == DWG_TYPE_CIRCLE)
247         {
248           Dwg_Entity_CIRCLE *circle = obj->tio.entity->tio.CIRCLE;
249           BITCODE_3DPOINT center;
250           transform_OCS (&center, circle->center, circle->extrusion);
251           PS_circle (ps, (float)center.x, (float)center.y,
252                      (float)circle->radius);
253         }
254     }
255 
256   /* End Model Space */
257   PS_end_page (ps);
258 
259   PS_close (ps);
260   PS_delete (ps);
261   PS_shutdown ();
262 }
263 
264 int
main(int argc,char * argv[])265 main (int argc, char *argv[])
266 {
267   int error;
268   char *outfile;
269   int i = 1;
270   Dwg_Data dwg;
271 
272   int c;
273 #ifdef HAVE_GETOPT_LONG
274   int option_index = 0;
275   static struct option long_options[]
276       = { { "verbose", 1, &opts, 1 }, // optional
277           { "help", 0, 0, 0 },
278           { "version", 0, 0, 0 },
279           { NULL, 0, NULL, 0 } };
280 #endif
281 
282   if (argc < 2)
283     return usage ();
284 
285   while
286 #ifdef HAVE_GETOPT_LONG
287       ((c = getopt_long (argc, argv, ":v::h", long_options, &option_index))
288        != -1)
289 #else
290       ((c = getopt (argc, argv, ":v::hi")) != -1)
291 #endif
292     {
293       if (c == -1)
294         break;
295       switch (c)
296         {
297         case ':': // missing arg
298           if (optarg && !strcmp (optarg, "v"))
299             {
300               opts = 1;
301               break;
302             }
303           fprintf (stderr, "%s: option '-%c' requires an argument\n", argv[0],
304                    optopt);
305           break;
306 #ifdef HAVE_GETOPT_LONG
307         case 0:
308           /* This option sets a flag */
309           if (!strcmp (long_options[option_index].name, "verbose"))
310             {
311               if (opts < 0 || opts > 9)
312                 return usage ();
313 #  if defined(USE_TRACING) && defined(HAVE_SETENV)
314               {
315                 char v[2];
316                 *v = opts + '0';
317                 *(v + 1) = 0;
318                 setenv ("LIBREDWG_TRACE", v, 1);
319               }
320 #  endif
321               break;
322             }
323           if (!strcmp (long_options[option_index].name, "version"))
324             return opt_version ();
325           if (!strcmp (long_options[option_index].name, "help"))
326             return help ();
327           break;
328 #else
329         case 'i':
330           return opt_version ();
331 #endif
332         case 'v': // support -v3 and -v
333           i = (optind > 0 && optind < argc) ? optind - 1 : 1;
334           if (!memcmp (argv[i], "-v", 2))
335             {
336               opts = argv[i][2] ? argv[i][2] - '0' : 1;
337             }
338           if (opts < 0 || opts > 9)
339             return usage ();
340 #if defined(USE_TRACING) && defined(HAVE_SETENV)
341           {
342             char v[2];
343             *v = opts + '0';
344             *(v + 1) = 0;
345             setenv ("LIBREDWG_TRACE", v, 1);
346           }
347 #endif
348           break;
349         case 'h':
350           return help ();
351         case '?':
352           fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0],
353                    optopt);
354           break;
355         default:
356           return usage ();
357         }
358     }
359   i = optind;
360   if (i >= argc)
361     return usage ();
362 
363   memset (&dwg, 0, sizeof (Dwg_Data));
364   dwg.opts = opts;
365   error = dwg_read_file (argv[i], &dwg);
366   if (error >= DWG_ERR_CRITICAL)
367     {
368       fprintf (stderr, "READ ERROR 0x%x\n", error);
369       dwg_free (&dwg);
370       return 1;
371     }
372 
373   outfile = suffix (argv[i], "ps");
374   create_postscript (&dwg, outfile);
375 
376   printf ("Success! See the file '%s'\n", outfile);
377   free (outfile);
378   dwg_free (&dwg);
379   return 0;
380 }
381