Hi!

Here is the polished version of the snippet conversion patch.
Changes to last version:

* no directories are created by accident
* creates bitmaps for more than one graphic format (currently PNG+EPS)
* create DocBook hooks for PNG, EPS, PDF and BMP graphics like in InsetGraphics
* refactored insetGraphics::toDocbookLength() and writeImageObject() to
output_docbook.[hC]
* create additional anchors for math equation labels (this is not directly related to
math bitmaps but I couldn't resist. Prevents "Undefined IDREF" errors in exported
DocBook documents)


The complete Changelog entries are at the beginning of the patch.

Ciao
/Andreas

PS: Lars has been quiet about this patch, no? :-)


The Changelog for src/graphics:

2005-02-17  Andreas Vox  <[EMAIL PROTECTED]>

        * Makefile.am: new files SnippetConverion.[hC]

        * SnippetConversion.[hC]: new files containing refactored code from 
PreviewLoader

        * PreviewLoader.[hC] (setConverter): renamed to defaultConverter and 
moved
                             (dumpPreamble,dumpData,setAscentFraction): also 
moved
                             (InProgress): replaced by SnippetConversion



The Changelog for src/insets:

2005-02-17  Andreas Vox  <[EMAIL PROTECTED]>

        * insetgraphics.C (toDocbookLength, writeImageObject): moved to
        output_docbook.[hC]


The Changelog for src/mathed:

2005-02-17  Andreas Vox  <[EMAIL PROTECTED]>

        * math_hullinset.C (docbook): removed workaround for db2latex, this 
        has to be fixed in db2latex

        * math_hullinset.C (docbook): changed the filenames of bitmaps 
        from "eqn/xyz"  to  buffer.filename() + "_math/xyz"

        * math_hullinset.C (docbook): add the mathbitmaps to exportData

        * math_hullinset.C (registerExternalFile,registerExternalDirectory)
        new helper functions

        * math_hullinset.C (docbook): generate anchors for additional labels


The Changelog for src/:

2005-02-17  Andreas Vox  <[EMAIL PROTECTED]>

        * exporter.[hC] (ExportedFile::isDirectory): new bool member

        * exporter.[hC] (ExportData::addExternalDirectory): new function

        * exporter.[hC] (ExportData::bitmaps_):  a map which gives a pointer 
        to a SnippetConversion for each graphic format

        * exporter.C (Exporter::Export): handle exported directories

        * buffer.C (makeDocBookFile, createBitmaps): create a SnippetConversion
        object for PNG / EPS each and associate it with exportData

        * output_docbook.[hC] (toDocbookLength, docbookImageObject) moved to
        this place from insetgraphics.C



PATCH PROPER:

Index: src/buffer.C
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/buffer.C,v
retrieving revision 1.612
diff -u -p -r1.612 buffer.C
--- src/buffer.C        2005/02/08 13:17:57     1.612
+++ src/buffer.C        2005/02/26 00:30:17
@@ -62,6 +62,7 @@
 #include "frontends/Alert.h"
 
 #include "graphics/Previews.h"
+#include "graphics/SnippetConversion.h"
 
 #include "support/filetools.h"
 #include "support/fs_extras.h"
@@ -113,6 +114,8 @@ using lyx::support::subst;
 using lyx::support::tempName;
 using lyx::support::trim;
 
+using lyx::graphics::SnippetConversion;
+
 namespace os = lyx::support::os;
 namespace fs = boost::filesystem;
 
@@ -1021,6 +1024,56 @@ void Buffer::makeLinuxDocFile(string con
                lyxerr << "File '" << fname << "' was not closed properly." << 
endl;
 }
 
