module defineClass GIFReader morph dataBuffer LZWData LZWDataPos GIFArray K LSD width height GCTFlag cr GCTBits NoPixelsIndexColor Parameters PixelAspectRatio GlobalColorTable ColorTableSize GlobalColorTablePos tempPos GCE TransparentColor ImageBlock LZWCodeSize LZWData LZWDataBlockSize LZWDataBlockSize LZWDataPos indexPos clearCode codeNumber newCode preCodeNumber codeSize codeTable EOICode method addToBuffer GIFReader { if (LZWDataPos <= (count LZWData)) { while ((count dataBuffer) < codeSize) { addFirst dataBuffer (byteToBits this (at LZWData LZWDataPos)) dataBuffer = (flattened dataBuffer) LZWDataPos += 1 } } else { halt addFirst dataBuffer (byteToBits this 0) addFirst dataBuffer (byteToBits this 0) dataBuffer = (flattened dataBuffer) } } method bitsToNumber GIFReader bits { bits = (reversed bits) local 'number' 0 for i (count bits) { number = (number + ((at bits i) << (i - 1))) } return number } method byteToBits GIFReader n { local 'bits' (list 1 2 3 4 5 6 7 8) for i 8 { atPut bits i ((n >> (8 - i)) & 1) } return bits } method displayList GIFReader data { local 'var' (list) for i (count data) { add var (join (toString i) ':' (at data i)) } local 'menu' (selectFromMenu var) } method enforceList GIFReader data { if ((count data) == 0) {return (list data)} return data } method getParam GIFReader key { return (at Parameters key) } method setParam GIFReader key value { atPut Parameters key value } method indexToPixel GIFReader points { local 'points' (enforceList this points) local 'color' (colorFromSwatch (colorSwatch 35 190 30 255)) for loop (count points) { local 'var' (at points loop) color = (at GlobalColorTable (var + 1)) local 'y' (truncate ((indexPos - 1) / width)) local 'x' ((indexPos - 1) % width) self_setPixel (x + 1) (y + 1) color indexPos += 1 } } method loadGIF GIFReader fileName scratchFlag { if (isNil scratchFlag) {local 'scratchFlag' (booleanConstant false)} GIFArray = (toArray (readFile fileName true)) LSD = (copyFromTo GIFArray 7 13) width = ((at LSD 1) + ((at LSD 2) * 256)) height = ((at LSD 3) + ((at LSD 4) * 256)) local bits = (byteToBits this (at LSD 5)) GCTFlag = (at bits 1) cr = (round (+ ((at bits 2) * 4) ((at bits 3) * 2) ((at bits 4) * 1))) local 'SortFlag' (at bits 5) GCTBits = (round (+ ((at bits 6) * 4) ((at bits 7) * 2) ((at bits 8) * 1))) NoPixelsIndexColor = (at LSD 6) PixelAspectRatio = (at LSD 7) if (GCTFlag == 1) { ColorTableSize = (round (raise 2 (GCTBits + 1))) GlobalColorTablePos = 14 GlobalColorTable = (list) for i (range 0 (ColorTableSize - 1)) { local 'alpha' 255 if (and (i == 0) scratchFlag) { local 'alpha' 0 } add GlobalColorTable (color (at GIFArray (GlobalColorTablePos + (i * 3))) (at GIFArray (+ GlobalColorTablePos (i * 3) 1)) (at GIFArray (+ GlobalColorTablePos (i * 3) 2)) alpha) } } tempPos = (14 + (ColorTableSize * 3)) comment 'GCE section There could me multiple application extensions but we will loop pass all of them except the one that uses the standard id=249' while ((at GIFArray tempPos) == 33) { if ((at GIFArray (tempPos + 1)) == 249) { if ((at GIFArray (tempPos + 2)) == 4) { GCE = (copyFromTo GIFArray tempPos (tempPos + 7)) TransparentColor = (at GIFArray (tempPos + 7)) tempPos = (+ tempPos 4 (at GIFArray (tempPos + 2))) } else { tempPos += 1 while ((at GIFArray tempPos) != 33) { tempPos += 1 } } } else { tempPos += 1 while ((at GIFArray tempPos) != 33) { tempPos += 1 } } } comment 'Image descriptor section' if ((at GIFArray tempPos) != 44) { error 'SW2 unexpected byte in GIF File read' } ImageBlock = (copyFromTo GIFArray tempPos (tempPos + 9)) tempPos = (tempPos + 10) LZWCodeSize = (at GIFArray tempPos) comment 'read all data bytes in to LZWData' LZWData = (list) tempPos = (tempPos + 1) LZWDataBlockSize = (at GIFArray tempPos) while (LZWDataBlockSize != 0) { addAll LZWData (copyFromTo GIFArray (tempPos + 1) (tempPos + LZWDataBlockSize)) tempPos = (tempPos + (LZWDataBlockSize + 1)) LZWDataBlockSize = (at GIFArray tempPos) } comment 'Real work starts' self_createCostume width height self_fillWithColor (transparent) indexPos = 1 LZWDataPos = 1 dataBuffer = (list) comment 'start reading LZWData preload 1st code (normally == clearCode)' resetCodes this addToBuffer this readNextCodeNumber this if (codeNumber == clearCode) { addToBuffer this readNextCodeNumber this indexToPixel this codeNumber } else { error 'Error SW1 in GIF Reader' } comment 'Main Loop' while (codeNumber != EOICode) { comment 'read next code' addToBuffer this preCodeNumber = codeNumber readNextCodeNumber this comment 'check if end of data' if (codeNumber != EOICode) { comment 'check if a clear issued' if (codeNumber == clearCode) { resetCodes this addToBuffer this readNextCodeNumber this indexToPixel this codeNumber addToBuffer this preCodeNumber = codeNumber readNextCodeNumber this } comment 'the actual LZW decompression stuff :)' if (codeNumber > ((count codeTable) - 1)) { comment 'Code not found in codeTable' K = (first (enforceList this (at codeTable (preCodeNumber + 1)))) newCode = (list (at codeTable (preCodeNumber + 1))) newCode = (flattened newCode) add newCode K indexToPixel this newCode add codeTable newCode } else { comment 'Code found in codeTable' indexToPixel this (enforceList this (at codeTable (codeNumber + 1))) K = (first (enforceList this (at codeTable (codeNumber + 1)))) newCode = (list (at codeTable (preCodeNumber + 1))) newCode = (flattened newCode) add newCode K add codeTable newCode } if ((count codeTable) == (round (raise 2 codeSize))) { if (codeSize < 12) { codeSize += 1 } else { self_say LZWDataPos } } } } } method readNextCodeNumber GIFReader { codeNumber = (bitsToNumber this (copyFromTo dataBuffer ((count dataBuffer) - (codeSize - 1)) (count dataBuffer))) dataBuffer = (copyFromTo dataBuffer 1 ((count dataBuffer) - codeSize)) } method resetCodes GIFReader { codeSize = (LZWCodeSize + 1) codeTable = (list) for i (range 0 ((round (raise 2 LZWCodeSize)) - 1)) { add codeTable i } clearCode = (count codeTable) add codeTable clearCode EOICode = (count codeTable) add codeTable EOICode } script 'GIFReader' 449 221 { loadGIF this 'C:\Users\Simon\Downloads\Miaaaaoux_Micael_Reynaud.gif' false } script 'GIFReader' 341 97 { loadGIF this 'C:\Users\Simon\Downloads\sample_1.gif' } script 'GIFReader' 403 138 { loadGIF this 'filename.gif' } script 'GIFReader' 53 131 { whenBroadcastReceived 'go' loadGIF this 'C:\Users\Simon\Pictures\boy4-walking-a.gif' true } script 'GIFReader' 283 50 { loadGIF this 'C:\Users\Simon\Downloads\cat1.gif' false } script 'GIFReader' 546 178 { loadGIF this 'C:\Users\Simon\Downloads\sample_1.gif' } script 'GIFReader' 539 284 (readFile 'C:\Users\Simon\Pictures\boy4-walking-a.gif' true)