Issue #19: Add LayerSettings Class

* Remove Command line and GUI rendering code
* Add LayerSettings Class with all options
* Prepare to remove mapping parser. Is now integrated in LayerSettings
* Adopt all renderers to check if the supplied layer_info struct has to be rendered.

Further todos:
* Implement correct command line parsing.
* Implement Layerselector and GUI to use new LayerSettings class
This commit is contained in:
Mario Hüttel 2019-06-21 21:41:31 +02:00
parent f5bc8de86e
commit 3ffd63115f
13 changed files with 678 additions and 161 deletions

View File

@ -55,8 +55,17 @@ static void delete_layer_info_with_name(struct layer_info *info)
} }
} }
void command_line_convert_gds(const char *gds_name, const char *cell_name, const char *output_file_name, const char *layer_file, const char *so_path, static void check_renderers_and_output_files()
enum command_line_renderer renderer, enum cmd_options options, double scale) {
}
void command_line_convert_gds(const char *gds_name,
const char *cell_name,
const char * const *renderers,
const char * const *output_file_names,
const char *layer_file,
const char *so_path)
{ {
GList *libs = NULL; GList *libs = NULL;
int res; int res;
@ -77,11 +86,13 @@ void command_line_convert_gds(const char *gds_name, const char *cell_name, const
gboolean tex_layers = FALSE, tex_standalone = FALSE; gboolean tex_layers = FALSE, tex_standalone = FALSE;
/* Check if parameters are valid */ /* Check if parameters are valid */
if (!gds_name || !cell_name || !output_file_name || !layer_file) { if (!gds_name || !cell_name || !output_file_names || !layer_file || !renderers) {
printf("Probably missing argument. Check --help option\n"); printf("Probably missing argument. Check --help option\n");
return; return;
} }
/* Load GDS */ /* Load GDS */
clear_lib_list(&libs); clear_lib_list(&libs);
res = parse_gds_from_file(gds_name, &libs); res = parse_gds_from_file(gds_name, &libs);
@ -167,39 +178,8 @@ void command_line_convert_gds(const char *gds_name, const char *cell_name, const
/* Render */ /* Render */
if (options & CMD_OPT_LATEX_LAYERS)
tex_layers = TRUE;
if (options & CMD_OPT_LATEX_STANDALONE)
tex_standalone = TRUE;
switch (renderer) {
case CMD_CAIRO_SVG:
output_renderer = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_svg());
break;
case CMD_LATEX:
output_renderer = GDS_RENDER_OUTPUT_RENDERER(latex_renderer_new_with_options(tex_layers, tex_standalone));
break;
case CMD_CAIRO_PDF:
output_renderer = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_pdf());
break;
case CMD_EXTERNAL:
output_renderer = GDS_RENDER_OUTPUT_RENDERER(external_renderer_new_with_so(so_path));
break;
case CMD_NONE:
/* Do nothing */
output_renderer = NULL;
break;
default:
output_renderer = NULL;
fprintf(stderr, "Invalid renderer supplied");
break;
}
if (output_renderer) {
gds_output_renderer_render_output(output_renderer, toplevel_cell, layer_info_list, output_file_name, scale);
g_object_unref(output_renderer);
}
/* Render end */ /* Render end */
ret_clear_layer_list: ret_clear_layer_list:
g_list_free_full(layer_info_list, (GDestroyNotify)delete_layer_info_with_name); g_list_free_full(layer_info_list, (GDestroyNotify)delete_layer_info_with_name);

View File

@ -37,8 +37,8 @@
#include <gds-render/widgets/activity-bar.h> #include <gds-render/widgets/activity-bar.h>
#include <gds-render/cell-selector/tree-store.h> #include <gds-render/cell-selector/tree-store.h>
#include <gds-render/cell-selector/lib-cell-renderer.h> #include <gds-render/cell-selector/lib-cell-renderer.h>
#include <gds-render/output-renderers/latex-output.h> //#include <gds-render/output-renderers/latex-output.h>
#include <gds-render/output-renderers/cairo-output.h> //#include <gds-render/output-renderers/cairo-output.h>
#include <gds-render/widgets/conv-settings-dialog.h> #include <gds-render/widgets/conv-settings-dialog.h>
#include <gds-render/geometric/cell-geometrics.h> #include <gds-render/geometric/cell-geometrics.h>
#include <gds-render/version.h> #include <gds-render/version.h>
@ -296,7 +296,7 @@ static void on_convert_clicked(gpointer button, gpointer user)
return; return;
/* Get layers that are rendered */ /* Get layers that are rendered */
layer_list = layer_selector_export_rendered_layer_info(self->layer_selector); //layer_list = layer_selector_export_rendered_layer_info(self->layer_selector);
/* Calculate cell size in DB units */ /* Calculate cell size in DB units */
bounding_box_prepare_empty(&cell_box); bounding_box_prepare_empty(&cell_box);
@ -360,13 +360,13 @@ static void on_convert_clicked(gpointer button, gpointer user)
switch (sett->renderer) { switch (sett->renderer) {
case RENDERER_LATEX_TIKZ: case RENDERER_LATEX_TIKZ:
output_file = fopen(file_name, "w"); output_file = fopen(file_name, "w");
latex_render_cell_to_code(cell_to_render, layer_list, output_file, sett->scale, /*latex_render_cell_to_code(cell_to_render, layer_list, output_file, sett->scale,
sett->tex_pdf_layers, sett->tex_standalone); sett->tex_pdf_layers, sett->tex_standalone);
fclose(output_file); */fclose(output_file);
break; break;
case RENDERER_CAIROGRAPHICS_SVG: case RENDERER_CAIROGRAPHICS_SVG:
case RENDERER_CAIROGRAPHICS_PDF: case RENDERER_CAIROGRAPHICS_PDF:
cairo_render_cell_to_vector_file(cell_to_render, layer_list, /*cairo_render_cell_to_vector_file(cell_to_render, layer_list,
(sett->renderer == RENDERER_CAIROGRAPHICS_PDF (sett->renderer == RENDERER_CAIROGRAPHICS_PDF
? file_name ? file_name
: NULL), : NULL),
@ -374,7 +374,7 @@ static void on_convert_clicked(gpointer button, gpointer user)
? file_name ? file_name
: NULL), : NULL),
sett->scale); sett->scale);
break; */break;
} }
g_free(file_name); g_free(file_name);
@ -382,7 +382,8 @@ static void on_convert_clicked(gpointer button, gpointer user)
gtk_widget_destroy(dialog); gtk_widget_destroy(dialog);
} }
ret_layer_destroy: ret_layer_destroy:
g_list_free_full(layer_list, (GDestroyNotify)layer_info_delete_struct); ;
// g_list_free_full(layer_list, (GDestroyNotify)layer_info_delete_struct);
} }
/** /**

View File

@ -33,32 +33,21 @@
#include <glib.h> #include <glib.h>
enum command_line_renderer {
CMD_NONE = 0,
CMD_EXTERNAL,
CMD_CAIRO_SVG,
CMD_CAIRO_PDF,
CMD_LATEX,
};
enum cmd_options {
CMD_OPT_NONE = 0U,
CMD_OPT_LATEX_STANDALONE = (1U<<0),
CMD_OPT_LATEX_LAYERS = (1U<<1),
};
/** /**
* @brief render output file according to command line parameters * @brief Convert GDS according to command line parameters
* @param gds_name Name of GDS file * @param gds_name Path to GDS File
* @param cell_name Name of cell to render * @param cell_name Cell name
* @param output_file_name Output file name * @param renderers Renderer ids
* @param so_file Shared object file to search external rendering function * @param output_file_names Output file names
* @param renderer Type of output renderer * @param layer_file Layer mapping file
* @param options Additional options for output renderer * @param so_path Shared object path
* @param scale Scale value
*/ */
void command_line_convert_gds(const char *gds_name, const char *cell_name, const char *output_file_name, const char *layer_file, void command_line_convert_gds(const char *gds_name,
const char *so_file, enum command_line_renderer renderer, enum cmd_options options, double scale); const char *cell_name,
const char * const *renderers,
const char * const *output_file_names,
const char *layer_file,
const char *so_path);
#endif /* _COMMAND_LINE_H_ */ #endif /* _COMMAND_LINE_H_ */

