]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetGraphics.cpp
reorder entries
[lyx.git] / src / insets / InsetGraphics.cpp
index 04ed735f6898529fd9d48d7878fd6f3da9ec1ec4..15c87e4e5e98aab81b2f901f28dfa2ef9b3c99ac 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>
@@ -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)
@@ -559,7 +630,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 +738,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 +783,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 +842,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 +1014,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;
@@ -947,18 +1031,18 @@ string InsetGraphics::prepareHTMLFile(OutputParams const & runparams) const
 
 docstring InsetGraphics::xhtml(XHTMLStream & xs, OutputParams const & op) const
 {
-       string const output_file = prepareHTMLFile(op);
+       string const output_file = op.dryrun ? string() : prepareHTMLFile(op);
 
-       if (output_file.empty()) {
-               LYXERR0("InsetGraphics::xhtml: Unable to prepare file `" 
+       if (output_file.empty() && !op.dryrun) {
+               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 +1064,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 +1176,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 +1195,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 +1213,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 +1233,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