├── 30log.lua ├── 30logLICENSE ├── Example.png ├── LICENSE ├── README.md ├── deflate.lua ├── deflateLICENSE ├── logo.png ├── numberlua.lua ├── numberluaLICENSE ├── png.lua ├── stream.lua └── test.lua /30log.lua: -------------------------------------------------------------------------------- 1 | local assert, pairs, type, tostring, baseMt, _instances, _classes, class = assert, pairs, type, tostring, {}, {}, {} 2 | local function deep_copy(t, dest, aType) 3 | local t, r = t or {}, dest or {} 4 | for k,v in pairs(t) do 5 | if aType and type(v)==aType then r[k] = v elseif not aType then 6 | if type(v) == 'table' and k ~= "__index" then r[k] = deep_copy(v) else r[k] = v end 7 | end 8 | end; return r 9 | end 10 | local function instantiate(self,...) 11 | local instance = deep_copy(self) ; _instances[instance] = tostring(instance); setmetatable(instance,self) 12 | if self.__init then 13 | if type(self.__init) == 'table' then deep_copy(self.__init, instance) else self.__init(instance, ...) end 14 | end 15 | return instance 16 | end 17 | local function extends(self,extra_params) 18 | local heirClass = deep_copy(self, class(extra_params)); heirClass.__index, heirClass.super = heirClass, self 19 | return setmetatable(heirClass,self) 20 | end 21 | baseMt = { __call = function (self,...) return self:new(...) end, 22 | __tostring = function(self,...) 23 | if _instances[self] then return ('object (of %s): <%s>'):format((rawget(getmetatable(self),'__name') or 'Unnamed'), _instances[self]) end 24 | return _classes[self] and ('class (%s): <%s>'):format((rawget(self,'__name') or 'Unnamed'),_classes[self]) or self 25 | end} 26 | class = function(attr) 27 | local c = deep_copy(attr) ; _classes[c] = tostring(c); 28 | c.with = function(self,include) assert(_classes[self], 'Mixins can only be used on classes') return deep_copy(include, self, 'function') end 29 | c.new, c.extends, c.__index, c.__call, c.__tostring = instantiate, extends, c, baseMt.__call, baseMt.__tostring; return setmetatable(c,baseMt) 30 | end; return class -------------------------------------------------------------------------------- /30logLICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - 2013 Roland Yonaba 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DelusionalLogic/pngLua/c2bb6b210e0a06d36a4df16a73c20eaf73f75a6e/Example.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 DelusionalLogic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![pngLua logo](/logo.png?raw=true) 2 | 3 | A pure lua implementation of a PNG decoder 4 | 5 | Usage 6 | ----- 7 | 8 | To initialize a new png image: 9 | 10 | img = pngImage(, newRowCallback) 11 | 12 | The image will then be decoded. The available data from the image is as follows 13 | ``` 14 | img.width = 0 15 | img.height = 0 16 | img.depth = 0 17 | img.colorType = 0 18 | 19 | img:getPixel(x, y) 20 | ``` 21 | Decoding the image is synchronous, and will take a long time for large images. 22 | 23 | Support 24 | ------- 25 | 26 | The supported colortypes are as follows: 27 | 28 | - Grayscale 29 | - Truecolor 30 | - Indexed 31 | - Greyscale/alpha 32 | - Truecolor/alpha 33 | 34 | So far the module only supports 256 Colors in png-8, png-24 as well as png-32 files. and no ancillary chunks. 35 | 36 | More than 256 colors might be supported (Bit-depths over 8) as long as they align with whole bytes. These have not been tested. 37 | 38 | Multiple IDAT chunks of arbitrary lengths are supported, as well as all filters. 39 | 40 | Errors 41 | ------- 42 | So far no error-checking has been implemented. No crc32 checks are done. 43 | -------------------------------------------------------------------------------- /deflate.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | LUA MODULE 4 | 5 | compress.deflatelua - deflate (and gunzip/zlib) implemented in Lua. 6 | 7 | SYNOPSIS 8 | local DEFLATE = require 'compress.deflatelua' 9 | -- uncompress gzip file 10 | local fh = assert(io.open'foo.txt.gz', 'rb') 11 | local ofh = assert(io.open'foo.txt', 'wb') 12 | DEFLATE.gunzip {input=fh, output=ofh} 13 | fh:close(); ofh:close() 14 | -- can also uncompress from string including zlib and raw DEFLATE formats. 15 | DESCRIPTION 16 | This is a pure Lua implementation of decompressing the DEFLATE format, 17 | including the related zlib and gzip formats. 18 | Note: This library only supports decompression. 19 | Compression is not currently implemented. 20 | 21 | API 22 | 23 | Note: in the following functions, input stream `fh` may be 24 | a file handle, string, or an iterator function that returns strings. 25 | Output stream `ofh` may be a file handle or a function that 26 | consumes one byte (number 0..255) per call. 27 | 28 | DEFLATE.inflate {input=fh, output=ofh} 29 | 30 | Decompresses input stream `fh` in the DEFLATE format 31 | while writing to output stream `ofh`. 32 | DEFLATE is detailed in http://tools.ietf.org/html/rfc1951 . 33 | DEFLATE.gunzip {input=fh, output=ofh, disable_crc=disable_crc} 34 | Decompresses input stream `fh` with the gzip format 35 | while writing to output stream `ofh`. 36 | `disable_crc` (defaults to `false`) will disable CRC-32 checking 37 | to increase speed. 38 | gzip is detailed in http://tools.ietf.org/html/rfc1952 . 39 | 40 | DEFLATE.inflate_zlib {input=fh, output=ofh, disable_crc=disable_crc} 41 | Decompresses input stream `fh` with the zlib format 42 | while writing to output stream `ofh`. 43 | `disable_crc` (defaults to `false`) will disable CRC-32 checking 44 | to increase speed. 45 | zlib is detailed in http://tools.ietf.org/html/rfc1950 . 46 | 47 | DEFLATE.adler32(byte, crc) --> rcrc 48 | Returns adler32 checksum of byte `byte` (number 0..255) appended 49 | to string with adler32 checksum `crc`. This is internally used by 50 | `inflate_zlib`. 51 | ADLER32 in detailed in http://tools.ietf.org/html/rfc1950 . 52 | 53 | COMMAND LINE UTILITY 54 | 55 | A `gunziplua` command line utility (in folder `bin`) is also provided. 56 | This mimicks the *nix `gunzip` utility but is a pure Lua implementation 57 | that invokes this library. For help do 58 | gunziplua -h 59 | DEPENDENCIES 60 | 61 | Requires 'digest.crc32lua' (used for optional CRC-32 checksum checks). 62 | https://github.com/davidm/lua-digest-crc32lua 63 | 64 | Will use a bit library ('bit', 'bit32', 'bit.numberlua') if available. This 65 | is not that critical for this library but is required by digest.crc32lua. 66 | 67 | 'pythonic.optparse' is only required by the optional `gunziplua` 68 | command-line utilty for command line parsing. 69 | https://github.com/davidm/lua-pythonic-optparse 70 | 71 | INSTALLATION 72 | 73 | Copy the `compress` directory into your LUA_PATH. 74 | REFERENCES 75 | 76 | [1] DEFLATE Compressed Data Format Specification version 1.3 77 | http://tools.ietf.org/html/rfc1951 78 | [2] GZIP file format specification version 4.3 79 | http://tools.ietf.org/html/rfc1952 80 | [3] http://en.wikipedia.org/wiki/DEFLATE 81 | [4] pyflate, by Paul Sladen 82 | http://www.paul.sladen.org/projects/pyflate/ 83 | [5] Compress::Zlib::Perl - partial pure Perl implementation of 84 | Compress::Zlib 85 | http://search.cpan.org/~nwclark/Compress-Zlib-Perl/Perl.pm 86 | 87 | LICENSE 88 | 89 | (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). 90 | 91 | Permission is hereby granted, free of charge, to any person obtaining a copy 92 | of this software and associated documentation files (the "Software"), to deal 93 | in the Software without restriction, including without limitation the rights 94 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 95 | copies of the Software, and to permit persons to whom the Software is 96 | furnished to do so, subject to the following conditions: 97 | 98 | The above copyright notice and this permission notice shall be included in 99 | all copies or substantial portions of the Software. 100 | 101 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 102 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 103 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 104 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 105 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 106 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 107 | THE SOFTWARE. 108 | (end license) 109 | --]] 110 | 111 | local M = {_TYPE='module', _NAME='compress.deflatelua', _VERSION='0.3.20111128'} 112 | 113 | local assert = assert 114 | local error = error 115 | local ipairs = ipairs 116 | local pairs = pairs 117 | local print = print 118 | local require = require 119 | local tostring = tostring 120 | local type = type 121 | local setmetatable = setmetatable 122 | local io = io 123 | local math = math 124 | local table_sort = table.sort 125 | local math_max = math.max 126 | local string_char = string.char 127 | 128 | --[[ 129 | Requires the first module listed that exists, else raises like `require`. 130 | If a non-string is encountered, it is returned. 131 | Second return value is module name loaded (or ''). 132 | --]] 133 | local function requireany(...) 134 | local errs = {} 135 | for i = 1, select('#', ...) do local name = select(i, ...) 136 | if type(name) ~= 'string' then return name, '' end 137 | local ok, mod = pcall(require, name) 138 | if ok then return mod, name end 139 | errs[#errs+1] = mod 140 | end 141 | error(table.concat(errs, '\n'), 2) 142 | end 143 | 144 | 145 | --local crc32 = require "digest.crc32lua" . crc32_byte 146 | local bit, name_ = requireany('bit', 'bit32', 'bit.numberlua', nil) 147 | 148 | local DEBUG = false 149 | 150 | -- Whether to use `bit` library functions in current module. 151 | -- Unlike the crc32 library, it doesn't make much difference in this module. 152 | local NATIVE_BITOPS = (bit ~= nil) 153 | 154 | local band, lshift, rshift 155 | if NATIVE_BITOPS then 156 | band = bit.band 157 | lshift = bit.lshift 158 | rshift = bit.rshift 159 | end 160 | 161 | 162 | local function warn(s) 163 | io.stderr:write(s, '\n') 164 | end 165 | 166 | 167 | local function debug(...) 168 | print('DEBUG', ...) 169 | end 170 | 171 | 172 | local function runtime_error(s, level) 173 | level = level or 1 174 | error({s}, level+1) 175 | end 176 | 177 | 178 | local function make_outstate(outbs) 179 | local outstate = {} 180 | outstate.outbs = outbs 181 | outstate.window = {} 182 | outstate.window_pos = 1 183 | return outstate 184 | end 185 | 186 | 187 | local function output(outstate, byte) 188 | -- debug('OUTPUT:', s) 189 | local window_pos = outstate.window_pos 190 | outstate.outbs(byte) 191 | outstate.window[window_pos] = byte 192 | outstate.window_pos = window_pos % 32768 + 1 -- 32K 193 | end 194 | 195 | 196 | local function noeof(val) 197 | return assert(val, 'unexpected end of file') 198 | end 199 | 200 | 201 | local function hasbit(bits, bit) 202 | return bits % (bit + bit) >= bit 203 | end 204 | 205 | 206 | local function memoize(f) 207 | local mt = {} 208 | local t = setmetatable({}, mt) 209 | function mt:__index(k) 210 | local v = f(k) 211 | t[k] = v 212 | return v 213 | end 214 | return t 215 | end 216 | 217 | 218 | -- small optimization (lookup table for powers of 2) 219 | local pow2 = memoize(function(n) return 2^n end) 220 | 221 | --local tbits = memoize( 222 | -- function(bits) 223 | -- return memoize( function(bit) return getbit(bits, bit) end ) 224 | -- end ) 225 | 226 | 227 | -- weak metatable marking objects as bitstream type 228 | local is_bitstream = setmetatable({}, {__mode='k'}) 229 | 230 | 231 | -- DEBUG 232 | -- prints LSB first 233 | --[[ 234 | local function bits_tostring(bits, nbits) 235 | local s = '' 236 | local tmp = bits 237 | local function f() 238 | local b = tmp % 2 == 1 and 1 or 0 239 | s = s .. b 240 | tmp = (tmp - b) / 2 241 | end 242 | if nbits then 243 | for i=1,nbits do f() end 244 | else 245 | while tmp ~= 0 do f() end 246 | end 247 | 248 | return s 249 | end 250 | --]] 251 | 252 | local function bytestream_from_file(fh) 253 | local o = {} 254 | function o:read() 255 | local sb = fh:read(1) 256 | if sb then return sb:byte() end 257 | end 258 | return o 259 | end 260 | 261 | 262 | local function bytestream_from_string(s) 263 | local i = 1 264 | local o = {} 265 | function o:read() 266 | local by 267 | if i <= #s then 268 | by = s:byte(i) 269 | i = i + 1 270 | end 271 | return by 272 | end 273 | return o 274 | end 275 | 276 | 277 | local function bytestream_from_function(f) 278 | local i = 0 279 | local buffer = '' 280 | local o = {} 281 | function o:read() 282 | i = i + 1 283 | if i > #buffer then 284 | buffer = f() 285 | if not buffer then return end 286 | i = 1 287 | end 288 | return buffer:byte(i,i) 289 | end 290 | return o 291 | end 292 | 293 | 294 | local function bitstream_from_bytestream(bys) 295 | local buf_byte = 0 296 | local buf_nbit = 0 297 | local o = {} 298 | 299 | function o:nbits_left_in_byte() 300 | return buf_nbit 301 | end 302 | 303 | if NATIVE_BITOPS then 304 | function o:read(nbits) 305 | nbits = nbits or 1 306 | while buf_nbit < nbits do 307 | local byte = bys:read() 308 | if not byte then return end -- note: more calls also return nil 309 | buf_byte = buf_byte + lshift(byte, buf_nbit) 310 | buf_nbit = buf_nbit + 8 311 | end 312 | local bits 313 | if nbits == 0 then 314 | bits = 0 315 | elseif nbits == 32 then 316 | bits = buf_byte 317 | buf_byte = 0 318 | else 319 | bits = band(buf_byte, rshift(0xffffffff, 32 - nbits)) 320 | buf_byte = rshift(buf_byte, nbits) 321 | end 322 | buf_nbit = buf_nbit - nbits 323 | return bits 324 | end 325 | else 326 | function o:read(nbits) 327 | nbits = nbits or 1 328 | while buf_nbit < nbits do 329 | local byte = bys:read() 330 | if not byte then return end -- note: more calls also return nil 331 | buf_byte = buf_byte + pow2[buf_nbit] * byte 332 | buf_nbit = buf_nbit + 8 333 | end 334 | local m = pow2[nbits] 335 | local bits = buf_byte % m 336 | buf_byte = (buf_byte - bits) / m 337 | buf_nbit = buf_nbit - nbits 338 | return bits 339 | end 340 | end 341 | 342 | is_bitstream[o] = true 343 | 344 | return o 345 | end 346 | 347 | 348 | local function get_bitstream(o) 349 | local bs 350 | if is_bitstream[o] then 351 | return o 352 | elseif io.type(o) == 'file' then 353 | bs = bitstream_from_bytestream(bytestream_from_file(o)) 354 | elseif type(o) == 'string' then 355 | bs = bitstream_from_bytestream(bytestream_from_string(o)) 356 | elseif type(o) == 'function' then 357 | bs = bitstream_from_bytestream(bytestream_from_function(o)) 358 | else 359 | runtime_error 'unrecognized type' 360 | end 361 | return bs 362 | end 363 | 364 | 365 | local function get_obytestream(o) 366 | local bs 367 | if io.type(o) == 'file' then 368 | bs = function(sbyte) o:write(string_char(sbyte)) end 369 | elseif type(o) == 'function' then 370 | bs = o 371 | else 372 | runtime_error('unrecognized type: ' .. tostring(o)) 373 | end 374 | return bs 375 | end 376 | 377 | 378 | local function HuffmanTable(init, is_full) 379 | local t = {} 380 | if is_full then 381 | for val,nbits in pairs(init) do 382 | if nbits ~= 0 then 383 | t[#t+1] = {val=val, nbits=nbits} 384 | --debug('*',val,nbits) 385 | end 386 | end 387 | else 388 | for i=1,#init-2,2 do 389 | local firstval, nbits, nextval = init[i], init[i+1], init[i+2] 390 | --debug(val, nextval, nbits) 391 | if nbits ~= 0 then 392 | for val=firstval,nextval-1 do 393 | t[#t+1] = {val=val, nbits=nbits} 394 | end 395 | end 396 | end 397 | end 398 | table_sort(t, function(a,b) 399 | return a.nbits == b.nbits and a.val < b.val or a.nbits < b.nbits 400 | end) 401 | 402 | -- assign codes 403 | local code = 1 -- leading 1 marker 404 | local nbits = 0 405 | for i,s in ipairs(t) do 406 | if s.nbits ~= nbits then 407 | code = code * pow2[s.nbits - nbits] 408 | nbits = s.nbits 409 | end 410 | s.code = code 411 | --debug('huffman code:', i, s.nbits, s.val, code, bits_tostring(code)) 412 | code = code + 1 413 | end 414 | 415 | local minbits = math.huge 416 | local look = {} 417 | for i,s in ipairs(t) do 418 | minbits = math.min(minbits, s.nbits) 419 | look[s.code] = s.val 420 | end 421 | 422 | --for _,o in ipairs(t) do 423 | -- debug(':', o.nbits, o.val) 424 | --end 425 | 426 | -- function t:lookup(bits) return look[bits] end 427 | 428 | local msb = NATIVE_BITOPS and function(bits, nbits) 429 | local res = 0 430 | for i=1,nbits do 431 | res = lshift(res, 1) + band(bits, 1) 432 | bits = rshift(bits, 1) 433 | end 434 | return res 435 | end or function(bits, nbits) 436 | local res = 0 437 | for i=1,nbits do 438 | local b = bits % 2 439 | bits = (bits - b) / 2 440 | res = res * 2 + b 441 | end 442 | return res 443 | end 444 | 445 | local tfirstcode = memoize( 446 | function(bits) return pow2[minbits] + msb(bits, minbits) end) 447 | 448 | function t:read(bs) 449 | local code = 1 -- leading 1 marker 450 | local nbits = 0 451 | while 1 do 452 | if nbits == 0 then -- small optimization (optional) 453 | code = tfirstcode[noeof(bs:read(minbits))] 454 | nbits = nbits + minbits 455 | else 456 | local b = noeof(bs:read()) 457 | nbits = nbits + 1 458 | code = code * 2 + b -- MSB first 459 | --[[NATIVE_BITOPS 460 | code = lshift(code, 1) + b -- MSB first 461 | --]] 462 | end 463 | --debug('code?', code, bits_tostring(code)) 464 | local val = look[code] 465 | if val then 466 | --debug('FOUND', val) 467 | return val 468 | end 469 | end 470 | end 471 | 472 | return t 473 | end 474 | 475 | 476 | local function parse_gzip_header(bs) 477 | -- local FLG_FTEXT = 2^0 478 | local FLG_FHCRC = 2^1 479 | local FLG_FEXTRA = 2^2 480 | local FLG_FNAME = 2^3 481 | local FLG_FCOMMENT = 2^4 482 | 483 | local id1 = bs:read(8) 484 | local id2 = bs:read(8) 485 | if id1 ~= 31 or id2 ~= 139 then 486 | runtime_error 'not in gzip format' 487 | end 488 | local cm = bs:read(8) -- compression method 489 | local flg = bs:read(8) -- FLaGs 490 | local mtime = bs:read(32) -- Modification TIME 491 | local xfl = bs:read(8) -- eXtra FLags 492 | local os = bs:read(8) -- Operating System 493 | 494 | if DEBUG then 495 | debug("CM=", cm) 496 | debug("FLG=", flg) 497 | debug("MTIME=", mtime) 498 | -- debug("MTIME_str=",os.date("%Y-%m-%d %H:%M:%S",mtime)) -- non-portable 499 | debug("XFL=", xfl) 500 | debug("OS=", os) 501 | end 502 | 503 | if not os then runtime_error 'invalid header' end 504 | 505 | if hasbit(flg, FLG_FEXTRA) then 506 | local xlen = bs:read(16) 507 | local extra = 0 508 | for i=1,xlen do 509 | extra = bs:read(8) 510 | end 511 | if not extra then runtime_error 'invalid header' end 512 | end 513 | 514 | local function parse_zstring(bs) 515 | repeat 516 | local by = bs:read(8) 517 | if not by then runtime_error 'invalid header' end 518 | until by == 0 519 | end 520 | 521 | if hasbit(flg, FLG_FNAME) then 522 | parse_zstring(bs) 523 | end 524 | 525 | if hasbit(flg, FLG_FCOMMENT) then 526 | parse_zstring(bs) 527 | end 528 | 529 | if hasbit(flg, FLG_FHCRC) then 530 | local crc16 = bs:read(16) 531 | if not crc16 then runtime_error 'invalid header' end 532 | -- IMPROVE: check CRC. where is an example .gz file that 533 | -- has this set? 534 | if DEBUG then 535 | debug("CRC16=", crc16) 536 | end 537 | end 538 | end 539 | 540 | local function parse_zlib_header(bs) 541 | local cm = bs:read(4) -- Compression Method 542 | local cinfo = bs:read(4) -- Compression info 543 | local fcheck = bs:read(5) -- FLaGs: FCHECK (check bits for CMF and FLG) 544 | local fdict = bs:read(1) -- FLaGs: FDICT (present dictionary) 545 | local flevel = bs:read(2) -- FLaGs: FLEVEL (compression level) 546 | local cmf = cinfo * 16 + cm -- CMF (Compresion Method and flags) 547 | local flg = fcheck + fdict * 32 + flevel * 64 -- FLaGs 548 | 549 | if cm ~= 8 then -- not "deflate" 550 | runtime_error("unrecognized zlib compression method: " .. cm) 551 | end 552 | if cinfo > 7 then 553 | runtime_error("invalid zlib window size: cinfo=" .. cinfo) 554 | end 555 | local window_size = 2^(cinfo + 8) 556 | 557 | if (cmf*256 + flg) % 31 ~= 0 then 558 | runtime_error("invalid zlib header (bad fcheck sum)") 559 | end 560 | 561 | if fdict == 1 then 562 | runtime_error("FIX:TODO - FDICT not currently implemented") 563 | local dictid_ = bs:read(32) 564 | end 565 | 566 | return window_size 567 | end 568 | 569 | local function parse_huffmantables(bs) 570 | local hlit = bs:read(5) -- # of literal/length codes - 257 571 | local hdist = bs:read(5) -- # of distance codes - 1 572 | local hclen = noeof(bs:read(4)) -- # of code length codes - 4 573 | 574 | local ncodelen_codes = hclen + 4 575 | local codelen_init = {} 576 | local codelen_vals = { 577 | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} 578 | for i=1,ncodelen_codes do 579 | local nbits = bs:read(3) 580 | local val = codelen_vals[i] 581 | codelen_init[val] = nbits 582 | end 583 | local codelentable = HuffmanTable(codelen_init, true) 584 | 585 | local function decode(ncodes) 586 | local init = {} 587 | local nbits 588 | local val = 0 589 | while val < ncodes do 590 | local codelen = codelentable:read(bs) 591 | --FIX:check nil? 592 | local nrepeat 593 | if codelen <= 15 then 594 | nrepeat = 1 595 | nbits = codelen 596 | --debug('w', nbits) 597 | elseif codelen == 16 then 598 | nrepeat = 3 + noeof(bs:read(2)) 599 | -- nbits unchanged 600 | elseif codelen == 17 then 601 | nrepeat = 3 + noeof(bs:read(3)) 602 | nbits = 0 603 | elseif codelen == 18 then 604 | nrepeat = 11 + noeof(bs:read(7)) 605 | nbits = 0 606 | else 607 | error 'ASSERT' 608 | end 609 | for i=1,nrepeat do 610 | init[val] = nbits 611 | val = val + 1 612 | end 613 | end 614 | local huffmantable = HuffmanTable(init, true) 615 | return huffmantable 616 | end 617 | 618 | local nlit_codes = hlit + 257 619 | local ndist_codes = hdist + 1 620 | 621 | local littable = decode(nlit_codes) 622 | local disttable = decode(ndist_codes) 623 | 624 | return littable, disttable 625 | end 626 | 627 | 628 | local tdecode_len_base 629 | local tdecode_len_nextrabits 630 | local tdecode_dist_base 631 | local tdecode_dist_nextrabits 632 | local function parse_compressed_item(bs, outstate, littable, disttable) 633 | local val = littable:read(bs) 634 | --debug(val, val < 256 and string_char(val)) 635 | if val < 256 then -- literal 636 | output(outstate, val) 637 | elseif val == 256 then -- end of block 638 | return true 639 | else 640 | if not tdecode_len_base then 641 | local t = {[257]=3} 642 | local skip = 1 643 | for i=258,285,4 do 644 | for j=i,i+3 do t[j] = t[j-1] + skip end 645 | if i ~= 258 then skip = skip * 2 end 646 | end 647 | t[285] = 258 648 | tdecode_len_base = t 649 | --for i=257,285 do debug('T1',i,t[i]) end 650 | end 651 | if not tdecode_len_nextrabits then 652 | local t = {} 653 | if NATIVE_BITOPS then 654 | for i=257,285 do 655 | local j = math_max(i - 261, 0) 656 | t[i] = rshift(j, 2) 657 | end 658 | else 659 | for i=257,285 do 660 | local j = math_max(i - 261, 0) 661 | t[i] = (j - (j % 4)) / 4 662 | end 663 | end 664 | t[285] = 0 665 | tdecode_len_nextrabits = t 666 | --for i=257,285 do debug('T2',i,t[i]) end 667 | end 668 | local len_base = tdecode_len_base[val] 669 | local nextrabits = tdecode_len_nextrabits[val] 670 | local extrabits = bs:read(nextrabits) 671 | local len = len_base + extrabits 672 | 673 | if not tdecode_dist_base then 674 | local t = {[0]=1} 675 | local skip = 1 676 | for i=1,29,2 do 677 | for j=i,i+1 do t[j] = t[j-1] + skip end 678 | if i ~= 1 then skip = skip * 2 end 679 | end 680 | tdecode_dist_base = t 681 | --for i=0,29 do debug('T3',i,t[i]) end 682 | end 683 | if not tdecode_dist_nextrabits then 684 | local t = {} 685 | if NATIVE_BITOPS then 686 | for i=0,29 do 687 | local j = math_max(i - 2, 0) 688 | t[i] = rshift(j, 1) 689 | end 690 | else 691 | for i=0,29 do 692 | local j = math_max(i - 2, 0) 693 | t[i] = (j - (j % 2)) / 2 694 | end 695 | end 696 | tdecode_dist_nextrabits = t 697 | --for i=0,29 do debug('T4',i,t[i]) end 698 | end 699 | local dist_val = disttable:read(bs) 700 | local dist_base = tdecode_dist_base[dist_val] 701 | local dist_nextrabits = tdecode_dist_nextrabits[dist_val] 702 | local dist_extrabits = bs:read(dist_nextrabits) 703 | local dist = dist_base + dist_extrabits 704 | 705 | --debug('BACK', len, dist) 706 | for i=1,len do 707 | local pos = (outstate.window_pos - 1 - dist) % 32768 + 1 -- 32K 708 | output(outstate, assert(outstate.window[pos], 'invalid distance')) 709 | end 710 | end 711 | return false 712 | end 713 | 714 | 715 | local function parse_block(bs, outstate) 716 | local bfinal = bs:read(1) 717 | local btype = bs:read(2) 718 | 719 | local BTYPE_NO_COMPRESSION = 0 720 | local BTYPE_FIXED_HUFFMAN = 1 721 | local BTYPE_DYNAMIC_HUFFMAN = 2 722 | local BTYPE_RESERVED_ = 3 723 | 724 | if DEBUG then 725 | debug('bfinal=', bfinal) 726 | debug('btype=', btype) 727 | end 728 | 729 | if btype == BTYPE_NO_COMPRESSION then 730 | bs:read(bs:nbits_left_in_byte()) 731 | local len = bs:read(16) 732 | local nlen_ = noeof(bs:read(16)) 733 | 734 | for i=1,len do 735 | local by = noeof(bs:read(8)) 736 | output(outstate, by) 737 | end 738 | elseif btype == BTYPE_FIXED_HUFFMAN or btype == BTYPE_DYNAMIC_HUFFMAN then 739 | local littable, disttable 740 | if btype == BTYPE_DYNAMIC_HUFFMAN then 741 | littable, disttable = parse_huffmantables(bs) 742 | else 743 | littable = HuffmanTable {0,8, 144,9, 256,7, 280,8, 288,nil} 744 | disttable = HuffmanTable {0,5, 32,nil} 745 | end 746 | 747 | repeat 748 | local is_done = parse_compressed_item( 749 | bs, outstate, littable, disttable) 750 | until is_done 751 | else 752 | runtime_error 'unrecognized compression type' 753 | end 754 | 755 | return bfinal ~= 0 756 | end 757 | 758 | 759 | function M.inflate(t) 760 | local bs = get_bitstream(t.input) 761 | local outbs = get_obytestream(t.output) 762 | local outstate = make_outstate(outbs) 763 | 764 | repeat 765 | local is_final = parse_block(bs, outstate) 766 | until is_final 767 | end 768 | local inflate = M.inflate 769 | 770 | 771 | function M.gunzip(t) 772 | local bs = get_bitstream(t.input) 773 | local outbs = get_obytestream(t.output) 774 | local disable_crc = t.disable_crc 775 | if disable_crc == nil then disable_crc = false end 776 | 777 | parse_gzip_header(bs) 778 | 779 | local data_crc32 = 0 780 | 781 | inflate{input=bs, output= 782 | disable_crc and outbs or 783 | function(byte) 784 | data_crc32 = crc32(byte, data_crc32) 785 | outbs(byte) 786 | end 787 | } 788 | 789 | bs:read(bs:nbits_left_in_byte()) 790 | 791 | local expected_crc32 = bs:read(32) 792 | local isize = bs:read(32) -- ignored 793 | if DEBUG then 794 | debug('crc32=', expected_crc32) 795 | debug('isize=', isize) 796 | end 797 | if not disable_crc and data_crc32 then 798 | if data_crc32 ~= expected_crc32 then 799 | runtime_error('invalid compressed data--crc error') 800 | end 801 | end 802 | if bs:read() then 803 | warn 'trailing garbage ignored' 804 | end 805 | end 806 | 807 | 808 | function M.adler32(byte, crc) 809 | local s1 = crc % 65536 810 | local s2 = (crc - s1) / 65536 811 | s1 = (s1 + byte) % 65521 812 | s2 = (s2 + s1) % 65521 813 | return s2*65536 + s1 814 | end -- 65521 is the largest prime smaller than 2^16 815 | 816 | 817 | function M.inflate_zlib(t) 818 | local bs = get_bitstream(t.input) 819 | local outbs = get_obytestream(t.output) 820 | local disable_crc = t.disable_crc 821 | if disable_crc == nil then disable_crc = false end 822 | 823 | local window_size_ = parse_zlib_header(bs) 824 | 825 | local data_adler32 = 1 826 | 827 | inflate{input=bs, output= 828 | disable_crc and outbs or 829 | function(byte) 830 | data_adler32 = M.adler32(byte, data_adler32) 831 | outbs(byte) 832 | end 833 | } 834 | 835 | bs:read(bs:nbits_left_in_byte()) 836 | 837 | local b3 = bs:read(8) 838 | local b2 = bs:read(8) 839 | local b1 = bs:read(8) 840 | local b0 = bs:read(8) 841 | local expected_adler32 = ((b3*256 + b2)*256 + b1)*256 + b0 842 | if DEBUG then 843 | debug('alder32=', expected_adler32) 844 | end 845 | if not disable_crc then 846 | if data_adler32 ~= expected_adler32 then 847 | runtime_error('invalid compressed data--crc error') 848 | end 849 | end 850 | if bs:read() then 851 | warn 'trailing garbage ignored' 852 | end 853 | end 854 | 855 | 856 | return M -------------------------------------------------------------------------------- /deflateLICENSE: -------------------------------------------------------------------------------- 1 | lua-compress-deflatelua License 2 | 3 | =============================================================================== 4 | 5 | Copyright (C) 2008, David Manura. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | 25 | =============================================================================== -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DelusionalLogic/pngLua/c2bb6b210e0a06d36a4df16a73c20eaf73f75a6e/logo.png -------------------------------------------------------------------------------- /numberlua.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | LUA MODULE 4 | 5 | bit.numberlua - Bitwise operations implemented in pure Lua as numbers, 6 | with Lua 5.2 'bit32' and (LuaJIT) LuaBitOp 'bit' compatibility interfaces. 7 | 8 | SYNOPSIS 9 | 10 | local bit = require 'bit.numberlua' 11 | print(bit.band(0xff00ff00, 0x00ff00ff)) --> 0xffffffff 12 | -- Interface providing strong Lua 5.2 'bit32' compatibility 13 | local bit32 = require 'bit.numberlua'.bit32 14 | assert(bit32.band(-1) == 0xffffffff) 15 | -- Interface providing strong (LuaJIT) LuaBitOp 'bit' compatibility 16 | local bit = require 'bit.numberlua'.bit 17 | assert(bit.tobit(0xffffffff) == -1) 18 | DESCRIPTION 19 | This library implements bitwise operations entirely in Lua. 20 | This module is typically intended if for some reasons you don't want 21 | to or cannot install a popular C based bit library like BitOp 'bit' [1] 22 | (which comes pre-installed with LuaJIT) or 'bit32' (which comes 23 | pre-installed with Lua 5.2) but want a similar interface. 24 | This modules represents bit arrays as non-negative Lua numbers. [1] 25 | It can represent 32-bit bit arrays when Lua is compiled 26 | with lua_Number as double-precision IEEE 754 floating point. 27 | 28 | The module is nearly the most efficient it can be but may be a few times 29 | slower than the C based bit libraries and is orders or magnitude 30 | slower than LuaJIT bit operations, which compile to native code. Therefore, 31 | this library is inferior in performane to the other modules. 32 | 33 | The `xor` function in this module is based partly on Roberto Ierusalimschy's 34 | post in http://lua-users.org/lists/lua-l/2002-09/msg00134.html . 35 | The included BIT.bit32 and BIT.bit sublibraries aims to provide 100% 36 | compatibility with the Lua 5.2 "bit32" and (LuaJIT) LuaBitOp "bit" library. 37 | This compatbility is at the cost of some efficiency since inputted 38 | numbers are normalized and more general forms (e.g. multi-argument 39 | bitwise operators) are supported. 40 | STATUS 41 | 42 | WARNING: Not all corner cases have been tested and documented. 43 | Some attempt was made to make these similar to the Lua 5.2 [2] 44 | and LuaJit BitOp [3] libraries, but this is not fully tested and there 45 | are currently some differences. Addressing these differences may 46 | be improved in the future but it is not yet fully determined how to 47 | resolve these differences. 48 | The BIT.bit32 library passes the Lua 5.2 test suite (bitwise.lua) 49 | http://www.lua.org/tests/5.2/ . The BIT.bit library passes the LuaBitOp 50 | test suite (bittest.lua). However, these have not been tested on 51 | platforms with Lua compiled with 32-bit integer numbers. 52 | 53 | API 54 | 55 | BIT.tobit(x) --> z 56 | Similar to function in BitOp. 57 | BIT.tohex(x, n) 58 | Similar to function in BitOp. 59 | BIT.band(x, y) --> z 60 | Similar to function in Lua 5.2 and BitOp but requires two arguments. 61 | BIT.bor(x, y) --> z 62 | Similar to function in Lua 5.2 and BitOp but requires two arguments. 63 | 64 | BIT.bxor(x, y) --> z 65 | Similar to function in Lua 5.2 and BitOp but requires two arguments. 66 | BIT.bnot(x) --> z 67 | Similar to function in Lua 5.2 and BitOp. 68 | 69 | BIT.lshift(x, disp) --> z 70 | Similar to function in Lua 5.2 (warning: BitOp uses unsigned lower 5 bits of shift), 71 | BIT.rshift(x, disp) --> z 72 | Similar to function in Lua 5.2 (warning: BitOp uses unsigned lower 5 bits of shift), 73 | 74 | BIT.extract(x, field [, width]) --> z 75 | Similar to function in Lua 5.2. 76 | BIT.replace(x, v, field, width) --> z 77 | Similar to function in Lua 5.2. 78 | BIT.bswap(x) --> z 79 | Similar to function in Lua 5.2. 80 | 81 | BIT.rrotate(x, disp) --> z 82 | BIT.ror(x, disp) --> z 83 | Similar to function in Lua 5.2 and BitOp. 84 | 85 | BIT.lrotate(x, disp) --> z 86 | BIT.rol(x, disp) --> z 87 | 88 | Similar to function in Lua 5.2 and BitOp. 89 | BIT.arshift 90 | Similar to function in Lua 5.2 and BitOp. 91 | BIT.btest 92 | Similar to function in Lua 5.2 with requires two arguments. 93 | 94 | BIT.bit32 95 | This table contains functions that aim to provide 100% compatibility 96 | with the Lua 5.2 "bit32" library. 97 | bit32.arshift (x, disp) --> z 98 | bit32.band (...) --> z 99 | bit32.bnot (x) --> z 100 | bit32.bor (...) --> z 101 | bit32.btest (...) --> true | false 102 | bit32.bxor (...) --> z 103 | bit32.extract (x, field [, width]) --> z 104 | bit32.replace (x, v, field [, width]) --> z 105 | bit32.lrotate (x, disp) --> z 106 | bit32.lshift (x, disp) --> z 107 | bit32.rrotate (x, disp) --> z 108 | bit32.rshift (x, disp) --> z 109 | 110 | BIT.bit 111 | This table contains functions that aim to provide 100% compatibility 112 | with the LuaBitOp "bit" library (from LuaJIT). 113 | bit.tobit(x) --> y 114 | bit.tohex(x [,n]) --> y 115 | bit.bnot(x) --> y 116 | bit.bor(x1 [,x2...]) --> y 117 | bit.band(x1 [,x2...]) --> y 118 | bit.bxor(x1 [,x2...]) --> y 119 | bit.lshift(x, n) --> y 120 | bit.rshift(x, n) --> y 121 | bit.arshift(x, n) --> y 122 | bit.rol(x, n) --> y 123 | bit.ror(x, n) --> y 124 | bit.bswap(x) --> y 125 | DEPENDENCIES 126 | 127 | None (other than Lua 5.1 or 5.2). 128 | DOWNLOAD/INSTALLATION 129 | 130 | If using LuaRocks: 131 | luarocks install lua-bit-numberlua 132 | 133 | Otherwise, download . 134 | Alternately, if using git: 135 | git clone git://github.com/davidm/lua-bit-numberlua.git 136 | cd lua-bit-numberlua 137 | Optionally unpack: 138 | ./util.mk 139 | or unpack and install in LuaRocks: 140 | ./util.mk install 141 | 142 | REFERENCES 143 | 144 | [1] http://lua-users.org/wiki/FloatingPoint 145 | [2] http://www.lua.org/manual/5.2/ 146 | [3] http://bitop.luajit.org/ 147 | LICENSE 148 | 149 | (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). 150 | 151 | Permission is hereby granted, free of charge, to any person obtaining a copy 152 | of this software and associated documentation files (the "Software"), to deal 153 | in the Software without restriction, including without limitation the rights 154 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 155 | copies of the Software, and to permit persons to whom the Software is 156 | furnished to do so, subject to the following conditions: 157 | 158 | The above copyright notice and this permission notice shall be included in 159 | all copies or substantial portions of the Software. 160 | 161 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 162 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 163 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 164 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 165 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 166 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 167 | THE SOFTWARE. 168 | (end license) 169 | 170 | --]] 171 | 172 | local M = {_TYPE='module', _NAME='bit.numberlua', _VERSION='0.3.1.20120131'} 173 | 174 | local floor = math.floor 175 | 176 | local MOD = 2^32 177 | local MODM = MOD-1 178 | 179 | local function memoize(f) 180 | local mt = {} 181 | local t = setmetatable({}, mt) 182 | function mt:__index(k) 183 | local v = f(k); t[k] = v 184 | return v 185 | end 186 | return t 187 | end 188 | 189 | local function make_bitop_uncached(t, m) 190 | local function bitop(a, b) 191 | local res,p = 0,1 192 | while a ~= 0 and b ~= 0 do 193 | local am, bm = a%m, b%m 194 | res = res + t[am][bm]*p 195 | a = (a - am) / m 196 | b = (b - bm) / m 197 | p = p*m 198 | end 199 | res = res + (a+b)*p 200 | return res 201 | end 202 | return bitop 203 | end 204 | 205 | local function make_bitop(t) 206 | local op1 = make_bitop_uncached(t,2^1) 207 | local op2 = memoize(function(a) 208 | return memoize(function(b) 209 | return op1(a, b) 210 | end) 211 | end) 212 | return make_bitop_uncached(op2, 2^(t.n or 1)) 213 | end 214 | 215 | -- ok? probably not if running on a 32-bit int Lua number type platform 216 | function M.tobit(x) 217 | return x % 2^32 218 | end 219 | 220 | M.bxor = make_bitop {[0]={[0]=0,[1]=1},[1]={[0]=1,[1]=0}, n=4} 221 | local bxor = M.bxor 222 | 223 | function M.bnot(a) return MODM - a end 224 | local bnot = M.bnot 225 | 226 | function M.band(a,b) return ((a+b) - bxor(a,b))/2 end 227 | local band = M.band 228 | 229 | function M.bor(a,b) return MODM - band(MODM - a, MODM - b) end 230 | local bor = M.bor 231 | 232 | local lshift, rshift -- forward declare 233 | 234 | function M.rshift(a,disp) -- Lua5.2 insipred 235 | if disp < 0 then return lshift(a,-disp) end 236 | return floor(a % 2^32 / 2^disp) 237 | end 238 | rshift = M.rshift 239 | 240 | function M.lshift(a,disp) -- Lua5.2 inspired 241 | if disp < 0 then return rshift(a,-disp) end 242 | return (a * 2^disp) % 2^32 243 | end 244 | lshift = M.lshift 245 | 246 | function M.tohex(x, n) -- BitOp style 247 | n = n or 8 248 | local up 249 | if n <= 0 then 250 | if n == 0 then return '' end 251 | up = true 252 | n = - n 253 | end 254 | x = band(x, 16^n-1) 255 | return ('%0'..n..(up and 'X' or 'x')):format(x) 256 | end 257 | local tohex = M.tohex 258 | 259 | function M.extract(n, field, width) -- Lua5.2 inspired 260 | width = width or 1 261 | return band(rshift(n, field), 2^width-1) 262 | end 263 | local extract = M.extract 264 | 265 | function M.replace(n, v, field, width) -- Lua5.2 inspired 266 | width = width or 1 267 | local mask1 = 2^width-1 268 | v = band(v, mask1) -- required by spec? 269 | local mask = bnot(lshift(mask1, field)) 270 | return band(n, mask) + lshift(v, field) 271 | end 272 | local replace = M.replace 273 | 274 | function M.bswap(x) -- BitOp style 275 | local a = band(x, 0xff); x = rshift(x, 8) 276 | local b = band(x, 0xff); x = rshift(x, 8) 277 | local c = band(x, 0xff); x = rshift(x, 8) 278 | local d = band(x, 0xff) 279 | return lshift(lshift(lshift(a, 8) + b, 8) + c, 8) + d 280 | end 281 | local bswap = M.bswap 282 | 283 | function M.rrotate(x, disp) -- Lua5.2 inspired 284 | disp = disp % 32 285 | local low = band(x, 2^disp-1) 286 | return rshift(x, disp) + lshift(low, 32-disp) 287 | end 288 | local rrotate = M.rrotate 289 | 290 | function M.lrotate(x, disp) -- Lua5.2 inspired 291 | return rrotate(x, -disp) 292 | end 293 | local lrotate = M.lrotate 294 | 295 | M.rol = M.lrotate -- LuaOp inspired 296 | M.ror = M.rrotate -- LuaOp insipred 297 | 298 | 299 | function M.arshift(x, disp) -- Lua5.2 inspired 300 | local z = rshift(x, disp) 301 | if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end 302 | return z 303 | end 304 | local arshift = M.arshift 305 | 306 | function M.btest(x, y) -- Lua5.2 inspired 307 | return band(x, y) ~= 0 308 | end 309 | 310 | -- 311 | -- Start Lua 5.2 "bit32" compat section. 312 | -- 313 | 314 | M.bit32 = {} -- Lua 5.2 'bit32' compatibility 315 | 316 | 317 | local function bit32_bnot(x) 318 | return (-1 - x) % MOD 319 | end 320 | M.bit32.bnot = bit32_bnot 321 | 322 | local function bit32_bxor(a, b, c, ...) 323 | local z 324 | if b then 325 | a = a % MOD 326 | b = b % MOD 327 | z = bxor(a, b) 328 | if c then 329 | z = bit32_bxor(z, c, ...) 330 | end 331 | return z 332 | elseif a then 333 | return a % MOD 334 | else 335 | return 0 336 | end 337 | end 338 | M.bit32.bxor = bit32_bxor 339 | 340 | local function bit32_band(a, b, c, ...) 341 | local z 342 | if b then 343 | a = a % MOD 344 | b = b % MOD 345 | z = ((a+b) - bxor(a,b)) / 2 346 | if c then 347 | z = bit32_band(z, c, ...) 348 | end 349 | return z 350 | elseif a then 351 | return a % MOD 352 | else 353 | return MODM 354 | end 355 | end 356 | M.bit32.band = bit32_band 357 | 358 | local function bit32_bor(a, b, c, ...) 359 | local z 360 | if b then 361 | a = a % MOD 362 | b = b % MOD 363 | z = MODM - band(MODM - a, MODM - b) 364 | if c then 365 | z = bit32_bor(z, c, ...) 366 | end 367 | return z 368 | elseif a then 369 | return a % MOD 370 | else 371 | return 0 372 | end 373 | end 374 | M.bit32.bor = bit32_bor 375 | 376 | function M.bit32.btest(...) 377 | return bit32_band(...) ~= 0 378 | end 379 | 380 | function M.bit32.lrotate(x, disp) 381 | return lrotate(x % MOD, disp) 382 | end 383 | 384 | function M.bit32.rrotate(x, disp) 385 | return rrotate(x % MOD, disp) 386 | end 387 | 388 | function M.bit32.lshift(x,disp) 389 | if disp > 31 or disp < -31 then return 0 end 390 | return lshift(x % MOD, disp) 391 | end 392 | 393 | function M.bit32.rshift(x,disp) 394 | if disp > 31 or disp < -31 then return 0 end 395 | return rshift(x % MOD, disp) 396 | end 397 | 398 | function M.bit32.arshift(x,disp) 399 | x = x % MOD 400 | if disp >= 0 then 401 | if disp > 31 then 402 | return (x >= 0x80000000) and MODM or 0 403 | else 404 | local z = rshift(x, disp) 405 | if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end 406 | return z 407 | end 408 | else 409 | return lshift(x, -disp) 410 | end 411 | end 412 | 413 | function M.bit32.extract(x, field, ...) 414 | local width = ... or 1 415 | if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end 416 | x = x % MOD 417 | return extract(x, field, ...) 418 | end 419 | 420 | function M.bit32.replace(x, v, field, ...) 421 | local width = ... or 1 422 | if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end 423 | x = x % MOD 424 | v = v % MOD 425 | return replace(x, v, field, ...) 426 | end 427 | 428 | 429 | -- 430 | -- Start LuaBitOp "bit" compat section. 431 | -- 432 | 433 | M.bit = {} -- LuaBitOp "bit" compatibility 434 | 435 | function M.bit.tobit(x) 436 | x = x % MOD 437 | if x >= 0x80000000 then x = x - MOD end 438 | return x 439 | end 440 | local bit_tobit = M.bit.tobit 441 | 442 | function M.bit.tohex(x, ...) 443 | return tohex(x % MOD, ...) 444 | end 445 | 446 | function M.bit.bnot(x) 447 | return bit_tobit(bnot(x % MOD)) 448 | end 449 | 450 | local function bit_bor(a, b, c, ...) 451 | if c then 452 | return bit_bor(bit_bor(a, b), c, ...) 453 | elseif b then 454 | return bit_tobit(bor(a % MOD, b % MOD)) 455 | else 456 | return bit_tobit(a) 457 | end 458 | end 459 | M.bit.bor = bit_bor 460 | 461 | local function bit_band(a, b, c, ...) 462 | if c then 463 | return bit_band(bit_band(a, b), c, ...) 464 | elseif b then 465 | return bit_tobit(band(a % MOD, b % MOD)) 466 | else 467 | return bit_tobit(a) 468 | end 469 | end 470 | M.bit.band = bit_band 471 | 472 | local function bit_bxor(a, b, c, ...) 473 | if c then 474 | return bit_bxor(bit_bxor(a, b), c, ...) 475 | elseif b then 476 | return bit_tobit(bxor(a % MOD, b % MOD)) 477 | else 478 | return bit_tobit(a) 479 | end 480 | end 481 | M.bit.bxor = bit_bxor 482 | 483 | function M.bit.lshift(x, n) 484 | return bit_tobit(lshift(x % MOD, n % 32)) 485 | end 486 | 487 | function M.bit.rshift(x, n) 488 | return bit_tobit(rshift(x % MOD, n % 32)) 489 | end 490 | 491 | function M.bit.arshift(x, n) 492 | return bit_tobit(arshift(x % MOD, n % 32)) 493 | end 494 | 495 | function M.bit.rol(x, n) 496 | return bit_tobit(lrotate(x % MOD, n % 32)) 497 | end 498 | 499 | function M.bit.ror(x, n) 500 | return bit_tobit(rrotate(x % MOD, n % 32)) 501 | end 502 | 503 | function M.bit.bswap(x) 504 | return bit_tobit(bswap(x % MOD)) 505 | end 506 | 507 | return M -------------------------------------------------------------------------------- /numberluaLICENSE: -------------------------------------------------------------------------------- 1 | lua-bit-numberlua License 2 | 3 | =============================================================================== 4 | 5 | Copyright (C) 2008, David Manura. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | 25 | =============================================================================== -------------------------------------------------------------------------------- /png.lua: -------------------------------------------------------------------------------- 1 | class = require '30log' 2 | deflate = require 'deflate' 3 | require 'stream' 4 | 5 | Chunk = class() 6 | Chunk.__name = "Chunk" 7 | Chunk.length = 0 8 | Chunk.name = "" 9 | Chunk.data = "" 10 | Chunk.crc = "" 11 | 12 | function Chunk:__init(stream) 13 | if stream.__name == "Chunk" then 14 | self.length = stream.length 15 | self.name = stream.name 16 | self.data = stream.data 17 | self.crc = stream.crc 18 | else 19 | self.length = stream:readInt() 20 | self.name = stream:readChars(4) 21 | self.data = stream:readChars(self.length) 22 | self.crc = stream:readChars(4) 23 | end 24 | end 25 | 26 | function Chunk:getDataStream() 27 | return Stream({input = self.data}) 28 | end 29 | 30 | IHDR = Chunk:extends() 31 | IHDR.__name = "IHDR" 32 | IHDR.width = 0 33 | IHDR.height = 0 34 | IHDR.bitDepth = 0 35 | IHDR.colorType = 0 36 | IHDR.compression = 0 37 | IHDR.filter = 0 38 | IHDR.interlace = 0 39 | 40 | function IHDR:__init(chunk) 41 | self.super.__init(self, chunk) 42 | local stream = chunk:getDataStream() 43 | self.width = stream:readInt() 44 | self.height = stream:readInt() 45 | self.bitDepth = stream:readByte() 46 | self.colorType = stream:readByte() 47 | self.compression = stream:readByte() 48 | self.filter = stream:readByte() 49 | self.interlace = stream:readByte() 50 | end 51 | 52 | IDAT = Chunk:extends() 53 | IDAT.__name = "IDAT" 54 | 55 | function IDAT:__init(chunk) 56 | self.super.__init(self, chunk) 57 | end 58 | 59 | PLTE = Chunk:extends() 60 | PLTE.__name = "PLTE" 61 | PLTE.numColors = 0 62 | PLTE.colors = {} 63 | 64 | function PLTE:__init(chunk) 65 | self.super.__init(self, chunk) 66 | self.numColors = math.floor(chunk.length/3) 67 | local stream = chunk:getDataStream() 68 | for i = 1, self.numColors do 69 | self.colors[i] = { 70 | R = stream:readByte(), 71 | G = stream:readByte(), 72 | B = stream:readByte(), 73 | } 74 | end 75 | end 76 | 77 | function PLTE:getColor(index) 78 | return self.colors[index] 79 | end 80 | 81 | Pixel = class() 82 | Pixel.__name = "Pixel" 83 | Pixel.R = 0 84 | Pixel.G = 0 85 | Pixel.B = 0 86 | Pixel.A = 0 87 | 88 | function Pixel:__init(stream, depth, colorType, palette) 89 | local bps = math.floor(depth/8) 90 | if colorType == 0 then 91 | local grey = stream:readInt(bps) 92 | self.R = grey 93 | self.G = grey 94 | self.B = grey 95 | self.A = 255 96 | end 97 | if colorType == 2 then 98 | self.R = stream:readInt(bps) 99 | self.G = stream:readInt(bps) 100 | self.B = stream:readInt(bps) 101 | self.A = 255 102 | end 103 | if colorType == 3 then 104 | local index = stream:readInt(bps)+1 105 | local color = palette:getColor(index) 106 | self.R = color.R 107 | self.G = color.G 108 | self.B = color.B 109 | self.A = 255 110 | end 111 | if colorType == 4 then 112 | local grey = stream:readInt(bps) 113 | self.R = grey 114 | self.G = grey 115 | self.B = grey 116 | self.A = stream:readInt(bps) 117 | end 118 | if colorType == 6 then 119 | self.R = stream:readInt(bps) 120 | self.G = stream:readInt(bps) 121 | self.B = stream:readInt(bps) 122 | self.A = stream:readInt(bps) 123 | end 124 | end 125 | 126 | function Pixel:format() 127 | return string.format("R: %d, G: %d, B: %d, A: %d", self.R, self.G, self.B, self.A) 128 | end 129 | 130 | ScanLine = class() 131 | ScanLine.__name = "ScanLine" 132 | ScanLine.pixels = {} 133 | ScanLine.filterType = 0 134 | 135 | function ScanLine:__init(stream, depth, colorType, palette, length) 136 | bpp = math.floor(depth/8) * self:bitFromColorType(colorType) 137 | bpl = bpp*length 138 | self.filterType = stream:readByte() 139 | stream:seek(-1) 140 | stream:writeByte(0) 141 | local startLoc = stream.position 142 | if self.filterType == 0 then 143 | for i = 1, length do 144 | self.pixels[i] = Pixel(stream, depth, colorType, palette) 145 | end 146 | end 147 | if self.filterType == 1 then 148 | for i = 1, length do 149 | for j = 1, bpp do 150 | local curByte = stream:readByte() 151 | stream:seek(-(bpp+1)) 152 | local lastByte = 0 153 | if stream.position >= startLoc then lastByte = stream:readByte() or 0 else stream:readByte() end 154 | stream:seek(bpp-1) 155 | stream:writeByte((curByte + lastByte) % 256) 156 | end 157 | stream:seek(-bpp) 158 | self.pixels[i] = Pixel(stream, depth, colorType, palette) 159 | end 160 | end 161 | if self.filterType == 2 then 162 | for i = 1, length do 163 | for j = 1, bpp do 164 | local curByte = stream:readByte() 165 | stream:seek(-(bpl+2)) 166 | local lastByte = stream:readByte() or 0 167 | stream:seek(bpl) 168 | stream:writeByte((curByte + lastByte) % 256) 169 | end 170 | stream:seek(-bpp) 171 | self.pixels[i] = Pixel(stream, depth, colorType, palette) 172 | end 173 | end 174 | if self.filterType == 3 then 175 | for i = 1, length do 176 | for j = 1, bpp do 177 | local curByte = stream:readByte() 178 | stream:seek(-(bpp+1)) 179 | local lastByte = 0 180 | if stream.position >= startLoc then lastByte = stream:readByte() or 0 else stream:readByte() end 181 | stream:seek(-(bpl)+bpp-2) 182 | local priByte = stream:readByte() or 0 183 | stream:seek(bpl) 184 | stream:writeByte((curByte + math.floor((lastByte+priByte)/2)) % 256) 185 | end 186 | stream:seek(-bpp) 187 | self.pixels[i] = Pixel(stream, depth, colorType, palette) 188 | end 189 | end 190 | if self.filterType == 4 then 191 | for i = 1, length do 192 | for j = 1, bpp do 193 | local curByte = stream:readByte() 194 | stream:seek(-(bpp+1)) 195 | local lastByte = 0 196 | if stream.position >= startLoc then lastByte = stream:readByte() or 0 else stream:readByte() end 197 | stream:seek(-(bpl + 2 - bpp)) 198 | local priByte = stream:readByte() or 0 199 | stream:seek(-(bpp+1)) 200 | local lastPriByte = 0 201 | if stream.position >= startLoc - (length * bpp + 1) then lastPriByte = stream:readByte() or 0 else stream:readByte() end 202 | stream:seek(bpl + bpp) 203 | stream:writeByte((curByte + self:_PaethPredict(lastByte, priByte, lastPriByte)) % 256) 204 | end 205 | stream:seek(-bpp) 206 | self.pixels[i] = Pixel(stream, depth, colorType, palette) 207 | end 208 | end 209 | end 210 | 211 | function ScanLine:bitFromColorType(colorType) 212 | if colorType == 0 then return 1 end 213 | if colorType == 2 then return 3 end 214 | if colorType == 3 then return 1 end 215 | if colorType == 4 then return 2 end 216 | if colorType == 6 then return 4 end 217 | error 'Invalid colortype' 218 | end 219 | 220 | function ScanLine:getPixel(pixel) 221 | return self.pixels[pixel] 222 | end 223 | 224 | --Stolen right from w3. 225 | function ScanLine:_PaethPredict(a, b, c) 226 | local p = a + b - c 227 | local varA = math.abs(p - a) 228 | local varB = math.abs(p - b) 229 | local varC = math.abs(p - c) 230 | if varA <= varB and varA <= varC then return a end 231 | if varB <= varC then return b end 232 | return c 233 | end 234 | 235 | pngImage = class() 236 | pngImage.__name = "PNG" 237 | pngImage.width = 0 238 | pngImage.height = 0 239 | pngImage.depth = 0 240 | pngImage.colorType = 0 241 | pngImage.scanLines = {} 242 | 243 | function pngImage:__init(path, progCallback) 244 | local str = Stream({inputF = path}) 245 | if str:readChars(8) ~= "\137\080\078\071\013\010\026\010" then error 'Not a PNG' end 246 | local ihdr = {} 247 | local plte = {} 248 | local idat = {} 249 | local num = 1 250 | while true do 251 | ch = Chunk(str) 252 | if ch.name == "IHDR" then ihdr = IHDR(ch) end 253 | if ch.name == "PLTE" then plte = PLTE(ch) end 254 | if ch.name == "IDAT" then idat[num] = IDAT(ch) num = num+1 end 255 | if ch.name == "IEND" then break end 256 | end 257 | self.width = ihdr.width 258 | self.height = ihdr.height 259 | self.depth = ihdr.bitDepth 260 | self.colorType = ihdr.colorType 261 | 262 | local dataStr = "" 263 | for k,v in pairs(idat) do dataStr = dataStr .. v.data end 264 | local output = {} 265 | deflate.inflate_zlib {input = dataStr, output = function(byte) output[#output+1] = string.char(byte) end, disable_crc = true} 266 | imStr = Stream({input = table.concat(output)}) 267 | 268 | for i = 1, self.height do 269 | self.scanLines[i] = ScanLine(imStr, self.depth, self.colorType, plte, self.width) 270 | if progCallback ~= nil then progCallback(i, self.height) end 271 | end 272 | end 273 | 274 | function pngImage:getPixel(x, y) 275 | local pixel = self.scanLines[y].pixels[x] 276 | return pixel 277 | end -------------------------------------------------------------------------------- /stream.lua: -------------------------------------------------------------------------------- 1 | class = require '30log' 2 | Stream = class() 3 | Stream.data = {} 4 | Stream.position = 1 5 | Stream.__name = "Stream" 6 | 7 | function Stream:bsRight(num, pow) 8 | return math.floor(num / 2^pow) 9 | end 10 | 11 | function Stream:bsLeft(num, pow) 12 | return math.floor(num * 2^pow) 13 | end 14 | 15 | function Stream:bytesToNum(bytes) 16 | local n = 0 17 | for k,v in ipairs(bytes) do 18 | n = self:bsLeft(n, 8) + v 19 | end 20 | n = (n > 2147483647) and (n - 4294967296) or n 21 | return n 22 | end 23 | 24 | function Stream:__init(param) 25 | local str = "" 26 | if (param.inputF ~= nil) then 27 | str = io.open(param.inputF, "rb"):read("*all") 28 | end 29 | if (param.input ~= nil) then 30 | str = param.input 31 | end 32 | 33 | for i=1,#str do 34 | self.data[i] = str:byte(i, i) 35 | end 36 | end 37 | 38 | function Stream:seek(amount) 39 | self.position = self.position + amount 40 | end 41 | 42 | function Stream:readByte() 43 | if self.position <= 0 then self:seek(1) return nil end 44 | local byte = self.data[self.position] 45 | self:seek(1) 46 | return byte 47 | end 48 | 49 | function Stream:readChars(num) 50 | if self.position <= 0 then self:seek(1) return nil end 51 | local str = "" 52 | local i = 1 53 | while i <= num do 54 | str = str .. self:readChar() 55 | i = i + 1 56 | end 57 | return str, i-1 58 | end 59 | 60 | function Stream:readChar() 61 | if self.position <= 0 then self:seek(1) return nil end 62 | return string.char(self:readByte()) 63 | end 64 | 65 | function Stream:readBytes(num) 66 | if self.position <= 0 then self:seek(1) return nil end 67 | local tabl = {} 68 | local i = 1 69 | while i <= num do 70 | local curByte = self:readByte() 71 | if curByte == nil then break end 72 | tabl[i] = curByte 73 | i = i + 1 74 | end 75 | return tabl, i-1 76 | end 77 | 78 | function Stream:readInt(num) 79 | if self.position <= 0 then self:seek(1) return nil end 80 | num = num or 4 81 | local bytes, count = self:readBytes(num) 82 | return self:bytesToNum(bytes), count 83 | end 84 | 85 | function Stream:writeByte(byte) 86 | if self.position <= 0 then self:seek(1) return end 87 | self.data[self.position] = byte 88 | self:seek(1) 89 | end 90 | 91 | function Stream:writeChar(char) 92 | if self.position <= 0 then self:seek(1) return end 93 | self:writeByte(string.byte(char)) 94 | end 95 | 96 | function Stream:writeBytes(buffer) 97 | if self.position <= 0 then self:seek(1) return end 98 | local str = "" 99 | for k,v in pairs(buffer) do 100 | str = str .. string.char(v) 101 | end 102 | writeChars(str) 103 | end 104 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | require 'png' 2 | 3 | function printProg(line, totalLine) 4 | print(line .. " of " .. totalLine) 5 | end 6 | 7 | img = pngImage("Example.png", printProg) 8 | print("Width: " .. img.width) 9 | print("Height: " .. img.height) 10 | print("Depth: " .. img.depth) 11 | 12 | print("Color of pixel (10, 10): " .. img:getPixel(10,10):format()) --------------------------------------------------------------------------------