Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --Script to be used with Bizhawk and Majora's Mask (USA)
- --Image must be 8-bit grayscale .bmp with width divisible by 8 and no larger than 160x112
- --Function converts the ASCII String to its decimal equivalent value
- function str2dec(str, bytes)
- local sum = 0
- for i=1, bytes do
- sum = sum + math.pow(256,i-1)*string.byte(str,i)
- end
- return sum
- end
- --Function creates a 2D array with the given dimensions
- function createPixelArray(height, width)
- local pixelArray = { }
- for y = 1, height do
- pixelArray[y] = { }
- for x = 1, width do
- pixelArray[y][x] = 0
- end
- end
- return pixelArray
- end
- --Reference: https://en.wikipedia.org/wiki/BMP_file_format
- local f = assert(io.open("input.bmp", "rb"))
- f:seek ("set", 10)
- local offset = str2dec(f:read(4), 4)
- --TODO: Check header to insure the width and height are 4 bytes
- --in the wild they typically are
- f:seek ("set", 18)
- local width = str2dec(f:read(4), 4)
- local height = str2dec(f:read(4), 4)
- pixelArray = createPixelArray(height, width)
- --Catches if the image won't fit into the pictograph image (160x112)
- if(width > 160 or height > 112) then
- print("Invalid Dimensions: ("..width..", "..height..")")
- f:close()
- do return end
- end
- --TODO: Pad the final image
- --Catches if the output needs padding (Also catches if the pixel array has padding)
- if(width%8 > 0) then
- print("Width is not divisible by 8!!")
- local buffer = 8 - width%8
- f:close()
- do return end
- end
- f:seek ("set", offset) --Jumps right to the pixel array
- --TODO: Catch if there are multiple color channels and convert to grayscale
- --TODO: Catch if the image is padded (width%4 ~= 0)
- --Pixel Array as it is in the image
- for y = height, 1, -1 do
- for x = 1, width do
- pixelArray[y][x] = str2dec(f:read(1), 1)
- end
- end
- f:close()
- --Converts from 8-bit to 5-bit
- for y = 1, height do
- for x = 1, width do
- pixelArray[y][x] = bit.rshift(pixelArray[y][x], 3)
- end
- end
- --Create a new array that will hold the output
- local newHeight = height
- local newWidth = math.ceil(width*5/8) --Ceiling isn't really required since it breaks earlier in the check if the width was divisible by 8
- output = createPixelArray(newHeight, newWidth)
- --Fills the output array
- for y = 1, newHeight do
- for x = 1, newWidth/5 do
- --index for arrays
- old = (x-1)*8
- new = (x-1)*5
- --New array has 5 bytes for every 8 bytes in the old array
- --So here is a little bit of shifting
- --most significant bits = previous pixel data
- output[y][new+1] = bit.band(bit.lshift(pixelArray[y][old+1], 3) + bit.rshift(pixelArray[y][old+2], 2), 0xFF) --5 + top3
- output[y][new+2] = bit.band(bit.lshift(pixelArray[y][old+2], 6) + bit.lshift(pixelArray[y][old+3], 1) + bit.rshift(pixelArray[y][old+4], 4), 0xFF) -- bottom2 + 5 + top1
- output[y][new+3] = bit.band(bit.lshift(pixelArray[y][old+4], 4) + bit.rshift(pixelArray[y][old+5], 1), 0xFF) -- bottom4 + top4
- output[y][new+4] = bit.band(bit.lshift(pixelArray[y][old+5], 7) + bit.lshift(pixelArray[y][old+6], 2) + bit.rshift(pixelArray[y][old+7], 3), 0xFF) -- bottom1 + 5 + top2
- output[y][new+5] = bit.band(bit.lshift(pixelArray[y][old+7], 5) + pixelArray[y][old+8], 0xFF) -- bottom3 + 5
- end
- end
- --Center the image
- offsetY = math.floor((112 - newHeight)/2)
- offsetX = math.floor((100 - newWidth)/2)
- local pictographAddress = 0x1F0750 + offsetX + 100*offsetY
- --Write to game (Pictograph images are 5-bit grayscale)
- for y = 1, newHeight do
- for x = 1, newWidth do
- mainmemory.writebyte(pictographAddress + (x-1) + (y-1)*100, output[y][x])
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement