]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetGraphics.cpp
de.po
[lyx.git] / src / insets / InsetGraphics.cpp
index 335c92d6269c16285e8b24b8f7ea60f59b77af7a..c05075583b01416edd530ee3541140a1d522ea39 100644 (file)
@@ -74,6 +74,10 @@ TODO
 #include "frontends/alert.h"
 #include "frontends/Application.h"
 
+#include "graphics/GraphicsCache.h"
+#include "graphics/GraphicsCacheItem.h"
+#include "graphics/GraphicsImage.h"
+
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/docstream.h"
@@ -83,8 +87,11 @@ TODO
 #include "support/lyxlib.h"
 #include "support/lstrings.h"
 #include "support/os.h"
+#include "support/qstring_helpers.h"
 #include "support/Systemcall.h"
 
+#include <QProcess>
+
 #include <algorithm>
 #include <sstream>
 #include <tuple>
@@ -102,7 +109,7 @@ namespace {
 /// Note that \p format may be unknown (i. e. an empty string)
 string findTargetFormat(string const & format, OutputParams const & runparams)
 {
-       // Are we using latex or XeTeX/LuaTeX/pdflatex?
+       // Are we latexing to DVI or PDF?
        if (runparams.flavor == OutputParams::PDFLATEX
            || runparams.flavor == OutputParams::XETEX
            || runparams.flavor == OutputParams::LUATEX) {
@@ -165,7 +172,7 @@ void readInsetGraphics(Lexer & lex, Buffer const & buf, bool allowOrigin,
        }
 }
 
-} // namespace anon
+} // namespace
 
 
 InsetGraphics::InsetGraphics(Buffer * buf)
@@ -226,7 +233,7 @@ void InsetGraphics::doDispatch(Cursor & cur, FuncRequest & cmd)
                // if the inset is part of a graphics group, all the
                // other members should be updated too.
                if (!params_.groupId.empty())
-                       graphics::unifyGraphicsGroups(buffer(), 
+                       graphics::unifyGraphicsGroups(buffer(),
                                                      to_utf8(cmd.argument()));
                break;
        }
@@ -304,17 +311,81 @@ void InsetGraphics::read(Lexer & lex)
 }
 
 
-string InsetGraphics::createLatexOptions() const
+void InsetGraphics::outBoundingBox(graphics::BoundingBox & bbox) const
+{
+       if (bbox.empty())
+               return;
+
+       FileName const file(params().filename.absFileName());
+
+       // No correction is necessary for a postscript image
+       bool const zipped = theFormats().isZippedFile(file);
+       FileName const unzipped_file = zipped ? unzipFile(file) : file;
+       string const format = theFormats().getFormatFromFile(unzipped_file);
+       if (zipped)
+               unzipped_file.removeFile();
+       if (Formats::isPostScriptFileFormat(format))
+               return;
+
+       // Get the actual image dimensions in pixels
+       int width = 0;
+       int height = 0;
+       graphics::Cache & gc = graphics::Cache::get();
+       if (gc.inCache(file)) {
+               graphics::Image const * image = gc.item(file)->image();
+               if (image) {
+                       width  = image->width();
+                       height = image->height();
+               }
+       }
+       if (width == 0 || height == 0)
+               return;
+
+       // Use extractbb to find the dimensions in the typeset output
+       QProcess extractbb;
+       extractbb.start("extractbb", QStringList() << "-O" << toqstr(file.absFileName()));
+       if (!extractbb.waitForStarted() || !extractbb.waitForFinished()) {
+               LYXERR0("Cannot read output bounding box of " << file);
+               return;
+       }
+
+       string const result = extractbb.readAll().constData();
+       size_t i = result.find("%%BoundingBox:");
+       if (i == string::npos) {
+               LYXERR0("Cannot find output bounding box of " << file);
+               return;
+       }
+
+       string const bb = result.substr(i);
+       int out_width = convert<int>(token(bb, ' ', 3));
+       int out_height = convert<int>(token(bb, ' ', 4));
+
+       // Compute the scaling ratio and correct the bounding box
+       double scalex = out_width / double(width);
+       double scaley = out_height / double(height);
+
+       bbox.xl.value(scalex * bbox.xl.value());
+       bbox.xr.value(scalex * bbox.xr.value());
+       bbox.yb.value(scaley * bbox.yb.value());
+       bbox.yt.value(scaley * bbox.yt.value());
+}
+
+
+string InsetGraphics::createLatexOptions(bool const ps) const
 {
        // Calculate the options part of the command, we must do it to a string
        // stream since we might have a trailing comma that we would like to remove
        // before writing it to the output stream.
        ostringstream options;
-       if (!params().bbox.empty())
-               options << "bb=" << params().bbox.xl.asLatexString() << ' '
-                       << params().bbox.yb.asLatexString() << ' '
-                       << params().bbox.xr.asLatexString() << ' '
-                       << params().bbox.yt.asLatexString() << ',';
+       if (!params().bbox.empty()) {
+               graphics::BoundingBox out_bbox = params().bbox;
+               outBoundingBox(out_bbox);
+               string const key = ps ? "bb=" : "viewport=";
+               options << key << out_bbox.xl.asLatexString() << ' '
+                       << out_bbox.yb.asLatexString() << ' '
+                       << out_bbox.xr.asLatexString() << ' '
+                       << out_bbox.yt.asLatexString() << ',';
+       }
        if (params().draft)
            options << "draft,";
        if (params().clip)
@@ -515,8 +586,14 @@ copyToDirIfNeeded(DocFileName const & file, string const & dir)
                // extension removed, because base.eps and base.eps.gz may
                // have different content but would get the same mangled
                // name in this case.
+               // Also take into account that if the name of the zipped file
+               // has no zip extension then the name of the unzipped one is
+               // prefixed by "unzipped_".
                string const base = removeExtension(file.unzippedFileName());
-               string::size_type const ext_len = file_in.length() - base.length();
+               string::size_type const prefix_len =
+                       prefixIs(onlyFileName(base), "unzipped_") ? 9 : 0;
+               string::size_type const ext_len =
+                       file_in.length() + prefix_len - base.length();
                mangled[mangled.length() - ext_len] = '.';
        }
        FileName const file_out(makeAbsPath(mangled, dir));
@@ -559,7 +636,7 @@ string const stripExtensionIfPossible(string const & file, string const & to, bo
        return latex_path(file, EXCLUDE_EXTENSION);
 }
 
-} // namespace anon
+} // namespace
 
 
 string InsetGraphics::prepareFile(OutputParams const & runparams) const
@@ -667,12 +744,12 @@ string InsetGraphics::prepareFile(OutputParams const & runparams) const
                        // The LaTeX compiler will not be able to determine
                        // the file format from the extension, so we must
                        // change it.
-                       FileName const new_file = 
+                       FileName const new_file =
                                FileName(changeExtension(temp_file.absFileName(), ext));
                        if (temp_file.moveTo(new_file)) {
                                temp_file = new_file;
                                output_file = changeExtension(output_file, ext);
-                               source_file = 
+                               source_file =
                                        FileName(changeExtension(source_file.absFileName(), ext));
                        } else {
                                LYXERR(Debug::GRAPHICS, "Could not rename file `"
@@ -712,9 +789,15 @@ string InsetGraphics::prepareFile(OutputParams const & runparams) const
 
        // FIXME (Abdel 12/08/06): Is there a need to show these errors?
        ErrorList el;
-       if (theConverters().convert(&buffer(), temp_file, to_file, params().filename,
+       Converters::RetVal const rv = 
+           theConverters().convert(&buffer(), temp_file, to_file, params().filename,
                               from, to, el,
-                              Converters::try_default | Converters::try_cache)) {
+                              Converters::try_default | Converters::try_cache);
+       if (rv == Converters::KILLED) {
+               LYXERR0("Graphics preparation killed.");
+               if (buffer().isClone() && buffer().isExporting())
+                       throw ConversionException();
+       } else if (rv == Converters::SUCCESS) {
                runparams.exportdata->addExternalFile(tex_format,
                                to_file, output_to_file);
                runparams.exportdata->addExternalFile("dvi",
@@ -765,7 +848,9 @@ void InsetGraphics::latex(otexstream & os,
        before += "\\includegraphics";
 
        // Write the options if there are any.
-       string const opts = createLatexOptions();
+       bool const ps = runparams.flavor == OutputParams::LATEX
+               || runparams.flavor == OutputParams::DVILUATEX;
+       string const opts = createLatexOptions(ps);
        LYXERR(Debug::GRAPHICS, "\tOpts = " << opts);
 
        if (!opts.empty() && !message.empty())
@@ -935,10 +1020,15 @@ string InsetGraphics::prepareHTMLFile(OutputParams const & runparams) const
 
        // FIXME (Abdel 12/08/06): Is there a need to show these errors?
        ErrorList el;
-       bool const success = 
+       Converters::RetVal const rv =
                theConverters().convert(&buffer(), temp_file, to_file, params().filename,
                        from, to, el, Converters::try_default | Converters::try_cache);
-       if (!success)   
+       if (rv == Converters::KILLED) {
+               if (buffer().isClone() && buffer().isExporting())
+                       throw ConversionException();
+               return string();
+       }
+       if (rv != Converters::SUCCESS)
                return string();
        runparams.exportdata->addExternalFile("xhtml", to_file, output_to_file);
        return output_to_file;
@@ -950,15 +1040,15 @@ docstring InsetGraphics::xhtml(XHTMLStream & xs, OutputParams const & op) const
        string const output_file = op.dryrun ? string() : prepareHTMLFile(op);
 
        if (output_file.empty() && !op.dryrun) {
-               LYXERR0("InsetGraphics::xhtml: Unable to prepare file `" 
+               LYXERR0("InsetGraphics::xhtml: Unable to prepare file `"
                        << params().filename << "' for output. File missing?");
-               string const attr = "src='" + params().filename.absFileName() 
+               string const attr = "src='" + params().filename.absFileName()
                                    + "' alt='image: " + output_file + "'";
                xs << html::CompTag("img", attr);
                return docstring();
        }
 
-       // FIXME XHTML 
+       // FIXME XHTML
        // We aren't doing anything with the crop and rotate parameters, and it would
        // really be better to do width and height conversion, rather than to output
        // these parameters here.
@@ -980,7 +1070,7 @@ docstring InsetGraphics::xhtml(XHTMLStream & xs, OutputParams const & op) const
        if (!imgstyle.empty())
                imgstyle = "style='" + imgstyle + "' ";
 
-       string const attr = imgstyle + "src='" + output_file + "' alt='image: " 
+       string const attr = imgstyle + "src='" + output_file + "' alt='image: "
                            + output_file + "'";
        xs << html::CompTag("img", attr);
        return docstring();
@@ -1092,13 +1182,14 @@ void getGraphicsGroups(Buffer const & b, set<string> & ids)
        Inset & inset = b.inset();
        InsetIterator it  = inset_iterator_begin(inset);
        InsetIterator const end = inset_iterator_end(inset);
-       for (; it != end; ++it)
-               if (it->lyxCode() == GRAPHICS_CODE) {
-                       InsetGraphics & ins = static_cast<InsetGraphics &>(*it);
-                       InsetGraphicsParams inspar = ins.getParams();
-                       if (!inspar.groupId.empty())
-                               ids.insert(inspar.groupId);
-               }
+       for (; it != end; ++it) {
+               InsetGraphics const * ins = it->asInsetGraphics();
+               if (!ins)
+                       continue;
+               InsetGraphicsParams const & inspar = ins->getParams();
+               if (!inspar.groupId.empty())
+                       ids.insert(inspar.groupId);
+       }
 }
 
 
@@ -1110,12 +1201,13 @@ int countGroupMembers(Buffer const & b, string const & groupId)
        Inset & inset = b.inset();
        InsetIterator it = inset_iterator_begin(inset);
        InsetIterator const end = inset_iterator_end(inset);
-       for (; it != end; ++it)
-               if (it->lyxCode() == GRAPHICS_CODE) {
-                       InsetGraphics & ins = static_cast<InsetGraphics &>(*it);
-                       if (ins.getParams().groupId == groupId)
-                               ++n;
-               }
+       for (; it != end; ++it) {
+               InsetGraphics const * ins = it->asInsetGraphics();
+               if (!ins)
+                       continue; 
+               if (ins->getParams().groupId == groupId)
+                       ++n;
+       }
        return n;
 }
 
@@ -1127,16 +1219,17 @@ string getGroupParams(Buffer const & b, string const & groupId)
        Inset & inset = b.inset();
        InsetIterator it  = inset_iterator_begin(inset);
        InsetIterator const end = inset_iterator_end(inset);
-       for (; it != end; ++it)
-               if (it->lyxCode() == GRAPHICS_CODE) {
-                       InsetGraphics & ins = static_cast<InsetGraphics &>(*it);
-                       InsetGraphicsParams inspar = ins.getParams();
-                       if (inspar.groupId == groupId) {
-                               InsetGraphicsParams tmp = inspar;
-                               tmp.filename.erase();
-                               return InsetGraphics::params2string(tmp, b);
-                       }
+       for (; it != end; ++it) {
+               InsetGraphics const * ins = it->asInsetGraphics();
+               if (!ins)
+                       continue;
+               InsetGraphicsParams const & inspar = ins->getParams();
+               if (inspar.groupId == groupId) {
+                       InsetGraphicsParams tmp = inspar;
+                       tmp.filename.erase();
+                       return InsetGraphics::params2string(tmp, b);
                }
+       }
        return string();
 }
 
@@ -1146,34 +1239,34 @@ void unifyGraphicsGroups(Buffer & b, string const & argument)
        InsetGraphicsParams params;
        InsetGraphics::string2params(argument, b, params);
 
-       b.undo().beginUndoGroup();
+       // This handles undo groups automagically
+       UndoGroupHelper ugh(&b);
        Inset & inset = b.inset();
        InsetIterator it  = inset_iterator_begin(inset);
        InsetIterator const end = inset_iterator_end(inset);
        for (; it != end; ++it) {
-               if (it->lyxCode() == GRAPHICS_CODE) {
-                       InsetGraphics & ins = static_cast<InsetGraphics &>(*it);
-                       InsetGraphicsParams inspar = ins.getParams();
-                       if (params.groupId == inspar.groupId) {
-                               b.undo().recordUndo(CursorData(it));
-                               params.filename = inspar.filename;
-                               ins.setParams(params);
-                       }
+               InsetGraphics * ins = it->asInsetGraphics();
+               if (!ins)
+                       continue;
+               InsetGraphicsParams const & inspar = ins->getParams();
+               if (params.groupId == inspar.groupId) {
+                       CursorData(it).recordUndo();
+                       params.filename = inspar.filename;
+                       ins->setParams(params);
                }
        }
-       b.undo().endUndoGroup();
 }
 
 
 InsetGraphics * getCurrentGraphicsInset(Cursor const & cur)
 {
        Inset * instmp = &cur.inset();
-       if (instmp->lyxCode() != GRAPHICS_CODE)
+       if (!instmp->asInsetGraphics())
                instmp = cur.nextInset();
-       if (!instmp || instmp->lyxCode() != GRAPHICS_CODE)
+       if (!instmp || !instmp->asInsetGraphics())
                return 0;
 
-       return static_cast<InsetGraphics *>(instmp);
+       return instmp->asInsetGraphics();
 }
 
 } // namespace graphics