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 (¢er, 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 (¢er, 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