+namespace {
+void createBitmaps(Buffer const & buffer, OutputParams const & runparams) 
+{
+       string const from = "lyxpreview";
+       string const to_1   = "png";
+       string const to_2   = "eps";
+       string const fore = "000000";
+       string const back = "FFFFFF";
+       double const scale = 100;
+       
+       Converter const * converter_1 = converters.getConverter(from, to_1);
+       Converter const * converter_2 = converters.getConverter(from, to_2);
+       
+       if (!converter_1 && !converter_2) {
+               lyxerr << "couldn't find converter from " << from 
+                       << " to " << to_1 << " or " << to_2 << endl;
+               return;
+       }
+       
+       string const & filename_base = buffer.temppath() + "/eqn";
+
+       SnippetConversion::SnippetList snippets;
+       
+       InsetBase & inset = buffer.inset();
+       InsetIterator it = inset_iterator_begin(inset);
+       InsetIterator const end = inset_iterator_end(inset);
+
+       for (; it != end; ++it)
+               if (it->lyxCode() == InsetBase::MATH_CODE)
+               {
+                       ostringstream cs;
+                       it->latex(buffer, cs, runparams);
+                       snippets.push_back(cs.str());
+               }
+       
+       SnippetConversion * snipp;
+       
+       if (converter_1) {
+               snipp = new SnippetConversion(filename_base, converter_1, 
snippets);
+               snipp->startAndWait(buffer, fore, back, scale);
+               runparams.exportdata->addBitmaps(to_1, snipp);
+       }
+
+       if (converter_2) {
+               snipp = new SnippetConversion(filename_base, converter_2, 
snippets);
+               snipp->startAndWait(buffer, fore, back, scale);
+               runparams.exportdata->addBitmaps(to_2, snipp);
+       }
+}
+} // namespace
 
 void Buffer::makeDocBookFile(string const & fname,
                             OutputParams const & runparams,
@@ -1034,6 +1087,8 @@ void Buffer::makeDocBookFile(string cons
        validate(features);
 
        texrow().reset();
+
+       createBitmaps(*this, runparams);
 
        LyXTextClass const & tclass = params().getLyXTextClass();
        string const & top_element = tclass.latexname();
Index: src/exporter.C
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/exporter.C,v
retrieving revision 1.58
diff -u -p -r1.58 exporter.C
--- src/exporter.C      2005/01/31 10:42:18     1.58
+++ src/exporter.C      2005/02/26 00:30:18
@@ -30,7 +30,10 @@
 #include "outputparams.h"
 #include "frontends/Alert.h"
 
+#include "graphics/SnippetConversion.h"
+
 #include "support/filetools.h"
+#include "support/lstrings.h"
 #include "support/lyxlib.h"
 #include "support/package.h"
 
@@ -44,8 +47,11 @@ using lyx::support::MakeAbsPath;
 using lyx::support::MakeDisplayPath;
 using lyx::support::OnlyFilename;
 using lyx::support::OnlyPath;
+using lyx::support::IsDirWriteable;
+using lyx::support::createDirectory;
 using lyx::support::package;
 using lyx::support::prefixIs;
+using lyx::support::subst;
 
 using std::find;
 using std::string;
@@ -70,7 +76,7 @@ int checkOverwrite(string const & filena
 {
        if (fs::exists(filename)) {
                string text = bformat(_("The file %1$s already exists.\n\n"
-                                       "Do you want to over-write that file?"),
+                                     "Do you want to over-write that file?"),
                                      MakeDisplayPath(filename));
                return Alert::prompt(_("Over-write file?"),
                                     text, 0, 2,
@@ -136,7 +142,7 @@ CopyStatus copyFile(string const & forma
 
 
 bool Exporter::Export(Buffer * buffer, string const & format,
-                     bool put_in_tempdir, string & result_file)
+                      bool put_in_tempdir, string & result_file)
 {
        string backend_format;
        OutputParams runparams;
@@ -185,9 +191,9 @@ bool Exporter::Export(Buffer * buffer, s
        else if (backend_format == format) {
                runparams.nice = true;
                buffer->makeLaTeXFile(filename, string(), runparams);
-       } else if (contains(buffer->filePath(), ' ')) {
+       } else if (false && contains(buffer->filePath(), ' ')) {
                Alert::error(_("File name error"),
-                          _("The directory path to the document cannot contain 
spaces."));
+                            _("The directory path to the document cannot 
contain spaces."));
                return false;
        } else {
                runparams.nice = false;
@@ -195,7 +201,7 @@ bool Exporter::Export(Buffer * buffer, s
        }
 
        if (!converters.convert(buffer, filename, filename,
-                               backend_format, format, result_file))
+                               backend_format, format, result_file))
                return false;
 
        if (!put_in_tempdir) {
@@ -208,13 +214,32 @@ bool Exporter::Export(Buffer * buffer, s
                        runparams.exportdata->externalFiles(format);
                string const dest = OnlyPath(result_file);
                CopyStatus status = SUCCESS;
+               // first pass: create directories if needed
+               for (vector<ExportedFile>::const_iterator it = files.begin();
+                               it != files.end() && status != CANCEL; ++it) {
+                       if (it->isDirectory) {
+                               string const path = MakeAbsPath(it->exportName, 
dest);
+                               if (IsDirWriteable(path)) {
+                                       // ok, reuse that
+                               }
+                               else if (!createDirectory(path,0777)) {
+                                       Alert::error(_("Directory not 
writeable"),
+                                                    bformat(_("Copying to 
directory %1$s failed."),
+                                                    MakeDisplayPath(path)));
+                                       status = CANCEL;
+                               }
+                       }
+               }
+               // second pass: copy files
                for (vector<ExportedFile>::const_iterator it = files.begin();
                                it != files.end() && status != CANCEL; ++it) {
-                       string const fmt =
-                               formats.getFormatFromFile(it->sourceName);
-                       status = copyFile(fmt, it->sourceName,
-                                         MakeAbsPath(it->exportName, dest),
-                                         it->exportName, status == FORCE);
+                       if (!(it->isDirectory)) {
+                               string const path = MakeAbsPath(it->exportName, 
dest);
+                               string const fmt =
+                                       
formats.getFormatFromFile(it->sourceName);
+                               status = copyFile(fmt, it->sourceName, path,
+                                                 it->exportName, status == 
FORCE);
+                       }
                }
                if (status == CANCEL) {
                        buffer->message(_("Document export cancelled."));
@@ -279,13 +304,14 @@ Exporter::GetExportableFormats(Buffer co
 
 
 ExportedFile::ExportedFile(string const & s, string const & e) :
-       sourceName(s), exportName(e) {}
+       sourceName(s), exportName(e), isDirectory(false) {}
 
 
 bool operator==(ExportedFile const & f1, ExportedFile const & f2)
 {
        return f1.sourceName == f2.sourceName &&
-              f1.exportName == f2.exportName;
+              f1.exportName == f2.exportName && 
+              f1.isDirectory == f2.isDirectory;
 
 }
 
@@ -304,6 +330,18 @@ void ExportData::addExternalFile(string 
                files.push_back(file);
 }
 
+void ExportData::addExternalDirectory(string const & format,
+                                string const & exportName)
+{
+       // Make sure that we have every file only once, otherwise copyFile()
+       // would ask several times if it should overwrite a file.
+       vector<ExportedFile> & files = externalfiles[format];
+       ExportedFile dir("", exportName);
+       dir.isDirectory = true;
+       if (find(files.begin(), files.end(), dir) == files.end())
+               files.push_back(dir);
+}
+
 
 void ExportData::addExternalFile(string const & format,
                                 string const & sourceName)
@@ -319,4 +357,18 @@ ExportData::externalFiles(string const &
        if (cit != externalfiles.end())
                return cit->second;
        return vector<ExportedFile>();
+}
+
+
+void ExportData::addBitmaps(string const & gr_format, 
lyx::graphics::SnippetConversion * bitmaps) 
+{ 
+       bitmaps_[gr_format] = bitmaps; 
+}
+
+lyx::graphics::SnippetConversion * ExportData::bitmaps(string const & 
gr_format) const 
+{ 
+       SnippetConversionMap::const_iterator cit = bitmaps_.find(gr_format);
+       if (cit != bitmaps_.end()) 
+               return cit->second;
+       return 0; 
 }
Index: src/exporter.h
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/exporter.h,v
retrieving revision 1.22
diff -u -p -r1.22 exporter.h
--- src/exporter.h      2005/01/19 15:03:29     1.22
+++ src/exporter.h      2005/02/26 00:30:18
@@ -17,10 +17,12 @@
 #include <string>
 #include <vector>
 
+#include "graphics/SnippetConversion.h"
 
 class Buffer;
 class Format;
 
+
 class Exporter {
 public:
        ///
@@ -53,6 +55,7 @@ public:
        /// final name that the exported file should get (absolute name or
        /// relative to the directory of the master document)
        std::string exportName;
+       bool isDirectory;
 };
 
 
@@ -82,15 +85,31 @@ public:
         */
        void addExternalFile(std::string const & format,
                             std::string const & sourceName);
+       /** add a referenced directory for one format.
+        * \param format     format that references the given directory
+        * \param exportName resulting directory name. Can be either absolute
+        *                   or relative to the exported document.
+        */
+       void addExternalDirectory(std::string const & format,
+                                 std::string const & exportName);
        /// get referenced files for \p format
        std::vector<ExportedFile> const
        externalFiles(std::string const & format) const;
+       /// add a list of bitmap file with format gr_format
+       void addBitmaps(std::string const & gr_format, 
lyx::graphics::SnippetConversion * bitmaps);
+       /// get the bitmaps for this graphics format
+       lyx::graphics::SnippetConversion * bitmaps(std::string const & 
gr_format) const;
 private:
        typedef std::map<std::string, std::vector<ExportedFile> > FileMap;
        /** Files that are referenced by the export result in the
         *  different formats.
         */
        FileMap externalfiles;
+
+       typedef std::map<std::string, lyx::graphics::SnippetConversion * > 
+               SnippetConversionMap;
+       /** Snippets which are used to generate bitmaps for equations etc. */
+        SnippetConversionMap bitmaps_;
 };
 
 #endif
Index: src/output_docbook.C
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/output_docbook.C,v
retrieving revision 1.28
diff -u -p -r1.28 output_docbook.C
--- src/output_docbook.C        2005/02/25 11:55:32     1.28
+++ src/output_docbook.C        2005/02/26 00:30:19
@@ -18,6 +18,8 @@
 #include "bufferparams.h"
 #include "counters.h"
 #include "debug.h"
+#include "lyxtext.h"
+#include "outputparams.h"
 #include "paragraph.h"
 #include "paragraph_funcs.h"
 #include "ParagraphList_fwd.h"
@@ -31,6 +33,8 @@
 #include "support/convert.h"
 #include "support/types.h"
 
+#include <sstream>
+
 #ifdef HAVE_LOCALE
 #endif
 
@@ -308,4 +313,93 @@ void docbookParagraphs(ParagraphList con
                        break;
                }
        }
+}
+
+
+int docbookImageObject(char * format, string const filename, string const 
attributes,
+                       ostream & os, OutputParams const & runparams, bool 
graphictag = false)
+{
+               if (runparams.flavor != OutputParams::XML) {
+                       os << "<![ %output.print." << format << "; [" << 
std::endl;
+               }
+               
+               if (graphictag)
+                       os << "<graphic";
+               else
+                       os <<"<imageobject><imagedata";
+                       
+               os << " fileref=\"" << filename << "." << format << "\" " << 
attributes ;
+               if (runparams.flavor == OutputParams::XML) {
+                       os <<  " role=\"" << format << "\"/>" ;
+               }
+               else {
+                       os << " format=\"" << format << "\">" ;
+               }
+               
+               if (! graphictag)
+                       os << "</imageobject>";
+                       
+               if (runparams.flavor != OutputParams::XML) {
+                       os << std::endl << "]]>" ;
+               }
+               return runparams.flavor == OutputParams::XML ? 0 : 2;
+}
+
+
+
+string const toDocbookLength(LyXLength const & len)
+{
+       std::ostringstream result;
+       switch (len.unit()) {
+               case LyXLength::SP: // Scaled point (65536sp = 1pt) TeX's 
smallest unit.
+                       result << len.value() * 65536.0 * 72 / 72.27 << "pt";
+                       break;
+               case LyXLength::PT: // Point = 1/72.27in = 0.351mm
+                       result << len.value() * 72 / 72.27 << "pt";
+                       break;
+               case LyXLength::BP: // Big point (72bp = 1in), also PostScript 
point
+                       result << len.value() << "pt";
+                       break;
+               case LyXLength::DD: // Didot point = 1/72 of a French inch, = 
0.376mm
+                       result << len.value() * 0.376 << "mm";
+                       break;
+               case LyXLength::MM: // Millimeter = 2.845pt
+                       result << len.value() << "mm";
+                       break;
+               case LyXLength::PC: // Pica = 12pt = 4.218mm
+                       result << len.value() << "pc";
+                       break;
+               case LyXLength::CC: // Cicero = 12dd = 4.531mm
+                       result << len.value() * 4.531 << "mm";
+                       break;
+               case LyXLength::CM: // Centimeter = 10mm = 2.371pc
+                       result << len.value() << "cm";
+                       break;
+               case LyXLength::IN: // Inch = 25.4mm = 72.27pt = 6.022pc
+                       result << len.value() << "in";
+                       break;
+               case LyXLength::EX: // Height of a small "x" for the current 
font.
+                       // Obviously we have to compromise here. Any better 
ratio than 1.5 ?
+                       result << len.value() / 1.5 << "em";
+                       break;
+               case LyXLength::EM: // Width of capital "M" in current font.
+                       result << len.value() << "em";
+                       break;
+               case LyXLength::MU: // Math unit (18mu = 1em) for positioning 
in math mode
+                       result << len.value() * 18 << "em";
+                       break;
+               case LyXLength::PTW: // Percent of TextWidth
+               case LyXLength::PCW: // Percent of ColumnWidth
+               case LyXLength::PPW: // Percent of PageWidth
+               case LyXLength::PLW: // Percent of LineWidth
+               case LyXLength::PTH: // Percent of TextHeight
+               case LyXLength::PPH: // Percent of Paper
+                       // Sigh, this will go wrong.
+                       result << len.value() << "%";
+                       break;
+               default:
+                       result << len.asString();
+                       break;
+       }
+       return result.str();
 }
Index: src/output_docbook.h
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/output_docbook.h,v
retrieving revision 1.4
diff -u -p -r1.4 output_docbook.h
--- src/output_docbook.h        2004/10/24 00:02:38     1.4
+++ src/output_docbook.h        2005/02/26 00:30:19
@@ -13,6 +13,8 @@
 #ifndef OUTPUT_DOCBOOK_H
 #define OUTPUT_DOCBOOK_H
 
+#include "lyxlength.h"
+
 #include <iosfwd>
 
 class Buffer;
@@ -24,4 +26,17 @@ void docbookParagraphs(ParagraphList con
                       Buffer const & buf,
                       std::ostream & os,
                       OutputParams const & runparams);
+/** Write an <IMAGEOBJECT> or <GRAPHIC> element to os. Uses parameter entities 
to 
+ *  control the format.
+ *  If graphictag is true, an <GRAPHIC> element is written.
+ */
+int docbookImageObject(char * format, 
+                       std::string const filename, 
+                       std::string const attributes,
+                       std::ostream & os, 
+                       OutputParams const & runparams,
+                       bool graphictag = false);
+/// Create length values for docbook export.
+std::string const toDocbookLength(LyXLength const & len);
+
 #endif
Index: src/graphics/Makefile.am
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/graphics/Makefile.am,v
retrieving revision 1.32
diff -u -p -r1.32 Makefile.am
--- src/graphics/Makefile.am    2004/12/04 14:50:24     1.32
+++ src/graphics/Makefile.am    2005/02/26 00:30:24
@@ -5,6 +5,8 @@ noinst_LTLIBRARIES = libgraphics.la
 AM_CPPFLAGS = $(PCH_FLAGS) -I$(srcdir)/.. $(BOOST_INCLUDES)
 
 libgraphics_la_SOURCES = \
+       SnippetConversion.h \
+       SnippetConversion.C \
        GraphicsCache.h \
        GraphicsCache.C \
        GraphicsCacheItem.h \
Index: src/graphics/PreviewLoader.C
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/graphics/PreviewLoader.C,v
retrieving revision 1.86
diff -u -p -r1.86 PreviewLoader.C
--- src/graphics/PreviewLoader.C        2005/01/27 21:05:38     1.86
+++ src/graphics/PreviewLoader.C        2005/02/26 00:30:24
@@ -10,27 +10,22 @@
 
 #include <config.h>
 
+#include "GraphicsCache.h"
+#include "SnippetConversion.h"
 #include "PreviewLoader.h"
 #include "PreviewImage.h"
-#include "GraphicsCache.h"
 
 #include "buffer.h"
 #include "converter.h"
 #include "debug.h"
 #include "format.h"
-#include "insetiterator.h"
 #include "LColor.h"
 #include "lyxrc.h"
 #include "outputparams.h"
-#include "paragraph.h"
 
 #include "frontends/lyx_gui.h" // hexname
 
-#include "insets/inset.h"
-
 #include "support/filetools.h"
-#include "support/forkedcall.h"
-#include "support/forkedcontr.h"
 #include "support/lstrings.h"
 #include "support/lyxlib.h"
 #include "support/convert.h"
@@ -61,59 +56,17 @@ using std::pair;
 using std::vector;
 using std::string;
 
-
 namespace {
 
-typedef pair<string, string> StrPair;
+typedef lyx::graphics::SnippetConversion::SnippetList SnippetList;
 
-// A list of alll snippets to be converted to previews
-typedef list<string> PendingSnippets;
 
-// Each item in the vector is a pair<snippet, image file name>.
-typedef vector<StrPair> BitmapFile;
-
 string const unique_filename(string const bufferpath);
 
 Converter const * setConverter();
 
-void setAscentFractions(vector<double> & ascent_fractions,
-                       string const & metrics_file);
-
-class FindFirst : public std::unary_function<StrPair, bool> {
-public:
-       FindFirst(string const & comp) : comp_(comp) {}
-       bool operator()(StrPair const & sp) const
-       {
-               return sp.first == comp_;
-       }
-private:
-       string const comp_;
-};
-
-
-/// Store info on a currently executing, forked process.
-class InProgress {
-public:
-       ///
-       InProgress() : pid(0) {}
-       ///
-       InProgress(string const & filename_base,
-                  PendingSnippets const & pending,
-                  string const & to_format);
-       /// Remove any files left lying around and kill the forked process.
-       void stop() const;
-
-       ///
-       pid_t pid;
-       ///
-       string command;
-       ///
-       string metrics_file;
-       ///
-       BitmapFile snippets;
-};
 
-typedef map<pid_t, InProgress>  InProgressProcesses;
+typedef map<pid_t, lyx::graphics::SnippetConversion>  InProgressProcesses;
 
 typedef InProgressProcesses::value_type InProgressProcess;
 
@@ -127,7 +80,7 @@ class PreviewLoader::Impl : public boost
 public:
        ///
        Impl(PreviewLoader & p, Buffer const & b);
-       /// Stop any InProgress items still executing.
+       /// Stop any SnippetConversion items still executing.
        ~Impl();
        ///
        PreviewImage const * preview(string const & latex_snippet) const;
@@ -148,10 +101,6 @@ public:
 private:
        /// Called by the Forkedcall process that generated the bitmap files.
        void finishedGenerating(pid_t, int);
-       ///
-       void dumpPreamble(ostream &) const;
-       ///
-       void dumpData(ostream &, BitmapFile const &) const;
 
        /** cache_ allows easy retrieval of already-generated images
         *  using the LaTeX snippet as the identifier.
@@ -165,7 +114,7 @@ private:
        /** pending_ stores the LaTeX snippets in anticipation of them being
         *  sent to the converter.
         */
-       PendingSnippets pending_;
+       SnippetList pending_;
 
        /** in_progress_ stores all forked processes so that we can proceed
         *  thereafter.
@@ -253,66 +202,7 @@ Buffer const & PreviewLoader::buffer() c
 // The details of the Impl
 // =======================
 
-namespace {
 
-class IncrementedFileName {
-public:
-       IncrementedFileName(string const & to_format,
-                           string const & filename_base)
-               : to_format_(to_format), base_(filename_base), counter_(1)
-       {}
-
-       StrPair const operator()(string const & snippet)
-       {
-               ostringstream os;
-               os << base_ << counter_++ << '.' << to_format_;
-               string const file = os.str();
-
-               return make_pair(snippet, file);
-       }
-
-private:
-       string const & to_format_;
-       string const & base_;
-       int counter_;
-};
-
-
-InProgress::InProgress(string const & filename_base,
-                      PendingSnippets const & pending,
-                      string const & to_format)
-       : pid(0),
-         metrics_file(filename_base + ".metrics"),
-         snippets(pending.size())
-{
-       PendingSnippets::const_iterator pit  = pending.begin();
-       PendingSnippets::const_iterator pend = pending.end();
-       BitmapFile::iterator sit = snippets.begin();
-
-       std::transform(pit, pend, sit,
-                      IncrementedFileName(to_format, filename_base));
-}
-
-
-void InProgress::stop() const
-{
-       if (pid)
-               support::ForkedcallsController::get().kill(pid, 0);
-
-       if (!metrics_file.empty())
-               support::unlink(metrics_file);
-
-       BitmapFile::const_iterator vit  = snippets.begin();
-       BitmapFile::const_iterator vend = snippets.end();
-       for (; vit != vend; ++vit) {
-               if (!vit->second.empty())
-                       support::unlink(vit->second);
-       }
-}
-
-} // namespace anon
-
-
 namespace lyx {
 namespace graphics {
 
@@ -326,7 +216,7 @@ PreviewLoader::Impl::Impl(PreviewLoader 
                                << font_scaling_factor_ << endl;
 
        if (!pconverter_)
-               pconverter_ = setConverter();
+               pconverter_ = defaultConverter();
 }
 
 
@@ -351,15 +241,15 @@ PreviewLoader::Impl::preview(string cons
 
 namespace {
 
+typedef SnippetConversion::SnippetList SnippetList;
+
+
 class FindSnippet : public std::unary_function<InProgressProcess, bool> {
 public:
        FindSnippet(string const & s) : snippet_(s) {}
        bool operator()(InProgressProcess const & process) const
        {
-               BitmapFile const & snippets = process.second.snippets;
-               BitmapFile::const_iterator beg  = snippets.begin();
-               BitmapFile::const_iterator end = snippets.end();
-               return find_if(beg, end, FindFirst(snippet_)) != end;
+               return ! (process.second.findSnippet(snippet_).empty());
        }
 
 private:
@@ -375,8 +265,8 @@ PreviewLoader::Impl::status(string const
        if (cit != cache_.end())
                return Ready;
 
-       PendingSnippets::const_iterator pit  = pending_.begin();
-       PendingSnippets::const_iterator pend = pending_.end();
+       SnippetList::const_iterator pit  = pending_.begin();
+       SnippetList::const_iterator pend = pending_.end();
 
        pit = find(pit, pend, latex_snippet);
        if (pit != pend)
@@ -415,13 +305,7 @@ public:
        EraseSnippet(string const & s) : snippet_(s) {}
        void operator()(InProgressProcess & process)
        {
-               BitmapFile & snippets = process.second.snippets;
-               BitmapFile::iterator it  = snippets.begin();
-               BitmapFile::iterator end = snippets.end();
-
-               it = find_if(it, end, FindFirst(snippet_));
-               if (it != end)
-                       snippets.erase(it, it+1);
+               process.second.eraseSnippet(snippet_);
        }
 
 private:
@@ -437,8 +321,8 @@ void PreviewLoader::Impl::remove(string 
        if (cit != cache_.end())
                cache_.erase(cit);
 
-       PendingSnippets::iterator pit  = pending_.begin();
-       PendingSnippets::iterator pend = pending_.end();
+       SnippetList::iterator pit  = pending_.begin();
+       SnippetList::iterator pend = pending_.end();
 
        pending_.erase(std::remove(pit, pend, latex_snippet), pend);
 
@@ -449,7 +333,7 @@ void PreviewLoader::Impl::remove(string 
 
        while (ipit != ipend) {
                InProgressProcesses::iterator curr = ipit++;
-               if (curr->second.snippets.empty())
+               if (curr->second.empty())
                        in_progress_.erase(curr);
        }
 }
@@ -471,58 +355,23 @@ void PreviewLoader::Impl::startLoading()
 
        string const filename_base(unique_filename(directory));
 
-       // Create an InProgress instance to place in the map of all
+       // Create an SnippetConversion instance to place in the map of all
        // such processes if it starts correctly.
-       InProgress inprogress(filename_base, pending_, pconverter_->to);
+       SnippetConversion inprogress(filename_base, pconverter_, pending_);
 
        // clear pending_, so we're ready to start afresh.
        pending_.clear();
 
-       // Output the LaTeX file.
-       string const latexfile = filename_base + ".tex";
-
-       ofstream of(latexfile.c_str());
-       if (!of) {
-               lyxerr[Debug::GRAPHICS] << "PreviewLoader::startLoading()\n"
-                                       << "Unable to create LaTeX file\n"
-                                       << latexfile << endl;
-               return;
-       }
-       of << "\\batchmode\n";
-       dumpPreamble(of);
-       of << "\n\\begin{document}\n";
-       dumpData(of, inprogress.snippets);
-       of << "\n\\end{document}\n";
-       of.close();
-
-       // The conversion command.
-       ostringstream cs;
-       cs << pconverter_->command << ' ' << pconverter_->to << ' '
-          << latexfile << ' ' << int(font_scaling_factor_) << ' '
-          << lyx_gui::hexname(LColor::preview) << ' '
-          << lyx_gui::hexname(LColor::background);
-
-       string const command = support::LibScriptSearch(cs.str());
-
        // Initiate the conversion from LaTeX to bitmap images files.
-       support::Forkedcall::SignalTypePtr
-               convert_ptr(new support::Forkedcall::SignalType);
+       support::Forkedcall::SignalTypePtr convert_ptr(new 
support::Forkedcall::SignalType);
        convert_ptr->connect(bind(&Impl::finishedGenerating, this, _1, _2));
 
-       support::Forkedcall call;
-       int ret = call.startscript(command, convert_ptr);
-
-       if (ret != 0) {
-               lyxerr[Debug::GRAPHICS] << "PreviewLoader::startLoading()\n"
-                                       << "Unable to start process\n"
-                                       << command << endl;
-               return;
-       }
-
        // Store the generation process in a list of all such processes
-       inprogress.pid = call.pid();
-       inprogress.command = command;
-       in_progress_[inprogress.pid] = inprogress;
+       inprogress.start(buffer_, 
+                        lyx_gui::hexname(LColor::preview),
+                        lyx_gui::hexname(LColor::background),
+                        font_scaling_factor_, convert_ptr);
+       in_progress_[inprogress.pid()] = inprogress;
 }
 
 
@@ -536,7 +385,7 @@ void PreviewLoader::Impl::finishedGenera
                return;
        }
 
-       string const command = git->second.command;
+       string const command = git->second.command();
        string const status = retval > 0 ? "failed" : "succeeded";
        lyxerr[Debug::GRAPHICS] << "PreviewLoader::finishedInProgress("
                                << retval << "): processing " << status
@@ -545,21 +394,19 @@ void PreviewLoader::Impl::finishedGenera
                return;
 
        // Read the metrics file, if it exists
-       vector<double> ascent_fractions(git->second.snippets.size());
-       setAscentFractions(ascent_fractions, git->second.metrics_file);
+       git->second.setAscentFractions();
+
+       std::list<PreviewImagePtr> newimages;
 
        // Add these newly generated bitmap files to the cache and
        // start loading them into LyX.
-       BitmapFile::const_iterator it  = git->second.snippets.begin();
-       BitmapFile::const_iterator end = git->second.snippets.end();
+       vector<SnippetConversion::Entry>::const_iterator it  = 
git->second.begin();
+       vector<SnippetConversion::Entry>::const_iterator end = 
git->second.end();
 
-       std::list<PreviewImagePtr> newimages;
-
-       int metrics_counter = 0;
-       for (; it != end; ++it, ++metrics_counter) {
-               string const & snip = it->first;
-               string const & file = it->second;
-               double af = ascent_fractions[metrics_counter];
+       for (; it != end; ++it) {
+               string const & snip = it->latex;
+               string const & file = it->filename;
+               double af = it->ascentfraction;
 
                PreviewImagePtr ptr(new PreviewImage(parent_, snip, file, af));
                cache_[snip] = ptr;
@@ -580,84 +427,8 @@ void PreviewLoader::Impl::finishedGenera
        }
 }
 
-
-void PreviewLoader::Impl::dumpPreamble(ostream & os) const
-{
-       // Why on earth is Buffer::makeLaTeXFile a non-const method?
-       Buffer & tmp = const_cast<Buffer &>(buffer_);
-       // Dump the preamble only.
-       OutputParams runparams;
-       runparams.flavor = OutputParams::LATEX;
-       runparams.nice = true;
-       runparams.moving_arg = true;
-       runparams.free_spacing = true;
-       tmp.makeLaTeXFile(os, buffer_.filePath(), runparams, true, false);
-
-       // FIXME! This is a HACK! The proper fix is to control the 'true'
-       // passed to WriteStream below:
-       // int InsetFormula::latex(Buffer const &, ostream & os,
-       //                         OutputParams const & runparams) const
-       // {
-       //      WriteStream wi(os, runparams.moving_arg, true);
-       //      par_->write(wi);
-       //      return wi.line();
-       // }
-       os << "\n"
-          << "\\def\\lyxlock{}\n"
-          << "\n";
-
-       // Loop over the insets in the buffer and dump all the math-macros.
-       InsetBase & inset = buffer_.inset();
-       InsetIterator it = inset_iterator_begin(inset);
-       InsetIterator const end = inset_iterator_end(inset);
-
-       for (; it != end; ++it)
-               if (it->lyxCode() == InsetBase::MATHMACRO_CODE)
-                       it->latex(buffer_, os, runparams);
-
-       // All equation lables appear as "(#)" + preview.sty's rendering of
-       // the label name
-       if (lyxrc.preview_hashed_labels)
-               os << "\\renewcommand{\\theequation}{\\#}\n";
-
-       // Use the preview style file to ensure that each snippet appears on a
-       // fresh page.
-       os << "\n"
-          << "\\usepackage[active,delayed,dvips,showlabels,lyx]{preview}\n"
-          << "\n";
-}
-
-
-void PreviewLoader::Impl::dumpData(ostream & os,
-                                  BitmapFile const & vec) const
-{
-       if (vec.empty())
-               return;
-
-       BitmapFile::const_iterator it  = vec.begin();
-       BitmapFile::const_iterator end = vec.end();
-
-       for (; it != end; ++it) {
-               os << "\\begin{preview}\n"
-                  << it->first
-                  << "\n\\end{preview}\n\n";
-       }
-}
-
-} // namespace graphics
-} // namespace lyx
-
-namespace {
-
-string const unique_filename(string const bufferpath)
-{
-       static int theCounter = 0;
-       string const filename = convert<string>(theCounter++) + "lyxpreview";
-       return support::AddName(bufferpath, filename);
-}
-
 
-Converter const * setConverter()
+Converter const * defaultConverter()
 {
        string const from = "lyxpreview";
 
@@ -689,57 +460,20 @@ Converter const * setConverter()
        return 0;
 }
 
-
-void setAscentFractions(vector<double> & ascent_fractions,
-                       string const & metrics_file)
-{
-       // If all else fails, then the images will have equal ascents and
-       // descents.
-       vector<double>::iterator it  = ascent_fractions.begin();
-       vector<double>::iterator end = ascent_fractions.end();
-       fill(it, end, 0.5);
-
-       ifstream in(metrics_file.c_str());
-       if (!in.good()) {
-               lyxerr[Debug::GRAPHICS]
-                       << "setAscentFractions(" << metrics_file << ")\n"
-                       << "Unable to open file!" << endl;
-               return;
-       }
-
-       bool error = false;
-
-       int snippet_counter = 1;
-       while (!in.eof() && it != end) {
-               string snippet;
-               int id;
-               double ascent_fraction;
 
-               in >> snippet >> id >> ascent_fraction;
-
-               if (!in.good())
-                       // eof after all
-                       break;
+} // namespace graphics
+} // namespace lyx
 
-               error = snippet != "Snippet";
-               if (error)
-                       break;
+namespace {
 
-               error = id != snippet_counter;
-               if (error)
-                       break;
+string const unique_filename(string const bufferpath)
+{
+       static int theCounter = 0;
+       string const filename = convert<string>(theCounter++) + "lyxpreview";
+       return support::AddName(bufferpath, filename);
+}
 
-               *it = ascent_fraction;
 
-               ++snippet_counter;
-               ++it;
-       }
 
-       if (error) {
-               lyxerr[Debug::GRAPHICS]
-                       << "setAscentFractions(" << metrics_file << ")\n"
-                       << "Error reading file!\n" << endl;
-       }
-}
 
 } // namespace anon
Index: src/graphics/PreviewLoader.h
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/graphics/PreviewLoader.h,v
retrieving revision 1.16
diff -u -p -r1.16 PreviewLoader.h
--- src/graphics/PreviewLoader.h        2004/09/26 14:19:47     1.16
+++ src/graphics/PreviewLoader.h        2005/02/26 00:30:24
@@ -23,11 +23,14 @@
 #include <boost/signal.hpp>
 
 class Buffer;
+class Converter;
 
 namespace lyx {
 namespace graphics {
 
 class PreviewImage;
+
+Converter const * defaultConverter();
 
 class PreviewLoader : boost::noncopyable {
 public:
Index: src/insets/insetgraphics.C
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/insets/insetgraphics.C,v
retrieving revision 1.274
diff -u -p -r1.274 insetgraphics.C
--- src/insets/insetgraphics.C  2005/02/22 16:57:36     1.274
+++ src/insets/insetgraphics.C  2005/02/26 00:30:26
@@ -68,6 +68,7 @@ TODO
 #include "lyxlex.h"
 #include "metricsinfo.h"
 #include "mover.h"
+#include "output_docbook.h"
 #include "outputparams.h"
 #include "sgml.h"
 
@@ -338,63 +339,6 @@ string const InsetGraphics::createLatexO
 }
 
 
-string const InsetGraphics::toDocbookLength(LyXLength const & len) const
-{
-       ostringstream result;
-       switch (len.unit()) {
-               case LyXLength::SP: // Scaled point (65536sp = 1pt) TeX's 
smallest unit.
-                       result << len.value() * 65536.0 * 72 / 72.27 << "pt";
-                       break;
-               case LyXLength::PT: // Point = 1/72.27in = 0.351mm
-                       result << len.value() * 72 / 72.27 << "pt";
-                       break;
-               case LyXLength::BP: // Big point (72bp = 1in), also PostScript 
point
-                       result << len.value() << "pt";
-                       break;
-               case LyXLength::DD: // Didot point = 1/72 of a French inch, = 
0.376mm
-                       result << len.value() * 0.376 << "mm";
-                       break;
-               case LyXLength::MM: // Millimeter = 2.845pt
-                       result << len.value() << "mm";
-                       break;
-               case LyXLength::PC: // Pica = 12pt = 4.218mm
-                       result << len.value() << "pc";
-                       break;
-               case LyXLength::CC: // Cicero = 12dd = 4.531mm
-                       result << len.value() * 4.531 << "mm";
-                       break;
-               case LyXLength::CM: // Centimeter = 10mm = 2.371pc
-                       result << len.value() << "cm";
-                       break;
-               case LyXLength::IN: // Inch = 25.4mm = 72.27pt = 6.022pc
-                       result << len.value() << "in";
-                       break;
-               case LyXLength::EX: // Height of a small "x" for the current 
font.
-                       // Obviously we have to compromise here. Any better 
ratio than 1.5 ?
-                       result << len.value() / 1.5 << "em";
-                       break;
-               case LyXLength::EM: // Width of capital "M" in current font.
-                       result << len.value() << "em";
-                       break;
-               case LyXLength::MU: // Math unit (18mu = 1em) for positioning 
in math mode
-                       result << len.value() * 18 << "em";
-                       break;
-               case LyXLength::PTW: // Percent of TextWidth
-               case LyXLength::PCW: // Percent of ColumnWidth
-               case LyXLength::PPW: // Percent of PageWidth
-               case LyXLength::PLW: // Percent of LineWidth
-               case LyXLength::PTH: // Percent of TextHeight
-               case LyXLength::PPH: // Percent of Paper
-                       // Sigh, this will go wrong.
-                       result << len.value() << "%";
-                       break;
-               default:
-                       result << len.asString();
-                       break;
-       }
-       return result.str();
-}
-
 string const InsetGraphics::createDocBookAttributes() const
 {
        // Calculate the options part of the command, we must do it to a string
@@ -783,32 +727,7 @@ int InsetGraphics::linuxdoc(Buffer const
 }
 
 
-namespace {
 
-int writeImageObject(char * format, ostream& os, OutputParams const & 
runparams,
-                                        string const graphic_label, string 
const attributes)
-{
-               if (runparams.flavor != OutputParams::XML) {
-                       os << "<![ %output.print." << format << "; [" << 
std::endl;
-               }
-               os <<"<imageobject><imagedata fileref=\"&"
-                  << graphic_label << ";." << format << "\" " << attributes ;
-               if (runparams.flavor == OutputParams::XML) {
-                       os <<  " role=\"" << format << "\"/>" ;
-               }
-               else {
-                       os << " format=\"" << format << "\">" ;
-               }
-               os << "</imageobject>";
-               if (runparams.flavor != OutputParams::XML) {
-                       os << std::endl << "]]>" ;
-               }
-               return runparams.flavor == OutputParams::XML ? 0 : 2;
-}
-// end anonymous namespace
-}
-
-
 // For explanation on inserting graphics into DocBook checkout:
 // http://en.tldp.org/LDP/LDP-Author-Guide/html/inserting-pictures.html
 // See also the docbook guide at http://www.docbook.org/
@@ -825,14 +744,16 @@ int InsetGraphics::docbook(Buffer const 
                runparams.exportdata->addExternalFile("docbook",
                                                      
params().filename.absFilename());
        }
+
        os << "<inlinemediaobject>";
 
        int r = 0;
        string attributes = createDocBookAttributes();
-       r += writeImageObject("png", os, runparams, graphic_label, attributes);
-       r += writeImageObject("pdf", os, runparams, graphic_label, attributes);
-       r += writeImageObject("eps", os, runparams, graphic_label, attributes);
-       r += writeImageObject("bmp", os, runparams, graphic_label, attributes);
+       string filename_entitity = "&" + graphic_label + ";" ;
+       r += docbookImageObject("pdf", filename_entitity, attributes, os, 
runparams);
+       r += docbookImageObject("eps", filename_entitity, attributes, os, 
runparams);
+       r += docbookImageObject("png", filename_entitity, attributes, os, 
runparams);
+       r += docbookImageObject("bmp", filename_entitity, attributes, os, 
runparams);
 
        os << "</inlinemediaobject>";
        return r;
Index: src/insets/insetgraphics.h
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/insets/insetgraphics.h,v
retrieving revision 1.103
diff -u -p -r1.103 insetgraphics.h
--- src/insets/insetgraphics.h  2004/11/25 19:13:04     1.103
+++ src/insets/insetgraphics.h  2005/02/26 00:30:26
@@ -92,8 +92,6 @@ private:
        std::string const statusMessage() const;
        /// Create the options for the latex command.
        std::string const createLatexOptions() const;
-       /// Create length values for docbook export.
-       std::string const toDocbookLength(LyXLength const & len) const;
        /// Create the atributes for docbook export.
        std::string const createDocBookAttributes() const;
        /// Convert the file if needed, and return the location of the file.
Index: src/mathed/math_hullinset.C
===================================================================
RCS file: /cvs/lyx/lyx-devel/src/mathed/math_hullinset.C,v
retrieving revision 1.161
diff -u -p -r1.161 math_hullinset.C
--- src/mathed/math_hullinset.C 2005/02/14 14:25:17     1.161
+++ src/mathed/math_hullinset.C 2005/02/26 00:30:29
@@ -18,6 +18,7 @@
 #include "math_streamstr.h"
 #include "math_support.h"
 
+#include "buffer.h"
 #include "BufferView.h"
 #include "CutAndPaste.h"
 #include "FuncStatus.h"
@@ -26,10 +27,12 @@
 #include "cursor.h"
 #include "debug.h"
 #include "dispatchresult.h"
+#include "exporter.h"
 #include "funcrequest.h"
 #include "gettext.h"
 #include "lyx_main.h"
 #include "lyxrc.h"
+#include "output_docbook.h"
 #include "outputparams.h"
 #include "sgml.h"
 #include "textpainter.h"
@@ -41,8 +44,10 @@
 
 #include "graphics/PreviewImage.h"
 #include "graphics/PreviewLoader.h"
+#include "graphics/SnippetConversion.h"
 
 #include "support/lstrings.h"
+#include "support/filetools.h"
 
 #include <boost/bind.hpp>
 
@@ -51,6 +56,9 @@
 using lyx::cap::grabAndEraseSelection;
 using lyx::support::bformat;
 using lyx::support::subst;
+using lyx::support::GetExtension;
+using lyx::support::ChangeExtension;
+using lyx::support::OnlyFilename;
 
 using std::endl;
 using std::max;
@@ -1351,7 +1373,37 @@ int MathHullInset::linuxdoc(Buffer const
        return docbook(buf, os, runparams);
 }
 
+namespace {
+void registerExternalFile(string const & gr_format, OutputParams const & 
runparams,
+                          string const & latex_snippet, string const & 
external_name)
+{
+       lyx::graphics::SnippetConversion const * bitmaps = 
runparams.exportdata->bitmaps(gr_format);    
+       if (!bitmaps) {
+               return;
+       }
+       string const bitmapfile = bitmaps->findSnippet(latex_snippet);
+       string const ext = "." + GetExtension(bitmapfile);
+       if (runparams.flavor == OutputParams::XML) {
+               runparams.exportdata->addExternalFile("docbook-xml",
+                                                     bitmapfile, external_name 
+ ext);
+       } else {
+               runparams.exportdata->addExternalFile("docbook",
+                                                     bitmapfile, external_name 
+ ext);
+       }
+}
 
+void registerExternalDirectory(OutputParams const & runparams, string const & 
dirname)
+{
+       if (runparams.flavor == OutputParams::XML) {
+               runparams.exportdata->addExternalDirectory("docbook-xml", 
dirname);
+       } else {
+               runparams.exportdata->addExternalDirectory("docbook", dirname);
+       }
+}
+
+} // namespace
+
+
 int MathHullInset::docbook(Buffer const & buf, ostream & os,
                          OutputParams const & runparams) const
 {
@@ -1366,38 +1418,51 @@ int MathHullInset::docbook(Buffer const 
        string bname = name;
        if (!label(0).empty())
                bname += " id=\"" + sgml::cleanID(buf, runparams, label(0)) + 
"\"";
+       // Let's do something about the other labels ...        
+       for (row_type i=1; i < nrows(); i++) {
+               if (!label(i).empty()) {
+                       string aname = "anchor id=\"" + sgml::cleanID(buf, 
runparams, label(i)) + "\"";
+                       ms << MTag(aname.c_str());
+                       if (runparams.flavor == OutputParams::XML) {
+                               ms << ETag("anchor");
+                       }
+               }
+       }
        ms << MTag(bname.c_str());
 
        ostringstream ls;
+       res = latex(buf, ls, runparams);
+
+       ms << MTag("alt role=\"tex\" ");
+       ms << subst(subst(ls.str(), "&", "&amp;"), "<", "&lt;");
+       ms << ETag("alt");
        if (runparams.flavor == OutputParams::XML) {
-               ms << MTag("alt role=\"tex\" ");
-               // Workaround for db2latex: db2latex always includes equations 
with
-               // \ensuremath{} or \begin{display}\end{display}
-               // so we strip LyX' math environment
-               WriteStream wi(ls, false, false);
-               MathGridInset::write(wi);
-               ms << subst(subst(ls.str(), "&", "&amp;"), "<", "&lt;");
-               ms << ETag("alt");
                ms << MTag("math");
                MathGridInset::mathmlize(ms);
                ms << ETag("math");
-       } else {
-               ms << MTag("alt role=\"tex\"");
-               res = latex(buf, ls, runparams);
-               ms << subst(subst(ls.str(), "&", "&amp;"), "<", "&lt;");
-               ms << ETag("alt");
        }
 
-       ms <<  "<graphic fileref=\"eqn/";
+       string const dirname = ChangeExtension(OnlyFilename(buf.fileName()), 
string()) + "_math";
+       ostringstream efs;
+       efs << dirname << "/";
        if ( !label(0).empty())
-               ms << sgml::cleanID(buf, runparams, label(0));
+               efs << sgml::cleanID(buf, runparams, label(0));
        else {
-               ms << sgml::uniqueID("anon");
+               efs << sgml::uniqueID("anon");
        }
-       if (runparams.flavor == OutputParams::XML)
-               ms << "\"/>";
-       else
-               ms << "\">";
+
+       registerExternalDirectory(runparams, dirname);  
+       registerExternalFile("pdf", runparams, ls.str(), efs.str());
+       registerExternalFile("eps", runparams, ls.str(), efs.str());
+       registerExternalFile("png", runparams, ls.str(), efs.str());
+       registerExternalFile("bmp", runparams, ls.str(), efs.str());
+        
+       string const attributes;
+       // this would be the place to include the alignment information. AV
+       docbookImageObject("pdf", efs.str(), attributes, os, runparams, true);
+       docbookImageObject("eps", efs.str(), attributes, os, runparams, true);
+       docbookImageObject("png", efs.str(), attributes, os, runparams, true);
+       docbookImageObject("bmp", efs.str(), attributes, os, runparams, true);
 
        ms << ETag(name.c_str());
        return ms.line() + res;
// -*- C++ -*-
/**
 * \file SnippetConversion.C
 * This file is part of LyX, the document processor.
 * Licence details can be found in the file COPYING.
 *
 * \author Andreas Vox
 *
 * Full author contact details are available in file CREDITS.
 *
 * lyx::graphics::SnippetConversion converts latex snippets to bitmap
 * files. 
 * snippets are collected one by one. Then, on start converting, these 
 * are dumped to file and processed, converting each snippet to a 
 * separate bitmap image file. 
 */

#include "SnippetConversion.h"

#include "buffer.h"
#include "debug.h"
#include "insetiterator.h"
#include "lyxrc.h"
#include "paragraph.h"

#include "insets/inset.h"

#include "support/filetools.h"
#include "support/forkedcontr.h"
#include "support/lyxlib.h"



#include <boost/utility.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/signal.hpp>

namespace support = lyx::support;

using std::vector;
using std::string;

using std::ostream;
using std::ostringstream;
using std::ofstream;
using std::ifstream;
using std::endl;


// some helpers:

namespace {
        
typedef vector<lyx::graphics::SnippetConversion::Entry> BitmapFileList;

typedef lyx::graphics::SnippetConversion::SnippetList SnippetList;

typedef lyx::graphics::SnippetConversion::Entry Entry;

class IncrementedFileName {
public:
        IncrementedFileName(string const & to_format,
                            string const & filename_base)
                : to_format_(to_format), base_(filename_base), counter_(1)
        {}

        Entry const operator()(string const & snippet)
        {
                ostringstream os;
                os << base_ << counter_++ << '.' << to_format_;
                
                Entry result;
                result.filename = os.str();
                result.latex = snippet;
                return result;
        }

private:
        string const & to_format_;
        string const & base_;
        int counter_;
};

class FindFirst : public std::unary_function<Entry, bool> {
public:
        FindFirst(string const & comp) : comp_(comp) {}
        bool operator()(Entry const & sp) const
        {
                return sp.latex == comp_;
        }
private:
        string const comp_;
};

        
        
} // namespace anon

namespace lyx {
namespace graphics {



SnippetConversion::SnippetConversion(string const & filename_base,
                Converter const * converter, SnippetList const & pending)       
  
                : pid_(0),
                  filename_base(filename_base),
                  metrics_file(filename_base + ".metrics"),
                  snippets(pending.size()),
                  converter_(converter) 
{                  
        SnippetList::const_iterator pit  = pending.begin();
        SnippetList::const_iterator pend = pending.end();
        BitmapFileList::iterator sit = snippets.begin();

        std::transform(pit, pend, sit,
                       IncrementedFileName(converter->to, filename_base));      
           
}


bool SnippetConversion::empty() const 
{
        return snippets.empty();
}


int SnippetConversion::size() const 
{
        return snippets.size();
}

BitmapFileList::const_iterator SnippetConversion::begin() const 
{
        return snippets.begin();
}

BitmapFileList::const_iterator SnippetConversion::end() const 
{
        return snippets.end();
}


string const SnippetConversion::findSnippet(string const & snippet_) const
{
                BitmapFileList::const_iterator beg  = snippets.begin();
                BitmapFileList::const_iterator end = snippets.end();
                BitmapFileList::const_iterator res = find_if(beg, end, 
FindFirst(snippet_));
                if (res != end) {
                        return res-> filename;
                }
                else {
                        return string();
                }
}

void SnippetConversion::eraseSnippet(string const & snippet_)
{
                BitmapFileList::iterator it  = snippets.begin();
                BitmapFileList::iterator end = snippets.end();

                it = find_if(it, end, FindFirst(snippet_));
                if (it != end)
                        snippets.erase(it, it+1);
}


string SnippetConversion::prepareCommand(Buffer const & buffer, 
                              string const & hex_foreground, 
                              string const & hex_background,
                              double font_scaling_factor_,
                              bool showLabels)
{
                // Output the LaTeX file.
        string const latexfile = filename_base + ".tex";

        lyxerr << "preview snippets in " << latexfile << endl;
        
        ofstream of(latexfile.c_str());
        if (!of) {
                lyxerr[Debug::GRAPHICS] << "SnippetConversion::start()\n"
                                        << "Unable to create LaTeX file\n"
                                        << latexfile << endl;
                return "";
        }
        
        lyxerr << "writing preview snippets now" << endl;

        of << "\\batchmode\n";
        dumpPreamble(of, buffer, showLabels);
        of << "\n\\begin{document}\n";
        dumpData(of, snippets);
        of << "\n\\end{document}\n";
        of.close();

        lyxerr << "done writing preview snippets" << endl;

        
        // The conversion command.
        ostringstream cs;
        cs << converter_->command << ' ' << converter_->to << ' '
           << latexfile << ' ' << int(font_scaling_factor_) << ' '
           << hex_foreground << ' ' << hex_background;
           
        lyxerr << "preview command is " << cs.str() << endl;
        
        return support::LibScriptSearch(cs.str());
}

void SnippetConversion::start(Buffer const & buffer, 
                              string const & hex_foreground, 
                              string const & hex_background,
                              double font_scaling_factor,
                              support::Forkedcall::SignalTypePtr convert_ptr) 
{
        command_ = prepareCommand(buffer, hex_foreground, hex_background, 
font_scaling_factor,true);
        support::Forkedcall call;
        int ret = call.startscript(command_, convert_ptr);

        if (ret != 0) {
                lyxerr[Debug::GRAPHICS] << "SnippetConversion::start()\n"
                                        << "Unable to start process\n"
                                        << command_ << endl;
                return;
        }
        pid_ = call.pid();
           
}


int SnippetConversion::startAndWait(Buffer const & buffer, 
                              string const & hex_foreground, 
                              string const & hex_background,
                              double font_scaling_factor) 
{
        command_ = prepareCommand(buffer, hex_foreground, hex_background, 
font_scaling_factor,false);
        support::Forkedcall call;
        int ret = call.startscript(support::ForkedProcess::Wait, command_);
        
        if (ret != 0) {
                lyxerr[Debug::GRAPHICS] << "SnippetConversion::startAndWait()\n"
                                        << "Unable to start process\n"
                                        << command_ << endl;
        }
        
        return ret;
           
}

void SnippetConversion::stop()
{
        if (!metrics_file.empty())
                support::unlink(metrics_file);

        BitmapFileList::const_iterator vit  = snippets.begin();
        BitmapFileList::const_iterator vend = snippets.end();
        for (; vit != vend; ++vit) {
                if (!vit->filename.empty())
                        support::unlink(vit->filename);
        }

        if (pid_)
                support::ForkedcallsController::get().kill(pid_, 0);

}



void SnippetConversion::dumpPreamble(ostream & os, Buffer const & buffer, bool 
showLabels) const
{
        // Why on earth is Buffer::makeLaTeXFile a non-const method?
        Buffer & tmp = const_cast<Buffer &>(buffer);
        // Dump the preamble only.
        OutputParams runparams;
        runparams.flavor = OutputParams::LATEX;
        runparams.nice = true;
        runparams.moving_arg = true;
        runparams.free_spacing = true;
        tmp.makeLaTeXFile(os, buffer.filePath(), runparams, true, false);

        // FIXME! This is a HACK! The proper fix is to control the 'true'
        // passed to WriteStream below:
        // int InsetFormula::latex(Buffer const &, ostream & os,
        //                         OutputParams const & runparams) const
        // {
        //      WriteStream wi(os, runparams.moving_arg, true);
        //      par_->write(wi);
        //      return wi.line();
        // }
        os << "\n"
           << "\\def\\lyxlock{}\n"
           << "\n";

        // Loop over the insets in the buffer and dump all the math-macros.
        InsetBase & inset = buffer.inset();
        InsetIterator it = inset_iterator_begin(inset);
        InsetIterator const end = inset_iterator_end(inset);

        for (; it != end; ++it)
                if (it->lyxCode() == InsetBase::MATHMACRO_CODE)
                        it->latex(buffer, os, runparams);

        // All equation lables appear as "(#)" + preview.sty's rendering of
        // the label name
        if (lyxrc.preview_hashed_labels)
                os << "\\renewcommand{\\theequation}{\\#}\n";

        // Use the preview style file to ensure that each snippet appears on a
        // fresh page.
        os << "\n"
           << "\\usepackage[active,delayed,dvips,"
           << (showLabels? "showlabels," : "")
           << "lyx]{preview}\n"
           << "\n";
}


void SnippetConversion::dumpData(ostream & os,
                                   BitmapFileList const & vec) const
{
        if (vec.empty())
                return;

        BitmapFileList::const_iterator it  = vec.begin();
        BitmapFileList::const_iterator end = vec.end();

        for (; it != end; ++it) {
                os << "\\begin{preview}\n"
                   << it->latex
                   << "\n\\end{preview}\n\n";
        }
}


void SnippetConversion::setAscentFractions() 
{
        BitmapFileList::iterator it  = snippets.begin();
        BitmapFileList::iterator end = snippets.end();

        bool error = false;

        ifstream in(metrics_file.c_str());
        if (!in.good()) {
                lyxerr[Debug::GRAPHICS]
                        << "setAscentFractions(" << metrics_file << ")\n"
                        << "Unable to open file!" << endl;
        }
        else {
                int snippet_counter = 1;
                while (!in.eof() && it != end) {
                        string snippet;
                        int id;
                        double ascent_fraction;
        
                        in >> snippet >> id >> ascent_fraction;
        
                        if (!in.good())
                                // eof after all
                                break;
        
                        error = snippet != "Snippet";
                        if (error)
                                break;
        
                        error = id != snippet_counter;
                        if (error)
                                break;
        
                        it->ascentfraction = ascent_fraction;
        
                        ++snippet_counter;
                        ++it;
                }
        }
        
        // If all else fails, then the images will have equal ascents and
        // descents.
        while (it != end) {
                it->ascentfraction = 0.5;
                ++it;
        }
        
        if (error) {
                lyxerr[Debug::GRAPHICS]
                        << "setAscentFractions(" << metrics_file << ")\n"
                        << "Error reading file!\n" << endl;
        }
}

} // namespace
} // lyx::graphics
// -*- C++ -*-
/**
 * \file SnippetConversion.h
 * This file is part of LyX, the document processor.
 * Licence details can be found in the file COPYING.
 *
 * \author Andreas Vox
 *
 * Full author contact details are available in file CREDITS.
 *
 * lyx::graphics::SnippetConversion converts latex snippets to bitmap
 * files. 
 * snippets are collected one by one. Then, on start converting, these 
 * are dumped to file and processed, converting each snippet to a 
 * separate bitmap image file. 
 */

#ifndef SNIPPETCONVERSION_H
#define SNIPPETCONVERSION_H

#include "converter.h"

#include "support/forkedcall.h"

#include <boost/utility.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/signal.hpp>
#include <boost/bind.hpp>

#include <sstream>
#include <fstream>


namespace lyx {
namespace graphics {

/// Converts a set of LaTeX snippets to graphic files using yxpreview2bitmap
class SnippetConversion {
public:

        /// Holds one snippet and its associated graphics file
        struct Entry {
            std::string latex;
            std::string filename;
            double ascentfraction;
        };

        // A list of all snippets to be converted to previews
        typedef std::list<std::string> SnippetList;

        /// Default constructor. No conversions are intitiated.
        SnippetConversion() : pid_(0) {}
        
        /// Initialise member variables. Do not initiate conversions.
        SnippetConversion(std::string const & filename_base,
                   Converter const * converter, SnippetList const & pending);
                   
        /// Dynamically forget about a snippet
        void eraseSnippet(std::string const & snippet_);

        /// return start of entry list
        std::vector<Entry>::const_iterator begin() const;

        /// return end of entry list
        std::vector<Entry>::const_iterator end() const;

        /// is the entry list empty?
        bool empty() const;

        /// how many entries are in the list?
        int size() const;

        /// Find a snippet in the entry list. Return its associated graphics 
filename
        std::string const findSnippet(std::string const & snippet_) const;

    /** Start the conversion and return immediately.
     *  The conversion process is run asynchronously.
     */
        void start(Buffer const & buffer, 
                   std::string const & hex_foreground, 
                   std::string const & hex_background,
                   double font_scaling_factor_,
                   lyx::support::Forkedcall::SignalTypePtr convert_ptr);

    /** Start the conversion and block further execution until
     *  the conversion process finiishes.
     */
        int startAndWait(Buffer const & buffer, 
                   std::string const & hex_foreground, 
                   std::string const & hex_background,
                   double font_scaling_factor_);

        /// Remove any files left lying around and kill the forked process.
        void stop();

        /// Read the metrics file and set ascentfractions in entries
        void setAscentFractions();

        ///     The external command which gets forked
        std::string const & command() const { return command_; }
        /// The PID of the forked process
        pid_t pid() const { return pid_; }

private:
        ///
        void dumpPreamble(std::ostream &, Buffer const & buffer, bool 
showLabels) const;
        ///
        void dumpData(std::ostream &, std::vector<Entry> const &) const;
        ///
        std::string prepareCommand(Buffer const & buffer, 
                                   std::string const & hex_foreground, 
                                   std::string const & hex_background,
                                   double font_scaling_factor_,
                                   bool showLabels);

        ///
        std::string command_;
        ///
        pid_t pid_;
        ///
        std::string filename_base;
        ///
        std::string metrics_file;
        ///
        std::vector<Entry> snippets;
 
        Converter const * converter_;
 };


} // namespace graphics
} // namespace lyx

#endif // SNIPPETCONVERSION_H

Reply via email to