From a4fc7841248e3e177d70a82f42e56dca75f0b447 Mon Sep 17 00:00:00 2001 From: Angus Leeming Date: Wed, 3 Sep 2003 17:23:38 +0000 Subject: [PATCH] Fix export of graphics images when compiling latex file. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@7649 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/insets/ChangeLog | 6 ++ src/insets/insetexternal.C | 37 ++++---- src/insets/insetgraphics.C | 174 ++++++++++++++++++++++++------------- src/support/ChangeLog | 12 ++- src/support/filename.C | 37 +++++++- src/support/filename.h | 20 ++++- src/support/filetools.C | 60 ++++++------- src/support/filetools.h | 17 ++-- 8 files changed, 244 insertions(+), 119 deletions(-) diff --git a/src/insets/ChangeLog b/src/insets/ChangeLog index e008e172d3..adcff625be 100644 --- a/src/insets/ChangeLog +++ b/src/insets/ChangeLog @@ -1,3 +1,9 @@ +2003-09-03 Angus Leeming + + * insetexternal.C (updateExternal): + * insetgraphics.C (prepareFile): Fix the conversion when exporting to + latex. + 2003-09-03 Angus Leeming * insetexternal.C: don't bring namespace lyx::support into the global diff --git a/src/insets/insetexternal.C b/src/insets/insetexternal.C index eb4142fedd..5681bd9a22 100644 --- a/src/insets/insetexternal.C +++ b/src/insets/insetexternal.C @@ -518,28 +518,33 @@ void InsetExternal::updateExternal(string const & format, if (external_in_tmpdir && !from_file.empty()) { // We are running stuff through LaTeX - from_file = support::copyFileToDir(buf.tmppath, from_file); - if (from_file.empty()) + string const temp_file = + support::MakeAbsPath(params_.filename.mangledFilename(), + buf.tmppath); + unsigned long const from_checksum = support::sum(from_file); + unsigned long const temp_checksum = support::sum(temp_file); + + // Nothing to do... + if (from_checksum == temp_checksum) return; + + // Cannot proceed... + if (!support::copy(from_file, temp_file)) + return; + from_file = temp_file; } string const to_file = doSubstitution(params_, buf, outputFormat.updateResult); + string const abs_to_file = support::MakeAbsPath(to_file, buf.filePath()); - support::FileInfo fi(from_file); - string abs_to_file = to_file; - if (!support::AbsolutePath(to_file)) - abs_to_file = support::MakeAbsPath(to_file, - support::OnlyPath(from_file)); - support::FileInfo fi2(abs_to_file); - if (fi2.exist() && fi.exist() && - difftime(fi2.getModificationTime(), - fi.getModificationTime()) >= 0) { - } else { - string const to_filebase = support::ChangeExtension(to_file, string()); - converters.convert(&buf, from_file, to_filebase, - from_format, to_format); - } + // Do we need to perform the conversion? + // Yes if to_file does not exist or if from_file is newer than to_file + if (support::compare_timestamps(from_file, abs_to_file) < 0) + return; + + string const to_filebase = support::ChangeExtension(to_file, string()); + converters.convert(&buf, from_file, to_filebase, from_format, to_format); } diff --git a/src/insets/insetgraphics.C b/src/insets/insetgraphics.C index 59b811390d..ec7b4e0e95 100644 --- a/src/insets/insetgraphics.C +++ b/src/insets/insetgraphics.C @@ -74,6 +74,7 @@ TODO #include "frontends/Alert.h" #include "frontends/Dialogs.h" +#include "support/LAssert.h" #include "support/filetools.h" #include "support/lyxalgo.h" // lyx::count #include "support/lyxlib.h" // float_equal @@ -81,11 +82,13 @@ TODO #include "support/systemcall.h" #include +#include #include // For the std::max // set by Exporters +namespace support = lyx::support; using namespace lyx::support; using std::ostream; @@ -328,14 +331,79 @@ string const InsetGraphics::createLatexOptions() const } +namespace { + +enum CopyStatus { + SUCCESS, + FAILURE, + IDENTICAL_PATHS, + IDENTICAL_CONTENTS +}; + + +std::pair const +copyToDirIfNeeded(string const & file_in, string const & dir) +{ + using support::rtrim; + + support::Assert(AbsolutePath(file_in)); + + string const only_path = support::OnlyPath(file_in); + if (rtrim(support::OnlyPath(file_in) , "/") == rtrim(dir, "/")) + return std::make_pair(IDENTICAL_PATHS, file_in); + + string mangled; + if (support::zippedFile(file_in)) { + string const ext = GetExtension(file_in); + string const unzipped = support::unzippedFileName(file_in); + mangled = FileName(unzipped).mangledFilename(); + mangled += "." + ext; + } else + mangled = FileName(file_in).mangledFilename(); + + string const file_out = support::MakeAbsPath(mangled, dir); + + unsigned long const checksum_in = support::sum(file_in); + unsigned long const checksum_out = support::sum(file_out); + + if (checksum_in == checksum_out) + // Nothing to do... + return std::make_pair(IDENTICAL_CONTENTS, file_out); + + bool const success = support::copy(file_in, file_out); + if (!success) { + lyxerr[Debug::GRAPHICS] + << support::bformat(_("Could not copy the file\n%1$s\n" + "into the temporary directory."), + file_in) + << std::endl; + } + + CopyStatus status = success ? SUCCESS : FAILURE; + return std::make_pair(status, file_out); +} + + +string const stripExtensionIfPossible(string const & file, string const & to) +{ + // No conversion is needed. LaTeX can handle the graphic file as is. + // This is true even if the orig_file is compressed. + if (formats.getFormat(to)->extension() == GetExtension(file)) + return RemoveExtension(file); + return file; +} + +} // namespace anon + + string const InsetGraphics::prepareFile(Buffer const & buf, LatexRunParams const & runparams) const { - // LaTeX can cope if the graphics file doesn't exist, so just return the - // filename. string orig_file = params().filename.absFilename(); string const rel_file = params().filename.relFilename(buf.filePath()); + // LaTeX can cope if the graphics file doesn't exist, so just return the + // filename. if (!IsFileReadable(orig_file)) { lyxerr[Debug::GRAPHICS] << "InsetGraphics::prepareFile\n" @@ -343,11 +411,11 @@ string const InsetGraphics::prepareFile(Buffer const & buf, return rel_file; } - bool const zipped = zippedFile(orig_file); - // If the file is compressed and we have specified that it // should not be uncompressed, then just return its name and // let LaTeX do the rest! + bool const zipped = params().filename.isZipped(); + if (zipped && params().noUnzip) { lyxerr[Debug::GRAPHICS] << "\tpass zipped file to LaTeX but with full path.\n"; @@ -361,95 +429,85 @@ string const InsetGraphics::prepareFile(Buffer const & buf, string temp_file = orig_file; if (zipped) { - // Uncompress the file if necessary. - // If it has been uncompressed in a previous call to - // prepareFile, do nothing. - temp_file = MakeAbsPath(OnlyFilename(temp_file), buf.tmppath); - lyxerr[Debug::GRAPHICS] - << "\ttemp_file: " << temp_file << endl; - if (graphic_->hasFileChanged() || !IsFileReadable(temp_file)) { - bool const success = copy(orig_file, temp_file); - lyxerr[Debug::GRAPHICS] - << "\tCopying zipped file from " - << orig_file << " to " << temp_file - << (success ? " succeeded\n" : " failed\n"); - } else + CopyStatus status; + boost::tie(status, temp_file) = + copyToDirIfNeeded(orig_file, buf.tmppath); + + if (status == FAILURE) + return orig_file; + + orig_file = unzippedFileName(temp_file); + if (!IsFileReadable(orig_file)) { + unzipFile(temp_file); lyxerr[Debug::GRAPHICS] - << "\tzipped file " << temp_file - << " exists! Maybe no tempdir ...\n"; - orig_file = unzipFile(temp_file); - lyxerr[Debug::GRAPHICS] - << "\tunzipped to " << orig_file << endl; + << "\tunzipped to " << orig_file << endl; + } } - + string const from = getExtFromContents(orig_file); string const to = findTargetFormat(from, runparams); lyxerr[Debug::GRAPHICS] << "\t we have: from " << from << " to " << to << '\n'; - if (from == to && !lyxrc.use_tempdir) { - // No conversion is needed. LaTeX can handle the - // graphic file as is. - // This is true even if the orig_file is compressed. - if (formats.getFormat(to)->extension() == GetExtension(orig_file)) - return RemoveExtension(orig_file); - return orig_file; - } + if (from == to && !lyxrc.use_tempdir) + return stripExtensionIfPossible(orig_file, to); // We're going to be running the exported buffer through the LaTeX // compiler, so must ensure that LaTeX can cope with the graphics // file format. - // Perform all these manipulations on a temporary file if possible. - // If we are not using a temp dir, then temp_file contains the - // original file. - // to allow files with the same name in different dirs - // we manipulate the original file "any.dir/file.ext" - // to "any_dir_file.ext"! changing the dots in the - // dirname is important for the use of ChangeExtension lyxerr[Debug::GRAPHICS] << "\tthe orig file is: " << orig_file << endl; + bool conversion_needed = true; if (lyxrc.use_tempdir) { - temp_file = copyFileToDir(buf.tmppath, orig_file); - if (temp_file.empty()) { - string str = bformat(_("Could not copy the file\n%1$s\n" - "into the temporary directory."), - orig_file); - Alert::error(_("Graphics display failed"), str); + CopyStatus status; + boost::tie(status, temp_file) = + copyToDirIfNeeded(orig_file, buf.tmppath); + + if (status == FAILURE) return orig_file; - } + else if (status == IDENTICAL_CONTENTS) + conversion_needed = false; + } - if (from == to) { - // No conversion is needed. LaTeX can handle the - // graphic file as is. - if (formats.getFormat(to)->extension() == GetExtension(orig_file)) - return RemoveExtension(temp_file); - return temp_file; - } + if (from == to) + return stripExtensionIfPossible(temp_file, to); + + string const to_file_base = RemoveExtension(temp_file); + string const to_file = ChangeExtension(to_file_base, to); + + // Do we need to perform the conversion? + // Yes if to_file does not exist or if temp_file is newer than to_file + if (!conversion_needed || + support::compare_timestamps(temp_file, to_file) < 0) { + lyxerr[Debug::GRAPHICS] + << bformat(_("No conversion of %1$s is needed after all"), + rel_file) + << std::endl; + return to_file_base; } - string const outfile_base = RemoveExtension(temp_file); lyxerr[Debug::GRAPHICS] << "\tThe original file is " << orig_file << "\n" << "\tA copy has been made and convert is to be called with:\n" << "\tfile to convert = " << temp_file << '\n' - << "\toutfile_base = " << outfile_base << '\n' + << "\tto_file_base = " << to_file_base << '\n' << "\t from " << from << " to " << to << '\n'; // if no special converter defined, than we take the default one // from ImageMagic: convert from:inname.from to:outname.to - if (!converters.convert(&buf, temp_file, outfile_base, from, to)) { + if (!converters.convert(&buf, temp_file, to_file_base, from, to)) { string const command = "sh " + LibFileSearch("scripts", "convertDefault.sh") + ' ' + from + ':' + temp_file + ' ' + - to + ':' + outfile_base + '.' + to; + to + ':' + to_file_base + '.' + to; lyxerr[Debug::GRAPHICS] << "No converter defined! I use convertDefault.sh:\n\t" << command << endl; Systemcall one; one.startscript(Systemcall::Wait, command); - if (!IsFileReadable(ChangeExtension(outfile_base, to))) { + if (!IsFileReadable(ChangeExtension(to_file_base, to))) { string str = bformat(_("No information for converting %1$s " "format files to %2$s.\n" "Try defining a convertor in the preferences."), from, to); @@ -457,7 +515,7 @@ string const InsetGraphics::prepareFile(Buffer const & buf, } } - return RemoveExtension(temp_file); + return to_file_base; } diff --git a/src/support/ChangeLog b/src/support/ChangeLog index f9041cab91..bd049f820e 100644 --- a/src/support/ChangeLog +++ b/src/support/ChangeLog @@ -1,3 +1,13 @@ +2003-09-03 Angus Leeming + + * filename.[Ch] (FileName): new c-tor takes abs_filename arg. + (mangledFilename): new function, returning a mangled version of the + absolute file name, suitable for use in the temp dir when, for example, + converting an image file to another format. + + * filetools.[Ch] (copyFileToDir): removed. + (compare_timestamps): new function. + 2003-09-03 Angus Leeming * translator.h: Assert is in namespace lyx::support... @@ -22,7 +32,7 @@ 2003-07-29 Lars Gullik Bjønnes - * Makefile.am: contidionalize USE_COMPRESSION + * Makefile.am: conditionalize USE_COMPRESSION. 2003-07-28 Lars Gullik Bjønnes diff --git a/src/support/filename.C b/src/support/filename.C index fa23523d18..121925250e 100644 --- a/src/support/filename.C +++ b/src/support/filename.C @@ -13,6 +13,8 @@ #include "filename.h" #include "support/filetools.h" +#include "lstrings.h" +#include "LAssert.h" namespace lyx { @@ -24,6 +26,13 @@ FileName::FileName() {} +FileName::FileName(string const & abs_filename, bool save_abs) + : name_(abs_filename), save_abs_path_(save_abs) +{ + Assert(AbsolutePath(name_)); +} + + void FileName::set(string const & name, string const & buffer_path) { save_abs_path_ = AbsolutePath(name); @@ -49,6 +58,32 @@ string const FileName::outputFilename(string const & path) const } +string const FileName::mangledFilename() const +{ + string mname = os::slashify_path(name_); + // Remove the extension. + mname = ChangeExtension(name_, string()); + // Replace '/' in the file name with '_' + mname = subst(mname, "/", "_"); + // Replace '.' in the file name with '_' + mname = subst(mname, ".", "_"); + // Add the extension back on + return ChangeExtension(mname, GetExtension(name_)); +} + + +bool FileName::isZipped() const +{ + return zippedFile(name_); +} + + +string const FileName::unzippedFilename() const +{ + return unzippedFileName(name_); +} + + bool operator==(FileName const & lhs, FileName const & rhs) { return lhs.absFilename() == rhs.absFilename() && @@ -61,5 +96,5 @@ bool operator!=(FileName const & lhs, FileName const & rhs) return !(lhs == rhs); } -} //namespace support +} // namespace support } // namespace lyx diff --git a/src/support/filename.h b/src/support/filename.h index e3571be478..feba602a6b 100644 --- a/src/support/filename.h +++ b/src/support/filename.h @@ -22,11 +22,15 @@ namespace support { class FileName { public: FileName(); + /** \param filename the file in question. Must have an absolute path. + * \param save_abs_path how is the file to be output to file? + */ + FileName(string const & abs_filename, bool save_abs_path = true); /** \param filename the file in question. May have either a relative - or an absolute path. - \param buffer_path if \c filename has a relative path, generate - the absolute path using this. + * or an absolute path. + * \param buffer_path if \c filename has a relative path, generate + * the absolute path using this. */ void set(string const & filename, string const & buffer_path); @@ -39,6 +43,16 @@ public: string const relFilename(string const & buffer_path = string()) const; /// \param buf_path if empty, uses `pwd` string const outputFilename(string const & buf_path = string()) const; + /** \return a mangled version of the absolute file name, + * suitable for use in the temp dir when, for example, converting + * an image file to another format. + */ + string const mangledFilename() const; + + /// \return true if the file is compressed. + bool isZipped() const; + /// \return the absolute file name without its .gz, .z, .Z extension + string const unzippedFilename() const; private: string name_; diff --git a/src/support/filetools.C b/src/support/filetools.C index bf0ba61973..f87a0cf7e0 100644 --- a/src/support/filetools.C +++ b/src/support/filetools.C @@ -1134,10 +1134,18 @@ bool zippedFile(string const & name) } +string const unzippedFileName(string const & zipped_file) +{ + string const ext = GetExtension(zipped_file); + if (ext == "gz" || ext == "z" || ext == "Z") + return ChangeExtension(zipped_file, string()); + return "unzipped_" + zipped_file; +} + + string const unzipFile(string const & zipped_file) { - string const file = ChangeExtension(zipped_file, string()); - string const tempfile = tempName(string(), file); + string const tempfile = unzippedFileName(zipped_file); // Run gunzip string const command = "gunzip -c " + zipped_file + " > " + tempfile; Systemcall one; @@ -1333,43 +1341,29 @@ string const readBB_from_PSFile(string const & file) } -string const copyFileToDir(string const & path, string const & file_in) +int compare_timestamps(string const & file1, string const & file2) { - Assert(AbsolutePath(path)); - - // First, make the file path relative to path. - string file_out = MakeRelPath(path, NormalizePath(file_in)); - file_out = os::slashify_path(file_out); - - // Now generate a unique filename. - // Remove the extension. - file_out = ChangeExtension(file_out, string()); - // Replace '/' in the file name with '_' - file_out = subst(file_out, "/", "_"); - // Replace '.' in the file name with '_' - file_out = subst(file_out, ".", "_"); - // Append a unique ID -// static int id; -// file_out += '_' + tostr(id++); - // Add the extension back on - file_out = ChangeExtension(file_out, GetExtension(file_in)); - // Put this file in the buffer's temp dir - file_out = MakeAbsPath(file_out, path); + Assert(AbsolutePath(file1) && AbsolutePath(file2)); // If the original is newer than the copy, then copy the original // to the new directory. - FileInfo fi(file_in); - FileInfo fi2(file_out); - - bool success = true; - if (fi.exist()) { - if (!fi2.exist() || - difftime(fi.getModificationTime(), - fi2.getModificationTime()) >= 0) - success = copy(file_in, file_out); + FileInfo f1(file1); + FileInfo f2(file2); + + int cmp = 0; + if (f1.exist() && f2.exist()) { + double const tmp = difftime(f1.getModificationTime(), + f2.getModificationTime()); + if (tmp != 0) + cmp = tmp > 0 ? 1 : -1; + + } else if (f1.exist()) { + cmp = 1; + } else if (f2.exist()) { + cmp = -1; } - return success ? file_out : string(); + return cmp; } } //namespace support diff --git a/src/support/filetools.h b/src/support/filetools.h index 8203d3aaa7..d576a4f744 100644 --- a/src/support/filetools.h +++ b/src/support/filetools.h @@ -143,6 +143,9 @@ string const getExtFromContents(string const & name); /// check for zipped file bool zippedFile(string const & name); +/// \return the name that LyX will give to the unzipped file. +string const unzippedFileName(string const & zipped_file); + /// unzip a file string const unzipFile(string const & zipped_file); @@ -210,14 +213,14 @@ void removeAutosaveFile(string const & filename); /// read the BoundingBox entry from a ps/eps/pdf-file string const readBB_from_PSFile(string const & file); -/** Copy \c file to directory \c path. The file name is manipulated - so that eg some/path/to/file becomes some_path_to_file. - \param path where to put the file - \param file the file that is copied - \returns this file name if the file is copied successfully, else - \returns an empty string. +/** \param file1, file2 the two files to be compared. Must have absolute paths. + * \returns 1 if \c file1 has a more recent timestamp than \c file2, + * 0 if their timestamps are the same, + * -1 if \c file2 has a more recent timestamp than \c file1. + * If one of the files does not exist, the return value indicates the file + * which does exist. Eg, if \c file1 exists but \c file2 does not, return 1. */ -string const copyFileToDir(string const & path, string const & file); +int compare_timestamps(string const & file1, string const & file2); typedef std::pair cmd_ret; -- 2.39.2