package Ġru . ily ass ha fig in . open rnd r . editor . gif Ċ Ċ import Ġmu . Kotlin Logging Ċ import Ġorg . lwjgl . Buffer Utils Ċ import Ġorg . open rnd r . color . Color RGB a Ċ import Ġorg . open rnd r . draw . Color Buffer Ċ import Ġorg . open rnd r . draw . Color Format Ċ import Ġorg . open rnd r . draw . RenderTarget Ċ import Ġorg . open rnd r . draw . render Target Ċ import Ġjava . io . Buffered OutputStream Ċ import Ġjava . io . File OutputStream Ċ import Ġjava . io . IOException Ċ import Ġjava . io . OutputStream Ċ import Ġjava . nio . ByteBuffer Ċ import Ġjava . nio . Byte Order Ċ import Ġkotlin . math . round ToInt Ċ Ċ private Ġval Ġlogger Ġ= ĠKotlin Logging . logger Ġ{} Ċ Ċ class ĠG if Writer Ġprivate Ġconstructor () Ġ{ ĊĊĠĠĠ Ġprivate Ġvar Ġencoder : ĠG if Encoder ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġvar Ġfile Stream : ĠOutputStream ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġvar Ġis First Frame : ĠBoolean Ġ= Ġtrue ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġframe Buffer : ĠByteBuffer ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġf lipped Buffer : ĠByteBuffer ĊĊĠĠĠ Ġprivate Ġvar ĠfileName : ĠString Ġ= Ġ" rnd r . gif " ĊĠĠĠ Ġprivate Ġvar Ġwidth : ĠInt Ġ= Ġ 3 2 0 ĊĠĠĠ Ġprivate Ġvar Ġheight : ĠInt Ġ= Ġ 2 4 0 ĊĠĠĠ Ġprivate Ġvar Ġtransparent Color : ĠColor RGB a ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġvar Ġrepeat : ĠInt Ġ= Ġ- 1 ĊĠĠĠ Ġprivate Ġvar Ġdelay : ĠInt Ġ= Ġ 0 ĊĠĠĠ Ġprivate Ġvar Ġdispose : ĠInt Ġ= Ġ- 1 Ġ// Ġ- 1 Ġ= Ġuse Ġdefault ĊĠĠĠ Ġprivate Ġvar Ġquality : ĠInt Ġ= Ġ 1 0 ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSets Ġof Ġcontaining Ġoutput Ġfile Ġname ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġoutput ( fileName : ĠString ) Ġ= Ġapply Ġ{ ĊĠĠĠĠĠĠĠ Ġthis . fileName Ġ= ĠfileName ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSets Ġthe Ġsize Ġof Ġthe ĠGIF - file . Ġif Ġthis Ġmethod Ġis Ġnot Ġinvoked , Ġthe Ġsize Ġof ĊĠĠĠĠ Ġ* Ġthe Ġfirst Ġadded Ġframe Ġwill Ġbe Ġthe Ġimage Ġsize . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġsize ( width : ĠInt , Ġheight : ĠInt ) Ġ= Ġapply Ġ{ ĊĠĠĠĠĠĠĠ Ġrequire ( width Ġ% Ġ 2 Ġ== Ġ 0 Ġ&& Ġheight Ġ% Ġ 2 Ġ== Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" width Ġ($ width ) Ġand Ġheight Ġ($ height ) Ġshould Ġbe Ġdiv isible Ġby Ġ 2 " ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġthis . width Ġ= Ġwidth ĊĠĠĠĠĠĠĠ Ġthis . height Ġ= Ġheight ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSets Ġthe Ġtransparent Ġcolor Ġfor Ġthe Ġlast Ġadded Ġframe Ġand Ġany Ġsubsequent ĊĠĠĠĠ Ġ* Ġframes . ĠSince Ġall Ġcolors Ġare Ġsubject Ġto Ġmodification Ġin Ġthe Ġquant ization ĊĠĠĠĠ Ġ* Ġprocess , Ġthe Ġcolor Ġin Ġthe Ġfinal Ġpalette Ġfor Ġeach Ġframe Ġclosest Ġto Ġthe Ġgiven ĊĠĠĠĠ Ġ* Ġcolor Ġbecomes Ġthe Ġtransparent Ġcolor Ġfor Ġthat Ġframe . ĠMay Ġbe Ġset Ġto Ġnull Ġto ĊĠĠĠĠ Ġ* Ġindicate Ġno Ġtransparent Ġcolor . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ param Ġcolor ĠColor Ġto Ġbe Ġtreated Ġas Ġtransparent Ġon Ġdisplay . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġtransparent Color ( color : ĠColor RGB a ?) Ġ= Ġapply Ġ{ ĊĠĠĠĠĠĠĠ Ġthis . transparent Color Ġ= Ġcolor ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSets Ġthe Ġnumber Ġof Ġtimes Ġthe Ġset Ġof ĠGIF Ġframes Ġshould Ġbe Ġplayed . ĠDefault Ġis Ġ- 1 ; ĊĠĠĠĠ Ġ* Ġ 0 Ġmeans Ġplay Ġin def initely . ĠMust Ġbe Ġinvoked Ġbefore Ġthe Ġfirst Ġimage Ġis Ġadded . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ param Ġrepeat Ġint Ġnumber Ġof Ġiterations . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġrepeat ( repeat : ĠInt ) Ġ= Ġapply Ġ{ ĊĠĠĠĠĠĠĠ Ġthis . repeat Ġ= Ġrepeat ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSets Ġthe Ġdelay Ġtime Ġbetween Ġeach Ġframe , Ġor Ġchanges Ġit Ġfor Ġsubsequent Ġframes ĊĠĠĠĠ Ġ* Ġ( app lies Ġto Ġlast Ġframe Ġadded ). ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ param Ġdelay Ġint Ġdelay Ġtime Ġin Ġmilliseconds ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġdelay ( delay : ĠInt ) Ġ= Ġapply Ġ{ ĊĠĠĠĠĠĠĠ Ġthis . delay Ġ= Ġ( delay Ġ/ Ġ 1 0 . 0 ). round ToInt () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSets Ġframe Ġrate Ġin Ġframes Ġper Ġsecond . ĠE quivalent Ġto Ġ` delay ( 1 0 0 0 / fps )`. ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ param Ġfps Ġframe Ġrate Ġ( frames Ġper Ġsecond ) ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġframe Rate ( fps : ĠDouble ) Ġ= Ġapply Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( fps Ġ> Ġ 0 . 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthis . delay Ġ= Ġ( 1 0 0 Ġ/ Ġfps ). round ToInt () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSet Ġthe Ġdis posal Ġmode Ġfor Ġthe Ġlast Ġadded Ġframe ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* ĠFrom ĠGIF Ġspecs : ĊĠĠĠĠ Ġ* Ġ* Ġ 0 0 ĠCODE ĠME AN ING Ġ- ĠNothing Ġspecial ĊĠĠĠĠ Ġ* Ġ* Ġ 0 1 ĠK EE P Ġ- Ġretain Ġthe Ġcurrent Ġimage ĊĠĠĠĠ Ġ* Ġ* Ġ 0 2 ĠREST ORE ĠBACK GROUND Ġ- Ġrestore Ġthe Ġbackground Ġcolor ĊĠĠĠĠ Ġ* Ġ* Ġ 0 3 ĠREMOVE Ġ- Ġremove Ġthe Ġcurrent Ġimage , Ġand Ġrestore Ġwhatever Ġimage Ġwas Ġbene ath Ġit ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġdispose ( dispose : ĠInt ) Ġ= Ġapply Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( dispose Ġ>= Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthis . dispose Ġ= Ġdispose ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSets Ġquality Ġof Ġcolor Ġquant ization Ġ( conversion Ġof Ġimages Ġto Ġthe Ġmaximum Ġ 2 5 6 Ġcolors Ġallowed Ġby ĊĠĠĠĠ Ġ* Ġthe ĠGIF Ġspecification ). ĠLower Ġvalues Ġ( minimum Ġ= Ġ 1 ) Ġproduce Ġbetter Ġcolors , ĊĠĠĠĠ Ġ* Ġbut Ġslow Ġprocessing Ġsignificantly . Ġ 1 0 Ġis Ġthe Ġdefault , Ġand Ġproduces Ġgood ĊĠĠĠĠ Ġ* Ġcolor Ġmapping Ġat Ġreasonable Ġspeed s . ĠValues Ġgreater Ġthan Ġ 2 0 Ġdo Ġnot Ġyield ĊĠĠĠĠ Ġ* Ġsignificant Ġimprovements Ġin Ġspeed . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ param Ġquality Ġint Ġgreater Ġthan Ġ 0 . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġquality ( quality : ĠInt ) Ġ= Ġapply Ġ{ ĊĠĠĠĠĠĠĠ Ġthis . quality Ġ= Ġif Ġ( quality Ġ< Ġ 1 ) Ġ 1 Ġelse Ġquality ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġcreate RenderTarget (): ĠRender Target Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġrender Target ( width , Ġheight ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcolor Buffer ( Color Format . RGB ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdepth Buffer () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠStart Ġwriting Ġto Ġthe ĠGIF Ġfile ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġstart (): ĠG if Writer Ġ{ ĊĠĠĠĠĠĠĠ Ġlogger . debug Ġ{ Ġ" starting Ġgif Ġwriter Ġwith Ġ$ width Ġx Ġ$ height Ġoutput Ġwriting Ġto Ġ$ fileName " Ġ} ĊĊĠĠĠĠĠĠĠ Ġcheck ( width Ġ> Ġ 0 ) Ġ{ Ġ" invalid Ġwidth Ġor Ġwidth Ġnot Ġset Ġ$ width " Ġ} ĊĠĠĠĠĠĠĠ Ġcheck ( height Ġ> Ġ 0 ) Ġ{ Ġ" invalid Ġheight Ġor Ġheight Ġnot Ġset Ġ$ height " Ġ} ĊĊĠĠĠĠĠĠĠ Ġframe Buffer Ġ= ĠBuffer Utils . create ByteBuffer ( width Ġ* Ġheight Ġ* ĠColor Format . RGB . component Count ) ĊĠĠĠĠĠĠĠ Ġf lipped Buffer Ġ= ĠBuffer Utils . create ByteBuffer ( width Ġ* Ġheight Ġ* ĠColor Format . RGB . component Count ) ĊĠĠĠĠĠĠĠ Ġis First Frame Ġ= Ġtrue ĊĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfile Stream Ġ= ĠBuffered OutputStream ( File OutputStream ( fileName )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . debug Ġ{ Ġ" created Ġfile Ġstream Ġfor Ġ$ fileName " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġencoder Ġ= ĠG if Encoder ( width , Ġheight , Ġtransparent Color , Ġrepeat , Ġdelay , Ġdispose ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . debug Ġ{ Ġ" created Ġgif Ġencoder " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġencoder !!. start ( file Stream !! ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . debug Ġ{ Ġ" started Ġgif Ġencoder " Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġthis ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( exception : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠRuntimeException (" Failed Ġto Ġstart ĠG if Ġwriter ", Ġexception ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġframe ( frame : ĠColor Buffer ) Ġ{ ĊĠĠĠĠĠĠĠ Ġcheck ( frame . width Ġ== Ġwidth Ġ&& Ġframe . height Ġ== Ġheight ) Ġ{ Ġ" Frame Ġsize Ġmismatch " Ġ} ĊĠĠĠĠĠĠĠ Ġcheck ( frame . format Ġ== ĠColor Format . RGB ) Ġ{ Ġ" Frame Ġcolor Ġformat Ġnot Ġequals ĠRGB " Ġ} ĊĠĠĠĠĠĠĠ ĠcheckNotNull ( file Stream ) Ġ{ Ġ" File Ġstream Ġnot Ġopened " Ġ} ĊĊĠĠĠĠĠĠĠ Ġframe Buffer . rewind () ĊĠĠĠĠĠĠĠ Ġframe Buffer . order ( Byte Order . native Order ()) ĊĠĠĠĠĠĠĠ Ġframe . read ( frame Buffer ) ĊĠĠĠĠĠĠĠ Ġframe Buffer . rewind () ĊĊĠĠĠĠĠĠĠ Ġif Ġ(! frame . flip V ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġf lipped Buffer . rewind () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġstride Ġ= Ġwidth Ġ* Ġframe . format . component Count ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġrow Ġ= ĠByteArray ( stride ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( y Ġin Ġ 0 Ġuntil Ġheight ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġframe Buffer . position (( height Ġ- Ġy Ġ- Ġ 1 ) Ġ* Ġstride ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġframe Buffer . get ( row ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġf lipped Buffer . put ( row ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġf lipped Buffer . rewind () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġframe Buffer . rewind () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġframe Buffer . put ( f lipped Buffer ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġframe Buffer . rewind () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġpixels Ġ= ĠByteArray ( frame Buffer . remaining ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġframe Buffer . get ( pixels ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġencoder ?. write ( file Stream !! , Ġpixels , Ġis First Frame ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is First Frame ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis First Frame Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( exception : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalStateException (" Failed Ġto Ġwrite Ġframe ", Ġexception ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠFin ishes Ġoff Ġthe ĠGIF - file Ġand Ġsaves Ġit Ġto Ġthe Ġgiven Ġfilename ĊĠĠĠĠ Ġ* Ġin Ġthe Ġsketch Ġdirectory . Ġif Ġthe Ġfile Ġalready Ġexists , Ġit Ġwill ĊĠĠĠĠ Ġ* Ġbe Ġoverridden ! ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġstop (): ĠG if Writer Ġ{ ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġencoder ?. stop ( file Stream Ġ?: Ġthrow ĠIllegalStateException (" File Ġstream Ġnot Ġopened ")) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfile Stream ?. close () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġencoder Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfile Stream Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġthis ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( exception : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalStateException (" failed Ġto Ġclose Ġthe Ġgif Ġstream ", Ġexception ) ĊĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġencoder Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfile Stream Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĊĠĠĠĠĠĠĠ Ġconst Ġval ĠDIS POSE _ NOTH ING Ġ= Ġ 0 ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠDIS POSE _ KEEP Ġ= Ġ 1 ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠDIS POSE _ REST ORE _ BACKGROUND Ġ= Ġ 2 ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠDIS POSE _ REMOVE Ġ= Ġ 3 ĊĊĠĠĠĠĠĠĠ Ġfun Ġcreate (): ĠG if Writer Ġ= ĠG if Writer () ĊĠĠĠ Ġ} Ċ } Ċ