Пример #1
0
/**
 * \return   None
 * \brief    This is a generic function to use the save function of
 *           a module (including Autodetect)
 * \param    key       Identifier of which module to use
 * \param    doc       The document to be saved
 * \param    filename  The file that the document should be saved to
 * \param    official  (optional) whether to set :output_module and :modified in the
 *                     document; is true for normal save, false for temporary saves
 *
 * First things first, are we looking at an autodetection?  Well if that's the case then the module
 * needs to be found, and that is done with a database lookup through the module DB.  The foreach
 * function is called, with the parameter being a gpointer array.  It contains both the filename
 * (to find its extension) and where to write the module when it is found.
 *
 * If there is no autodetection the module database is queried with the key given.
 *
 * If everything is cool at this point, the module is loaded, and there is possibility for
 * preferences.  If there is a function, then it is executed to get the dialog to be displayed.
 * After it is finished the function continues.
 *
 * Lastly, the save function is called in the module itself.
 */
void
save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension, bool check_overwrite, bool official,
    Inkscape::Extension::FileSaveMethod save_method)
{
    Output *omod;
    if (key == NULL) {
        gpointer parray[2];
        parray[0] = (gpointer)filename;
        parray[1] = (gpointer)&omod;
        omod = NULL;
        db.foreach(save_internal, (gpointer)&parray);

        /* This is a nasty hack, but it is required to ensure that
           autodetect will always save with the Inkscape extensions
           if they are available. */
        if (omod != NULL && !strcmp(omod->get_id(), SP_MODULE_KEY_OUTPUT_SVG)) {
            omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE));
        }
        /* If autodetect fails, save as Inkscape SVG */
        if (omod == NULL) {
            // omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE)); use exception and let user choose
        }
    } else {
        omod = dynamic_cast<Output *>(key);
    }

    if (!dynamic_cast<Output *>(omod)) {
        g_warning("Unable to find output module to handle file: %s\n", filename);
        throw Output::no_extension_found();
    }

    omod->set_state(Extension::STATE_LOADED);
    if (!omod->loaded()) {
        throw Output::save_failed();
    }

    if (!omod->prefs()) {
        throw Output::save_cancelled();
    }

    gchar *fileName = NULL;
    if (setextension) {
        gchar *lowerfile = g_utf8_strdown(filename, -1);
        gchar *lowerext = g_utf8_strdown(omod->get_extension(), -1);

        if (!g_str_has_suffix(lowerfile, lowerext)) {
            fileName = g_strdup_printf("%s%s", filename, omod->get_extension());
        }

        g_free(lowerfile);
        g_free(lowerext);
    }

    if (fileName == NULL) {
        fileName = g_strdup(filename);
    }

    if (check_overwrite && !sp_ui_overwrite_file(fileName)) {
        g_free(fileName);
        throw Output::no_overwrite();
    }

    // test if the file exists and is writable
    // the test only checks the file attributes and might pass where ACL does not allow to write
    if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS) && !Inkscape::IO::file_is_writable(filename)) {
        g_free(fileName);
        throw Output::file_read_only();
    }

    Inkscape::XML::Node *repr = doc->getReprRoot();


    // remember attributes in case this is an unofficial save and/or overwrite fails
    gchar *saved_uri = g_strdup(doc->getURI());
    gchar *saved_output_extension = NULL;
    gchar *saved_dataloss = NULL;
    bool saved_modified = doc->isModifiedSinceSave();
    saved_output_extension = g_strdup(get_file_save_extension(save_method).c_str());
    saved_dataloss = g_strdup(repr->attribute("inkscape:dataloss"));
    if (official) {
        // The document is changing name/uri.
        doc->changeUriAndHrefs(fileName);
    }

    // Update attributes:
    {
        bool const saved = DocumentUndo::getUndoSensitive(doc);
        DocumentUndo::setUndoSensitive(doc, false);
        {
            // also save the extension for next use
            store_file_extension_in_prefs (omod->get_id(), save_method);
            // set the "dataloss" attribute if the chosen extension is lossy
            repr->setAttribute("inkscape:dataloss", NULL);
            if (omod->causes_dataloss()) {
                repr->setAttribute("inkscape:dataloss", "true");
            }
        }
        DocumentUndo::setUndoSensitive(doc, saved);
        doc->setModifiedSinceSave(false);
    }

    try {
        omod->save(doc, fileName);
    }
    catch(...) {
        // revert attributes in case of official and overwrite
        if(check_overwrite && official) {
            bool const saved = DocumentUndo::getUndoSensitive(doc);
            DocumentUndo::setUndoSensitive(doc, false);
            {
                store_file_extension_in_prefs (saved_output_extension, save_method);
                repr->setAttribute("inkscape:dataloss", saved_dataloss);
            }
            DocumentUndo::setUndoSensitive(doc, saved);
            doc->changeUriAndHrefs(saved_uri);
        }
        doc->setModifiedSinceSave(saved_modified);
        // free used ressources
        g_free(saved_output_extension);
        g_free(saved_dataloss);
        g_free(saved_uri);

        g_free(fileName);

        throw Inkscape::Extension::Output::save_failed();
    }

    // If it is an unofficial save, set the modified attributes back to what they were.
    if ( !official) {
        bool const saved = DocumentUndo::getUndoSensitive(doc);
        DocumentUndo::setUndoSensitive(doc, false);
        {
            store_file_extension_in_prefs (saved_output_extension, save_method);
            repr->setAttribute("inkscape:dataloss", saved_dataloss);
        }
        DocumentUndo::setUndoSensitive(doc, saved);
        doc->setModifiedSinceSave(saved_modified);

        g_free(saved_output_extension);
        g_free(saved_dataloss);
    }

    g_free(fileName);
    return;
}
Пример #2
0
ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
                                Geom::Rect const &area,
                                unsigned long width, unsigned long height, double xdpi, double ydpi,
                                unsigned long bgcolor,
                                unsigned (*status)(float, void *),
                                void *data, bool force_overwrite,
                                GSList *items_only)
{
    g_return_val_if_fail(doc != NULL, EXPORT_ERROR);
    g_return_val_if_fail(filename != NULL, EXPORT_ERROR);
    g_return_val_if_fail(width >= 1, EXPORT_ERROR);
    g_return_val_if_fail(height >= 1, EXPORT_ERROR);
    g_return_val_if_fail(!area.hasZeroArea(), EXPORT_ERROR);


    if (!force_overwrite && !sp_ui_overwrite_file(filename)) {
        // aborted overwrite
	return EXPORT_ABORTED;
    }

    doc->ensureUpToDate();

    /* Calculate translation by transforming to document coordinates (flipping Y)*/
    Geom::Point translation = Geom::Point(-area[Geom::X][0], area[Geom::Y][1] - doc->getHeight().value("px"));

    /*  This calculation is only valid when assumed that (x0,y0)= area.corner(0) and (x1,y1) = area.corner(2)
     * 1) a[0] * x0 + a[2] * y1 + a[4] = 0.0
     * 2) a[1] * x0 + a[3] * y1 + a[5] = 0.0
     * 3) a[0] * x1 + a[2] * y1 + a[4] = width
     * 4) a[1] * x0 + a[3] * y0 + a[5] = height
     * 5) a[1] = 0.0;
     * 6) a[2] = 0.0;
     *
     * (1,3) a[0] * x1 - a[0] * x0 = width
     * a[0] = width / (x1 - x0)
     * (2,4) a[3] * y0 - a[3] * y1 = height
     * a[3] = height / (y0 - y1)
     * (1) a[4] = -a[0] * x0
     * (2) a[5] = -a[3] * y1
     */

    Geom::Affine const affine(Geom::Translate(translation)
                            * Geom::Scale(width / area.width(),
                                        height / area.height()));

    //SP_PRINT_MATRIX("SVG2PNG", &affine);

    struct SPEBP ebp;
    ebp.width  = width;
    ebp.height = height;
    ebp.background = bgcolor;

    /* Create new drawing */
    Inkscape::Drawing drawing;
    drawing.setExact(true); // export with maximum blur rendering quality
    unsigned const dkey = SPItem::display_key_new(1);

    // Create ArenaItems and set transform
    drawing.setRoot(doc->getRoot()->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY));
    drawing.root()->setTransform(affine);
    ebp.drawing = &drawing;

    // We show all and then hide all items we don't want, instead of showing only requested items,
    // because that would not work if the shown item references something in defs
    if (items_only) {
        hide_other_items_recursively(doc->getRoot(), items_only, dkey);
    }

    ebp.status = status;
    ebp.data   = data;

    bool write_status = false;;

    ebp.sheight = 64;
    ebp.px = g_try_new(guchar, 4 * ebp.sheight * width);

    if (ebp.px) {
        write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp);
        g_free(ebp.px);
    }

    // Hide items, this releases arenaitem
    doc->getRoot()->invoke_hide(dkey);

    return write_status ? EXPORT_OK : EXPORT_ERROR;
}
/**
 * \return   None
 * \brief    This is a generic function to use the save function of
 *           a module (including Autodetect)
 * \param    key       Identifier of which module to use
 * \param    doc       The document to be saved
 * \param    filename  The file that the document should be saved to
 * \param    official  (optional) whether to set :output_module and :modified in the
 *                     document; is true for normal save, false for temporary saves
 *
 * First things first, are we looking at an autodetection?  Well if that's the case then the module
 * needs to be found, and that is done with a database lookup through the module DB.  The foreach
 * function is called, with the parameter being a gpointer array.  It contains both the filename
 * (to find its extension) and where to write the module when it is found.
 *
 * If there is no autodetection the module database is queried with the key given.
 *
 * If everything is cool at this point, the module is loaded, and there is possibility for
 * preferences.  If there is a function, then it is executed to get the dialog to be displayed.
 * After it is finished the function continues.
 *
 * Lastly, the save function is called in the module itself.
 */
void
save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension, bool check_overwrite, bool official)
{
    Output *omod;
    if (key == NULL) {
        gpointer parray[2];
        parray[0] = (gpointer)filename;
        parray[1] = (gpointer)&omod;
        omod = NULL;
        db.foreach(save_internal, (gpointer)&parray);

        /* This is a nasty hack, but it is required to ensure that
           autodetect will always save with the Inkscape extensions
           if they are available. */
        if (omod != NULL && !strcmp(omod->get_id(), SP_MODULE_KEY_OUTPUT_SVG)) {
            omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE));
        }
        /* If autodetect fails, save as Inkscape SVG */
        if (omod == NULL) {
            omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE));
        }
    } else {
        omod = dynamic_cast<Output *>(key);
    }

    if (!dynamic_cast<Output *>(omod)) {
        g_warning("Unable to find output module to handle file: %s\n", filename);
        throw Output::no_extension_found();
        return;
    }

    omod->set_state(Extension::STATE_LOADED);
    if (!omod->loaded()) {
        throw Output::save_failed();
    }

    if (!omod->prefs()) {
        throw Output::save_cancelled();
    }

    gchar *fileName = NULL;
    if (setextension) {
        gchar *lowerfile = g_utf8_strdown(filename, -1);
        gchar *lowerext = g_utf8_strdown(omod->get_extension(), -1);

        if (!g_str_has_suffix(lowerfile, lowerext)) {
            fileName = g_strdup_printf("%s%s", filename, omod->get_extension());
        }

        g_free(lowerfile);
        g_free(lowerext);
    }

    if (fileName == NULL) {
        fileName = g_strdup(filename);
    }

    if (check_overwrite && !sp_ui_overwrite_file(fileName)) {
        g_free(fileName);
        throw Output::no_overwrite();
    }

    Inkscape::XML::Node *repr = sp_document_repr_root(doc);

    // remember attributes in case this is an unofficial save
    bool saved_modified = false;
    gchar *saved_output_extension = NULL;
    gchar *saved_dataloss = NULL;
    gchar *saved_uri = NULL;
    if (!official) {
        saved_modified = doc->isModifiedSinceSave();
        if (repr->attribute("inkscape:output_extension")) {
            saved_output_extension = g_strdup(repr->attribute("inkscape:output_extension"));
        }
        if (repr->attribute("inkscape:dataloss")) {
            saved_dataloss = g_strdup(repr->attribute("inkscape:dataloss"));
        }
        if (doc->uri) {
            saved_uri = g_strdup(doc->uri);    
        }
    }    

    // update attributes:
    bool saved = sp_document_get_undo_sensitive(doc);
    sp_document_set_undo_sensitive (doc, false); 
        // save the filename for next use
        sp_document_set_uri(doc, fileName);
        // also save the extension for next use
        repr->setAttribute("inkscape:output_extension", omod->get_id());
        // set the "dataloss" attribute if the chosen extension is lossy
        repr->setAttribute("inkscape:dataloss", NULL);
        if ( omod->causes_dataloss() ) {
            repr->setAttribute("inkscape:dataloss", "true");
        }
    sp_document_set_undo_sensitive (doc, saved);
    doc->setModifiedSinceSave(false);

    omod->save(doc, fileName);
    
    // if it is an unofficial save, set the modified attributes back to what they were    
    if ( !official) {
        saved = sp_document_get_undo_sensitive(doc);
        sp_document_set_undo_sensitive (doc, false);
            repr->setAttribute("inkscape:output_extension", saved_output_extension);
            repr->setAttribute("inkscape:dataloss", saved_dataloss);
            sp_document_set_uri(doc, saved_uri);
        sp_document_set_undo_sensitive (doc, saved);
        doc->setModifiedSinceSave(saved_modified);
    }
    
    if (saved_output_extension)  g_free(saved_output_extension);
    if (saved_dataloss)          g_free(saved_dataloss);
    if (saved_uri)               g_free(saved_uri);    
    
    g_free(fileName);
    return;
}