2017-12-14 9 views
0

Ghostscript.Net을 사용하여 PostScript에서 PDF로 변환기를 만들려고합니다. GetArgs가 반환하는 Args는 일반적으로 gswin32c.exe를 호출 할 때 사용하는 Args이며 제대로 작동합니다.gsapi_init_with_args가 만들어졌습니다 : -100

하지만 내가 Process를 호출 할 때마다 "gsapi_init_with_args '호출이 만들어 질 때 오류가 발생했습니다 : -100"입니다. 그 오류를 인터넷으로 검색해도 아무 것도 제기하지 않았으므로 여기에서 물을 수도 있습니다.

Ghostscript.net에서 .dll을 직접 호출 할 때 고려해야 할 다른 인수가 있습니까? 또는 다른 곳에서 실수를 했습니까?

public class PdfConverter 
{ 
    #region Private Fields 
    private List<GhostscriptVersionInfo> _Versions = GhostscriptVersionInfo.GetInstalledVersions(GhostscriptLicense.GPL | GhostscriptLicense.AFPL | GhostscriptLicense.Artifex); 
    #endregion 


    #region Private Properties 
    private GhostscriptVersionInfo Version { get; set; } 
    #endregion 


    #region Construction 
    public PdfConverter() 
    { 
     Version = GhostscriptVersionInfo.GetLastInstalledVersion(); 
    } 
    #endregion 


    #region Public Members 
    public bool ConvertToPdf(DirectoryInfo dir) 
    { 
     var d = dir; 
     if(!d.Exists) 
      return false; 

     var postScriptFiles = d.GetFiles("*.ps"); 
     var pdfFiles  = postScriptFiles.Select(psf => new FileInfo(Path.ChangeExtension(psf.FullName, ".pdf"))); 

     foreach(var file in postScriptFiles) { 
      //ThreadPool.QueueUserWorkItem(new WaitCallback((o) => { 
       Process(file, new FileInfo(Path.ChangeExtension(file.FullName, ".pdf"))); 
      //})); 
     } 

     pdfFiles.ForEach(pdf => pdf?.Refresh()); 
     return pdfFiles.All(pdf => pdf.Exists); 
    } 
    #endregion 


    #region Private Helpers 
    private void Process(FileInfo inputFile, FileInfo outputFile) 
    { 
     Console.WriteLine($"Converting {inputFile} to {outputFile}"); 
     var proc = new GhostscriptProcessor(Version, true); 
     proc.Process(GetArgs(inputFile, outputFile).ToArray(), new ConsoleStdIO(true, true, true)); 
    } 


    private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile) 
    { 
     return new [] { 
      $"-q ", 
      $"-sDEVICE=pdfwrite", 
      $"-dSAFER", 
      $"-dNOPAUSE", 
      $"-dBATCH", 
      $"-sPAPERSIZE=a4", 
      $"-dEmbedAllFonts=true", 
      $"-dAutoRotatePages=/None", 
      $"-sOutputFile=\"{outputFile.FullName}\"", 
      $"-dCompatibilityLevel#1.4", 
      $"-c .setpdfwrite", 
      $"-f \"{inputFile.FullName}\"" 
     }; 
    } 
    #endregion 
} 

편집 :

여기 내 클래스의 내가 얘기를 깜빡 했네요 : 난 내 자신의 GhostsdcriptStdIO 클래스를했습니다를 구현하려면. 나는 내가이 권리를하는지 완전히 확신하지 못한다는 것을 인정한다. 예외없이 인스턴스화되고 StdOut (...) get이 호출 된 것을 오버라이드하지만 예상대로 출력이 콘솔에 기록됩니다. override void StdError (...) get이 호출되었습니다. 그리고 expeted으로 콘솔에 기록됩니다. 오류 btw의 출력은 다음과 같습니다.

"****"c : \ temp \ test.pdf "파일을 열 수 없습니다." "**** 초기 장치를 열 수 없습니다."

public class ConsoleStdIO : Ghostscript.NET.GhostscriptStdIO 
{ 
    #region Construction 
    public ConsoleStdIO(bool handleStdIn, bool handleStdOut, bool handleStdError) : base(handleStdIn, handleStdOut, handleStdError) { } 
    #endregion 


    #region Overrides 
    public override void StdError(string error) 
    { 
     var foo = Encoding.Default.GetBytes(error); 
     var lenght = foo.Length; 

     using (var err = Console.OpenStandardError()) { 
      if(err.CanWrite) 
       err.Write(foo, 0, lenght); 
     } 
    } 

    public override void StdIn(out string input, int count) 
    { 
     byte[] bytes = new byte[0]; 
     using(var stdInput = Console.OpenStandardInput()) { 
      stdInput.Read(bytes, 0, count); 
     } 
     input = Encoding.Default.GetString(bytes); 
    } 

    public override void StdOut(string output) 
    { 
     var foo = Encoding.Default.GetBytes(output); 
     var lenght = foo.Length; 

     using (var err = Console.OpenStandardError()) { 
      if(err.CanWrite) 
       err.Write(foo, 0, lenght); 
     }   
    } 
    #endregion 
} 

다시 : 동일한 파일과 인수 gswin32c.exe 잘 작동 사용하여 동일한 작업을 수행

