* This file Copyright 2000 Baruch Even.
* ====================================================== */
-/*
-How to use it for now:
- * The lyxfunc 'graphics-insert' will insert this inset into the document.
-*/
-
/*
Major tasks:
* Switch to convert the images in the background, this requires work on
Minor tasks:
* Pop up a dialog if the widget version is higher than what we accept.
- * Prepare code to read FigInset insets to upgrade upwards
* Provide sed/awk/C code to downgrade from InsetGraphics to FigInset(?)
*/
* We do not dither or resize the image in a WYSIWYM way, we load it at
its original size and color, resizing is done in the final output,
but not in the LyX window.
+
+ * The scale option is only handled for the horizontal part, the vertical
+ part will not work. For now it is also shown only for horizontal
+ resizing on the form.
+
+ * EPS figures are not fully detected, they may have a lot of possible
+ suffixes so we need to read the file and detect if it's EPS or not.
+ [Implemented, need testing]
TODO Before initial production release:
* Replace insetfig everywhere
- * Read it's file format
- * Get created by all commands used to create figinset currently.
* Search for comments of the form
// INSET_GRAPHICS: remove this when InsetFig is thrown.
- And act upon them.
+ And act upon them. Make sure not to remove InsetFig code for the
+ 1.2.0 release, only afterwards, after deployment shows InsetGraphics
+ to be ok.
TODO Extended features:
* Add support for the 'picinpar' package.
* Improve support for 'subfigure' - Allow to set the various options
that are possible.
+ * Add resizing by percentage of image size (50%, 150%) - usefull for two
+ images of different size to be resized where they both should have
+ the same scale compared to each other.
*/
/* NOTES:
* moving the document file and its images with no problem.
*
* Conversions:
- *
- * Apparently the PNG output is preferred over PDF images when doing PDF
- * documents (i.e. prefer imagemagick eps2png over eps2pdf)
+ * Postscript output means EPS figures.
+ *
+ * PDF output is best done with PDF figures if it's a direct conversion
+ * or PNG figures otherwise.
+ * Image format
+ * from to
+ * EPS epstopdf
+ * JPG/PNG direct
+ * PDF direct
+ * others PNG
*/
#include <config.h>
#include "lyxtext.h"
#include "lyxrc.h"
#include "font.h" // For the lyxfont class.
+#include "fstream" // for ifstream in isEPS
#include <algorithm> // For the std::max
#include "support/lyxmanip.h"
#include "debug.h"
extern string system_tempdir;
+using std::ifstream;
using std::ostream;
+using std::endl;
+
// This function is a utility function
inline
if (cacheHandle.get() && (pixmap = cacheHandle->getImage()))
return pixmap->getWidth();
else {
- string const msg = statusMessage();
int font_width = 0;
-
- if (!msg.empty())
- font_width = lyxfont::width(msg, font);
+
+ LyXFont msgFont(font);
+ msgFont.setFamily(LyXFont::SANS_FAMILY);
+
+ string const justname = OnlyFilename (params.filename);
+ if (!justname.empty()) {
+ msgFont.setSize(LyXFont::SIZE_FOOTNOTE);
+ font_width = lyxfont::width(justname, msgFont);
+ }
+
+ string const msg = statusMessage();
+ if (!msg.empty()) {
+ msgFont.setSize(LyXFont::SIZE_TINY);
+ int const msg_width = lyxfont::width(msg, msgFont);
+ font_width = std::max(font_width, msg_width);
+ }
return std::max(50, font_width + 15);
}
int lwidth = width(bv, font);
// Make sure x is updated upon exit from this routine
- int old_x = x;
+ int old_x = int(x);
x += lwidth;
// This will draw the graphics. If the graphics has not been loaded yet,
// Get the image status, default to unknown error.
GraphicsCacheItem::ImageStatus status = GraphicsCacheItem::UnknownError;
- if (cacheHandle.get())
+ if (lyxrc.display_graphics != "no" &&
+ params.display != InsetGraphicsParams::NONE &&
+ cacheHandle.get())
status = cacheHandle->getImageStatus();
// Check if the image is now ready.
return;
}
-
paint.rectangle(old_x + 2, baseline - lascent,
lwidth - 4,
lascent + ldescent);
- string const msg = statusMessage();
- if (!msg.empty()) {
- // Print the message.
- LyXFont msgFont(font);
- msgFont.setFamily(LyXFont::SANS_FAMILY);
+ // Print the file name.
+ LyXFont msgFont(font);
+ msgFont.setFamily(LyXFont::SANS_FAMILY);
+
+ string const justname = OnlyFilename (params.filename);
+ if (!justname.empty()) {
msgFont.setSize(LyXFont::SIZE_FOOTNOTE);
- string const justname = OnlyFilename (params.filename);
paint.text(old_x + 8,
- baseline - lyxfont::maxAscent(msgFont) - 4,
- justname, msgFont);
+ baseline - lyxfont::maxAscent(msgFont) - 4,
+ justname, msgFont);
+ }
+ // Print the message.
+ string const msg = statusMessage();
+ if (!msg.empty()) {
msgFont.setSize(LyXFont::SIZE_TINY);
paint.text(old_x + 8, baseline - 4, msg, msgFont);
}
}
+void InsetGraphics::edit(BufferView * bv, bool)
+{
+ edit(bv, 0, 0, 0);
+}
+
+
Inset::EDITABLE InsetGraphics::editable() const
{
return IS_EDITABLE;
void InsetGraphics::write(Buffer const * buf, ostream & os) const
{
- os << "GRAPHICS FormatVersion 1\n";
+ os << "Graphics FormatVersion 1\n";
params.Write(buf, os);
}
void InsetGraphics::read(Buffer const * buf, LyXLex & lex)
+{
+ string const token = lex.getString();
+
+ if (token == "Graphics")
+ readInsetGraphics(buf, lex);
+ else if (token == "Figure") // Compatibility reading of FigInset figures.
+ readFigInset(buf, lex);
+ else
+ lyxerr[Debug::INFO] << "Not a Graphics or Figure inset!\n";
+
+ updateInset();
+}
+
+void InsetGraphics::readInsetGraphics(Buffer const * buf, LyXLex & lex)
{
bool finished = false;
- while (lex.IsOK() && !finished) {
+ while (lex.isOK() && !finished) {
lex.next();
- string const token = lex.GetString();
+ string const token = lex.getString();
lyxerr[Debug::INFO] << "Token: '" << token << '\''
<< std::endl;
finished = true;
} else if (token == "FormatVersion") {
lex.next();
- int version = lex.GetInteger();
+ int version = lex.getInteger();
if (version > 1)
lyxerr
<< "This document was created with a newer Graphics widget"
<< std::endl;
}
}
+}
- updateInset();
+
+void InsetGraphics::readFigInset(Buffer const * buf, LyXLex & lex)
+{
+ bool finished = false;
+
+ while (lex.isOK() && !finished) {
+ lex.next();
+
+ string const token = lex.getString();
+ lyxerr[Debug::INFO] << "Token: " << token << endl;
+
+ if (token.empty())
+ continue;
+ else if (token == "\\end_inset") {
+ finished = true;
+ } else if (token == "file") {
+ if (lex.next()) {
+ string const name = lex.getString();
+ string const path = OnlyPath(buf->fileName());
+ params.filename = MakeAbsPath(name, path);
+ }
+ } else if (token == "extra") {
+ if (lex.next());
+ // kept for backwards compability. Delete in 0.13.x
+ } else if (token == "subcaption") {
+ if (lex.eatLine())
+ params.subcaptionText = lex.getString();
+ } else if (token == "label") {
+ if (lex.next());
+ // kept for backwards compability. Delete in 0.13.x
+ } else if (token == "angle") {
+ if (lex.next())
+ params.rotateAngle = lex.getFloat();
+ } else if (token == "size") {
+ // Size of image on screen is ignored in InsetGraphics, just eat
+ // the input.
+ if (lex.next()) {
+ lex.getInteger();
+ }
+ if (lex.next()) {
+ lex.getInteger();
+ }
+ } else if (token == "flags") {
+ InsetGraphicsParams::DisplayType tmp = InsetGraphicsParams::COLOR;
+ if (lex.next())
+ switch (lex.getInteger()) {
+ case 1: tmp = InsetGraphicsParams::MONOCHROME; break;
+ case 2: tmp = InsetGraphicsParams::GRAYSCALE; break;
+ }
+ params.display = tmp;
+ } else if (token == "subfigure") {
+ params.subcaption = true;
+ } else if (token == "width") {
+ if (lex.next()) {
+ params.widthResize = static_cast<InsetGraphicsParams::Resize>(lex.getInteger());
+ }
+ if (lex.next()) {
+ params.widthSize = lex.getFloat();
+ }
+ } else if (token == "height") {
+ if (lex.next()) {
+ params.heightResize = static_cast<InsetGraphicsParams::Resize>(lex.getInteger());
+ }
+ if (lex.next()) {
+ params.heightSize = lex.getFloat();
+ }
+ }
+ }
}
os << key << '=' << size / 100 << "\\column" << key << ',';
break;
+ case InsetGraphicsParams::SCALE:
+ os << "scale" << '=' << size/100 << ',';
}
}
formatResize(options, "width", params.widthResize, params.widthSize);
formatResize(options, "height", params.heightResize, params.heightSize);
- if (params.rotateAngle != 0) {
+ // Make sure it's not very close to zero, a float can be effectively
+ // zero but not exactly zero.
+ if (lyx::float_equal(params.rotateAngle, 0, 0.001)) {
options << "angle="
<< params.rotateAngle << ',';
}
return opts;
}
+namespace {
+
+enum FileType {
+ EPS,
+ PNG,
+ JPEG,
+ GIF,
+ PDF,
+ UNKNOWN
+};
+
+bool isEPS(string const & filename)
+{
+ if (filename.empty() || !IsFileReadable(filename)) return false;
+
+ ifstream ifs(filename.c_str());
+
+ if (!ifs) return false; // Couldn't open file...
+
+ bool is_eps = false; // Have we recognized the file as EPS?
+ string to_find = "%!PS-Adobe-"; // The string we use to recognize
+ int const max_attempts = 500; // Maximum strings to read to attempt recognition
+ int count = 0; // Counter of attempts.
+ string str;
+ for (; count < max_attempts; ++count) {
+ if (ifs.eof()) {
+ lyxerr[Debug::INFO] << "InsetGraphics (isEPS)"
+ " End of file reached and it wasn't found to be EPS!" << endl;
+ break;
+ }
+
+ ifs >> str;
+ if (str.find(to_find)) {
+ is_eps = true;
+ break;
+ }
+ }
+
+ return is_eps;
+}
+
+enum FileType classifyFileType(string const & filename, string const & suffix)
+{
+ if (suffix == "png")
+ return PNG;
+ else if (suffix == "jpg" || suffix == "jpeg")
+ return JPEG;
+ else if (suffix == "gif")
+ return GIF;
+ else if (suffix == "pdf")
+ return PDF;
+ else if (isEPS(filename))
+ return EPS;
+
+ return UNKNOWN;
+}
+
+string decideOutputImageFormat(string const & suffix, enum FileType type)
+{
+ // lyxrc.pdf_mode means:
+ // Are we creating a PDF or a PS file?
+ // (Should actually mean, are we using latex or pdflatex).
+
+ if (lyxrc.pdf_mode) {
+ if (type == EPS || type == EPS || type == PDF)
+ return "pdf";
+ else if (type == JPEG)
+ return suffix;
+ else
+ return "png";
+ }
+
+ // If it's postscript, we always do eps.
+ // There are many suffixes that are actually EPS (ask Garst for example)
+ // so we detect if it's an EPS by looking in the file, if it is, we return
+ // the same suffix of the file so it won't be converted.
+ if (type == EPS)
+ return suffix;
+
+ return "eps";
+}
+
+} // Anon. namespace
string const
InsetGraphics::prepareFile(Buffer const *buf) const
// Get the extension (format) of the original file.
string const extension = GetExtension(params.filename);
+ FileType type = classifyFileType(params.filename, extension);
// Are we creating a PDF or a PS file?
// (Should actually mean, are we usind latex or pdflatex).
- string const image_target = (lyxrc.pdf_mode ? "png" : "eps");
+ string const image_target = decideOutputImageFormat(extension, type);
if (extension == image_target)
return params.filename;
outfile = RemoveExtension(relname);
}
- converters.Convert(buf, params.filename, outfile, extension, image_target);
+ converters.convert(buf, params.filename, outfile, extension, image_target);
return outfile;
}
string before;
string after;
- // If it's not an inline image, surround it with the centering paragraph.
- if (! params.inlineFigure) {
- before += "\n" "\\vspace{0.3cm}\n" "{\\par\\centering ";
- after = " \\par}\n" "\\vspace{0.3cm}\n" + after;
- newlines += 4;
- }
-
// Do we want subcaptions?
if (params.subcaption) {
before += "\\subfigure[" + params.subcaptionText + "]{";
// For explanation on inserting graphics into DocBook checkout:
// http://linuxdoc.org/LDP/LDP-Author-Guide/inserting-pictures.html
// See also the docbook guide at http://www.docbook.org/
-int InsetGraphics::docBook(Buffer const * buf, ostream & os) const
+int InsetGraphics::docbook(Buffer const * buf, ostream & os) const
{
// Change the path to be relative to the main file.
string const buffer_dir = OnlyPath(buf->fileName());
if (params.filename.empty())
return ;
- features.graphicx = true;
+ features.require("graphicx");
if (params.subcaption)
- features.subfigure = true;
+ features.require("subfigure");
}
// We do it this way so that in the face of some error, we will still
// be in a valid state.
- if (!params.filename.empty()) {
+ if (!params.filename.empty() &&
+ lyxrc.display_graphics != "no" &&
+ params.display != InsetGraphicsParams::NONE) {
temp = gc.addFile(params.filename);
}