Paste: LZW with TIFF and GIF support

Author: klazuka
Mode: factor
Date: Fri, 25 Sep 2009 19:38:13
Plain Text |
! Copyright (C) 2009 Doug Coleman, Keith Lazuka
! See http://factorcode.org/license.txt for BSD license.
USING: accessors combinators io kernel math namespaces
prettyprint sequences vectors ;
QUALIFIED-WITH: bitstreams bs
IN: compression.lzw

SYMBOL: clear-code
4 clear-code set-global

SYMBOL: end-of-information
5 end-of-information set-global

TUPLE: lzw input output table code old-code initial-code-size code-size ;
TUPLE: tiff-lzw < lzw ;
TUPLE: gif-lzw < lzw ;

: initial-uncompress-table ( -- seq )
    end-of-information get 1 + iota [ 1vector ] V{ } map-as ;

: reset-lzw-uncompress ( lzw -- lzw )
    initial-uncompress-table >>table
    dup initial-code-size>> >>code-size ;

: <lzw-uncompress> ( input code-size class -- obj )
    new
        swap >>initial-code-size
        dup initial-code-size>> >>code-size
        swap >>input
        BV{ } clone >>output
        reset-lzw-uncompress ;

ERROR: not-in-table value ;

: lookup-old-code ( lzw -- vector )
    [ old-code>> ] [ table>> ] bi nth ;

: lookup-code ( lzw -- vector )
    [ code>> ] [ table>> ] bi nth ;

: code-in-table? ( lzw -- ? )
    [ code>> ] [ table>> length ] bi < ;

: code>old-code ( lzw -- lzw )
    dup code>> >>old-code ;

: write-code ( lzw -- )
    [ lookup-code ] [ output>> ] bi push-all ;

GENERIC: code-space-full? ( lzw -- ? )

M: tiff-lzw code-space-full?
    [ table>> length ] [ code-size>> 2^ 1 - ] bi = ;

M: gif-lzw code-space-full?
    [ table>> length ] [ code-size>> 2^ ] bi = ;

: maybe-increment-code-size ( lzw -- lzw )
    dup code-space-full? [ [ 1 + ] change-code-size ] when ;

: add-to-table ( seq lzw -- )
    [ table>> push ]
    [ maybe-increment-code-size 2drop ] 2bi ;

: lzw-read ( lzw -- lzw n )
    [ ] [ code-size>> ] [ input>> ] tri bs:read ;

DEFER: lzw-uncompress-char
: handle-clear-code ( lzw -- )
    reset-lzw-uncompress
    lzw-read dup end-of-information get = [
        2drop
    ] [
        >>code
        [ write-code ]
        [ code>old-code ] bi
        lzw-uncompress-char
    ] if ;

: handle-uncompress-code ( lzw -- lzw )
    dup code-in-table? [
        [ write-code ]
        [
            [
                [ lookup-old-code ]
                [ lookup-code first ] bi suffix
            ] [ add-to-table ] bi
        ] [ code>old-code ] tri
    ] [
        [
            [ lookup-old-code dup first suffix ] keep
            [ output>> push-all ] [ add-to-table ] 2bi
        ] [ code>old-code ] bi
    ] if ;
    
: lzw-uncompress-char ( lzw -- )
    lzw-read [
        >>code
        dup code>> end-of-information get = [
            drop
        ] [
            dup code>> clear-code get = [
                handle-clear-code
            ] [
                handle-uncompress-code
                lzw-uncompress-char
            ] if
        ] if
    ] [
        drop
    ] if* ;

: register-special-codes ( first-code-size -- first-code-size )
    [
        1 - 2^ dup clear-code set
        1 + end-of-information set
    ] keep ;

: lzw-uncompress ( bitstream code-size class -- byte-array )
    [ register-special-codes ] dip
    <lzw-uncompress>
    [ lzw-uncompress-char ] [ output>> ] bi ;

: tiff-lzw-uncompress ( seq -- byte-array )
    bs:<msb0-bit-reader> 9 tiff-lzw lzw-uncompress ;

: gif-lzw-uncompress ( seq code-size -- byte-array )
    [ bs:<lsb0-bit-reader> ] dip gif-lzw lzw-uncompress ;

Annotation: Simplified

Author: klazuka
Mode: factor
Date: Sun, 27 Sep 2009 01:16:07
Plain Text |
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien.accessors assocs byte-arrays combinators
io.encodings.binary io.streams.byte-array kernel math sequences
vectors ;
IN: compression.lzw

QUALIFIED-WITH: bitstreams bs

CONSTANT: clear-code 256
CONSTANT: end-of-information 257

TUPLE: lzw input output table code old-code ;

SYMBOL: table-full

: lzw-bit-width ( n -- n' )
    {
        { [ dup 510 <= ] [ drop 9 ] }
        { [ dup 1022 <= ] [ drop 10 ] }
        { [ dup 2046 <= ] [ drop 11 ] }
        { [ dup 4094 <= ] [ drop 12 ] }
        [ drop table-full ]
    } cond ;

: lzw-bit-width-uncompress ( lzw -- n )
    table>> length lzw-bit-width ;

: initial-uncompress-table ( -- seq )
    258 iota [ 1vector ] V{ } map-as ;

: reset-lzw-uncompress ( lzw -- lzw )
    initial-uncompress-table >>table ;

: <lzw-uncompress> ( input -- obj )
    lzw new
        swap >>input
        BV{ } clone >>output
        reset-lzw-uncompress ;

ERROR: not-in-table value ;

: lookup-old-code ( lzw -- vector )
    [ old-code>> ] [ table>> ] bi nth ;

: lookup-code ( lzw -- vector )
    [ code>> ] [ table>> ] bi nth ;

: code-in-table? ( lzw -- ? )
    [ code>> ] [ table>> length ] bi < ;

: code>old-code ( lzw -- lzw )
    dup code>> >>old-code ;

: write-code ( lzw -- )
    [ lookup-code ] [ output>> ] bi push-all ;

: add-to-table ( seq lzw -- ) table>> push ;

: lzw-read ( lzw -- lzw n )
    [ ] [ lzw-bit-width-uncompress ] [ input>> ] tri bs:read ;

DEFER: lzw-uncompress-char
: handle-clear-code ( lzw -- )
    reset-lzw-uncompress
    lzw-read dup end-of-information = [
        2drop
    ] [
        >>code
        [ write-code ]
        [ code>old-code ] bi
        lzw-uncompress-char
    ] if ;

: handle-uncompress-code ( lzw -- lzw )
    dup code-in-table? [
        [ write-code ]
        [
            [
                [ lookup-old-code ]
                [ lookup-code first ] bi suffix
            ] [ add-to-table ] bi
        ] [ code>old-code ] tri
    ] [
        [
            [ lookup-old-code dup first suffix ] keep
            [ output>> push-all ] [ add-to-table ] 2bi
        ] [ code>old-code ] bi
    ] if ;
    
: lzw-uncompress-char ( lzw -- )
    lzw-read [
        >>code
        dup code>> end-of-information = [
            drop
        ] [
            dup code>> clear-code = [
                handle-clear-code
            ] [
                handle-uncompress-code
                lzw-uncompress-char
            ] if
        ] if
    ] [
        drop
    ] if* ;

: lzw-uncompress ( seq -- byte-array )
    bs:<msb0-bit-reader>
    <lzw-uncompress>
    [ lzw-uncompress-char ] [ output>> ] bi ;

New Annotation

Summary:
Author:
Mode:
Body: