2016-09-05 3 views
3

아래 스크립트는 CAM::PDF을 사용하여 PDF 파일에서 모든 이미지를 제거 할 수 있습니다. 그러나 출력이 손상되었습니다. 그럼에도 불구하고 PDF 리더는 열 수는 있지만 오류에 대해 불평합니다. 예를 들어, mupdf 말한다 :CAM :: PDF를 사용하여 손상되지 않고 PDF에서 모든 이미지를 삭제하는 방법?

error: no XObject subtype specified 
error: cannot draw xobject/image 
warning: Ignoring errors during rendering 
mupdf: warning: Errors found on page 

지금, CPAN에서 CAM::PDF 페이지 (here는) 아마도 그것이 공공의 사용을위한 것 아니에요 의미 "깊은 유틸리티"에서 deleteObject() 방법을 보여줍니다. 또한 다음과 같이 경고합니다.

이 함수는이 개체에 대한 종속성을 처리하지 않습니다.

제 질문은 CAM::PDF을 사용하여 PDF 파일에서 개체를 제거하는 올바른 방법은 무엇입니까? 문제가 종속성과 관련된 경우 종속성을 처리하는 동안 객체를 제거하려면 어떻게해야합니까?

다른 도구를 사용하여 PDF에서 이미지를 제거하는 방법은 관련 질문 here을 참조하십시오.

use CAM::PDF;  
my $pdf = new CAM::PDF (shift) or die $CAM::PDF::errstr; 

foreach my $objnum (sort { $a <=> $b } keys %{ $pdf->{xref} }) { 
    my $xobj = $pdf->dereference ($objnum); 

    if ($xobj->{value}->{type} eq 'dictionary') { 
    my $im = $xobj->{value}->{value}; 
    if 
    (
     defined $im->{Type} and defined $im->{Subtype} 
     and $pdf->getValue ($im->{Type} ) eq 'XObject' 
     and $pdf->getValue ($im->{Subtype}) eq 'Image' 
    ) 
    { 
     $pdf->deleteObject ($objnum); 
    } 
    } 
} 

$pdf->cleanoutput ('-'); 
+0

mupdf 오류를 사용할 수있는 손상된 PDF 파일이 있습니까? 비슷한 문제를 디버깅 중이며 큰 도움이 될 것입니다. – Darajan

답변

4

이것은 CAM :: PDF를 사용하지만 약간 다른 접근 방식을 취합니다. 이미지를 지우려고 시도하는 것이 아니라, 각 이미지를 투명 이미지로 대체합니다.

첫째, 우리는 투명한 이미지만을 포함하지 않는 빈 PDF를 생성하는 이미지 매직을 사용할 수 있습니다 : 우리는 텍스트 편집기에서 생성 된 PDF를 볼 경우

% convert -size 200x100 xc:none transparent.pdf 

, 우리는 주요 이미지를 찾을 수 있습니다 객체 :

8 0 obj 
<< 
/Type /XObject 
/Subtype /Image 
/Name /Im0 
... 

여기서 주목해야 할 중요한 것은 우리가 개체 번호와 같은 투명한 이미지를 생성 한 것입니다 8. ​​

그 다음 꼬마 도깨비의 문제가된다 이 오브젝트를 오팅하여 PDF의 실제 이미지 각각을 대체하여 효과적으로 블랭킹합니다.

use warnings; use strict; 
use CAM::PDF;  
my $pdf = new CAM::PDF (shift) or die $CAM::PDF::errstr; 

my $trans_pdf = CAM::PDF->new("transparent.pdf") || die "$CAM::PDF::errstr\n"; 
my $trans_objnum = 8; # object number of transparent image 

foreach my $objnum (sort { $a <=> $b } keys %{ $pdf->{xref} }) { 
    my $xobj = $pdf->dereference ($objnum); 

    if ($xobj->{value}->{type} eq 'dictionary') { 
    my $im = $xobj->{value}->{value}; 
    if 
    (
     defined $im->{Type} and defined $im->{Subtype} 
     and $pdf->getValue ($im->{Type} ) eq 'XObject' 
     and $pdf->getValue ($im->{Subtype}) eq 'Image' 
    ) { 
     $pdf->replaceObject ($objnum, $trans_pdf, $trans_objnum, 1); 
    } 
    } 
} 

$pdf->cleanoutput ('-'); 

이 스크립트는 이제 가져온 투명 이미지 객체 (transparent.pdf에서 개체 번호 8)와 PDF에서 각 이미지를 대체합니다.

+0

왜 8인가요? 그거 어디서 났어? 원본 문서의 객체 번호 8을 투명한 이미지로 대체하지는 않습니까? –

+0

@ .n.r. 8은'transparent.pdf'에서 가져올 이미지의 객체 번호입니다. 대답에 대한 설명을 추가했습니다. – dwarring

2

정말 이미지를 삭제하는 또 다른 방법은 다음과 같습니다 자원 목록에서

  1. 발견 및 삭제 이미지 XObjects는
  2. 이름을 삭제 자원의,
  3. 대신에 배열을 유지 동일한 길이의 각 페이지 콘텐츠의 Do 연산자에 대한 공백,
  4. 을 청소하고 인쇄하십시오.

마지막으로 $doc->cleanse을 호출 할 필요가 없으므로 dwarring의 접근 방식이 더 안전하다는 점에 유의하십시오.CAM::PDF 문서 (here)는 cleanse 방법

제거되지 않는 객체에 따르면. 경고 :이 함수는 페이지 모델 계층 구조의 일부분이지만 어쨌든 필요합니다 (일부 글꼴 정의 객체와 같은) 객체를 제거하기 때문에 일부 PDF 문서를 손상시킵니다.

cleanse을 사용하면 문제가 얼마나되는지 알 수 없습니다.

use CAM::PDF; 
my $doc = new CAM::PDF (shift) or die $CAM::PDF::errstr; 

# delete image XObjects among resources 
# but keep their names 

my @names; 

foreach my $objnum (sort { $a <=> $b } keys %{ $doc->{xref} }) { 
    my $obj = $doc->dereference($objnum); 
    next unless $obj->{value}->{type} eq 'dictionary'; 

    my $n = $obj->{value}->{value}; 

    my $resources = $doc->getValue ($n->{Resources}  ) or next; 
    my $resource = $doc->getValue ($resources->{XObject}) or next; 

    foreach my $name (sort keys $resource) { 
    my $im = $doc->getValue ($resource->{$name}) or next; 

    next unless defined $im->{Type} 
      and defined $im->{Subtype} 
      and $doc->getValue ($im->{Type} ) eq 'XObject' 
      and $doc->getValue ($im->{Subtype}) eq 'Image'; 

    delete $resource->{$name};                           
    push @names, $name;                             
    }                                  
}                                   


# delete the corresponding Do operators                               

if (@names) {                                        
    foreach my $p (1 .. $doc->numPages) {                                  
    my $content = $doc->getPageContent ($p); 
    my $s; 
    foreach my $name (@names) { 
     ++$s if $content =~ s{(/ \Q$name\E \s+ Do \b)} { ' ' x length $1 }xeg; 
    } 
    $doc->setPageContent ($p, $content) if $s; 
    } 
} 

$doc->cleanse; 
$doc->cleanoutput;