View File

@ -19,7 +19,7 @@
/** /**
* @file layer-info.h * @file layer-info.h
* @brief Helper functions and definition of layer info struct * @brief LayerSettings class heade file
* @author Mario Hüttel <mario.huettel@gmx.net> * @author Mario Hüttel <mario.huettel@gmx.net>
*/ */
@ -28,24 +28,92 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
G_BEGIN_DECLS
/** /**
* @brief Layer information. * @brief Layer information.
* *
* This structs contains information on how to render a layer * This structs contains information on how to render a layer
* @note You probably don't want to use this struct standalone but in combination
* with a LayerSettings object.
*/ */
struct layer_info struct layer_info
{ {
int layer; /**< @brief Layer number */ int layer; /**< @brief Layer number */
char *name; /**< @brief Layer name */ char *name; /**< @brief Layer name. */
int stacked_position; ///< @brief Position of layer in output @warning This parameter is not used by any renderer so far @note Lower is bottom, higher is top int stacked_position; ///< @brief Position of layer in output @warning This parameter is not used by any renderer so far @note Lower is bottom, higher is top
GdkRGBA color; /**< @brief RGBA color used to render this layer */ GdkRGBA color; /**< @brief RGBA color used to render this layer */
int render; /**< @brief true: Render to output */
}; };
G_DECLARE_FINAL_TYPE(LayerSettings, layer_settings, GDS_RENDER, LAYER_SETTINGS, GObject)
#define GDS_RENDER_TYPE_LAYER_SETTINGS (layer_settings_get_type())
/** /**
* @brief Delete a layer_info struct * @brief Maximum length of a layer mapping CSV line
* @param info Struct to be deleted.
* @note The layer_info::name Element has to be freed manually
*/ */
void layer_info_delete_struct(struct layer_info *info); #define CSV_LINE_MAX_LEN (1024)
/**
* @brief New LayerSettings object
* @return New object
*/
LayerSettings *layer_settings_new();
/**
* @brief layer_settings_append_layer_info
* @param settings LayerSettings object.
* @param info Info to append
* @return Error code. 0 if successful
* @note \p info is copied internally. You can free this struct afterwards.
*/
int layer_settings_append_layer_info(LayerSettings *settings, struct layer_info *info);
/**
* @brief Clear all layers in this settings object
* @param settings LayerSettings object
*/
void layer_settings_clear(LayerSettings *settings);
/**
* @brief Remove a specific layer number from the layer settings.
* @param settings LayerSettings object
* @param layer Layer number
* @return Error code. 0 if successful
*/
int layer_settings_remove_layer(LayerSettings *settings, int layer);
/**
* @brief Get a GList with layer_info structs
*
* This function returns a GList with all layer_info structs in rendering order
* (bottom to top) that shall be rendered.
*
* @param settings LayerSettings object
* @return GList with struct layer_info elements.
*/
GList *layer_settings_get_layer_info_list(LayerSettings *settings);
/**
* @brief Write layer settings to a CSV file
* @param path
* @return 0 if successful
*/
int layer_settings_to_csv(LayerSettings *settings, const char *path);
/**
* @brief Load new layer Settings from CSV
*
* This function loads the layer information from a CSV file.
* All data inside the \p settings is cleared beforehand.
*
* @param settings Settings to write to.
* @param path CSV file path
* @return 0 if successful
*/
int layer_settings_load_from_csv(LayerSettings *settings, const char *path);
G_END_DECLS
#endif // _LAYER_INFO_H_ #endif // _LAYER_INFO_H_

View File

@ -34,6 +34,7 @@
#include <glib.h> #include <glib.h>
#include <gds-render/widgets/layer-element.h> #include <gds-render/widgets/layer-element.h>
#include <gds-render/layer/layer-info.h>
/** /**
* @brief Load a line from \p stream and parse try to parse it as layer information * @brief Load a line from \p stream and parse try to parse it as layer information

View File

@ -34,6 +34,7 @@
#include <gds-render/gds-utils/gds-types.h> #include <gds-render/gds-utils/gds-types.h>
#include <glib-object.h> #include <glib-object.h>
#include <glib.h> #include <glib.h>
#include <gds-render/layer/layer-info.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -52,9 +53,7 @@ struct _GdsOutputRendererClass {
* @brief Virtual render output function. Overwritten by final class implementation * @brief Virtual render output function. Overwritten by final class implementation
*/ */
int (*render_output)(GdsOutputRenderer *renderer, int (*render_output)(GdsOutputRenderer *renderer,
struct gds_cell *cell, struct gds_cell *cell,
GList *layer_infos,
const char *output_file,
double scale); double scale);
gpointer padding[4]; gpointer padding[4];
}; };
@ -70,21 +69,64 @@ enum {
*/ */
GdsOutputRenderer *gds_output_renderer_new(); GdsOutputRenderer *gds_output_renderer_new();
/**
* @brief Create a new GdsOutputRenderer GObject with its properties
* @param output_file Output file of the renderer
* @param layer_settings Layer settings object
* @return New object
*/
GdsOutputRenderer *gds_output_renderer_new_with_props(const char *output_file, LayerSettings *layer_settings);
/** /**
* @brief gds_output_renderer_render_output * @brief gds_output_renderer_render_output
* @param renderer Renderer object * @param renderer Renderer object
* @param cell Cell to render * @param cell Cell to render
* @param layer_infos List of Layer information (@ref layer_info)
* @param output_file Output file name
* @param scale scale value. The output is scaled *down* by this value * @param scale scale value. The output is scaled *down* by this value
* @return 0 if successful * @return 0 if successful
*/ */
int gds_output_renderer_render_output(GdsOutputRenderer *renderer, int gds_output_renderer_render_output(GdsOutputRenderer *renderer,
struct gds_cell *cell, struct gds_cell *cell,
GList *layer_infos,
const char *output_file,
double scale); double scale);
/**
* @brief Convenience function for setting the "output-file" property
* @param renderer Renderer object
* @param file_name Output file path
*/
void gds_output_renderer_set_output_file(GdsOutputRenderer *renderer, const gchar *file_name);
/**
* @brief Convenience function for getting the "output-file" property
* @param renderer
* @return Output file path. This must not be freed
*/
const char *gds_output_renderer_get_output_file(GdsOutputRenderer *renderer);
/**
* @brief Get layer settings
*
* This is a convenience function for getting the
* "layer-settings" property
*
* @param renderer Renderer
* @return Layer settings object
*/
LayerSettings *gds_output_renderer_get_layer_settings(GdsOutputRenderer *renderer);
/**
* @brief Set layer settings
*
* This is a convenience function for setting the
* "layer-settings" property.
*
* If another Layer settings has previously been supplied,
* it is unref'd.
*
* @param renderer Renderer
* @param settings LayerSettings object
*/
void gds_output_renderer_set_layer_settings(GdsOutputRenderer *renderer, LayerSettings *settings);
G_END_DECLS G_END_DECLS
#endif /* _GDS_OUTPUT_RENDERER_H_ */ #endif /* _GDS_OUTPUT_RENDERER_H_ */

View File

@ -19,15 +19,313 @@
/** /**
* @file layer-info.c * @file layer-info.c
* @brief Helper functions for layer info struct * @brief Implementation of the LayerSettings class
* @author Mario Hüttel <mario.huettel@gmx.net> * @author Mario Hüttel <mario.huettel@gmx.net>
*/ */
#include <gds-render/layer/layer-info.h> #include <gds-render/layer/layer-info.h>
#include <stdlib.h>
void layer_info_delete_struct(struct layer_info *info) struct _LayerSettings {
GObject parent;
GList *layer_infos;
gpointer padding[12];
};
G_DEFINE_TYPE(LayerSettings, layer_settings, G_TYPE_OBJECT)
static void layer_settings_init(LayerSettings *self)
{ {
if (info) self->layer_infos = NULL;
free(info);
} }
static void layer_settings_class_init(LayerSettingsClass *klass)
{
(void)klass;
return;
}
/**
* @brief Copy layer_info struct
*
* This function copies a layer info struct.
* Be aware, that it does not only copy the pointer to the
* layer name, but instead duplicates the string.
*
* @param info Info to copy
* @return new layer_info struct
*/
static struct layer_info *layer_info_copy(const struct layer_info * const info)
{
struct layer_info *copy;
if (!info)
return 0;
copy = (struct layer_info *)malloc(sizeof(struct layer_info));
if (!copy)
return 0;
/* Copy data */
memcpy(copy, info, sizeof(struct layer_info));
/* Duplicate string */
if (info->name)
copy->name = strdup(info->name);
return copy;
}
static void layer_info_delete_with_name(struct layer_info *const info)
{
if (!info)
return;
if (info->name)
free(info->name);
free(info);
}
LayerSettings *layer_settings_new()
{
return g_object_new(GDS_RENDER_TYPE_LAYER_SETTINGS, NULL);
}
int layer_settings_append_layer_info(LayerSettings *settings, struct layer_info *info)
{
struct layer_info *info_copy;
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -1);
if (!info)
return -2;
/* Copy layer info */
info_copy = layer_info_copy(info);
/* Append to list */
settings->layer_infos = g_list_append(settings->layer_infos, info_copy);
return (settings->layer_infos ? 0 : -3);
}
void layer_settings_clear(LayerSettings *settings)
{
g_return_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings));
/* Clear list and delete layer_info structs including the name field */
g_list_free_full(settings->layer_infos, (GDestroyNotify)layer_info_delete_with_name);
settings->layer_infos = NULL;
}
int layer_settings_remove_layer(LayerSettings *settings, int layer)
{
GList *list_iter;
GList *found = NULL;
struct layer_info *inf;
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -1);
/* Find in list */
for (list_iter = settings->layer_infos; list_iter; list_iter = list_iter->next) {
inf = (struct layer_info *)list_iter->data;
if (!inf)
continue;
if (inf->layer == layer)
found = list_iter;
}
if (found) {
/* Free the layer_info struct */
layer_info_delete_with_name((struct layer_info *)found->data);
/* Delete the list element */
settings->layer_infos = g_list_delete_link(settings->layer_infos, found);
return 0;
}
return -2;
}
GList *layer_settings_get_layer_info_list(LayerSettings *settings)
{
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), NULL);
return settings->layer_infos;
}
/**
* @brief Generate a layer mapping CSV line for a given layer_info struct
* @param string Buffer to write to
* @param linfo Layer information
*/
static void layer_settings_gen_csv_line(GString *string, struct layer_info *linfo)
{
int i;
g_string_printf(string, "%d:%lf:%lf:%lf:%lf:%d:%s\n",
linfo->layer, linfo->color.red, linfo->color.green,
linfo->color.blue, linfo->color.alpha, (linfo->render ? 1 : 0), linfo->name);
/* Fix broken locale settings */
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ',')
string->str[i] = '.';
}
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ':')
string->str[i] = ',';
}
}
int layer_settings_to_csv(LayerSettings *settings, const char *path)
{
GFile *file;
int i;
GOutputStream *w_fstream;
GString *string;
GList *info_iter;
struct layer_info *linfo;
int ret = 0;
file = g_file_new_for_path(path);
w_fstream = G_OUTPUT_STREAM(g_file_replace(file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL));
if (!w_fstream) {
ret = -1;
goto ret_unref_file;
}
/* Allocate new working buffer string. A size bigger than 200 is unexpected, but possible
* 200 is a tradeoff between memory usage and preventing the necessity of realloc'ing the string
*/
string = g_string_new_len(NULL, 200);
if (!string) {
ret = -2;
goto ret_close_file;
}
/* Loop over layers and write CSV lines */
for (info_iter = settings->layer_infos; info_iter; info_iter = info_iter->next) {
linfo = (struct layer_info *)info_iter->data;
layer_settings_gen_csv_line(string, linfo);
g_output_stream_write(w_fstream, string->str, sizeof(gchar), NULL, NULL);
}
/* Delete string */
g_string_free(string, TRUE);
ret_close_file:
g_output_stream_flush(w_fstream, NULL, NULL);
g_output_stream_close(w_fstream, NULL, NULL);
g_object_unref(w_fstream);
ret_unref_file:
g_object_unref(file);
return ret;
}
/**
* @brief Load a line from \p stream and parse try to parse it as layer information
* @param stream Input data stream
* @param linfo Layer info struct to fill
* @return 1 if malformatted line, 0 if parsing was successful and parameters are valid, -1 if file end
*/
static int layer_settings_load_csv_line_from_stream(GDataInputStream *stream, struct layer_info *linfo)
{
int ret;
gsize len;
gchar *line;
GRegex *regex;
GMatchInfo *mi;
char *match;
if (!linfo) {
ret = 1;
goto ret_direct;
}
regex = g_regex_new("^(?<layer>[0-9]+),(?<r>[0-9\\.]+),(?<g>[0-9\\.]+),(?<b>[0-9\\.]+),(?<a>[0-9\\.]+),(?<export>[01]),(?<name>.*)$", 0, 0, NULL);
line = g_data_input_stream_read_line(stream, &len, NULL, NULL);
if (!line) {
ret = -1;
goto destroy_regex;
}
/* Match line in CSV */
g_regex_match(regex, line, 0, &mi);
if (g_match_info_matches(mi)) {
/* Line is valid */
match = g_match_info_fetch_named(mi, "layer");
linfo->layer = (int)g_ascii_strtoll(match, NULL, 10);
g_free(match);
match = g_match_info_fetch_named(mi, "r");
linfo->color.red = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "g");
linfo->color.green = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "b");
linfo->color.blue = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "a");
linfo->color.alpha = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "export");
linfo->render = ((!strcmp(match, "1")) ? 1 : 0);
g_free(match);
match = g_match_info_fetch_named(mi, "name");
linfo->name = match;
ret = 0;
} else {
/* Line is malformatted */
printf("Could not recognize line in CSV as valid entry: %s\n", line);
ret = 1;
}
g_match_info_free(mi);
g_free(line);
destroy_regex:
g_regex_unref(regex);
ret_direct:
return ret;
}
int layer_settings_load_from_csv(LayerSettings *settings, const char *path)
{
GFile *file;
int ret = 0;
GInputStream *in_stream;
GDataInputStream *data_stream;
int parser_ret;
struct layer_info linfo;
file = g_file_new_for_path(path);
in_stream = G_INPUT_STREAM(g_file_read(file, NULL, NULL));
if (!in_stream) {
ret = -1;
goto ret_destroy_file;
}
/* Delete old settings */
layer_settings_clear(settings);
data_stream = g_data_input_stream_new(in_stream);
while ((parser_ret = layer_settings_load_csv_line_from_stream(data_stream, &linfo)) >= 0) {
/* Line broken */
if (parser_ret == 1)
continue;
layer_settings_append_layer_info(settings, &linfo);
/* Clear name to prevent memory leak */
if (linfo.name)
g_free(linfo.name);
}
g_object_unref(data_stream);
g_object_unref(in_stream);
ret_destroy_file:
g_object_unref(file);
return ret;
}

