PDF圧縮の最適化

いくつかのPDFファイルは、最高でない画像圧縮を使っています。このページは、ファイルを再圧縮/再生成することによって解決するいくつかの方法を列挙します。ただ、損失なく圧縮できない場合には、大きなファイルを投稿する方がいいです。

Contents

方法

PDF Split and Mergeを使う

このプログラムの情報については、PDFのロックを外す#PDF Split and Mergeを使うをご覧ください。

pdfimagesを使う

この方法は基本的に、画像を析出して、画像からPDFファイルを再生成することによってPDFファイルを再構築しようとするものです。以下は、それを行うためのRubyスクリプトです。

必要条件

この方法を使うことのできないPDFファイル

  • グレースケールとカラーのPDFファイル
  • 画像を含まないPDFファイル (たとえば、打ち込み入力したPDFファイル)
  • 普通でない作り方をしたその他のPDFファイル (基本的に、まれ)

既知の問題と解決方法

  • できあがったPDFファイルで、色が反転する
    • 解決方法: このスクリプトを最後に -negate を付けて走らせる。例えば、*nixでは./pdfcompress.rb somefile.pdf -negate、ウィンドウズでは、ruby pdfcompress.rb somefile.pdf -negate
#!/usr/bin/ruby
require( 'fileutils' )

BASICCONVERTOPTIONS = " -compress Group4"
DELETEIGNOREFILE = false #Automatically delete files which grow in size after recompression?
TMPDIRNAME = "tmpx139toslw"

if ARGV[0] === NIL
	$stderr.puts "Syntax: pdfcompress.rb <PDF file> ( <additional convert options> )"
	exit 1
end

if ARGV[1] === NIL
	convertoptions = BASICCONVERTOPTIONS
else
	convertoptions = ARGV[1] + BASICCONVERTOPTIONS
end

begin
	Dir.mkdir( TMPDIRNAME )
	$stderr.puts "Processing file " + ( file = ARGV[0] ) + "..."
	
	#Convert to individual PDFs
	system( "pdfimages \"" + file +"\" " + File.join( TMPDIRNAME, "images" ) )
	Dir.glob( File.join( TMPDIRNAME, "*" ) ).each { |imagefile|
		$stderr.printf( "\rCompressing " + File.basename( imagefile ) + "..." );
		system( "convert #{convertoptions} \"" + imagefile + "\" \"" + imagefile.sub( /\.[^.]*$/, ".tiff" ) + "\"" )
		system( "tiff2pdf \"" + imagefile.sub( /\.[^.]*$/, ".tiff" ) + "\" -o \"" + imagefile.sub( /\.[^.]*$/, ".pdf" ) +"\"" )
	}
	$stderr.printf( "\n" );
	
	#Put them all together now
	$stderr.printf( "Combining PDF files... " );
	system( "pdftk \"" + Dir.glob( File.join( TMPDIRNAME, "*.pdf" ) ).join( "\" \"" ) + "\" cat output \"" + ( output_filename = File.basename( file ).sub( /#{File.extname( file )}$/, ".2.pdf" ) ) + "\"" )
	$stderr.printf( "Done\n" );
	
	#Compare the sizes
	if( File.size( file ) > File.size( output_filename ) )
		$stdout.puts "Compressed file " + File.basename( file ) + " - Compressed from " + File.size( file ).to_s + " to " + File.size( output_filename ).to_s
	else
		$stdout.puts "Ignored file " + File.basename( file ) + " - Changed from " + File.size( file ).to_s + " to " + File.size( output_filename ).to_s
		File.delete( output_filename ) if DELETEIGNOREFILE
	end
ensure
	#Clean up temp dir
	Dir.glob( File.join( TMPDIRNAME, "*" ) ).each { |delfile| File.delete( delfile ) }
	Dir.delete( TMPDIRNAME );
end