/* Ċ Ġ* ĠCopyright Ġ 2 0 0 2 - 2 0 1 9 ĠD rew ĠNo akes Ġand Ġcontributors Ċ Ġ* Ċ Ġ* ĠĠĠ ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* ĠĠĠ Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠĠĠ ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* ĠĠĠĠĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠĠĠ ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* ĠĠĠ Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠĠĠ ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠĠĠ ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* ĠĠĠ Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ* Ċ Ġ* ĠMore Ġinformation Ġabout Ġthis Ġproject Ġis Ġavailable Ġat : Ċ Ġ* Ċ Ġ* ĠĠĠ Ġhttps :// d rew no akes . com / code / ex if / Ċ Ġ* ĠĠĠ Ġhttps :// github . com / d rew no akes / metadata - extractor Ċ Ġ*/ Ċ package Ġcom . d rew . metadata . gif Ċ Ċ import Ġcom . d rew . lang . ASCII Ċ import Ġcom . d rew . lang . ByteArray Reader Ċ import Ġcom . d rew . lang . Sequential Reader Ċ import Ġcom . d rew . lang . UTF _ 8 Ċ import Ġcom . d rew . metadata .* Ċ import Ġcom . d rew . metadata . gif . Gif Control Directory . Dis posal Method . Companion . type Of Ċ import Ġcom . d rew . metadata . icc . I cc Reader Ċ import Ġcom . d rew . metadata . x mp . X mp Reader Ċ import Ġjava . io . ByteArray OutputStream Ċ import Ġjava . io . IOException Ċ Ċ /** Ċ Ġ* ĠReader Ġof ĠGIF Ġencoded Ġdata . Ċ Ġ* Ċ Ġ* ĠResources : Ċ Ġ* Ċ Ġ* Ġ Ġ* Ġhttps :// wiki . whatwg . org / wiki / G IF Ċ Ġ* Ġ Ġ* Ġhttps :// www . w 3 . org / Graphics / G IF / spec - gif 8 9 a . txt Ċ Ġ* Ġ Ġ* Ġhttp :// web . archive . org / web / 2 0 1 0 0 9 2 9 2 3 0 3 0 1 / http :// www . et sim o . un io vi . es / gif anim / gif 8 7 a . txt Ċ Ġ* Ċ Ġ* Ċ Ġ* Ġ@ author ĠD rew ĠNo akes Ġhttps :// d rew no akes . com Ċ Ġ* Ġ@ author ĠKevin ĠMot t Ġhttps :// github . com / k wh op per Ċ Ġ*/ Ċ class ĠG if Reader Ġ{ ĊĠ Ġfun Ġextract ( reader : ĠSequential Reader , Ġmetadata : ĠMetadata ) Ġ{ ĊĠĠĠ Ġreader . is Motorola Byte Order Ġ= Ġfalse ĊĠĠĠ Ġval Ġheader : ĠG if Header Directory ĊĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠ Ġheader Ġ= Ġread Gif Header ( reader ) ĊĠĠĠĠĠ Ġmetadata . add Directory ( header ) ĊĠĠĠ Ġ} Ġcatch Ġ( ex : ĠIOException ) Ġ{ ĊĠĠĠĠĠ Ġmetadata . add Directory ( Error Directory (" IOException Ġprocessing ĠGIF Ġdata ")) ĊĠĠĠĠĠ Ġreturn ĊĠĠĠ Ġ} ĊĠĠĠ Ġif Ġ( header . has Errors ()) Ġreturn ĊĠĠĠ Ġtry Ġ{ Ġ// ĠSkip Ġover Ġany Ġglobal Ġcolour Ġtable Ġif ĠGlobal Color Table Ġis Ġpresent . ĊĠĠĠĠĠ Ġvar Ġglobal Color Table Size : ĠInt ? Ġ= Ġnull ĊĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġhas Global Color Table Ġ= Ġheader . getBoolean ( Gif Header Directory . TAG _ HAS _ GLOBAL _ COLOR _ TABLE ) ĊĠĠĠĠĠĠĠ Ġif Ġ( has Global Color Table ) Ġ{ ĊĠĠĠĠĠĠĠĠĠ Ġglobal Color Table Size Ġ= Ġheader . getInteger ( Gif Header Directory . TAG _ COLOR _ TABLE _ SIZE ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠMetadata Exception ) Ġ{ Ġ// ĠThis Ġexception Ġshould Ġnever Ġoccur Ġhere . ĊĠĠĠĠĠĠĠ Ġmetadata . add Directory ( Error Directory (" G IF Ġdid Ġnot Ġhad Ġhas Global Color Table Ġbit .")) ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġif Ġ( global Color Table Size Ġ!= Ġnull ) Ġ{ Ġ// ĠColour Ġtable Ġhas ĠR / G / B Ġbyte Ġtrip lets ĊĠĠĠĠĠĠĠ Ġreader . skip ( 3 Ġ* Ġglobal Color Table Size . to Long ()) ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġ// ĠAfter Ġthe Ġheader Ġcomes Ġa Ġsequence Ġof Ġblocks ĊĠĠĠĠĠ Ġwhile Ġ( true ) Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġmarker : ĠByte Ġ= Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠ Ġreader . getInt 8 () ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( ex : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġwhen Ġ( marker ) Ġ{ ĊĠĠĠĠĠĠĠĠĠ Ġ'! '. to Byte () Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġread Gif Extension Block ( reader , Ġmetadata ) ĊĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠ Ġ',' . to Byte () Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmetadata . add Directory ( read Image Block ( reader )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġskip Ġimage Ġdata Ġblocks ĊĠĠĠĠĠĠĠĠĠĠĠ Ġskip Blocks ( reader ) ĊĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠ Ġ'; '. to Byte () Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġtermin ator ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAny thing Ġother Ġthan Ġthese Ġtypes Ġis Ġunexpected . Ċ // ĠGIF 8 7 a Ġspec Ġsays Ġto Ġkeep Ġreading Ġuntil Ġa Ġseparator Ġis Ġfound . Ċ // ĠGIF 8 9 a Ġspec Ġsays Ġfile Ġis Ġcorrupt . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmetadata . add Directory ( Error Directory (" Unknown Ġgif Ġblock Ġmarker Ġfound .")) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠ Ġmetadata . add Directory ( Error Directory (" IOException Ġprocessing ĠGIF Ġdata ")) ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠ Ġprivate Ġconst Ġval ĠGIF _ 8 7 A _ VERSION _ IDENTIFIER Ġ= Ġ" 8 7 a " ĊĠĠĠ Ġprivate Ġconst Ġval ĠGIF _ 8 9 A _ VERSION _ IDENTIFIER Ġ= Ġ" 8 9 a " ĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġread Gif Header ( reader : ĠSequential Reader ): ĠG if Header Directory Ġ{ Ġ// ĠFILE ĠHEADER Ċ // Ċ // Ġ 3 Ġ- Ġsignature : Ġ" G IF " Ċ // Ġ 3 Ġ- Ġversion : Ġeither Ġ" 8 7 a " Ġor Ġ" 8 9 a " Ċ // Ċ // ĠLOG ICAL ĠSCREEN ĠDESCRIP TOR Ċ // Ċ // Ġ 2 Ġ- Ġpixel Ġwidth Ċ // Ġ 2 Ġ- Ġpixel Ġheight Ċ // Ġ 1 Ġ- Ġscreen Ġand Ġcolor Ġmap Ġinformation Ġflags Ġ( 0 Ġis ĠL SB ) Ċ // ĠĠĠĠĠĠĠ 0 - 2 Ġ ĠSize Ġof Ġthe Ġglobal Ġcolor Ġtable Ċ // ĠĠĠĠĠĠĠ 3 ĠĠĠ ĠColor Ġtable Ġsort Ġflag Ġ( 8 9 a Ġonly ) Ċ // ĠĠĠĠĠĠĠ 4 - 6 Ġ ĠColor Ġresolution Ċ // ĠĠĠĠĠĠĠ 7 ĠĠĠ ĠGlobal Ġcolor Ġtable Ġflag Ċ // Ġ 1 Ġ- Ġbackground Ġcolor Ġindex Ċ // Ġ 1 Ġ- Ġpixel Ġaspect Ġratio ĊĠĠĠĠĠ Ġval Ġheader Directory Ġ= ĠG if Header Directory () ĊĠĠĠĠĠ Ġval Ġsignature Ġ= Ġreader . getString ( 3 ) ĊĠĠĠĠĠ Ġif Ġ( signature Ġ!= Ġ" G IF ") Ġ{ ĊĠĠĠĠĠĠĠ Ġheader Directory . add Error (" Invalid ĠGIF Ġfile Ġsignature ") ĊĠĠĠĠĠĠĠ Ġreturn Ġheader Directory ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġval Ġversion Ġ= Ġreader . getString ( 3 ) ĊĠĠĠĠĠ Ġif Ġ( version Ġ!= ĠGIF _ 8 7 A _ VERSION _ IDENTIFIER Ġ&& Ġversion Ġ!= ĠGIF _ 8 9 A _ VERSION _ IDENTIFIER ) Ġ{ ĊĠĠĠĠĠĠĠ Ġheader Directory . add Error (" Unexpected ĠGIF Ġversion ") ĊĠĠĠĠĠĠĠ Ġreturn Ġheader Directory ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġheader Directory . setString ( Gif Header Directory . TAG _ G IF _ FORMAT _ VERSION , Ġversion ) ĊĠĠĠĠĠ Ġ// ĠLOG ICAL ĠSCREEN ĠDESCRIP TOR ĊĠĠĠĠĠ Ġheader Directory . setInt ( Gif Header Directory . TAG _ IMAGE _ WIDTH , Ġreader . get UInt 1 6 ()) ĊĠĠĠĠĠ Ġheader Directory . setInt ( Gif Header Directory . TAG _ IMAGE _ HEIGHT , Ġreader . get UInt 1 6 ()) ĊĠĠĠĠĠ Ġval Ġflags Ġ= Ġreader . get UInt 8 (). toInt () ĊĠĠĠĠĠ Ġ// ĠFirst Ġthree Ġbits Ġ= Ġ( B PP Ġ- Ġ 1 ) ĊĠĠĠĠĠ Ġval Ġcolor Table Size Ġ= Ġ 1 Ġshl Ġ( flags Ġand Ġ 7 ) Ġ+ Ġ 1 ĊĠĠĠĠĠ Ġval Ġbits Per Pixel : ĠInt Ġ= Ġ( flags Ġand Ġ 0 x 7 0 Ġshr Ġ 4 ) Ġ+ Ġ 1 ĊĠĠĠĠĠ Ġval Ġhas Global Color Table Ġ= Ġflags Ġshr Ġ 7 Ġ!= Ġ 0 ĊĠĠĠĠĠ Ġheader Directory . setInt ( Gif Header Directory . TAG _ COLOR _ TABLE _ SIZE , Ġcolor Table Size ) ĊĠĠĠĠĠ Ġif Ġ( version Ġ== ĠGIF _ 8 9 A _ VERSION _ IDENTIFIER ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġis Color Table Sorted Ġ= Ġflags Ġand Ġ 8 Ġ!= Ġ 0 ĊĠĠĠĠĠĠĠ Ġheader Directory . set Boolean ( Gif Header Directory . TAG _ IS _ COLOR _ TABLE _ SORT ED , Ġis Color Table Sorted ) ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġheader Directory . setInt ( Gif Header Directory . TAG _ BITS _ PER _ PIXEL , Ġbits Per Pixel ) ĊĠĠĠĠĠ Ġheader Directory . set Boolean ( Gif Header Directory . TAG _ HAS _ GLOBAL _ COLOR _ TABLE , Ġhas Global Color Table ) ĊĠĠĠĠĠ Ġheader Directory . setInt ( Gif Header Directory . TAG _ BACKGROUND _ COLOR _ INDEX , Ġreader . get UInt 8 (). toInt ()) ĊĠĠĠĠĠ Ġval Ġaspect Ratio Byte Ġ= Ġreader . get UInt 8 (). toInt () ĊĠĠĠĠĠ Ġif Ġ( aspect Ratio Byte Ġ!= Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġpixel AspectRatio Ġ= Ġ(( aspect Ratio Byte Ġ+ Ġ 1 5 . 0 ) Ġ/ Ġ 6 4 . 0 ). toFloat () ĊĠĠĠĠĠĠĠ Ġheader Directory . set Float ( Gif Header Directory . TAG _ PIXEL _ AS PECT _ RATIO , Ġpixel AspectRatio ) ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġreturn Ġheader Directory ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġread Gif Extension Block ( reader : ĠSequential Reader , Ġmetadata : ĠMetadata ) Ġ{ ĊĠĠĠĠĠ Ġval Ġextension Label Ġ= Ġreader . getInt 8 () ĊĠĠĠĠĠ Ġval ĠblockSize Bytes Ġ= Ġreader . get UInt 8 () ĊĠĠĠĠĠ Ġval Ġblock Start Pos Ġ= Ġreader . position ĊĠĠĠĠĠ Ġwhen Ġ( extension Label ) Ġ{ ĊĠĠĠĠĠĠĠĠ 0 x 0 1 . to Byte () Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠ Ġval Ġplain TextBlock Ġ= Ġread Plain TextBlock ( reader , ĠblockSize Bytes . toInt ()) ĊĠĠĠĠĠĠĠĠĠ Ġif Ġ( plain TextBlock Ġ!= Ġnull ) Ġmetadata . add Directory ( plain TextBlock ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠ 0 xf 9 . to Byte () Ġ-> Ġmetadata . add Directory ( read Control Block ( reader , ĠblockSize Bytes . toInt ())) ĊĠĠĠĠĠĠĠĠ 0 xfe . to Byte () Ġ-> Ġmetadata . add Directory ( read Comment Block ( reader , ĠblockSize Bytes . toInt ())) ĊĠĠĠĠĠĠĠĠ 0 xff . to Byte () Ġ-> Ġread Application Extension Block ( reader , ĠblockSize Bytes . toInt (), Ġmetadata ) ĊĠĠĠĠĠĠĠ Ġelse Ġ-> Ġmetadata . add Directory ( Error Directory ( String . format (" Unsupported ĠGIF Ġextension Ġblock Ġwith Ġtype Ġ 0 x % 0 2 X .", Ġextension Label ))) ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġval Ġskip Count Ġ= Ġblock Start Pos Ġ+ ĠblockSize Bytes Ġ- Ġreader . position ĊĠĠĠĠĠ Ġif Ġ( skip Count Ġ> Ġ 0 ) Ġreader . skip ( skip Count ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġread Plain TextBlock ( reader : ĠSequential Reader , ĠblockSize Bytes : ĠInt ): ĠDirectory ? Ġ{ Ġ// ĠIt Ġseems Ġthis Ġextension Ġis Ġdeprecated . ĠIf Ġsome body Ġfinds Ġan Ġimage Ġwith Ġthis Ġin Ġit , Ġcould Ġimplement Ġhere . Ċ // ĠJust Ġskip Ġthe Ġentire Ġblock Ġfor Ġnow . ĊĠĠĠĠĠ Ġif Ġ( block Size Bytes Ġ!= Ġ 1 2 ) Ġreturn ĠError Directory ( String . format (" Invalid ĠGIF Ġplain Ġtext Ġblock Ġsize . ĠExpected Ġ 1 2 , Ġgot Ġ% d .", ĠblockSize Bytes )) ĊĠĠĠĠĠ Ġ// Ġskip Ġ' block Size Bytes ' Ġbytes ĊĠĠĠĠĠ Ġreader . skip ( 1 2 ) ĊĠĠĠĠĠ Ġ// Ġkeep Ġreading Ġand Ġskipping Ġuntil Ġa Ġ 0 Ġbyte Ġis Ġreached ĊĠĠĠĠĠ Ġskip Blocks ( reader ) ĊĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġread Comment Block ( reader : ĠSequential Reader , ĠblockSize Bytes : ĠInt ): ĠG if Comment Directory Ġ{ ĊĠĠĠĠĠ Ġval Ġbuffer Ġ= Ġgather Bytes ( reader , ĠblockSize Bytes ) ĊĠĠĠĠĠ Ġreturn ĠG if Comment Directory ( StringValue ( buffer , ĠASCII )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġread Application Extension Block ( reader : ĠSequential Reader , ĠblockSize Bytes : ĠInt , Ġmetadata : ĠMetadata ) Ġ{ ĊĠĠĠĠĠ Ġif Ġ( block Size Bytes Ġ!= Ġ 1 1 ) Ġ{ ĊĠĠĠĠĠĠĠ Ġmetadata . add Directory ( Error Directory ( String . format (" Invalid ĠGIF Ġapplication Ġextension Ġblock Ġsize . ĠExpected Ġ 1 1 , Ġgot Ġ% d .", ĠblockSize Bytes ))) ĊĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġval Ġextension Type : ĠString Ġ= Ġreader . getString ( block Size Bytes , ĠUTF _ 8 ) ĊĠĠĠĠĠ Ġif Ġ( extension Type Ġ== Ġ" X MP ĠData X MP ") Ġ{ Ġ// ĠX MP Ġdata Ġextension ĊĠĠĠĠĠĠĠ Ġval Ġx mp Bytes Ġ= Ġgather Bytes ( reader ) ĊĠĠĠĠĠĠĠ Ġval Ġx mp L eng h Ġ= Ġx mp Bytes . size Ġ- Ġ 2 5 7 Ġ// ĠExclude Ġthe Ġ" magic Ġtr ailer ", Ġsee ĠX MP ĠSpecification ĠPart Ġ 3 , Ġ 1 . 1 . 2 ĠGIF ĊĠĠĠĠĠĠĠ Ġif Ġ( x mp L eng h Ġ> Ġ 0 ) Ġ{ Ġ// ĠOnly Ġextract Ġvalid Ġblocks ĊĠĠĠĠĠĠĠĠĠ ĠX mp Reader (). extract ( x mp Bytes , Ġ 0 , Ġx mp Bytes . size Ġ- Ġ 2 5 7 , Ġmetadata , Ġnull ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġ} Ġelse Ġif Ġ( extension Type Ġ== Ġ" IC CR GB G 1 0 1 2 ") Ġ{ Ġ// ĠI CC Ġprofile Ġextension ĊĠĠĠĠĠĠĠ Ġval Ġic c Bytes Ġ= Ġgather Bytes ( reader , Ġreader . getByte (). toInt () Ġand Ġ 0 xff ) ĊĠĠĠĠĠĠĠ Ġif Ġ( icc Bytes . isNotEmpty ()) ĠI cc Reader (). extract ( ByteArray Reader ( icc Bytes ), Ġmetadata ) ĊĠĠĠĠĠ Ġ} Ġelse Ġif Ġ( extension Type Ġ== Ġ" NET SC APE 2 . 0 ") Ġ{ ĊĠĠĠĠĠĠĠ Ġreader . skip ( 2 ) ĊĠĠĠĠĠĠĠ Ġ// ĠNet scape 's Ġanimated ĠGIF Ġextension Ċ // ĠIteration Ġcount Ġ( 0 Ġmeans Ġinfinite ) ĊĠĠĠĠĠĠĠ Ġval Ġiteration Count Ġ= Ġreader . get UInt 1 6 () ĊĠĠĠĠĠĠĠ Ġ// ĠSkip Ġtermin ator ĊĠĠĠĠĠĠĠ Ġreader . skip ( 1 ) ĊĠĠĠĠĠĠĠ Ġval Ġanimation Directory Ġ= ĠG if Animation Directory () ĊĠĠĠĠĠĠĠ Ġanimation Directory . setInt ( Gif Animation Directory . TAG _ ITER ATION _ COUNT , Ġiteration Count ) ĊĠĠĠĠĠĠĠ Ġmetadata . add Directory ( animation Directory ) ĊĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠ Ġskip Blocks ( reader ) ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġread Control Block ( reader : ĠSequential Reader , ĠblockSize Bytes : ĠInt ): ĠG if Control Directory Ġ{ ĊĠĠĠĠĠ Ġvar ĠblockSize Bytes Ġ= ĠblockSize Bytes ĊĠĠĠĠĠ Ġif Ġ( block Size Bytes Ġ< Ġ 4 ) Ġ{ ĊĠĠĠĠĠĠĠ ĠblockSize Bytes Ġ= Ġ 4 ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġval Ġdirectory Ġ= ĠG if Control Directory () ĊĠĠĠĠĠ Ġval Ġpacked Fields Ġ= Ġreader . get UInt 8 (). toInt () ĊĠĠĠĠĠ Ġdirectory . set Object ( Gif Control Directory . TAG _ DIS POS AL _ METHOD , ĠtypeOf ( packed Fields Ġshr Ġ 2 Ġand Ġ 7 )) ĊĠĠĠĠĠ Ġdirectory . set Boolean ( Gif Control Directory . TAG _ USER _ INPUT _ FLAG , Ġpacked Fields Ġand Ġ 2 Ġshr Ġ 1 Ġ== Ġ 1 ) ĊĠĠĠĠĠ Ġdirectory . set Boolean ( Gif Control Directory . TAG _ TRANSP ARENT _ COLOR _ FLAG , Ġpacked Fields Ġand Ġ 1 Ġ== Ġ 1 ) ĊĠĠĠĠĠ Ġdirectory . setInt ( Gif Control Directory . TAG _ DELAY , Ġreader . get UInt 1 6 ()) ĊĠĠĠĠĠ Ġdirectory . setInt ( Gif Control Directory . TAG _ TRANSP ARENT _ COLOR _ INDEX , Ġreader . get UInt 8 (). toInt ()) ĊĠĠĠĠĠ Ġ// Ġskip Ġ 0 x 0 Ġblock Ġtermin ator ĊĠĠĠĠĠ Ġreader . skip ( 1 ) ĊĠĠĠĠĠ Ġreturn Ġdirectory ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġread Image Block ( reader : ĠSequential Reader ): ĠG if Image Directory Ġ{ ĊĠĠĠĠĠ Ġval Ġimage Directory Ġ= ĠG if Image Directory () ĊĠĠĠĠĠ Ġimage Directory . setInt ( Gif Image Directory . TAG _ LEFT , Ġreader . get UInt 1 6 ()) ĊĠĠĠĠĠ Ġimage Directory . setInt ( Gif Image Directory . TAG _ TOP , Ġreader . get UInt 1 6 ()) ĊĠĠĠĠĠ Ġimage Directory . setInt ( Gif Image Directory . TAG _ WIDTH , Ġreader . get UInt 1 6 ()) ĊĠĠĠĠĠ Ġimage Directory . setInt ( Gif Image Directory . TAG _ HEIGHT , Ġreader . get UInt 1 6 ()) ĊĠĠĠĠĠ Ġval Ġflags Ġ= Ġreader . getByte (). toInt () ĊĠĠĠĠĠ Ġval Ġhas Color Table Ġ= Ġflags Ġshr Ġ 7 Ġ!= Ġ 0 ĊĠĠĠĠĠ Ġval Ġis Inter l aced Ġ= Ġflags Ġand Ġ 0 x 4 0 Ġ!= Ġ 0 ĊĠĠĠĠĠ Ġimage Directory . set Boolean ( Gif Image Directory . TAG _ HAS _ LOCAL _ CO LO UR _ TABLE , Ġhas Color Table ) ĊĠĠĠĠĠ Ġimage Directory . set Boolean ( Gif Image Directory . TAG _ IS _ INTER L AC ED , Ġis Inter l aced ) ĊĠĠĠĠĠ Ġif Ġ( has Color Table ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġis Color Table Sorted Ġ= Ġflags Ġand Ġ 0 x 2 0 Ġ!= Ġ 0 ĊĠĠĠĠĠĠĠ Ġimage Directory . set Boolean ( Gif Image Directory . TAG _ IS _ COLOR _ TABLE _ SORT ED , Ġis Color Table Sorted ) ĊĠĠĠĠĠĠĠ Ġval Ġbits Per Pixel : ĠInt Ġ= Ġ( flags Ġand Ġ 0 x 7 ) Ġ+ Ġ 1 ĊĠĠĠĠĠĠĠ Ġimage Directory . setInt ( Gif Image Directory . TAG _ LOCAL _ CO LO UR _ TABLE _ BITS _ PER _ PIXEL , Ġbits Per Pixel ) ĊĠĠĠĠĠĠĠ Ġ// Ġskip Ġcolor Ġtable ĊĠĠĠĠĠĠĠ Ġreader . skip ( 3 Ġ* Ġ( 2 Ġshl Ġ( flags Ġand Ġ 0 x 7 )). to Long ()) ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġ// Ġskip Ġ" L ZW ĠMinimum ĠCode ĠSize " Ġbyte ĊĠĠĠĠĠ Ġreader . getByte () ĊĠĠĠĠĠ Ġreturn Ġimage Directory ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġgather Bytes ( reader : ĠSequential Reader ): ĠByteArray Ġ{ ĊĠĠĠĠĠ Ġval Ġbytes Ġ= ĠByteArrayOutputStream () ĊĠĠĠĠĠ Ġval Ġbuffer Ġ= ĠByteArray ( 2 5 7 ) ĊĠĠĠĠĠ Ġwhile Ġ( true ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġb Ġ= Ġreader . getByte () ĊĠĠĠĠĠĠĠ Ġif Ġ( b . toInt () Ġ== Ġ 0 ) Ġreturn Ġbytes . toByteArray () ĊĠĠĠĠĠĠĠ Ġval Ġb Int : ĠInt Ġ= Ġb . toInt () Ġand Ġ 0 xFF ĊĠĠĠĠĠĠĠ Ġbuffer [ 0 ] Ġ= Ġb ĊĠĠĠĠĠĠĠ Ġreader . getBytes ( buffer , Ġ 1 , Ġb Int ) ĊĠĠĠĠĠĠĠ Ġbytes . write ( buffer , Ġ 0 , Ġb Int Ġ+ Ġ 1 ) ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġgather Bytes ( reader : ĠSequential Reader , Ġfirst Length : ĠInt ): ĠByteArray Ġ{ ĊĠĠĠĠĠ Ġval Ġbuffer Ġ= ĠByteArrayOutputStream () ĊĠĠĠĠĠ Ġvar Ġlength Ġ= Ġfirst Length ĊĠĠĠĠĠ Ġwhile Ġ( length Ġ> Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠ Ġbuffer . write ( reader . getBytes ( length ), Ġ 0 , Ġlength ) ĊĠĠĠĠĠĠĠ Ġlength Ġ= Ġreader . getByte (). toInt () Ġand Ġ 0 xff ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġreturn Ġbuffer . toByteArray () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġskip Blocks ( reader : ĠSequential Reader ) Ġ{ ĊĠĠĠĠĠ Ġwhile Ġ( true ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġlength Ġ= Ġreader . get UInt 8 () ĊĠĠĠĠĠĠĠ Ġif Ġ( length . toInt () Ġ== Ġ 0 ) Ġreturn ĊĠĠĠĠĠĠĠ Ġreader . skip ( length . to Long ()) ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĠ Ġ} Ċ } Ċ