View File

@ -395,7 +395,6 @@ GList *layer_selector_export_rendered_layer_info(LayerSelector *selector)
linfo = (struct layer_info *)malloc(sizeof(struct layer_info)); linfo = (struct layer_info *)malloc(sizeof(struct layer_info));
layer_element_get_color(le, &linfo->color); layer_element_get_color(le, &linfo->color);
linfo->layer = layer_element_get_layer(le); linfo->layer = layer_element_get_layer(le);
linfo->stacked_position = i;
linfo->name = (char *)layer_element_get_name(le); linfo->name = (char *)layer_element_get_name(le);
/* Append to list */ /* Append to list */

70
main.c
View File

@ -241,20 +241,20 @@ int main(int argc, char **argv)
GOptionContext *context; GOptionContext *context;
gchar *gds_name; gchar *gds_name;
gchar *basename; gchar *basename;
gchar *output_path = NULL, *mappingname = NULL, *cellname = NULL; gchar **output_paths = NULL;
gchar *renderer_arg = NULL; gchar *mappingname = NULL;
gchar *cellname = NULL;
gchar **renderer_args = NULL;
gboolean version = FALSE, pdf_standalone = FALSE, pdf_layers = FALSE; gboolean version = FALSE, pdf_standalone = FALSE, pdf_layers = FALSE;
gchar *custom_library_path = NULL; gchar *custom_library_path = NULL;
int scale = 1000; int scale = 1000;
int app_status = 0; int app_status = 0;
enum command_line_renderer renderer = CMD_NONE;
enum cmd_options opt = CMD_OPT_NONE;
GOptionEntry entries[] = { GOptionEntry entries[] = {
{"version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print version", NULL}, {"version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print version", NULL},
{"renderer", 'r', 0, G_OPTION_ARG_STRING, &renderer_arg, "Renderer to use", "pdf|svg|tikz|ext"}, {"renderer", 'r', 0, G_OPTION_ARG_STRING_ARRAY, &renderer_args, "Renderer to use. Can be used multiple times.", "pdf|svg|tikz|ext"},
{"scale", 's', 0, G_OPTION_ARG_INT, &scale, "Divide output coordinates by <SCALE>", "<SCALE>" }, {"scale", 's', 0, G_OPTION_ARG_INT, &scale, "Divide output coordinates by <SCALE>", "<SCALE>" },
{"output-file", 'o', 0, G_OPTION_ARG_FILENAME, &output_path, "Output file path", "PATH" }, {"output-file", 'o', 0, G_OPTION_ARG_FILENAME_ARRAY, &output_paths, "Output file path. Can be used multiple times.", "PATH" },
{"mapping", 'm', 0, G_OPTION_ARG_FILENAME, &mappingname, "Path for Layer Mapping File", "PATH" }, {"mapping", 'm', 0, G_OPTION_ARG_FILENAME, &mappingname, "Path for Layer Mapping File", "PATH" },
{"cell", 'c', 0, G_OPTION_ARG_STRING, &cellname, "Cell to render", "NAME" }, {"cell", 'c', 0, G_OPTION_ARG_STRING, &cellname, "Cell to render", "NAME" },
{"tex-standalone", 'a', 0, G_OPTION_ARG_NONE, &pdf_standalone, "Create standalone PDF", NULL }, {"tex-standalone", 'a', 0, G_OPTION_ARG_NONE, &pdf_standalone, "Create standalone PDF", NULL },
@ -292,57 +292,25 @@ int main(int argc, char **argv)
printf("Ignored argument: %s", argv[i]); printf("Ignored argument: %s", argv[i]);
} }
/* Check if PDF/TeX names are supplied. if not generate */
basename = g_path_get_basename(gds_name);
if (!strcmp(renderer_arg, "pdf")) {
renderer = CMD_CAIRO_PDF;
if (!output_path)
output_path = g_strdup_printf("./%s.pdf", basename);
}
else if (!strcmp(renderer_arg, "svg")) {
renderer = CMD_NONE; // To buggy atm CMD_CAIRO_SVG;
if (!output_path)
output_path = g_strdup_printf("./%s.svg", basename);
} else if (!strcmp(renderer_arg, "tikz")) {
renderer = CMD_LATEX;
if (pdf_layers)
opt |= CMD_OPT_LATEX_LAYERS;
if (pdf_standalone)
opt |= CMD_OPT_LATEX_STANDALONE;
if (!output_path)
output_path = g_strdup_printf("./%s.tex", basename);
} else if (!strcmp(renderer_arg, "ext")) {
renderer = CMD_EXTERNAL;
} else {
fprintf(stderr, "No valid renderer specified\n");
}
if (basename)
g_free(basename);
if (!output_path || strlen(output_path) == 0) {
app_status = -2;
goto ret_free_renderer;
}
command_line_convert_gds(gds_name, cellname, output_path, mappingname, custom_library_path, renderer, opt, scale);
/* Clean up */
app_status = 0;
ret_free_renderer:
if (output_path)
g_free(output_path);
if (renderer_arg)
g_free(renderer_arg);
if (mappingname)
g_free(mappingname);
if (cellname)
g_free(cellname);
} else { } else {
app_status = start_gui(argc, argv); app_status = start_gui(argc, argv);
} }
ret_status: ret_status:
/* If necessary, free command line parameters */
if (output_paths)
g_strfreev(output_paths);
if (renderer_args)
g_strfreev(renderer_args);
if (mappingname)
g_free(mappingname);
if (cellname)
free(cellname);
if (custom_library_path);
free(custom_library_path);
return app_status; return app_status;
} }

