XSpriterv0.1
Extractor de Sprites em Lua
Extractor de Sprites em Lua
O que é o XSpriter?
O XSpriter foi desenvolvido com um intuito de aprendizagem. Este script mostra como ler ficheiros binários e, no caso de conter imagens, como extrair-las. Através deste script você poderá também adiquirir mais conhecimentos sobre a estrutura do Tibia.spr.
Este script só foi testado na versão 8.50 e 8.53, porém deverá funcionar em outras versões.
O projeto XSpriter é constituído por dois scripts (de minha autoria):
- BinaryStream - permite criar, ler e editar ficheiros binários
- XSpriter - o próprio extractor transforma o binário em imagens
(Para criar as imagens utilizo a biblioteca GD)
Como funciona?
Para extrair as imagens do Tibia.spr basta colocar o ficheiro na pasta do script e executar-lo. Será, então, criada uma nova pasta com o nome de Sprites, com as sprites dentro.
Scripts:
- BinaryStream.lua
--[[ Binary Stream Allows you to read, edit and create new binary files Developed by Colex (Alexandre Santos) ]]-- require("bit") _BINARY_STREAM = { Position = 0 } BinaryStream = function(filename) local obj = {} local file = io.open(filename, "rb") if not (file) then return nil end setmetatable(obj, _BINARY_STREAM) _BINARY_STREAM.__index = _BINARY_STREAM obj["Buffer"] = file:read("*all") obj["Length"] = obj.Buffer:len() obj["FileName"] = filename file:close() return obj end CreateBinary = function(filename) local obj = {} setmetatable(obj, _BINARY_STREAM) _BINARY_STREAM.__index = _BINARY_STREAM obj["Buffer"] = "" obj["Length"] = 0 obj["FileName"] = filename return obj end ---Read Functions _BINARY_STREAM.ReadByte = function(self) self.Position = self.Position + 1 return self.Buffer:byte(self.Position) end _BINARY_STREAM.ReadInt16 = function(self) local l1 = self:ReadByte() local l2 = bit.lshift(self:ReadByte(), 8) return l1 + l2 end _BINARY_STREAM.ReadInt32 = function(self) local l1 = self:ReadByte() local l2 = bit.lshift(self:ReadByte(), 8) local l3 = bit.lshift(self:ReadByte(), 16) local l4 = bit.lshift(self:ReadByte(), 24) return l1 + l2 + l3 + l4 end --Write Functions _BINARY_STREAM.WriteByte = function(self, byte, insert) self.Position = self.Position + 1 if not(insert) then self.Buffer = self.Buffer:sub(0,self.Position-1)..string.char(byte)..self.Buffer:sub(self.Position+1) else self.Buffer = self.Buffer:sub(0,self.Position-1)..string.char(byte)..self.Buffer:sub(self.Position) end end _BINARY_STREAM.WriteInt16 = function(self, int16, insert) local l1 = bit.rshift(bit.lshift(int16, 24), 24) local l2 = bit.rshift(bit.lshift(int16, 16), 24) WriteByte(l1, insert) WriteByte(l2, insert) end _BINARY_STREAM.WriteInt32 = function(self, int32, insert) local l1 = bit.rshift(bit.lshift(int32, 24), 24) local l2 = bit.rshift(bit.lshift(int32, 16), 24) local l3 = bit.rshift(bit.lshift(int32, 8), 24) local l4 = bit.rshift(int32, 24) WriteByte(l1, insert) WriteByte(l2, insert) WriteByte(l3, insert) WriteByte(l4, insert) end --Insert Function _BINARY_STREAM.InsertByte = function(self, byte) self:WriteByte(byte, true) end _BINARY_STREAM.InsertInt16 = function(self, int16) self:WriteInt16(int16, true) end _BINARY_STREAM.InsertInt32 = function(self, int32) self:WriteInt32(int32, true) end --Position Functions _BINARY_STREAM.Skip = function(self, bytes) self.Position = self.Position + bytes end _BINARY_STREAM.Seek = function(self, pos, origin) if (origin == 0) then --Begin self.Position = pos elseif (origin == 1) then --Current Position self.Position = self.Position + pos elseif (origin == 2) then --End self.Position = self.length + pos end end --Save function _BINARY_STREAM.Save = function(self, filename) filename = filename or self.FileName local file = io.open(filename, "wb") file:write(self.Buffer) file:close() end
- XSpriter.lua
--[[ XSpriter v0.1 Extract Sprites from a Tibia.spr Developed by Colex (Alexandre Santos) ]]-- require("bit") require("gd") require("os") require("BinaryStream") ---------Sprite Reader--------- local ExtractSprites = function() spriter = BinaryStream("Tibia.spr") if not(spriter) then print("Ficheiro Tibia.spr não encontrado!") return end spriter:Skip(4) local n_sprites = spriter:ReadInt16() os.execute("mkdir Sprites") print("Iniciando extração...") for n_sprite=1, n_sprites do print("Extraindo: " .. (math.floor(n_sprite/n_sprites*100)) .. "%") spriter:Seek(6 + n_sprite * 4, 0) spriter:Seek(spriter:ReadInt32() + 3, 0) local pixel = 0 local r, g, b, color local sprite = gd.createTrueColor(32, 32) sprite:filledRectangle(0, 0, 32, 32, sprite:colorAllocate(255, 0,255)) local offset = spriter.Position + spriter:ReadInt16(); while spriter.Position < offset do local tp = spriter:ReadInt16() local colored = spriter:ReadInt16() pixel = pixel + tp for x = 1, colored do r = spriter:ReadByte() g = spriter:ReadByte() b = spriter:ReadByte() color = sprite:colorAllocate(r, g, b) sprite:setPixel(pixel%32, math.floor(pixel/32), color) pixel = pixel + 1 end end sprite:png("Sprites\\"..n_sprite..".png") end end ExtractSprites()
Para executar-lo poderá utilizar o programa SciTE, ponha o XSpriter.lua do BinaryStream.lua e execute o XSpriter.lua.
Créditos a Jo3 pela estrutura do Tibia.spr