/// <summary>
        /// Process the input PDF file by compressing images and/or by converting color to CMYK.  The operations
        /// to perform are established by the constructor.
        /// </summary>
        public void ProcessPdfFile(string inputFile, string outputFile)
        {
            _inputPdfPath  = inputFile;
            _outputPdfPath = outputFile;
            var exePath = "/usr/bin/gs";

            if (SIL.PlatformUtilities.Platform.IsWindows)
            {
                exePath = FindGhostcriptOnWindows();
            }
            if (!String.IsNullOrWhiteSpace(exePath) && File.Exists(exePath))
            {
                if (_worker != null)
                {
                    _worker.ReportProgress(0, GetSpecificStatus());
                }
                using (var tempPdfFile = TempFile.WithExtension(".pdf"))
                {
                    var runner        = new CommandLineRunner();
                    var arguments     = GetArguments(tempPdfFile.Path);
                    var fromDirectory = String.Empty;
                    var progress      = new NullProgress();                     // I can't figure out how to use any IProgress based code, but we show progress okay as is.
                    var res           = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress, ProcessGhostcriptReporting);
                    if (res.DidTimeOut || !RobustFile.Exists(tempPdfFile.Path))
                    {
                        if (_inputPdfPath != _outputPdfPath)
                        {
                            RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                        }
                        return;
                    }
                    // If the process made the file larger and didn't change the color scheme, ignore the result.
                    var oldInfo = new FileInfo(_inputPdfPath);
                    var newInfo = new FileInfo(tempPdfFile.Path);
                    if (newInfo.Length < oldInfo.Length || _type == OutputType.Printshop)
                    {
                        RobustFile.Copy(tempPdfFile.Path, _outputPdfPath, true);
                    }
                    else if (_inputPdfPath != _outputPdfPath)
                    {
                        RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                    }
                }
            }
            else
            {
                // This shouldn't happen.  Linux Bloom package depends on the ghostscript package, and we'll include
                // ghostscript files in our installer to ensure it's available on Windows.  But we have this code here
                // as a failsafe fallback reminding the developers to ensure this installation work happens.
                Debug.WriteLine("ghostscript is not installed, so Bloom cannot process the PDF file.");
                if (_inputPdfPath != _outputPdfPath)
                {
                    RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                }
            }
        }
        /// <summary>
        /// Process the input PDF file by compressing images and/or by converting color to CMYK.  The operations
        /// to perform are established by the constructor.
        /// </summary>
        public void ProcessPdfFile(string inputFile, string outputFile, bool removeEvenPages = false)
        {
            _inputPdfPath  = inputFile;
            _outputPdfPath = outputFile;
            var exePath = "/usr/bin/gs";

            if (SIL.PlatformUtilities.Platform.IsWindows)
            {
                exePath = FindGhostcriptOnWindows();
            }
            if (!String.IsNullOrWhiteSpace(exePath) && File.Exists(exePath))
            {
                if (_worker != null)
                {
                    _worker.ReportProgress(0, GetSpecificStatus());
                }
                using (var tempPdfFile = TempFile.WithExtension(".pdf"))
                {
                    var runner        = new CommandLineRunner();
                    var arguments     = GetArguments(tempPdfFile.Path, null, removeEvenPages);
                    var fromDirectory = String.Empty;
                    var progress      = new NullProgress();                     // I can't figure out how to use any IProgress based code, but we show progress okay as is.
                    var res           = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress, ProcessGhostcriptReporting);
                    if (res.ExitCode != 0)
                    {
                        // On Linux, ghostscript doesn't deal well with some Unicode filenames.  Try renaming the input
                        // file temporarily to something innocuous to see if this makes the ghostscript process succeed.
                        // See https://issues.bloomlibrary.org/youtrack/issue/BL-7177.
                        using (var tempInputFile = TempFile.WithExtension(".pdf"))
                        {
                            RobustFile.Delete(tempInputFile.Path);                                      // Move won't replace even empty files.
                            RobustFile.Move(_inputPdfPath, tempInputFile.Path);
                            arguments = GetArguments(tempPdfFile.Path, tempInputFile.Path, removeEvenPages);
                            res       = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress, ProcessGhostcriptReporting);
                            RobustFile.Move(tempInputFile.Path, _inputPdfPath);
                        }
                    }
                    if (res.ExitCode != 0 || res.DidTimeOut || !RobustFile.Exists(tempPdfFile.Path))
                    {
                        if (_inputPdfPath != _outputPdfPath)
                        {
                            RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                        }
                        return;
                    }
                    // If the process made the file larger and didn't change the color scheme and we're not removing blank pages, ignore the result.
                    var oldInfo = new FileInfo(_inputPdfPath);
                    var newInfo = new FileInfo(tempPdfFile.Path);
                    if (newInfo.Length < oldInfo.Length || _type == OutputType.Printshop || removeEvenPages)
                    {
                        RobustFile.Copy(tempPdfFile.Path, _outputPdfPath, true);
                    }
                    else if (_inputPdfPath != _outputPdfPath)
                    {
                        RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                    }
                }
            }
            else
            {
                // This shouldn't happen.  Linux Bloom package depends on the ghostscript package, and we'll include
                // ghostscript files in our installer to ensure it's available on Windows.  But we have this code here
                // as a failsafe fallback reminding the developers to ensure this installation work happens.
                Debug.WriteLine("ghostscript is not installed, so Bloom cannot process the PDF file.");
                if (_inputPdfPath != _outputPdfPath)
                {
                    RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                }
            }
        }