View File

@ -240,7 +240,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis
/* Create recording surface for each layer */ /* Create recording surface for each layer */
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) { for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
linfo = (struct layer_info *)info_list->data; linfo = (struct layer_info *)info_list->data;
if (linfo->layer < MAX_LAYERS) { if (linfo->layer < MAX_LAYERS && linfo->render) {
lay = &(layers[(unsigned int)linfo->layer]); lay = &(layers[(unsigned int)linfo->layer]);
lay->linfo = linfo; lay->linfo = linfo;
lay->rec = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA, lay->rec = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA,
@ -266,6 +266,9 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis
continue; continue;
} }
if (!linfo->render)
continue;
/* Print size */ /* Print size */
cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0, cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0,
&rec_width, &rec_height); &rec_width, &rec_height);
@ -309,6 +312,9 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis
continue; continue;
} }
if (!linfo->render)
continue;
if (pdf_file && pdf_cr) { if (pdf_file && pdf_cr) {
cairo_set_source_surface(pdf_cr, layers[linfo->layer].rec, -xmin, -ymin); cairo_set_source_surface(pdf_cr, layers[linfo->layer].rec, -xmin, -ymin);
cairo_paint_with_alpha(pdf_cr, linfo->color.alpha); cairo_paint_with_alpha(pdf_cr, linfo->color.alpha);
@ -363,17 +369,25 @@ static void cairo_renderer_init(CairoRenderer *self)
static int cairo_renderer_render_output(GdsOutputRenderer *renderer, static int cairo_renderer_render_output(GdsOutputRenderer *renderer,
struct gds_cell *cell, struct gds_cell *cell,
GList *layer_infos,
const char *output_file,
double scale) double scale)
{ {
CairoRenderer *c_renderer = GDS_RENDER_CAIRO_RENDERER(renderer); CairoRenderer *c_renderer = GDS_RENDER_CAIRO_RENDERER(renderer);
const char *pdf_file = NULL; const char *pdf_file = NULL;
const char *svg_file = NULL; const char *svg_file = NULL;
LayerSettings *settings;
GList *layer_infos = NULL;
const char *output_file;
if (!c_renderer) if (!c_renderer)
return -2000; return -2000;
output_file = gds_output_renderer_get_output_file(renderer);
settings = gds_output_renderer_get_layer_settings(renderer);
/* Set layer info list. In case of failure it remains NULL */
if (settings)
layer_infos = layer_settings_get_layer_info_list(settings);
if (c_renderer->svg == TRUE) if (c_renderer->svg == TRUE)
svg_file = output_file; svg_file = output_file;
else else

View File

@ -99,11 +99,19 @@ ret_close_so_handle:
static int external_renderer_render_output(GdsOutputRenderer *renderer, static int external_renderer_render_output(GdsOutputRenderer *renderer,
struct gds_cell *cell, struct gds_cell *cell,
GList *layer_infos,
const char *output_file,
double scale) double scale)
{ {
ExternalRenderer *ext_renderer = GDS_RENDER_EXTERNAL_RENDERER(renderer); ExternalRenderer *ext_renderer = GDS_RENDER_EXTERNAL_RENDERER(renderer);
LayerSettings *settings;
GList *layer_infos = NULL;
const char *output_file;
output_file = gds_output_renderer_get_output_file(renderer);
settings = gds_output_renderer_get_layer_settings(renderer);
/* Set layer info list. In case of failure it remains NULL */
if (settings)
layer_infos = layer_settings_get_layer_info_list(settings);
return external_renderer_render_cell(cell, layer_infos, output_file, scale, ext_renderer->shared_object_path); return external_renderer_render_cell(cell, layer_infos, output_file, scale, ext_renderer->shared_object_path);
} }
@ -151,7 +159,7 @@ static void external_renderer_dispose(GObject *self_obj)
self->shared_object_path = NULL; self->shared_object_path = NULL;
} }
G_OBJECT_CLASS(external_renderer_parent_class)->dispose(G_OBJECT(self)); G_OBJECT_CLASS(external_renderer_parent_class)->dispose(self_obj);
} }
static GParamSpec *external_renderer_properties[N_PROPERTIES] = {NULL}; static GParamSpec *external_renderer_properties[N_PROPERTIES] = {NULL};

