unipdf/model/optimize/optimize.go

99 lines
34 KiB
Go
Raw Normal View History

2020-08-27 21:45:09 +00:00
//
// Copyright 2020 FoxyUtils ehf. All rights reserved.
//
// This is a commercial product and requires a license to operate.
// A trial license can be obtained at https://unidoc.io
//
// DO NOT EDIT: generated by unitwist Go source code obfuscator.
//
// Use of this source code is governed by the UniDoc End User License Agreement
// terms that can be accessed at https://unidoc.io/eula/
2020-09-28 23:18:17 +00:00
package optimize ;import (_c "bytes";_ab "crypto/md5";_aa "errors";_b "fmt";_dc "github.com/unidoc/unipdf/v3/common";_ge "github.com/unidoc/unipdf/v3/contentstream";_d "github.com/unidoc/unipdf/v3/core";_abb "github.com/unidoc/unipdf/v3/extractor";_ag "github.com/unidoc/unipdf/v3/internal/textencoding";_gf "github.com/unidoc/unipdf/v3/model";_ec "github.com/unidoc/unitype";_a "golang.org/x/image/draw";_e "image";_f "math";);
2020-08-31 21:12:07 +00:00
2020-09-28 23:18:17 +00:00
// Chain allows to use sequence of optimizers.
// It implements interface model.Optimizer.
type Chain struct{_bf []_gf .Optimizer };
2020-08-27 21:45:09 +00:00
2020-09-28 23:18:17 +00:00
// CleanFonts cleans up embedded fonts, reducing font sizes.
type CleanFonts struct{
2020-08-27 21:45:09 +00:00
2020-09-28 23:18:17 +00:00
// Subset embedded fonts if encountered (if true).
// Otherwise attempts to reduce the font program.
Subset bool ;};func _fgcg (_ggce *_d .PdfObjectStream ,_gcc []rune ,_fga []_ec .GlyphIndex )error {_ggce ,_feb :=_d .GetStream (_ggce );if !_feb {_dc .Log .Debug ("\u0045\u006d\u0062\u0065\u0064\u0064\u0065\u0064\u0020\u0066\u006f\u006e\u0074\u0020\u006f\u0062\u006a\u0065c\u0074\u0020\u006e\u006f\u0074\u0020\u0066o\u0075\u006e\u0064\u0020\u002d\u002d\u0020\u0041\u0042\u004f\u0052T\u0020\u0073\u0075\u0062\u0073\u0065\u0074\u0074\u0069\u006e\u0067");return _aa .New ("\u0066\u006f\u006e\u0074fi\u006c\u0065\u0032\u0020\u006e\u006f\u0074\u0020\u0066\u006f\u0075\u006e\u0064");};_fbf ,_ggd :=_d .DecodeStream (_ggce );if _ggd !=nil {_dc .Log .Debug ("\u0044\u0065c\u006f\u0064\u0065 \u0065\u0072\u0072\u006f\u0072\u003a\u0020\u0025\u0076",_ggd );return _ggd ;};_def ,_ggd :=_ec .Parse (_c .NewReader (_fbf ));if _ggd !=nil {_dc .Log .Debug ("\u0045\u0072\u0072\u006f\u0072\u0020\u0070\u0061\u0072\u0073\u0069n\u0067\u0020\u0025\u0064\u0020\u0062\u0079\u0074\u0065\u0020f\u006f\u006e\u0074",len (_ggce .Stream ));return _ggd ;};_cda :=_fga ;if len (_gcc )> 0{_bbb :=_def .LookupRunes (_gcc );_cda =append (_cda ,_bbb ...);};_def ,_ggd =_def .SubsetKeepIndices (_cda );if _ggd !=nil {_dc .Log .Debug ("\u0045R\u0052\u004f\u0052\u0020s\u0075\u0062\u0073\u0065\u0074t\u0069n\u0067 \u0066\u006f\u006e\u0074\u003a\u0020\u0025v",_ggd );return _ggd ;};var _cgf _c .Buffer ;_ggd =_def .Write (&_cgf );if _ggd !=nil {_dc .Log .Debug ("\u0045\u0052\u0052\u004fR \u0057\u0072\u0069\u0074\u0069\u006e\u0067\u0020\u0066\u006f\u006e\u0074\u003a\u0020%\u0076",_ggd );return _ggd ;};if _cgf .Len ()> len (_fbf ){_dc .Log .Debug ("\u0052\u0065-\u0077\u0072\u0069\u0074\u0074\u0065\u006e\u0020\u0066\u006f\u006e\u0074\u0020\u0069\u0073\u0020\u006c\u0061\u0072\u0067\u0065\u0072\u0020\u0074\u0068\u0061\u006e\u0020\u006f\u0072\u0069\u0067\u0069\u006e\u0061\u006c\u0020\u002d\u0020\u0073\u006b\u0069\u0070");return nil ;};_fgac ,_ggd :=_d .MakeStream (_cgf .Bytes (),_d .NewFlateEncoder ());if _ggd !=nil {_dc .Log .Debug ("\u0045\u0052\u0052\u004fR \u0057\u0072\u0069\u0074\u0069\u006e\u0067\u0020\u0066\u006f\u006e\u0074\u003a\u0020%\u0076",_ggd );return _ggd ;};*_ggce =*_fgac ;_ggce .Set ("\u004ce\u006e\u0067\u0074\u0068\u0031",_d .MakeInteger (int64 (_cgf .Len ())));return nil ;};
2020-08-27 21:45:09 +00:00
2020-09-28 23:18:17 +00:00
// Optimize optimizes PDF objects to decrease PDF size.
func (_fb *CleanContentstream )Optimize (objects []_d .PdfObject )(_abc []_d .PdfObject ,_ccc error ){_gg :=map[*_d .PdfObjectStream ]struct{}{};var _geg []*_d .PdfObjectStream ;_feg :=func (_ece *_d .PdfObjectStream ){if _ ,_gd :=_gg [_ece ];!_gd {_gg [_ece ]=struct{}{};_geg =append (_geg ,_ece );};};for _ ,_bed :=range objects {switch _bga :=_bed .(type ){case *_d .PdfIndirectObject :switch _bgd :=_bga .PdfObject .(type ){case *_d .PdfObjectDictionary :if _ed ,_af :=_d .GetName (_bgd .Get ("\u0054\u0079\u0070\u0065"));!_af ||_ed .String ()!="\u0050\u0061\u0067\u0065"{continue ;};if _bec ,_ba :=_d .GetStream (_bgd .Get ("\u0043\u006f\u006e\u0074\u0065\u006e\u0074\u0073"));_ba {_feg (_bec );}else if _bag ,_bgf :=_d .GetArray (_bgd .Get ("\u0043\u006f\u006e\u0074\u0065\u006e\u0074\u0073"));_bgf {for _ ,_ee :=range _bag .Elements (){if _cag ,_fea :=_d .GetStream (_ee );_fea {_feg (_cag );};};};};case *_d .PdfObjectStream :if _efe ,_dd :=_d .GetName (_bga .Get ("\u0054\u0079\u0070\u0065"));!_dd ||_efe .String ()!="\u0058O\u0062\u006a\u0065\u0063\u0074"{continue ;};if _cdg ,_bb :=_d .GetName (_bga .Get ("\u0053u\u0062\u0074\u0079\u0070\u0065"));!_bb ||_cdg .String ()!="\u0046\u006f\u0072\u006d"{continue ;};_feg (_bga );};};for _ ,_aab :=range _geg {_ccc =_fe (_aab );if _ccc !=nil {return nil ,_ccc ;};};return objects ,nil ;};func _fccf (_dedge _d .PdfObject )(_ddf string ,_daac []_d .PdfObject ){var _gge _c .Buffer ;switch _gacc :=_dedge .(type ){case *_d .PdfIndirectObject :_daac =append (_daac ,_gacc );_dedge =_gacc .PdfObject ;};switch _dadd :=_dedge .(type ){case *_d .PdfObjectStream :if _ecee ,_begg :=_d .DecodeStream (_dadd );_begg ==nil {_gge .Write (_ecee );_daac =append (_daac ,_dadd );};case *_d .PdfObjectArray :for _ ,_fag :=range _dadd .Elements (){switch _gffb :=_fag .(type ){case *_d .PdfObjectStream :if _cagd ,_bdfc :=_d .DecodeStream (_gffb );_bdfc ==nil {_gge .Write (_cagd );_daac =append (_daac ,_gffb );};};};};return _gge .String (),_daac ;};
2020-08-27 21:45:09 +00:00
2020-09-28 23:18:17 +00:00
// Optimize optimizes PDF objects to decrease PDF size.
func (_be *Chain )Optimize (objects []_d .PdfObject )(_abg []_d .PdfObject ,_gbc error ){_abg =objects ;for _ ,_gc :=range _be ._bf {_abg ,_gbc =_gc .Optimize (_abg );if _gbc !=nil {return _abg ,_gbc ;};};return _abg ,nil ;};
2020-08-27 21:45:09 +00:00
2020-09-21 01:20:10 +00:00
// Optimize optimizes PDF objects to decrease PDF size.
2020-09-28 23:18:17 +00:00
func (_aff *CleanFonts )Optimize (objects []_d .PdfObject )(_febd []_d .PdfObject ,_beca error ){var _cagf map[*_d .PdfObjectStream ]struct{};if _aff .Subset {var _fgg error ;_cagf ,_fgg =_de (objects );if _fgg !=nil {return nil ,_fgg ;};};for _ ,_efga :=range objects {_ga ,_gaa :=_d .GetStream (_efga );if !_gaa {continue ;};if _ ,_beab :=_cagf [_ga ];_beab {continue ;};_ecb ,_efdb :=_d .NewEncoderFromStream (_ga );if _efdb !=nil {_dc .Log .Debug ("\u0045\u0052RO\u0052\u0020\u0067e\u0074\u0074\u0069\u006eg e\u006eco\u0064\u0065\u0072\u003a\u0020\u0025\u0076 -\u0020\u0069\u0067\u006e\u006f\u0072\u0069n\u0067",_efdb );continue ;};_gad ,_efdb :=_ecb .DecodeStream (_ga );if _efdb !=nil {_dc .Log .Debug ("\u0044\u0065\u0063\u006f\u0064\u0069\u006e\u0067\u0020\u0065r\u0072\u006f\u0072\u0020\u003a\u0020\u0025v\u0020\u002d\u0020\u0069\u0067\u006e\u006f\u0072\u0069\u006e\u0067",_efdb );continue ;};if len (_gad )< 4{continue ;};_bad :=string (_gad [:4]);if _bad =="\u004f\u0054\u0054\u004f"{continue ;};if _bad !="\u0000\u0001\u0000\u0000"&&_bad !="\u0074\u0072\u0075\u0065"{continue ;};_egdg ,_efdb :=_ec .Parse (_c .NewReader (_gad ));if _efdb !=nil {_dc .Log .Debug ("\u0045\u0052\u0052\u004f\u0052\u0020P\u0061\u0072\u0073\u0069\u006e\u0067\u0020\u0066\u006f\u006e\u0074\u003a\u0020%\u0076\u0020\u002d\u0020\u0069\u0067\u006eo\u0072\u0069\u006e\u0067",_efdb );continue ;};_efdb =_egdg .Optimize ();if _efdb !=nil {continue ;};var _gccf _c .Buffer ;_efdb =_egdg .Write (&_gccf );if _efdb !=nil {_dc .Log .Debug ("\u0045\u0052\u0052\u004f\u0052\u0020W\u0072\u0069\u0074\u0069\u006e\u0067\u0020\u0066\u006f\u006e\u0074\u003a\u0020%\u0076\u0020\u002d\u0020\u0069\u0067\u006eo\u0072\u0069\u006e\u0067",_efdb );continue ;};if _gccf .Len ()> len (_gad ){_dc .Log .Debug ("\u0052\u0065-\u0077\u0072\u0069\u0074\u0074\u0065\u006e\u0020\u0066\u006f\u006e\u0074\u0020\u0069\u0073\u0020\u006c\u0061\u0072\u0067\u0065\u0072\u0020\u0074\u0068\u0061\u006e\u0020\u006f\u0072\u0069\u0067\u0069\u006e\u0061\u006c\u0020\u002d\u0020\u0073\u006b\u0069\u0070");continue ;};_bba ,_efdb :=_d .MakeStream (_gccf .Bytes (),_d .NewFlateEncoder ());if _efdb !=nil {continue ;};*_ga =*_bba ;_ga .Set ("\u004ce\u006e\u0067\u0074\u0068\u0031",_d .MakeInteger (int64 (_gccf .Len ())));};return objects ,nil ;};func _dedg (_efgae []_d .PdfObject ){for _dfgaa ,_eea :=range _efgae {switch _caec :=_eea .(type ){case *_d .PdfIndirectObject :_caec .ObjectNumber =int64 (_dfgaa +1);_caec .GenerationNumber =0;case *_d .PdfObjectStream :_caec .ObjectNumber =int64 (_dfgaa +1);_caec .GenerationNumber =0;case *_d .PdfObjectStreams :_caec .ObjectNumber =int64 (_dfgaa +1);_caec .GenerationNumber =0;};};};
// New creates a optimizers chain from options.
func New (options Options )*Chain {_agdc :=new (Chain );if options .CleanFonts ||options .SubsetFonts {_agdc .Append (&CleanFonts {Subset :options .SubsetFonts });};if options .CleanContentstream {_agdc .Append (new (CleanContentstream ));};if options .ImageUpperPPI > 0{_feabb :=new (ImagePPI );_feabb .ImageUpperPPI =options .ImageUpperPPI ;_agdc .Append (_feabb );};if options .ImageQuality > 0{_affc :=new (Image );_affc .ImageQuality =options .ImageQuality ;_agdc .Append (_affc );};if options .CombineDuplicateDirectObjects {_agdc .Append (new (CombineDuplicateDirectObjects ));};if options .CombineDuplicateStreams {_agdc .Append (new (CombineDuplicateStreams ));};if options .CombineIdenticalIndirectObjects {_agdc .Append (new (CombineIdenticalIndirectObjects ));};if options .UseObjectStreams {_agdc .Append (new (ObjectStreams ));};if options .CompressStreams {_agdc .Append (new (CompressStreams ));};return _agdc ;};func _db (_eb *_ge .ContentStreamOperations )*_ge .ContentStreamOperations {if _eb ==nil {return nil ;};_bg :=_ge .ContentStreamOperations {};for _ ,_cf :=range *_eb {switch _cf .Operand {case "\u0042\u0044\u0043","\u0042\u004d\u0043","\u0045\u004d\u0043":continue ;case "\u0054\u006d":if len (_cf .Params )==6{if _cg ,_ca :=_d .GetNumbersAsFloat (_cf .Params );_ca ==nil {if _cg [0]==1&&_cg [1]==0&&_cg [2]==0&&_cg [3]==1{_cf =&_ge .ContentStreamOperation {Params :[]_d .PdfObject {_cf .Params [4],_cf .Params [5]},Operand :"\u0054\u0064"};};};};};_bg =append (_bg ,_cf );};return &_bg ;};
2020-09-21 01:20:10 +00:00
// CleanContentstream cleans up redundant operands in content streams, including Page and XObject Form
// contents. This process includes:
// 1. Marked content operators are removed.
// 2. Some operands are simplified (shorter form).
// TODO: Add more reduction methods and improving the methods for identifying unnecessary operands.
type CleanContentstream struct{};
2020-08-27 21:45:09 +00:00
// Optimize optimizes PDF objects to decrease PDF size.
2020-09-28 23:18:17 +00:00
func (_dad *CompressStreams )Optimize (objects []_d .PdfObject )(_bbec []_d .PdfObject ,_cgbb error ){_bbec =make ([]_d .PdfObject ,len (objects ));copy (_bbec ,objects );for _ ,_edb :=range objects {_ddeb ,_caa :=_d .GetStream (_edb );if !_caa {continue ;};if _eed :=_ddeb .Get ("\u0046\u0069\u006c\u0074\u0065\u0072");_eed !=nil {if _ ,_bee :=_d .GetName (_eed );_bee {continue ;};if _eeg ,_aca :=_d .GetArray (_eed );_aca &&_eeg .Len ()> 0{continue ;};};_gcd :=_d .NewFlateEncoder ();var _bde []byte ;_bde ,_cgbb =_gcd .EncodeBytes (_ddeb .Stream );if _cgbb !=nil {return _bbec ,_cgbb ;};_ddd :=_gcd .MakeStreamDict ();if len (_bde )+len (_ddd .WriteString ())< len (_ddeb .Stream ){_ddeb .Stream =_bde ;_ddeb .PdfObjectDictionary .Merge (_ddd );_ddeb .PdfObjectDictionary .Set ("\u004c\u0065\u006e\u0067\u0074\u0068",_d .MakeInteger (int64 (len (_ddeb .Stream ))));};};return _bbec ,nil ;};
// CombineDuplicateStreams combines duplicated streams by its data hash.
// It implements interface model.Optimizer.
type CombineDuplicateStreams struct{};type content struct{_gbe string ;_fee *_gf .PdfPageResources ;};
2020-08-27 21:45:09 +00:00
2020-09-21 01:20:10 +00:00
// Optimize optimizes PDF objects to decrease PDF size.
2020-09-28 23:18:17 +00:00
func (_dge *ImagePPI )Optimize (objects []_d .PdfObject )(_bbg []_d .PdfObject ,_bbeea error ){if _dge .ImageUpperPPI <=0{return objects ,nil ;};_cgag :=_ccd (objects );if len (_cgag )==0{return objects ,nil ;};_fegd :=make (map[_d .PdfObject ]struct{});for _ ,_ddag :=range _cgag {_fbg :=_ddag .Stream .PdfObjectDictionary .Get (_d .PdfObjectName ("\u0053\u004d\u0061s\u006b"));_fegd [_fbg ]=struct{}{};};_ffa :=make (map[*_d .PdfObjectStream ]*imageInfo );for _ ,_dcg :=range _cgag {_ffa [_dcg .Stream ]=_dcg ;};var _gdcd *_d .PdfObjectDictionary ;for _ ,_faf :=range objects {if _agbeg ,_cdd :=_d .GetDict (_faf );_gdcd ==nil &&_cdd {if _bac ,_gcec :=_d .GetName (_agbeg .Get (_d .PdfObjectName ("\u0054\u0079\u0070\u0065")));_gcec &&*_bac =="\u0043a\u0074\u0061\u006c\u006f\u0067"{_gdcd =_agbeg ;};};};if _gdcd ==nil {return objects ,nil ;};_caeaa ,_fgbc :=_d .GetDict (_gdcd .Get (_d .PdfObjectName ("\u0050\u0061\u0067e\u0073")));if !_fgbc {return objects ,nil ;};_fdgb ,_cgfc :=_d .GetArray (_caeaa .Get (_d .PdfObjectName ("\u004b\u0069\u0064\u0073")));if !_cgfc {return objects ,nil ;};_cfe :=make (map[string ]*imageInfo );for _ ,_fae :=range _fdgb .Elements (){_cafgg ,_gega :=_d .GetDict (_fae );if !_gega {continue ;};_bbf ,_dfdb :=_d .GetArray (_cafgg .Get ("\u0043\u006f\u006e\u0074\u0065\u006e\u0074\u0073"));if !_dfdb {continue ;};_badg ,_gfca :=_d .GetDict (_cafgg .Get ("\u0052e\u0073\u006f\u0075\u0072\u0063\u0065s"));if !_gfca {continue ;};_ggab ,_egce :=_d .GetDict (_badg .Get ("\u0058O\u0062\u006a\u0065\u0063\u0074"));if !_egce {continue ;};_gedc :=_ggab .Keys ();for _ ,_geec :=range _gedc {if _bdf ,_ddda :=_d .GetStream (_ggab .Get (_geec ));_ddda {if _begc ,_accd :=_ffa [_bdf ];_accd {_cfe [string (_geec )]=_begc ;};};};for _ ,_cafb :=range _bbf .Elements (){if _eecg ,_adc :=_d .GetStream (_cafb );_adc {_dca ,_eff :=_d .NewEncoderFromStream (_eecg );if _eff !=nil {return nil ,_eff ;};_febg ,_eff :=_dca .DecodeStream (_eecg );if _eff !=nil {return nil ,_eff ;};_bdbc :=_ge .NewContentStreamParser (string (_febg ));_bff ,_eff :=_bdbc .Parse ();if _eff !=nil {return nil ,_eff ;};_fecd ,_edc :=1.0,1.0;for _ ,_dgd :=range *_bff {if _dgd .Operand =="\u0051"{_fecd ,_edc =1.0,1.0;};if _dgd .Operand =="\u0063\u006d"&&len (_dgd .Params )==6{if _ggbe ,_abgb :=_d .GetFloatVal (_dgd .Params [0]);_abgb {_fecd =_fecd *_ggbe ;};if _aadb ,_cdgd :=_d .GetFloatVal (_dgd .Params [3]);_cdgd {_edc =_edc *_aadb ;};if _ead ,_ddca :=_d .GetIntVal (_dgd .Params [0]);_ddca {_fecd =_fecd *float64 (_ead );};if _fef ,_gffff :=_d .GetIntVal (_dgd .Params [3]);_gffff {_edc =_edc *float64 (_fef );};};if _dgd .Operand =="\u0044\u006f"&&len (_dgd .Params )==1{_ffde ,_aagb :=_d .GetName (_dgd .Params [0]);if !_aagb {continue ;};if _bce ,_cfaa :=_cfe [string (*_ffde )];_cfaa {_adb ,_eefa :=_fecd /72.0,_edc /72.0;_cge ,_bcef :=float64 (_bce .Width )/_adb ,float64 (_bce .Height )/_eefa ;if _adb ==0||_eefa ==0{_cge =72.0;_bcef =72.0;};_bce .PPI =_f .Max (_bce .PPI ,_cge );_bce .PPI =_f .Max (_bce .PPI ,_bcef );};};};};};};for _ ,_bede :=range _cgag {if _ ,_aaab :=_fegd [_bede .Stream ];_aaab {continue ;};if _bede .PPI <=_dge .ImageUpperPPI {continue ;};_cbag :=_dge .ImageUpperPPI /_bede .PPI ;if _fdd :=_fgace (_bede .Stream ,_cbag );_fdd !=nil {_dc .Log .Debug ("\u0045\u0072\u0072\u006f\u0072 \u0073\u0063\u0061\u006c\u0065\u0020\u0069\u006d\u0061\u0067\u0065\u0020\u006be\u0065\u0070\u0020\u006f\u0072\u0069\u0067\u0069\u006e\u0061\u006c\u0020\u0069\u006d\u0061\u0067\u0065\u003a\u0020\u0025\u0073",_fdd );}else {if _gbg ,_cdbc :=_d .GetStream (_bede .Stream .PdfObjectDictionary .Get (_d .PdfObjectName ("\u0053\u004d\u0061s\u006b")));_cdbc {if _ffe :=_fgace (_gbg ,_cbag );_ffe !=nil {return nil ,_ffe ;};};};};return objects ,nil ;};
2020-09-14 09:32:45 +00:00
2020-09-28 23:18:17 +00:00
// ImagePPI optimizes images by scaling images such that the PPI (pixels per inch) is never higher than ImageUpperPPI.
// TODO(a5i): Add support for inline images.
// It implements interface model.Optimizer.
type ImagePPI struct{ImageUpperPPI float64 ;};type objectStructure struct{_egdb *_d .PdfObjectDictionary ;_daf *_d .PdfObjectDictionary ;_aae []*_d .PdfIndirectObject ;};func _bcd (_egb []_d .PdfObject ,_ffaa map[_d .PdfObject ]_d .PdfObject ){if _ffaa ==nil ||len (_ffaa )==0{return ;};for _dfga ,_ecdd :=range _egb {if _caeg ,_ffeb :=_ffaa [_ecdd ];_ffeb {_egb [_dfga ]=_caeg ;continue ;};_ffaa [_ecdd ]=_ecdd ;switch _ceed :=_ecdd .(type ){case *_d .PdfObjectArray :_bdbf :=make ([]_d .PdfObject ,_ceed .Len ());copy (_bdbf ,_ceed .Elements ());_bcd (_bdbf ,_ffaa );for _cccb ,_acbb :=range _bdbf {_ceed .Set (_cccb ,_acbb );};case *_d .PdfObjectStreams :_bcd (_ceed .Elements (),_ffaa );case *_d .PdfObjectStream :_fca :=[]_d .PdfObject {_ceed .PdfObjectDictionary };_bcd (_fca ,_ffaa );_ceed .PdfObjectDictionary =_fca [0].(*_d .PdfObjectDictionary );case *_d .PdfObjectDictionary :_dbb :=_ceed .Keys ();_feec :=make ([]_d .PdfObject ,len (_dbb ));for _aac ,_agdf :=range _dbb {_feec [_aac ]=_ceed .Get (_agdf );};_bcd (_feec ,_ffaa );for _fegc ,_ffcf :=range _dbb {_ceed .Set (_ffcf ,_feec [_fegc ]);};case *_d .PdfIndirectObject :_acd :=[]_d .PdfObject {_ceed .PdfObject };_bcd (_acd ,_ffaa );_ceed .PdfObject =_acd [0];};};};func _de (_bedb []_d .PdfObject )(_feab map[*_d .PdfObjectStream ]struct{},_bea error ){_feab =map[*_d .PdfObjectStream ]struct{}{};_beaf :=map[*_gf .PdfFont ]struct{}{};_eda :=_fdb (_bedb );for _ ,_eg :=range _eda ._aae {_daa ,_efd :=_d .GetDict (_eg .PdfObject );if !_efd {continue ;};_ggb ,_efd :=_d .GetDict (_daa .Get ("\u0052e\u0073\u006f\u0075\u0072\u0063\u0065s"));if !_efd {continue ;};_efg ,_ :=_fccf (_daa .Get ("\u0043\u006f\u006e\u0074\u0065\u006e\u0074\u0073"));_fc ,_dg :=_gf .NewPdfPageResourcesFromDict (_ggb );if _dg !=nil {return nil ,_dg ;};_ebd :=[]content {{_gbe :_efg ,_fee :_fc }};_cfc :=_afc (_daa .Get ("\u0041\u006e\u006e\u006f\u0074\u0073"));if _cfc !=nil {_ebd =append (_ebd ,_cfc ...);};for _ ,_ac :=range _ebd {_ggc ,_eeb :=_abb .NewFromContents (_ac ._gbe ,_ac ._fee );if _eeb !=nil {return nil ,_eeb ;};_cgb ,_ ,_ ,_eeb :=_ggc .ExtractPageText ();if _eeb !=nil {return nil ,_eeb ;};for _ ,_fg :=range _cgb .Marks ().Elements (){if _fg .Font ==nil {continue ;};if _ ,_dbf :=_beaf [_fg .Font ];!_dbf {_beaf [_fg .Font ]=struct{}{};};};};};_agb :=map[*_d .PdfObjectStream ][]*_gf .PdfFont {};for _dfd :=range _beaf {_cdb :=_dfd .FontDescriptor ();if _cdb ==nil ||_cdb .FontFile2 ==nil {continue ;};_fcd ,_dfa :=_d .GetStream (_cdb .FontFile2 );if !_dfa {continue ;};_agb [_fcd ]=append (_agb [_fcd ],_dfd );};for _ae :=range _agb {var _egd []rune ;var _ff []_ec .GlyphIndex ;for _ ,_cfa :=range _agb [_ae ]{switch _eba :=_cfa .Encoder ().(type ){case *_ag .IdentityEncoder :_fgc :=_eba .RegisteredRunes ();_feabg :=make ([]_ec .GlyphIndex ,len (_fgc ));for _dfg ,_eaa :=range _fgc {_feabg [_dfg ]=_ec .GlyphIndex (_eaa );};_ff =append (_ff ,_feabg ...);case *_ag .TrueTypeFontEncoder :_dfc :=_eba .RegisteredRunes ();_egd =append (_egd ,_dfc ...);case _ag .SimpleEncoder :_ggbf :=_eba .Charcodes ();for _ ,_ad :=range _ggbf {_cgbf ,_fec :=_eba .CharcodeToRune (_ad );if !_fec {_dc .Log .Debug ("\u0043\u0068a\u0072\u0063\u006f\u0064\u0065\u003c\u002d\u003e\u0072\u0075\u006e\u0065\u0020\u006e\u006f\u0074\u0020\u0066\u006f\u0075\u006e\u0064: \u0025\u0064",_ad );continue ;};_egd =append (_egd ,_cgbf );};};};_bea =_fgcg (_ae ,_egd ,_ff );if _bea !=nil {_dc .Log .Debug ("\u0045\u0052\u0052\u004f\u0052\u0020\u0073\u0075\u0062\u0073\u0065\u0074\u0074\u0069\u006eg\u0020f\u006f\u006e\u0074\u0020\u0073\u0074\u0072\u0065\u0061\u006d\u003a\u0020\u0025\u0076",_bea );return nil ,_bea ;};_feab [_ae ]=struct{}{};};return _feab ,nil ;};
// Image optimizes images by rewrite images into JPEG format with quality equals to ImageQuality.
// TODO(a5i): Add support for inline images.
// It implements interface model.Optimizer.
type Image struct{ImageQuality int ;};
// Append appends optimizers to the chain.
func (_gb *Chain )Append (optimizers ..._gf .Optimizer ){_gb ._bf =append (_gb ._bf ,optimizers ...)};func _ccd (_fgb []_d .PdfObject )[]*imageInfo {_gce :=_d .PdfObjectName ("\u0053u\u0062\u0074\u0079\u0070\u0065");_cce :=make (map[*_d .PdfObjectStream ]struct{});var _fbd error ;var _eec []*imageInfo ;for _ ,_agd :=range _fgb {_fed ,_bfg :=_d .GetStream (_agd );if !_bfg {continue ;};if _ ,_acc :=_cce [_fed ];_acc {continue ;};_cce [_fed ]=struct{}{};_gbdc :=_fed .PdfObjectDictionary .Get (_gce );_fgd ,_bfg :=_d .GetName (_gbdc );if !_bfg ||string (*_fgd )!="\u0049\u006d\u0061g\u0065"{continue ;};_cggf :=&imageInfo {BitsPerComponent :8,Stream :_fed };if _cggf .ColorSpace ,_fbd =_gf .DetermineColorspaceNameFromPdfObject (_fed .PdfObjectDictionary .Get ("\u0043\u006f\u006c\u006f\u0072\u0053\u0070\u0061\u0063\u0065"));_fbd !=nil {_dc .Log .Error ("\u0045\u0072\u0072\u006f\u0072\u0020\u0064\u0065\u0074\u0065r\u006d\u0069\u006e\u0065\u0020\u0063\u006fl\u006f\u0072\u0020\u0073\u0070\u0061\u0063\u0065\u0020\u0025\u0073",_fbd );continue ;};if _ggcd ,_bbee :=_d .GetIntVal (_fed .PdfObjectDictionary .Get ("\u0042\u0069t\u0073\u0050\u0065r\u0043\u006f\u006d\u0070\u006f\u006e\u0065\u006e\u0074"));_bbee {_cggf .BitsPerComponent =_ggcd ;};if _cee ,_egaa :=_d .GetIntVal (_fed .PdfObjectDictionary .Get ("\u0057\u0069\u0064t\u0068"));_egaa {_cggf .Width =_cee ;};if _gccb ,_ddb :=_d .GetIntVal (_fed .PdfObjectDictionary .Get ("\u0048\u0065\u0069\u0067\u0068\u0074"));_ddb {_cggf .Height =_gccb ;};switch _cggf .ColorSpace {case "\u0044e\u0076\u0069\u0063\u0065\u0052\u0047B":_cggf .ColorComponents =3;case "\u0044\u0065\u0076\u0069\u0063\u0065\u0047\u0072\u0061\u0079":_cggf .ColorComponents =1;default:_dc .Log .Warning ("\u004f\u0070\u0074\u0069\u006d\u0069\u007a\u0061t\u0069\u006f\u006e i\u0073\u0020\u006e\u006f\u0074\u0020s\u0075\u0070\u0070\u006f\u0072\u0074\u0065\u0064\u0020\u0066\u006f\u0072\u0020\u0063\u006fl\u006f\u0072\u0020\u0073\u0070\u0061\u0063\u0065 \u0025\u0073",_cggf .ColorSpace );continue ;};_eec =append (_eec ,_cggf );};return _eec ;};
2020-09-21 01:20:10 +00:00
// ObjectStreams groups PDF objects to object streams.
// It implements interface model.Optimizer.
2020-09-28 23:18:17 +00:00
type ObjectStreams struct{};type imageInfo struct{ColorSpace _d .PdfObjectName ;BitsPerComponent int ;ColorComponents int ;Width int ;Height int ;Stream *_d .PdfObjectStream ;PPI float64 ;};
2020-09-14 09:32:45 +00:00
// Optimize optimizes PDF objects to decrease PDF size.
2020-09-28 23:18:17 +00:00
func (_cgd *CombineIdenticalIndirectObjects )Optimize (objects []_d .PdfObject )(_ada []_d .PdfObject ,_cga error ){_dedg (objects );_ffc :=make (map[_d .PdfObject ]_d .PdfObject );_fgacc :=make (map[_d .PdfObject ]struct{});_egc :=make (map[string ][]*_d .PdfIndirectObject );for _ ,_fdg :=range objects {_egg ,_fdf :=_fdg .(*_d .PdfIndirectObject );if !_fdf {continue ;};if _aag ,_gfbg :=_egg .PdfObject .(*_d .PdfObjectDictionary );_gfbg {if _cbf ,_ffg :=_aag .Get ("\u0054\u0079\u0070\u0065").(*_d .PdfObjectName );_ffg &&*_cbf =="\u0050\u0061\u0067\u0065"{continue ;};_gbd :=_ab .New ();_gbd .Write ([]byte (_aag .WriteString ()));_ecag :=string (_gbd .Sum (nil ));_egc [_ecag ]=append (_egc [_ecag ],_egg );};};for _ ,_eee :=range _egc {if len (_eee )< 2{continue ;};_bbba :=_eee [0];for _egga :=1;_egga < len (_eee );_egga ++{_ebf :=_eee [_egga ];_ffc [_ebf ]=_bbba ;_fgacc [_ebf ]=struct{}{};};};_ada =make ([]_d .PdfObject ,0,len (objects )-len (_fgacc ));for _ ,_dac :=range objects {if _ ,_dedf :=_fgacc [_dac ];_dedf {continue ;};_ada =append (_ada ,_dac );};_bcd (_ada ,_ffc );return _ada ,nil ;};func _fgace (_dedfe *_d .PdfObjectStream ,_beg float64 )error {_abd ,_bgc :=_gf .NewXObjectImageFromStream (_dedfe );if _bgc !=nil {return _bgc ;};_ccdd ,_bgc :=_abd .ToImage ();if _bgc !=nil {return _bgc ;};_gfd ,_bgc :=_ccdd .ToGoImage ();if _bgc !=nil {return _bgc ;};_cafg :=int (_f .RoundToEven (float64 (_ccdd .Width )*_beg ));_bfb :=int (_f .RoundToEven (float64 (_ccdd .Height )*_beg ));_daed :=_e .Rect (0,0,_cafg ,_bfb );var _ebg _a .Image ;var _gdfg func (_e .Image )(*_gf .Image ,error );switch _abd .ColorSpace .String (){case "\u0044e\u0076\u0069\u0063\u0065\u0052\u0047B":_ebg =_e .NewRGBA (_daed );_gdfg =_gf .ImageHandling .NewImageFromGoImage ;case "\u0044\u0065\u0076\u0069\u0063\u0065\u0047\u0072\u0061\u0079":_ebg =_e .NewGray (_daed );_gdfg =_gf .ImageHandling .NewGrayImageFromGoImage ;default:return _b .Errorf ("\u006f\u0070\u0074\u0069\u006d\u0069\u007a\u0061t\u0069\u006f\u006e i\u0073\u0020\u006e\u006f\u0074\u0020s\u0075\u0070\u0070\u006f\u0072\u0074\u0065\u0064\u0020\u0066\u006f\u0072\u0020\u0063\u006fl\u006f\u0072\u0020\u0073\u0070\u0061\u0063\u0065 \u0025\u0073",_abd .ColorSpace .String ());};_a .CatmullRom .Scale (_ebg ,_ebg .Bounds (),_gfd ,_gfd .Bounds (),_a .Over ,&_a .Options {});if _ccdd ,_bgc =_gdfg (_ebg );_bgc !=nil {return _bgc ;};_cec :=_d .MakeDict ();_cec .Set ("\u0051u\u0061\u006c\u0069\u0074\u0079",_d .MakeInteger (100));_cec .Set ("\u0050r\u0065\u0064\u0069\u0063\u0074\u006fr",_d .MakeInteger (1));_abd .Filter .UpdateParams (_cec );if _bgc =_abd .SetImage (_ccdd ,nil );_bgc !=nil {return _bgc ;};_abd .ToPdfObject ();return nil ;};
2020-08-27 21:45:09 +00:00
2020-09-21 01:20:10 +00:00
// CompressStreams compresses uncompressed streams.
2020-09-07 00:23:12 +00:00
// It implements interface model.Optimizer.
2020-09-21 01:20:10 +00:00
type CompressStreams struct{};
2020-08-27 21:45:09 +00:00
2020-09-28 23:18:17 +00:00
// Options describes PDF optimization parameters.
type Options struct{CombineDuplicateStreams bool ;CombineDuplicateDirectObjects bool ;ImageUpperPPI float64 ;ImageQuality int ;UseObjectStreams bool ;CombineIdenticalIndirectObjects bool ;CompressStreams bool ;CleanFonts bool ;SubsetFonts bool ;CleanContentstream bool ;};func _afc (_eef _d .PdfObject )[]content {if _eef ==nil {return nil ;};_beb ,_ega :=_d .GetArray (_eef );if !_ega {_dc .Log .Debug ("\u0041\u006e\u006e\u006fts\u0020\u006e\u006f\u0074\u0020\u0061\u006e\u0020\u0061\u0072\u0072\u0061\u0079");return nil ;};var _bgdb []content ;for _ ,_cdgg :=range _beb .Elements (){_gfc ,_bd :=_d .GetDict (_cdgg );if !_bd {_dc .Log .Debug ("I\u0067\u006e\u006f\u0072\u0069\u006eg\u0020\u006e\u006f\u006e\u002d\u0064i\u0063\u0074\u0020\u0065\u006c\u0065\u006de\u006e\u0074\u0020\u0069\u006e\u0020\u0041\u006e\u006e\u006ft\u0073");continue ;};_ecf ,_bd :=_d .GetDict (_gfc .Get ("\u0041\u0050"));if !_bd {_dc .Log .Debug ("\u004e\u006f\u0020\u0041P \u0065\u006e\u0074\u0072\u0079\u0020\u002d\u0020\u0073\u006b\u0069\u0070\u0070\u0069n\u0067");continue ;};_aaba :=_d .TraceToDirectObject (_ecf .Get ("\u004e"));if _aaba ==nil {_dc .Log .Debug ("N\u006f\u0020\u004e\u0020en\u0074r\u0079\u0020\u002d\u0020\u0073k\u0069\u0070\u0070\u0069\u006e\u0067");continue ;};var _aeb *_d .PdfObjectStream ;switch _dec :=_aaba .(type ){case *_d .PdfObjectDictionary :_bgg ,_aaa :=_d .GetName (_gfc .Get ("\u0041\u0053"));if !_aaa {_dc .Log .Debug ("\u004e\u006f\u0020\u0041S \u0065\u006e\u0074\u0072\u0079\u0020\u002d\u0020\u0073\u006b\u0069\u0070\u0070\u0069n\u0067");continue ;};_aeb ,_aaa =_d .GetStream (_dec .Get (*_bgg ));if !_aaa {_dc .Log .Debug ("\u0046o\u0072\u006d\u0020\u006eo\u0074\u0020\u0066\u006f\u0075n\u0064 \u002d \u0073\u006b\u0069\u0070\u0070\u0069\u006eg");continue ;};case *_d .PdfObjectStream :_aeb =_dec ;};if _aeb ==nil {_dc .Log .Debug ("\u0046\u006f\u0072m\u0020\u006e\u006f\u0074 \u0066\u006f\u0075\u006e\u0064\u0020\u0028n\u0069\u006c\u0029\u0020\u002d\u0020\u0073\u006b\u0069\u0070\u0070\u0069\u006e\u0067");continue ;};_cba ,_aaf :=_gf .NewXObjectFormFromStream (_aeb );if _aaf !=nil {_dc .Log .Debug ("\u0045\u0072\u0072\u006f\u0072\u0020l\u006f\u0061\u0064\u0069\u006e\u0067\u0020\u0066\u006f\u0072\u006d\u003a\u0020%\u0076\u0020\u002d\u0020\u0069\u0067\u006eo\u0072\u0069\u006e\u0067",_aaf );continue ;};_gee ,_aaf :=_cba .GetContentStream ();if _aaf !=nil {_dc .Log .Debug ("E\u0072\u0072\u006f\u0072\u0020\u0064e\u0063\u006f\u0064\u0069\u006e\u0067\u0020\u0063\u006fn\u0074\u0065\u006et\u0073:\u0020\u0025\u0076",_aaf );continue ;};_bgdb =append (_bgdb ,content {_gbe :string (_gee ),_fee :_cba .Resources });};return _bgdb ;};
2020-08-27 21:45:09 +00:00
2020-09-14 09:32:45 +00:00
// Optimize optimizes PDF objects to decrease PDF size.
2020-09-28 23:18:17 +00:00
func (_gcee *ObjectStreams )Optimize (objects []_d .PdfObject )(_gcbb []_d .PdfObject ,_fefc error ){_eggf :=&_d .PdfObjectStreams {};_ffce :=make ([]_d .PdfObject ,0,len (objects ));for _ ,_gag :=range objects {if _gfeg ,_bdef :=_gag .(*_d .PdfIndirectObject );_bdef &&_gfeg .GenerationNumber ==0{_eggf .Append (_gag );}else {_ffce =append (_ffce ,_gag );};};if _eggf .Len ()==0{return _ffce ,nil ;};_gcbb =make ([]_d .PdfObject ,0,len (_ffce )+_eggf .Len ()+1);if _eggf .Len ()> 1{_gcbb =append (_gcbb ,_eggf );};_gcbb =append (_gcbb ,_eggf .Elements ()...);_gcbb =append (_gcbb ,_ffce ...);return _gcbb ,nil ;};
2020-09-14 09:32:45 +00:00
2020-09-21 01:20:10 +00:00
// CombineIdenticalIndirectObjects combines identical indirect objects.
2020-09-07 00:23:12 +00:00
// It implements interface model.Optimizer.
2020-09-21 01:20:10 +00:00
type CombineIdenticalIndirectObjects struct{};
2020-09-07 00:23:12 +00:00
2020-09-28 23:18:17 +00:00
// CombineDuplicateDirectObjects combines duplicated direct objects by its data hash.
2020-09-07 00:23:12 +00:00
// It implements interface model.Optimizer.
2020-09-28 23:18:17 +00:00
type CombineDuplicateDirectObjects struct{};func _fdb (_dgde []_d .PdfObject )objectStructure {_baa :=objectStructure {};_gfa :=false ;for _ ,_gdb :=range _dgde {switch _eacf :=_gdb .(type ){case *_d .PdfIndirectObject :_bgag ,_fbfd :=_d .GetDict (_eacf );if !_fbfd {continue ;};_dagg ,_fbfd :=_d .GetName (_bgag .Get ("\u0054\u0079\u0070\u0065"));if !_fbfd {continue ;};switch _dagg .String (){case "\u0043a\u0074\u0061\u006c\u006f\u0067":_baa ._egdb =_bgag ;_gfa =true ;};};if _gfa {break ;};};if !_gfa {return _baa ;};_cgab ,_dfeg :=_d .GetDict (_baa ._egdb .Get ("\u0050\u0061\u0067e\u0073"));if !_dfeg {return _baa ;};_baa ._daf =_cgab ;_efcc ,_dfeg :=_d .GetArray (_cgab .Get ("\u004b\u0069\u0064\u0073"));if !_dfeg {return _baa ;};for _ ,_cbd :=range _efcc .Elements (){_aacc ,_bdcc :=_d .GetIndirect (_cbd );if !_bdcc {break ;};_baa ._aae =append (_baa ._aae ,_aacc );};return _baa ;};func _fe (_da *_d .PdfObjectStream )error {_cd ,_ea :=_d .DecodeStream (_da );if _ea !=nil {return _ea ;};_ecd :=_ge .NewContentStreamParser (string (_cd ));_cc ,_ea :=_ecd .Parse ();if _ea !=nil {return _ea ;};_cc =_db (_cc );_gbce :=_cc .Bytes ();if len (_gbce )>=len (_cd ){return nil ;};_eac ,_ea :=_d .MakeStream (_cc .Bytes (),_d .NewFlateEncoder ());if _ea !=nil {return _ea ;};_da .Stream =_eac .Stream ;_da .Merge (_eac .PdfObjectDictionary );return nil ;};
2020-08-27 21:45:09 +00:00
2020-09-28 23:18:17 +00:00
// Optimize optimizes PDF objects to decrease PDF size.
func (_cbbg *Image )Optimize (objects []_d .PdfObject )(_fde []_d .PdfObject ,_bfe error ){if _cbbg .ImageQuality <=0{return objects ,nil ;};_cbfg :=_ccd (objects );if len (_cbfg )==0{return objects ,nil ;};_ecdf :=make (map[_d .PdfObject ]_d .PdfObject );_gda :=make (map[_d .PdfObject ]struct{});for _ ,_efde :=range _cbfg {_afg :=_efde .Stream .PdfObjectDictionary .Get (_d .PdfObjectName ("\u0053\u004d\u0061s\u006b"));_gda [_afg ]=struct{}{};};for _efec ,_acaa :=range _cbfg {_ceba :=_acaa .Stream ;if _ ,_bdb :=_gda [_ceba ];_bdb {continue ;};_cdga ,_afb :=_d .NewEncoderFromStream (_ceba );if _afb !=nil {_dc .Log .Warning ("\u0045\u0072\u0072\u006f\u0072 \u0067\u0065\u0074\u0020\u0065\u006e\u0063\u006f\u0064\u0065\u0072\u0020\u0066o\u0072\u0020\u0074\u0068\u0065\u0020\u0069\u006d\u0061\u0067\u0065\u0020\u0073\u0074\u0072\u0065\u0061\u006d\u0020\u0025\u0073");continue ;};_cfca ,_afb :=_cdga .DecodeStream (_ceba );if _afb !=nil {_dc .Log .Warning ("\u0045\u0072\u0072\u006f\u0072\u0020\u0064\u0065\u0063\u006f\u0064\u0065\u0020\u0074\u0068e\u0020i\u006d\u0061\u0067\u0065\u0020\u0073\u0074\u0072\u0065\u0061\u006d\u0020\u0025\u0073");continue ;};_ced :=_d .NewDCTEncoder ();_ced .ColorComponents =_acaa .ColorComponents ;_ced .Quality =_cbbg .ImageQuality ;_ced .BitsPerComponent =_acaa .BitsPerComponent ;_ced .Width =_acaa .Width ;_ced .Height =_acaa .Height ;_fgf ,_afb :=_ced .EncodeBytes (_cfca );if _afb !=nil {_dc .Log .Debug ("\u0045R\u0052\u004f\u0052\u003a\u0020\u0025v",_afb );return nil ,_afb ;};var _abba _d .StreamEncoder ;_abba =_ced ;{_gfbd :=_d .NewFlateEncoder ();_cggfc :=_d .NewMultiEncoder ();_cggfc .AddEncoder (_gfbd );_cggfc .AddEncoder (_ced );_gdf ,_gde :=_cggfc .EncodeBytes (_cfca );if _gde !=nil {return nil ,_gde ;};if len (_gdf )< len (_fgf ){_dc .Log .Debug ("\u004d\u0075\u006c\u0074\u0069\u0020\u0065\u006e\u0063\u0020\u0069\u006d\u0070\u0072\u006f\u0076\u0065\u0073\u003a\u0020\u0025\u0064\u0020\u0074o\u0020\u0025\u0064\u0020\u0028o\u0072\u0069g\u0020\u0025\u0064\u0029",len (_fgf ),len (_gdf ),len (_ceba .Stream ));_fgf =_gdf ;_abba =_cggfc ;};};_cea :=len (_ceba .Stream );if _cea < len (_fgf ){continue ;};_ggbd :=&_d .PdfObjectStream {Stream :_fgf };_ggbd .PdfObjectReference =_ceba .PdfObjectReference ;_ggbd .PdfObjectDictionary =_d .MakeDict ();_ggbd .Merge (_ceba .PdfObjectDictionary );_ggbd .Merge (_abba .MakeStreamDict ());_ggbd .Set ("\u004c\u0065\u006e\u0067\u0074\u0068",_d .MakeInteger (int64 (len (_fgf ))));_ecdf [_ceba ]=_ggbd ;_cbfg [_efec ].Stream =_ggbd ;};_fde =make ([]_d .PdfObject ,len (objects ));copy (_fde ,objects );_bcd (_fde ,_ecdf );return _fde ,nil ;};
// Optimize optimizes PDF objects to decrease PDF size.
func (_abcf *CombineDuplicateStreams )Optimize (objects []_d .PdfObject )(_ded []_d .PdfObject ,_aebd error ){_ecc :=make (map[_d .PdfObject ]_d .PdfObject );_badf :=make (map[_d .PdfObject ]struct{});_acb :=make (map[string ][]*_d .PdfObjectStream );for _ ,_cbe :=range objects {if _aaaf ,_caea :=_cbe .(*_d .PdfObjectStream );_caea {_gfff :=_ab .New ();_gfff .Write ([]byte (_aaaf .Stream ));_cgg :=string (_gfff .Sum (nil ));_acb [_cgg ]=append (_acb [_cgg ],_aaaf );};};for _ ,_fdc :=range _acb {if len (_fdc )< 2{continue ;};_aeba :=_fdc [0];for _edab :=1;_edab < len (_fdc );_edab ++{_agf :=_fdc [_edab ];_ecc [_agf ]=_aeba ;_badf [_agf ]=struct{}{};};};_ded =make ([]_d .PdfObject ,0,len (objects )-len (_badf ));for _ ,_cef :=range objects {if _ ,_cbb :=_badf [_cef ];_cbb {continue ;};_ded =append (_ded ,_cef );};_bcd (_ded ,_ecc );return _ded ,nil ;};
2020-09-14 09:32:45 +00:00
2020-09-21 01:20:10 +00:00
// Optimize optimizes PDF objects to decrease PDF size.
2020-09-28 23:18:17 +00:00
func (_bdc *CombineDuplicateDirectObjects )Optimize (objects []_d .PdfObject )(_eca []_d .PdfObject ,_abf error ){_dedg (objects );_cgfa :=make (map[string ][]*_d .PdfObjectDictionary );var _age func (_aabc *_d .PdfObjectDictionary );_age =func (_dbc *_d .PdfObjectDictionary ){for _ ,_dag :=range _dbc .Keys (){_bbe :=_dbc .Get (_dag );if _bge ,_ffd :=_bbe .(*_d .PdfObjectDictionary );_ffd {_caf :=_ab .New ();_caf .Write ([]byte (_bge .WriteString ()));_cdfe :=string (_caf .Sum (nil ));_cgfa [_cdfe ]=append (_cgfa [_cdfe ],_bge );_age (_bge );};};};for _ ,_aed :=range objects {_bcg ,_ddg :=_aed .(*_d .PdfIndirectObject );if !_ddg {continue ;};if _abbb ,_gcb :=_bcg .PdfObject .(*_d .PdfObjectDictionary );_gcb {_age (_abbb );};};_ceb :=make ([]_d .PdfObject ,0,len (_cgfa ));_ddc :=make (map[_d .PdfObject ]_d .PdfObject );for _ ,_aabcc :=range _cgfa {if len (_aabcc )< 2{continue ;};_fd :=_d .MakeDict ();_fd .Merge (_aabcc [0]);_fda :=_d .MakeIndirectObject (_fd );_ceb =append (_ceb ,_fda );for _dae :=0;_dae < len (_aabcc );_dae ++{_bdg :=_aabcc [_dae ];_ddc [_bdg ]=_fda ;};};_eca =make ([]_d .PdfObject ,len (objects ));copy (_eca ,objects );_eca =append (_ceb ,_eca ...);_bcd (_eca ,_ddc );return _eca ,nil ;};