여기 내 ConsoleStdIO 클래스입니다. 해피 해킹

답변

2

오류 -100은 '무언가 대재앙이 잘못되었습니다'라는 의미의 gs_error_Fatal입니다. 프로그램이 제대로 시작되지 못했고 그 이유를 알 수 없습니다. 뒷 채널은 더 많은 정보를 포함 할 수 있습니다.

그리고 실제로 백 채널은 무엇이 잘못되었는지를 알려줍니다 :

**** 파일을 열 수 없습니다 "C : \ 임시 \에있는 test.pdf **** 초기 장치를 열 수 없습니다, 종료 .

고스트 (즉 출력 파일이 필요하기 때문에) 따라서 그 동작을 중단는으로, pdfwrite 장치를 열 수없는 즉, 출력 파일을 열 수 없다.

이 다수있을 수 Ghostscript가 출력 파일을 열 수없는 이유는 무엇입니까? 인수의 수를 줄이십시오.

문제를 디버그하려고 할 때 -q (조용함)을 원하지 않으면 원하는 모든 정보를 원할 것입니다.

최소한 Ghostscript가 현재 작업 디렉토리 및 특정 '특수'디렉토리 외부의 디렉토리에 액세스하지 못하게하기 때문에 적어도 시작하려면 -dSAFER을 제거해야합니다. temp 디렉토리에 액세스하는 것을 막을 수 있습니다.

EmbedAllFonts을 기본값과 동일한 값으로 설정할 필요가 없습니다.

CompatibilityLevel (=) 대신 # 스위치를 사용하고이 스위치가 작동하는 동안 AutoRotatePages 스위치를 누를 수 있습니다.

"-c .setpdfwrite -f"문자열은 수년 동안 무의미했지만 사람들은 계속 사용하고 있습니다. 요즘에는 처리 시작이 느려지고 버려집니다.

마지막으로 문자열 처리가 엉망인 경우를 대비하여 백 슬래시 ('\') 문자를 슬래시 ('/')로 변경하거나 두 개의 백 슬래시 (나 슬래시를 직접 사용)를 사용할 수 있습니다.

또한 c : \ test \ temp.pdf가 존재하지 않거나 존재하지 않는 경우 읽기 전용이 아니거나 이미 다른 응용 프로그램에서 열려 있는지 확인해야합니다.

+0

그러나 한편으로는 Freenode에 #chsarp의 사용자가 Ghostscript.NET의 소스 코드의 버그로 저를 지적 :

그래서이 작업 GetArgs (...)의 모습입니다 https : //로 github.com/jhabjan/Ghostscript.NET/blob/6c74b1e416dea215754c8679fcc1f3caf0b085c3/Ghostscript.NET/Processor/GhostscriptProcessor.cs#L282 시스템 기본값 인 args를 인코딩하지만 UTF8이어야합니다. 어쨌든 Ghostscript.NET의 소스 코드를 다운로드하고 변경했습니다. 그러나 작동하지 않았습니다. 그리고 정의되지 않은 파일 이름 오류는별로 의미가 없습니다. 파일이 존재하고 내 임시 폴더가 확실히 특별한 것이 아니기 때문에 나는 그것을 만들었습니다. – Mathew

+0

첫 번째 의견 : 내가 말했듯이 스위치를 모두 제거했는데 다음 오류가 발생합니다./undefinedfilename in ("C : \\ temp \\ pdftest \\ temp1.ps") – Mathew

+0

세 번째 메모 : 여기에 전체 오류 메시지 : https : //pastebin.com/n9efzBRa – Mathew

0

그래서 문제를 해결했습니다 ...
KenS의 조언을 듣고 나서 Ghostscript (Ghostscript.NET이 아님)를 실행하면 오류가 발생합니다. 그러나 실제 PDF 파일은 생성되지 않았습니다.

KenS의 대답은 문제를 해결하지 못했지만 'less is more'이후로 IRC에서 내 args가 정확하다는 것을 확인하기 위해 시간을내어 대답 포인트를 줄 것입니다. 그럼에도 불구하고. 실제로 해결 무엇

내이었다 다음
여기 내 원래 GetArgs (...) #csharp에서

private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile) 
    { 
     return new [] { 
      $"-sDEVICE=pdfwrite", 
      $"-dNOPAUSE", 
      $"-dBATCH", 
      $"-sPAPERSIZE=a4", 
      @"-sFONTPATH=" + System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts), 
      $"-sOutputFile={outputFile.FullName}", 
      $"{inputFile.FullName}", 
     }; 
    } 

누군가가 C에서, 첫 번째 인수는 항상 이름임을 나에게 지적 명령의. 그래서 그는 "gs"를 첫 번째 인수 (더미)로 넣고 시도해 보라고 제안했습니다 ... 그리고 그것이 내 문제를 실제로 해결 한 것입니다.

private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile) 
    { 
     return new [] { 
      $"gs", 
      $"-sDEVICE=pdfwrite", 
      $"-dNOPAUSE", 
      $"-dBATCH", 
      $"-sPAPERSIZE=a4", 
      @"-sFONTPATH=" + System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts), 
      $"-sOutputFile={outputFile.FullName}", 
      $"{inputFile.FullName}", 
     }; 
    }