View File

@ -31,38 +31,123 @@
*/ */
#include <gds-render/output-renderers/gds-output-renderer.h> #include <gds-render/output-renderers/gds-output-renderer.h>
#include <gds-render/layer/layer-info.h>
typedef struct { typedef struct {
gpointer padding[12]; gchar *output_file;
LayerSettings *layer_settings;
gpointer padding[11];
} GdsOutputRendererPrivate; } GdsOutputRendererPrivate;
enum {
PROP_OUTPUT_FILE = 1,
PROP_LAYER_SETTINGS,
N_PROPERTIES
};
G_DEFINE_TYPE_WITH_PRIVATE(GdsOutputRenderer, gds_output_renderer, G_TYPE_OBJECT) G_DEFINE_TYPE_WITH_PRIVATE(GdsOutputRenderer, gds_output_renderer, G_TYPE_OBJECT)
static int gds_output_renderer_render_dummy(GdsOutputRenderer *renderer, static int gds_output_renderer_render_dummy(GdsOutputRenderer *renderer,
struct gds_cell *cell, struct gds_cell *cell,
GList *layer_infos,
const char *output_file,
double scale) double scale)
{ {
(void)renderer; (void)renderer;
(void)cell; (void)cell;
(void)layer_infos;
(void)output_file;
(void)scale; (void)scale;
g_warning("Output renderer does not define a render_output function!"); g_warning("Output renderer does not define a render_output function!");
return 0; return 0;
} }
static void gds_output_renderer_dispose(GObject *self_obj)
{
GdsOutputRenderer *renderer = GDS_RENDER_OUTPUT_RENDERER(self_obj);
GdsOutputRendererPrivate *priv;
priv = gds_output_renderer_get_instance_private(renderer);
if (priv->output_file)
g_free(priv->output_file);
g_clear_object(&priv->layer_settings);
/* Chain up to parent class */
G_OBJECT_CLASS(gds_output_renderer_parent_class)->dispose(self_obj);
}
static void gds_output_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
{
GdsOutputRenderer *self = GDS_RENDER_OUTPUT_RENDERER(obj);
GdsOutputRendererPrivate *priv;
priv = gds_output_renderer_get_instance_private(self);
switch (property_id) {
case PROP_OUTPUT_FILE:
g_value_set_string(value, priv->output_file);
break;
case PROP_LAYER_SETTINGS:
g_value_set_object(value, priv->layer_settings);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
break;
}
}
static void gds_output_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
{
GdsOutputRenderer *self = GDS_RENDER_OUTPUT_RENDERER(obj);
GdsOutputRendererPrivate *priv;
priv = gds_output_renderer_get_instance_private(self);
switch (property_id) {
case PROP_OUTPUT_FILE:
if (priv->output_file)
g_free(priv->output_file);
priv->output_file = g_strdup(g_value_get_string(value));
break;
case PROP_LAYER_SETTINGS:
g_clear_object(&priv->layer_settings);
priv->layer_settings = g_value_get_object(value);
g_object_ref(priv->layer_settings);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
break;
}
}
static GParamSpec *gds_output_renderer_properties[N_PROPERTIES] = {NULL};
static void gds_output_renderer_class_init(GdsOutputRendererClass *klass) static void gds_output_renderer_class_init(GdsOutputRendererClass *klass)
{ {
GObjectClass *oclass = G_OBJECT_CLASS(klass);
klass->render_output = gds_output_renderer_render_dummy; klass->render_output = gds_output_renderer_render_dummy;
oclass->dispose = gds_output_renderer_dispose;
oclass->set_property = gds_output_renderer_set_property;
oclass->get_property = gds_output_renderer_get_property;
/* Setup properties */
gds_output_renderer_properties[PROP_OUTPUT_FILE] =
g_param_spec_string("output-file", "output file", "Output file for renderer",
NULL, G_PARAM_READWRITE);
gds_output_renderer_properties[PROP_LAYER_SETTINGS] =
g_param_spec_object("layer-settings", "Layer Settings object",
"Object containing the layer rendering information",
GDS_RENDER_TYPE_LAYER_SETTINGS, G_PARAM_READWRITE);
g_object_class_install_properties(oclass, N_PROPERTIES, gds_output_renderer_properties);
} }
void gds_output_renderer_init(GdsOutputRenderer *self) void gds_output_renderer_init(GdsOutputRenderer *self)
{ {
(void)self; GdsOutputRendererPrivate *priv;
priv = gds_output_renderer_get_instance_private(self);
priv->output_file = NULL;
return; return;
} }
@ -71,17 +156,69 @@ GdsOutputRenderer *gds_output_renderer_new()
return GDS_RENDER_OUTPUT_RENDERER(g_object_new(GDS_RENDER_TYPE_OUTPUT_RENDERER, NULL)); return GDS_RENDER_OUTPUT_RENDERER(g_object_new(GDS_RENDER_TYPE_OUTPUT_RENDERER, NULL));
} }
int gds_output_renderer_render_output(GdsOutputRenderer *renderer, struct gds_cell *cell, GList *layer_infos, const char *output_file, double scale) GdsOutputRenderer *gds_output_renderer_new_with_props(const char *output_file, LayerSettings *layer_settings)
{
return GDS_RENDER_OUTPUT_RENDERER(g_object_new(GDS_RENDER_TYPE_OUTPUT_RENDERER,
"layer-settings", layer_settings,
"output-file", output_file,
NULL));
}
void gds_output_renderer_set_output_file(GdsOutputRenderer *renderer, const gchar *file_name)
{
g_return_if_fail(GDS_RENDER_IS_OUTPUT_RENDERER(renderer));
/* Check if the filename is actually filled */
if (!file_name || !file_name[0])
return;
g_object_set(renderer, "output-file", file_name, NULL);
}
const char *gds_output_renderer_get_output_file(GdsOutputRenderer *renderer)
{
const char *file = NULL;
g_object_get(renderer, "output-file", &file, NULL);
return file;
}
LayerSettings *gds_output_renderer_get_layer_settings(GdsOutputRenderer *renderer)
{
LayerSettings *ret = NULL;
g_object_get(renderer, "layer-settings", &ret, NULL);
return ret;
}
void gds_output_renderer_set_layer_settings(GdsOutputRenderer *renderer, LayerSettings *settings)
{
g_return_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings));
g_object_set(renderer, "layer_settings", settings, NULL);
}
int gds_output_renderer_render_output(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale)
{ {
GdsOutputRendererClass *klass; GdsOutputRendererClass *klass;
GdsOutputRendererPrivate *priv = gds_output_renderer_get_instance_private(renderer);
if (GDS_RENDER_IS_OUTPUT_RENDERER(renderer) == FALSE) { if (GDS_RENDER_IS_OUTPUT_RENDERER(renderer) == FALSE) {
g_error("Output Renderer not valid."); g_error("Output Renderer not valid.");
return GDS_OUTPUT_RENDERER_GEN_ERR; return GDS_OUTPUT_RENDERER_GEN_ERR;
} }
if (!cell || !layer_infos || !output_file) { if (!priv->output_file || !priv->output_file[0]) {
g_error("Output renderer called with insufficient parameters."); g_error("No/invalid output file set.");
return GDS_OUTPUT_RENDERER_GEN_ERR;
}
if (!priv->layer_settings) {
g_error("No layer specification supplied.");
return GDS_OUTPUT_RENDERER_GEN_ERR;
}
if (!cell) {
g_error("Output renderer called without cell to render.");
return GDS_OUTPUT_RENDERER_PARAM_ERR; return GDS_OUTPUT_RENDERER_PARAM_ERR;
} }
@ -91,7 +228,7 @@ int gds_output_renderer_render_output(GdsOutputRenderer *renderer, struct gds_ce
return GDS_OUTPUT_RENDERER_GEN_ERR; return GDS_OUTPUT_RENDERER_GEN_ERR;
} }
return klass->render_output(renderer, cell, layer_infos, output_file, scale); return klass->render_output(renderer, cell, scale);
} }

