2016-09-05 4 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 
... 

ここで注意すべき重要なことは、それはその後、IMPの問題となっオブジェクト番号8

として、我々は透明の画像を生成していることですこのオブジェクトをortingし、それを使用して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を呼び出す必要がないので、ドワーリングのアプローチはより安全です。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; 
関連する問題