예제 #3
0
        public void MakePdf(PdfMakingSpecs specs, Control owner, BackgroundWorker worker,
                            DoWorkEventArgs doWorkEventArgs)
        {
            _worker = worker;
#if !__MonoCS__
            // Mono doesn't current provide System.Printing.  Leave the 'if' here to emphasize the
            // system specific nature of the following check.
            if (Platform.IsWindows)
            {
                // Check whether we have a default printer set (or for that matter, any printers).
                // Gecko on Windows requires a default printer for any print operation, even one
                // to a file.  See https://jira.sil.org/browse/BL-1237.
                string errorMessage = null;
                System.Printing.LocalPrintServer printServer = null;
                try
                {
                    printServer = new System.Printing.LocalPrintServer();
                }
                catch (Exception)                 // System.Printing.PrintQueueException isn't in our System.Printing assembly, so... using Exception
                {
                    // http://issues.bloomlibrary.org/youtrack/issue/BL-4060
                    Logger.WriteEvent("reproduced BL-4060 when trying to create LocalPrinterServer");
                }
                if (printServer == null || !printServer.GetPrintQueues().Any())
                {
                    errorMessage = GetNoDefaultPrinterErrorMessage();
                }
                else
                {
                    System.Printing.PrintQueue defaultPrinter;
                    // BL-2535 it's possible get past the above printQueues.Any() but then get
                    // a System.Printing.PrintQueueException exception with "Access Denied" error here, if
                    // the default printer for some reason is no longer "allowed".
                    try
                    {
                        defaultPrinter = System.Printing.LocalPrintServer.GetDefaultPrintQueue();

                        if (defaultPrinter == null || String.IsNullOrEmpty(defaultPrinter.FullName))
                        {
                            errorMessage = GetNoDefaultPrinterErrorMessage();
                        }
                    }
                    catch (Exception error)                    // System.Printing.PrintQueueException isn't in our System.Printing assembly, so... using Exception
                    {
                        defaultPrinter = null;
                        errorMessage   = L10NSharp.LocalizationManager.GetString(@"PublishTab.PDF.Error.PrinterError",
                                                                                 "Bloom requires access to a printer in order to make a PDF, even though you are not printing.  Windows gave this error when Bloom tried to access the default printer: {0}",
                                                                                 @"Error message displayed in a message dialog box");
                        errorMessage = string.Format(errorMessage, error.Message);
                    }
                }

                if (errorMessage != null)
                {
                    var exception = new ApplicationException(errorMessage);
                    // Note that if we're being run by a BackgroundWorker, it will catch the exception.
                    // If not, but the caller provides a DoWorkEventArgs, pass the exception through
                    // that object rather than throwing it.
                    if (worker != null || doWorkEventArgs == null)
                    {
                        throw exception;
                    }
                    doWorkEventArgs.Result = exception;
                    return;
                }
            }
#endif
            if (_worker != null)
            {
                _worker.ReportProgress(0, L10NSharp.LocalizationManager.GetString(@"PublishTab.PdfMaker.MakingFromHtml",
                                                                                  "Making PDF from HTML",
                                                                                  @"Message displayed in a progress report dialog box"));
            }

            var    runner = new CommandLineRunner();
            string exePath;
            var    bldr = new StringBuilder();
            // Codebase is reliable even when Resharper copies the EXE somewhere else for testing.
            var execDir       = BloomFileLocator.GetCodeBaseFolder();
            var fromDirectory = String.Empty;
            var filePath      = Path.Combine(execDir, "BloomPdfMaker.exe");
            if (!RobustFile.Exists(filePath))
            {
                var msg = LocalizationManager.GetString("InstallProblem.BloomPdfMaker",
                                                        "A component of Bloom, BloomPdfMaker.exe, seems to be missing. This prevents previews and printing. Antivirus software sometimes does this. You may need technical help to repair the Bloom installation and protect this file from being deleted again.");
                throw new FileNotFoundException(msg, "BloomPdfMaker.exe");                 // must be this class to trigger the right reporting mechanism.
            }
            if (Platform.IsMono)
            {
                exePath = Path.ChangeExtension(filePath, "sh");
            }
            else
            {
                exePath = filePath;
            }

            SetArguments(bldr, specs);
            var arguments = bldr.ToString();
            var progress  = new NullProgress();
            var res       = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress,
                                         ProcessGeckofxReporting);
            if (res.DidTimeOut || !RobustFile.Exists(specs.OutputPdfPath))
            {
                Logger.WriteEvent(@"***ERROR PDF generation failed: res.StandardOutput = " + res.StandardOutput);

                var msg = L10NSharp.LocalizationManager.GetString(@"PublishTab.PDF.Error.Failed",
                                                                  "Bloom was not able to create the PDF file ({0}).{1}{1}Details: BloomPdfMaker (command line) did not produce the expected document.",
                                                                  @"Error message displayed in a message dialog box. {0} is the filename, {1} is a newline character.");

                // This message string is intentionally separate because it was added after the previous string had already been localized in most languages.
                // It's not useful to add if we're already in save memory mode.
                var msg2 = specs.SaveMemoryMode ? "" : L10NSharp.LocalizationManager.GetString(@"PublishTab.PDF.Error.TrySinglePage",
                                                                                               "The book's images might have exceeded the amount of RAM memory available. Please turn on the \"Use Less Memory\" option which is slower but uses less memory.",
                                                                                               @"Error message displayed in a message dialog box") + Environment.NewLine;

                var fullMsg = String.Format(msg, specs.OutputPdfPath, Environment.NewLine) + Environment.NewLine +
                              msg2 + res.StandardOutput;

                var except = new ApplicationException(fullMsg);
                // Note that if we're being run by a BackgroundWorker, it will catch the exception.
                // If not, but the caller provides a DoWorkEventArgs, pass the exception through
                // that object rather than throwing it.
                if (worker != null || doWorkEventArgs == null)
                {
                    throw except;
                }
                else
                {
                    doWorkEventArgs.Result = except;
                }
            }
        }