View File

@ -69,10 +69,13 @@ static void write_layer_definitions(FILE *tex_file, GList *layer_infos, GString
{ {
GList *list; GList *list;
struct layer_info *lifo; struct layer_info *lifo;
char *end_str;
for (list = layer_infos; list != NULL; list = list->next) { for (list = layer_infos; list != NULL; list = list->next) {
lifo = (struct layer_info *)list->data; lifo = (struct layer_info *)list->data;
if (!lifo->render)
continue;
g_string_printf(buffer, "\\pgfdeclarelayer{l%d}\n\\definecolor{c%d}{rgb}{%lf,%lf,%lf}\n", g_string_printf(buffer, "\\pgfdeclarelayer{l%d}\n\\definecolor{c%d}{rgb}{%lf,%lf,%lf}\n",
lifo->layer, lifo->layer, lifo->layer, lifo->layer,
lifo->color.red, lifo->color.green, lifo->color.blue); lifo->color.red, lifo->color.green, lifo->color.blue);
@ -85,14 +88,13 @@ static void write_layer_definitions(FILE *tex_file, GList *layer_infos, GString
for (list = layer_infos; list != NULL; list = list->next) { for (list = layer_infos; list != NULL; list = list->next) {
lifo = (struct layer_info *)list->data; lifo = (struct layer_info *)list->data;
if (list->next == NULL) if (!lifo->render)
end_str = ",main}"; continue;
else
end_str = ","; g_string_printf(buffer, "l%d,", lifo->layer);
g_string_printf(buffer, "l%d%s", lifo->layer, end_str);
WRITEOUT_BUFFER(buffer); WRITEOUT_BUFFER(buffer);
} }
fwrite("\n", sizeof(char), 1, tex_file); fwrite("main}\n", sizeof(char), 1, tex_file);
} }
/** /**
@ -128,7 +130,7 @@ static gboolean write_layer_env(FILE *tex_file, GdkRGBA *color, int layer, GList
for (temp = linfo; temp != NULL; temp = temp->next) { for (temp = linfo; temp != NULL; temp = temp->next) {
inf = (struct layer_info *)temp->data; inf = (struct layer_info *)temp->data;
if (inf->layer == layer) { if (inf->layer == layer && inf->render) {
color->alpha = inf->color.alpha; color->alpha = inf->color.alpha;
color->red = inf->color.red; color->red = inf->color.red;
color->green = inf->color.green; color->green = inf->color.green;
@ -322,19 +324,29 @@ static int latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos,
static int latex_renderer_render_output(GdsOutputRenderer *renderer, static int latex_renderer_render_output(GdsOutputRenderer *renderer,
struct gds_cell *cell, struct gds_cell *cell,
GList *layer_infos,
const char *output_file,
double scale) double scale)
{ {
LatexRenderer *l_renderer = GDS_RENDER_LATEX_RENDERER(renderer); LatexRenderer *l_renderer = GDS_RENDER_LATEX_RENDERER(renderer);
FILE *tex_file; FILE *tex_file;
int ret = -2; int ret = -2;
LayerSettings *settings;
GList *layer_infos = NULL;
const char *output_file;
output_file = gds_output_renderer_get_output_file(renderer);
settings = gds_output_renderer_get_layer_settings(renderer);
/* Set layer info list. In case of failure it remains NULL */
if (settings)
layer_infos = layer_settings_get_layer_info_list(settings);
tex_file = fopen(output_file, "w"); tex_file = fopen(output_file, "w");
if (tex_file) { if (tex_file) {
ret = latex_render_cell_to_code(cell, layer_infos, tex_file, scale, ret = latex_render_cell_to_code(cell, layer_infos, tex_file, scale,
l_renderer->pdf_layers, l_renderer->tex_standalone); l_renderer->pdf_layers, l_renderer->tex_standalone);
fclose(tex_file); fclose(tex_file);
} else {
g_error("Could not open LaTeX outpur file");
} }
return ret; return ret;