#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"
#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>
}
}
-} // namespace anon
+} // namespace
InsetGraphics::InsetGraphics(Buffer * buf)
// 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;
}
}
-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)
return latex_path(file, EXCLUDE_EXTENSION);
}
-} // namespace anon
+} // namespace
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 `"
// 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",
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())
// 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;
docstring InsetGraphics::xhtml(XHTMLStream & xs, OutputParams const & op) const
{
- string const output_file;
- if (!op.dryrun)
- 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.
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();
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);
+ }
}
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;
}
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();
}
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