/*****************************************************************************/ /* LibreDWG - free implementation of the DWG file format */ /* */ /* Copyright (C) 2013-2020,2023 Free Software Foundation, Inc. */ /* */ /* This library is free software, licensed under the terms of the GNU */ /* General Public License as published by the Free Software Foundation, */ /* either version 3 of the License, or (at your option) any later version. */ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ /*****************************************************************************/ /* * dwg2svg2.c: convert a DWG to SVG via the API. if there are paperspace entities, only output them. else all modelspace entities. * written by Gaganjyot Singh * modified by Reini Urban */ #include "../src/config.h" #include #include #include #include #include #include #ifdef ENABLE_MIMALLOC # include #endif #include #include #include "geom.h" static int opts = 0; static dwg_data g_dwg; static double model_xmin, model_ymin; static double page_width, page_height, scale; static int usage (void) { printf ("\nUsage: dwg2svg2 [-v[0-9]] DWGFILE\n"); return 1; } static int opt_version (void) { printf ("dwg2svg2 %s\n", PACKAGE_VERSION); return 0; } static int help (void) { printf ("\nUsage: dwg2svg2 [OPTION]... DWGFILE >file.svg\n"); printf ("Example to use the DWG api\n" "\n"); #ifdef HAVE_GETOPT_LONG printf (" -v[0-9], --verbose [0-9] verbosity\n"); printf (" --help display this help and exit\n"); printf (" --version output version information and exit\n" "\n"); #else printf (" -v[0-9] verbosity\n"); printf (" -h display this help and exit\n"); printf (" -i output version information and exit\n" "\n"); #endif printf ("GNU LibreDWG online manual: " "\n"); return 0; } #define log_if_error(msg) \ if (error) \ { \ fprintf (stderr, "ERROR: %s", msg); \ exit (1); \ } #define log_error(msg) \ { \ fprintf (stderr, "ERROR: %s", msg); \ exit (1); \ } #define dynget(obj, name, field, var) \ if (!dwg_dynapi_entity_value (obj, "" name, "" field, var, NULL)) \ { \ fprintf (stderr, "ERROR: %s.%s", name, field); \ exit (1); \ } #define dynget_utf8(obj, name, field, var) \ if (!dwg_dynapi_entity_utf8text (obj, "" name, "" field, var, &isnew, \ NULL)) \ { \ fprintf (stderr, "ERROR: %s.%s", name, field); \ exit (1); \ } static double transform_X (double x) { return x - model_xmin; } static double transform_Y (double y) { return page_height - (y - model_ymin); } static void output_SVG (dwg_data *dwg); static int test_SVG (char *filename) { int error; memset (&g_dwg, 0, sizeof (dwg_data)); g_dwg.opts = opts; error = dwg_read_file (filename, &g_dwg); if (error < DWG_ERR_CRITICAL) output_SVG (&g_dwg); dwg_free (&g_dwg); /* This value is the return value for `main', so clamp it to either 0 or 1. */ return error < DWG_ERR_CRITICAL ? 0 : 1; } static void output_TEXT (dwg_object *obj) { int error, index; dwg_point_2d ins_pt; Dwg_Entity_TEXT *text; char *text_value; double fontsize; const Dwg_Version_Type dwg_version = obj->parent->header.version; int isnew = 0; index = dwg_object_get_index (obj, &error); log_if_error ("object_get_index"); text = dwg_object_to_TEXT (obj); if (!text) log_error ("dwg_object_to_TEXT"); dynget_utf8 (text, "TEXT", "text_value", &text_value); dynget (text, "TEXT", "ins_pt", &ins_pt); dynget (text, "TEXT", "height", &fontsize); printf ("\t%s\n", index, transform_X (ins_pt.x), transform_Y (ins_pt.y), fontsize, text_value); if (text_value && isnew) free (text_value); } static void output_LINE (dwg_object *obj) { int error, index; Dwg_Entity_LINE *line; dwg_point_3d start, end; index = dwg_object_get_index (obj, &error); log_if_error ("object_get_index"); line = dwg_object_to_LINE (obj); if (!line) log_error ("dwg_object_to_LINE"); if (!dwg_get_LINE (line, "start", &start)) log_error ("LINE.start"); if (!dwg_get_LINE (line, "end", &end)) log_error ("LINE.end"); printf ("\t\n", index, transform_X (start.x), transform_Y (start.y), transform_X (end.x), transform_Y (end.y)); } static void output_CIRCLE (dwg_object *obj) { Dwg_Entity_CIRCLE *circle; int error, index; double radius; dwg_point_3d center; index = dwg_object_get_index (obj, &error); log_if_error ("object_get_index"); circle = dwg_object_to_CIRCLE (obj); if (!circle) log_error ("dwg_object_to_CIRCLE"); if (!dwg_get_CIRCLE (circle, "center", ¢er)) log_error ("CIRCLE.center"); if (!dwg_get_CIRCLE (circle, "radius", &radius)) log_error ("CIRCLE.radius"); printf ("\t\n", index, transform_X (center.x), transform_Y (center.y), radius); } static void output_ARC (dwg_object *obj) { Dwg_Entity_ARC *arc; int error, index; double radius, start_angle, end_angle; dwg_point_3d center; double x_start, y_start, x_end, y_end; int large_arc; index = dwg_object_get_index (obj, &error); log_if_error ("object_get_index"); arc = dwg_object_to_ARC (obj); if (!arc) log_error ("dwg_object_to_ARC"); dynget (arc, "ARC", "radius", &radius); dynget (arc, "ARC", "center", ¢er); dynget (arc, "ARC", "start_angle", &start_angle); dynget (arc, "ARC", "end_angle", &end_angle); x_start = center.x + radius * cos (start_angle); y_start = center.y + radius * sin (start_angle); x_end = center.x + radius * cos (end_angle); y_end = center.y + radius * sin (end_angle); // Assuming clockwise arcs. large_arc = (end_angle - start_angle < M_PI) ? 0 : 1; printf ("\t\n", index, transform_X (x_start), transform_Y (y_start), radius, radius, large_arc, transform_X (x_end), transform_Y (y_end), 0.1); } static void output_INSERT (dwg_object *obj) { int index, error; BITCODE_RL abs_ref; double rotation; dwg_ent_insert *insert; dwg_point_3d ins_pt, _scale; dwg_handle *obj_handle, *ins_handle; Dwg_Data *dwg; insert = dwg_object_to_INSERT (obj); if (!insert) log_error ("dwg_object_to_INSERT"); dwg = obj->parent; index = dwg_object_get_index (obj, &error); log_if_error ("object_get_index"); dynget (insert, "INSERT", "rotation", &rotation); dynget (insert, "INSERT", "ins_pt", &ins_pt); dynget (insert, "INSERT", "scale", &_scale); obj_handle = dwg_object_get_handle (obj, &error); log_if_error ("get_handle"); if (!insert->block_header) log_error ("insert->block_header"); abs_ref = insert->block_header->absolute_ref; if (insert->block_header->handleref.code == 5 || dwg->header.version < R_13) { printf ("\t\n", index, transform_X (ins_pt.x), transform_Y (ins_pt.y), (180.0 / M_PI) * rotation, _scale.x, _scale.y, abs_ref, ARGS_H (*obj_handle)); } else { printf ("\n\n\n", ARGS_H (*obj_handle)); } } static int output_object (dwg_object *obj) { int i = 0; if (!obj) { fprintf (stderr, "object is NULL\n"); return 0; } if (dwg_object_get_fixedtype (obj) == DWG_TYPE_INSERT) { i++; output_INSERT (obj); } else if (dwg_object_get_fixedtype (obj) == DWG_TYPE_LINE) { i++; output_LINE (obj); } else if (dwg_object_get_fixedtype (obj) == DWG_TYPE_CIRCLE) { i++; output_CIRCLE (obj); } else if (dwg_object_get_fixedtype (obj) == DWG_TYPE_TEXT) { i++; output_TEXT (obj); } else if (dwg_object_get_fixedtype (obj) == DWG_TYPE_ARC) { i++; output_ARC (obj); } return i; } static int output_BLOCK_HEADER (dwg_object_ref *ref) { dwg_object *hdr, *obj; dwg_obj_block_header *_hdr; int error; BITCODE_RL abs_ref; char *name; int i = 0; if (!ref) { fprintf (stderr, "Empty BLOCK." " Could not output an SVG symbol for this BLOCK_HEADER\n"); return 0; } hdr = dwg_ref_get_object (ref, &error); if (!hdr || error) { abs_ref = dwg_ref_get_absref (ref, &error); fprintf (stderr, "Failed to resolve BLOCK handle %X.\n", (unsigned)abs_ref); return 0; } abs_ref = dwg_ref_get_absref (ref, &error); _hdr = dwg_object_to_BLOCK_HEADER (hdr); if (_hdr) { i++; dynget (_hdr, "BLOCK_HEADER", "name", &name); // name = dwg_obj_block_header_get_name (_hdr, &error); printf ("\t\n\t\t\n", abs_ref ? abs_ref : 0, name ? name : ""); if (name != NULL && name != _hdr->name && hdr->parent->header.version >= R_2007) free (name); } else printf ("\t\n\t\t\n", abs_ref ? abs_ref : 0); obj = get_first_owned_entity (hdr); while (obj) { i += output_object (obj); obj = get_next_owned_entity (hdr, obj); } printf ("\t\n"); return i; } static void output_SVG (dwg_data *dwg) { unsigned int i, num_hdr_objs; int error; dwg_obj_block_control *_ctrl; dwg_object_ref *hdr; dwg_object_ref **hdr_refs; dwg_object_ref *ms = dwg_model_space_ref (dwg); dwg_object_ref *ps = dwg_paper_space_ref (dwg); double dx = dwg_model_x_max (dwg) - dwg_model_x_min (dwg); double dy = dwg_model_y_max (dwg) - dwg_model_y_min (dwg); double pdx = dwg->header_vars.PLIMMAX.x - dwg->header_vars.PLIMMIN.x; double pdy = dwg->header_vars.PLIMMAX.y - dwg->header_vars.PLIMMIN.y; double scale_x = dx / (pdx == 0.0 ? 1.0 : pdx); double scale_y = dy / (pdy == 0.0 ? 1.0 : pdy); scale = 25.4 / 72.0; // pt:mm TODO model_xmin = dwg_model_x_min (dwg); model_ymin = dwg_model_y_min (dwg); page_width = dx; page_height = dy; scale *= (scale_x > scale_y ? scale_x : scale_y); _ctrl = dwg_block_control (dwg); hdr_refs = dwg_obj_block_control_get_block_headers (_ctrl, &error); log_if_error ("block_control_get_block_headers"); num_hdr_objs = dwg_obj_block_control_get_num_entries (_ctrl, &error); log_if_error ("block_control_get_num_entries"); printf ("\n" "\n", page_width, page_height); printf ("\t\n"); for (i = 0; i < num_hdr_objs; i++) { hdr = hdr_refs[i]; if (hdr == ms || hdr == ps) continue; output_BLOCK_HEADER (hdr_refs[i]); } printf ("\t\n"); if (ps) i = output_BLOCK_HEADER (ps); if (!ps || !i) output_BLOCK_HEADER (ms); free (hdr_refs); printf ("\n"); } int main (int argc, char *argv[]) { int i = 1; int c; #ifdef HAVE_GETOPT_LONG int option_index = 0; static struct option long_options[] = { { "verbose", 1, &opts, 1 }, // optional { "help", 0, 0, 0 }, { "version", 0, 0, 0 }, { NULL, 0, NULL, 0 } }; #endif if (argc < 2) return usage (); while #ifdef HAVE_GETOPT_LONG ((c = getopt_long (argc, argv, ":v::h", long_options, &option_index)) != -1) #else ((c = getopt (argc, argv, ":v::hi")) != -1) #endif { if (c == -1) break; switch (c) { case ':': // missing arg if (optarg && !strcmp (optarg, "v")) { opts = 1; break; } fprintf (stderr, "%s: option '-%c' requires an argument\n", argv[0], optopt); break; #ifdef HAVE_GETOPT_LONG case 0: /* This option sets a flag */ if (!strcmp (long_options[option_index].name, "verbose")) { if (opts < 0 || opts > 9) return usage (); # if defined(USE_TRACING) && defined(HAVE_SETENV) { char v[2]; *v = opts + '0'; *(v + 1) = 0; setenv ("LIBREDWG_TRACE", v, 1); } # endif break; } if (!strcmp (long_options[option_index].name, "version")) return opt_version (); if (!strcmp (long_options[option_index].name, "help")) return help (); break; #else case 'i': return opt_version (); #endif case 'v': // support -v3 and -v i = (optind > 0 && optind < argc) ? optind - 1 : 1; if (!memcmp (argv[i], "-v", 2)) { opts = argv[i][2] ? argv[i][2] - '0' : 1; } if (opts < 0 || opts > 9) return usage (); #if defined(USE_TRACING) && defined(HAVE_SETENV) { char v[2]; *v = opts + '0'; *(v + 1) = 0; setenv ("LIBREDWG_TRACE", v, 1); } #endif break; case 'h': return help (); case '?': fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0], optopt); break; default: return usage (); } } i = optind; if (i >= argc) return usage (); return test_SVG (argv[i]); }