Esempio n. 1
0
        public static MemoryStream RenderPDFPage(string pdf_filename, int page_number, int dpi, int height, int width, string password, ProcessPriorityClass priority_class)
        {
            WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

            render_count++;

            string process_parameters = String.Format(
                $"draw -q -w {width} -h {height} -r {dpi} -o -"
                + " " + (String.IsNullOrEmpty(password) ? "" : "-p " + password)
                + " " + '"' + pdf_filename + '"'
                + " " + page_number
                );

            string exe = Path.GetFullPath(Path.Combine(UnitTestDetector.StartupDirectoryForQiqqa, @"MuPDF/mutool.exe"));

            if (!File.Exists(exe))
            {
                throw new Exception($"PDF Page Rendering: missing modern MuPDF 'mudraw.exe': it does not exist in the expected path: '{exe}'");
            }
            if (!File.Exists(pdf_filename))
            {
                throw new Exception($"PDF Page Rendering: INTERNAL ERROR: missing PDF: it does not exist in the expected path: '{pdf_filename}'");
            }

            ExecResultAggregate rv = ReadEntireStandardOutput(exe, process_parameters, binary_output: true, priority_class);

            if (rv.error != null)
            {
                rv.stdoutStream?.Close();
                throw rv.error;
            }
            return(rv.stdoutStream);
        }
Esempio n. 2
0
        private static ExecResultAggregate ReadEntireStandardOutput(string pdfDrawExe, string process_parameters, bool binary_output, ProcessPriorityClass priority_class)
        {
            WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

            ExecResultAggregate rv = new ExecResultAggregate
            {
                executable         = pdfDrawExe,
                process_parameters = process_parameters,
                stdoutIsBinary     = binary_output
            };

            Stopwatch clk = Stopwatch.StartNew();

            // STDOUT/STDERR
            Logging.Debug("PDFDRAW :: ReadEntireStandardOutput command: pdfdraw.exe {0}", process_parameters);
            using (Process process = ProcessSpawning.SpawnChildProcess(pdfDrawExe, process_parameters, priority_class, stdout_is_binary: true))
            {
                using (ProcessOutputReader process_output_reader = new ProcessOutputReader(process, stdout_is_binary: true))
                {
                    // Read image from stdout
                    using (StreamReader sr = process.StandardOutput)
                    {
                        using (FileStream fs = (FileStream)sr.BaseStream)
                        {
                            long elapsed = clk.ElapsedMilliseconds;
                            Logging.Debug("PDFDRAW :: ReadEntireStandardOutput setup time: {0} ms for parameters:\n    {1}", elapsed, process_parameters);

                            rv.stdoutStream = new MemoryStream(1024 * 1024);
                            int total_size = StreamToFile.CopyStreamToStream(fs, rv.stdoutStream);

                            long elapsed2 = clk.ElapsedMilliseconds;
                            Logging.Debug("PDFDRAW image output {0} bytes in {1} ms (output copy took {2} ms) for command:\n    {4} {3}", total_size, elapsed2, elapsed2 - elapsed, process_parameters, pdfDrawExe);

                            // Check that the process has exited properly
                            process.WaitForExit(1000);

                            if (!process.HasExited)
                            {
                                Logging.Debug("PDFRenderer process did not terminate, so killing it.\n{0}", process_output_reader.GetOutputsDumpStrings().stderr);

                                try
                                {
                                    process.Kill();

                                    // wait for the completion signal; this also helps to collect all STDERR output of the application (even while it was KILLED)
                                    process.WaitForExit(3000);
                                }
                                catch (Exception ex)
                                {
                                    Logging.Error(ex, "There was a problem killing the PDFRenderer process after timeout ({0} ms)", elapsed2 + 1000);
                                }

                                // grab stderr output for successful runs and log it anyway: MuPDF diagnostics, etc. come this way:
                                var outs = process_output_reader.GetOutputsDumpStrings();
                                rv.errOutputDump = outs;

                                Logging.Error($"PDFRenderer process did not terminate, so killed it. Commandline:\n    {pdfDrawExe} {process_parameters}\n{outs.stderr}");

                                rv.error    = new ApplicationException($"PDFRenderer process did not terminate, so killed it.\n    Commandline: {pdfDrawExe} {process_parameters}");
                                rv.exitCode = 0;
                                if (process.HasExited)
                                {
                                    rv.exitCode = process.ExitCode;
                                }
                                if (rv.exitCode == 0)
                                {
                                    rv.exitCode = -666;  // timeout
                                }
                            }
                            else if (process.ExitCode != 0)
                            {
                                // grab stderr output for successful runs and log it anyway: MuPDF diagnostics, etc. come this way:
                                var outs = process_output_reader.GetOutputsDumpStrings();
                                rv.errOutputDump = outs;

                                Logging.Error("PDFDRAW did fail with exit code {0} for commandline:\n    {3} {1}\n{2}", process.ExitCode, process_parameters, outs.stderr, pdfDrawExe);

                                rv.error    = new ApplicationException($"PDFRenderer::PDFDRAW did fail with exit code {process.ExitCode}.\n    Commandline: {pdfDrawExe} {process_parameters}");
                                rv.exitCode = process.ExitCode;
                            }
                            else
                            {
                                // grab stderr output for successful runs and log it anyway: MuPDF diagnostics, etc. come this way:
                                var outs = process_output_reader.GetOutputsDumpStrings();
                                rv.errOutputDump = outs;

                                Logging.Error("PDFDRAW did SUCCEED with exit code {0} for commandline:\n    {3} {1}\n{2}", process.ExitCode, process_parameters, outs.stderr, pdfDrawExe);

                                rv.error    = null;
                                rv.exitCode = process.ExitCode;
                            }

                            return(rv);
                        }
                    }
                }
            }
        }