예제 #4
0
        /// <summary>
        ///
        /// </summary>
        /// <returns>false if it couldn't start</returns>
        public bool Start()
        {
            try
            {
                foreach (var hg in Process.GetProcessesByName("hg"))
                {
                    //EventLog.WriteEntry("Application", "Killing old hg...", EventLogEntryType.Information);
                    hg.Kill();
                    if (!hg.WaitForExit(10000))
                    {
                        //EventLog.WriteEntry("Application", "ChorusHub was unable to stop an old hg from running. It will now give up. You should stop the server and run it again after killing whatever 'hg.exe' process is running.", EventLogEntryType.Error);
                        return(false);
                    }
                }


                //we make directories based on what we see in there, so start it afresh lest we re-create folder names
                //that the user long ago stopped using

                if (File.Exists(AccessLogPath))
                {
                    File.Delete(AccessLogPath);
                }

                if (!Directory.Exists(_rootFolder))
                {
                    Directory.CreateDirectory(_rootFolder);
                }

                //EventLog.WriteEntry("Application", "Starting Mercurial Server", EventLogEntryType.Information);

                WriteConfigFile(_rootFolder);

                var arguments = "serve -A accessLog.txt -E log.txt -p " + Port + " --verbose ";

                //const float kHgVersion = (float)1.5;
                //if (kHgVersion < 1.9)
                //{
                arguments += "--webdir-conf hgweb.config";
                //}
                //else
                //{
                //	arguments += "--web-conf hgweb.config";
                //}

#if CommandWindow
                _hgServeProcess = new Process();
                _hgServeProcess.StartInfo.WorkingDirectory       = _rootFolder;
                _hgServeProcess.StartInfo.FileName               = Chorus.MercurialLocation.PathToHgExecutable;
                _hgServeProcess.StartInfo.Arguments              = arguments;
                _hgServeProcess.StartInfo.ErrorDialog            = true;
                _hgServeProcess.StartInfo.UseShellExecute        = false;
                _hgServeProcess.StartInfo.RedirectStandardOutput = true;
                _hgServeProcess.Start();
#else
                _hgServeThread = new Thread(() =>
                {
                    var commandLineRunner = new CommandLineRunner();
                    try
                    {
                        var progress = new ConsoleProgress();
                        commandLineRunner.Start(
                            Chorus.MercurialLocation.PathToHgExecutable,
                            arguments,
                            Encoding.UTF8, _rootFolder, -1,
                            progress, s => progress.WriteMessage(s));
                    }
                    catch (ThreadAbortException)
                    {
                        //Progress.WriteVerbose("Hg Serve command Thread Aborting (that's normal when stopping)");
                        try
                        {
                            if (!commandLineRunner.Abort(1))
                            {
                                //EventLog.WriteEntry("Application", "Hg Serve might not have closed down.", EventLogEntryType.Information);
                            }
                        }
                        catch { }
                    }
                });
                _hgServeThread.Start();
#endif

                return(true);
            }
            catch
            {
                //EventLog.WriteEntry("Application", error.Message, EventLogEntryType.Error);
                return(false);
            }
        }