local t={}t.__index=t local n=script.Chunks local a=script.Modules local E=require(a.Deflate)local I=require(a.Unfilter)local O=require(a.BinaryReader)local function C(t)if t==0 or t==3 then return 1 elseif t==4 then return 2 elseif t==2 then return 3 elseif t==6 then return 4 else return 0 end end local function A(t,n,a)local E=tonumber(t)or 0 E=math.floor(E+.5)return math.clamp(E,n,a)end local function K(t,n,a)local E=t.Width local I=t.Height local O=A(n,1,E)local C=A(a,1,I)local K=t.Bitmap local v=t.BytesPerPixel local p=(O-1)*v+1 local m=p+v return K[C],p,m end function t.GetPixel(a,t,n)local E,I,O=K(a,t,n)local C=a.ColorType local A,v do if C==0 then local t=unpack(E,I,O)A=Color3.fromHSV(0,0,t)v=255 elseif C==2 then local t,n,a=unpack(E,I,O)A=Color3.fromRGB(t,n,a)v=255 elseif C==3 then local t=a.Palette local n=a.AlphaData local C=unpack(E,I,O)C=C+1 if t then A=t[C]end if n then v=n[C]end elseif C==4 then local t,n=unpack(E,I,O)A=Color3.fromHSV(0,0,t)v=n elseif C==6 then local t,n,a,C=unpack(E,I,O)A=Color3.fromRGB(t,n,a,C)v=C end end if not A then A=Color3.new()end if not v then v=255 end return A,v end function t.new(a)local A=O.new(a)local K={Chunks={};Metadata={},Reading=true,ZlibStream=""}local v=A:ReadString(8)if v~="\137\080\078\071\r\n\026\n"then error("\080\078\071 - \073\110\112\117\116 \100\097\116\097 \105\115 \110\111\116 \097 \080\078\071 \102\105\108\101\046",2)end while K.Reading do local t=A:ReadInt32()local a=A:ReadString(4)local E,I if t>0 then E=A:ForkReader(t)I=A:ReadUInt32()end local O={Length=t;Type=a;Data=E;CRC=I}local C=n:FindFirstChild(a)if C then C=require(C)C(K,O)end table.insert(K.Chunks,O)end local p,m=pcall(function()local t={}local n=0 E:InflateZlib({Input=O.new(K.ZlibStream);Output=function(a)n=n+1 t[n]=string.char(a)end})return table.concat(t)end)if not p then error("\080\078\071 - \085\110\097\098\108\101 \116\111 \117\110\112\097\099\107 \080\078\071 \100\097\116\097\046 "..tostring(m),2)end local h=K.Width local T=K.Height local D=K.BitDepth local H=K.ColorType local U=O.new(m)K.ZlibStream=nil local Z={}K.Bitmap=Z local g=C(H)K.NumChannels=g local G=math.max(1,g*(D/8))K.BytesPerPixel=G for t=1,T,1 do local n=U:ReadByte()local a=U:ReadBytes(h*G,true)Z[t]={}if n==0 then I:None(a,Z,G,t)elseif n==1 then I:Sub(a,Z,G,t)elseif n==2 then I:Up(a,Z,G,t)elseif n==3 then I:Average(a,Z,G,t)elseif n==4 then I:Paeth(a,Z,G,t)end end return setmetatable(K,t)end return t
---------------------------------------------------------------------------------------------
-- @ CloneTrooper1019, 2019
---------------------------------------------------------------------------------------------
-- [PNG Library]
--
--  A module for opening PNG files into a readable bitmap.
--  This implementation works with most PNG files.
--
---------------------------------------------------------------------------------------------

local PNG = {}
PNG.__index = PNG

local chunks = script.Chunks
local modules = script.Modules

local Deflate = require(modules.Deflate)
local Unfilter = require(modules.Unfilter)
local BinaryReader = require(modules.BinaryReader)

local function getBytesPerPixel(colorType)
	if colorType == 0 or colorType == 3 then
		return 1
	elseif colorType == 4 then
		return 2
	elseif colorType == 2 then
		return 3
	elseif colorType == 6 then
		return 4
	else
		return 0
	end
end

local function clampInt(value, min, max)
	local num = tonumber(value) or 0
	num = math.floor(num + .5)
	
	return math.clamp(num, min, max)
end

local function indexBitmap(file, x, y)
	local width = file.Width
	local height = file.Height
	
	local x = clampInt(x, 1, width) 
	local y = clampInt(y, 1, height)
	
	local bitmap = file.Bitmap
	local bpp = file.BytesPerPixel
	
	local i0 = ((x - 1) * bpp) + 1
	local i1 = i0 + bpp
	
	return bitmap[y], i0, i1
end

function PNG:GetPixel(x, y)
	local row, i0, i1 = indexBitmap(self, x, y)
	local colorType = self.ColorType
	
	local color, alpha do
		if colorType == 0 then
			local gray = unpack(row, i0, i1)
			color = Color3.fromHSV(0, 0, gray)
			alpha = 255
		elseif colorType == 2 then
			local r, g, b = unpack(row, i0, i1)
			color = Color3.fromRGB(r, g, b)
			alpha = 255
		elseif colorType == 3 then
			local palette = self.Palette
			local alphaData = self.AlphaData
			
			local index = unpack(row, i0, i1)
			index = index + 1
			
			if palette then
				color = palette[index]
			end
			
			if alphaData then
				alpha = alphaData[index]
			end
		elseif colorType == 4 then
			local gray, a = unpack(row, i0, i1)
			color = Color3.fromHSV(0, 0, gray)
			alpha = a
		elseif colorType == 6 then
			local r, g, b, a = unpack(row, i0, i1)
			color = Color3.fromRGB(r, g, b, a)
			alpha = a
		end
	end
	
	if not color then
		color = Color3.new()
	end
	
	if not alpha then
		alpha = 255
	end
	
	return color, alpha
end

function PNG.new(buffer)
	-- Create the reader.
	local reader = BinaryReader.new(buffer)
	
	-- Create the file object.
	local file =
	{
		Chunks = {};
		Metadata = {};
		
		Reading = true;
		ZlibStream = "";
	}
	
	-- Verify the file header.
	local header = reader:ReadString(8)
	
	if header ~= "\137PNG\r\n\26\n" then
		error("PNG - Input data is not a PNG file.", 2)
	end
	
	while file.Reading do
		local length = reader:ReadInt32()
		local chunkType = reader:ReadString(4)
		
		local data, crc
		
		if length > 0 then
			data = reader:ForkReader(length)
			crc = reader:ReadUInt32()
		end
		
		local chunk = 
		{
			Length = length;
			Type = chunkType;
			
			Data = data;
			CRC = crc;
		}
		
		local handler = chunks:FindFirstChild(chunkType)
		
		if handler then
			handler = require(handler)
			handler(file, chunk)
		end
		
		table.insert(file.Chunks, chunk)
	end
	
	-- Decompress the zlib stream.
	local success, response = pcall(function ()
		local result = {}
		local index = 0
		
		Deflate:InflateZlib
		{
			Input = BinaryReader.new(file.ZlibStream);
			
			Output = function (byte)
				index = index + 1
				result[index] = string.char(byte)
			end
		}
		
		return table.concat(result)
	end)
	
	if not success then
		error("PNG - Unable to unpack PNG data. " .. tostring(response), 2)
	end
	
	-- Grab expected info from the file.
	
	local width = file.Width
	local height = file.Height
	
	local bitDepth = file.BitDepth
	local colorType = file.ColorType
	
	local buffer = BinaryReader.new(response)
	file.ZlibStream = nil
	
	local bitmap = {}
	file.Bitmap = bitmap
	
	local channels = getBytesPerPixel(colorType)
	file.NumChannels = channels
	
	local bpp = math.max(1, channels * (bitDepth / 8))
	file.BytesPerPixel = bpp
	
	-- Unfilter the buffer and 
	-- load it into the bitmap.
	
	for row = 1, height do	
		local filterType = buffer:ReadByte()
		local scanline = buffer:ReadBytes(width * bpp, true)
		
		bitmap[row] = {}
		
		if filterType == 0 then
			-- None
			Unfilter:None(scanline, bitmap, bpp, row)
		elseif filterType == 1 then
			-- Sub
			Unfilter:Sub(scanline, bitmap, bpp, row)
		elseif filterType == 2 then
			-- Up
			Unfilter:Up(scanline, bitmap, bpp, row)
		elseif filterType == 3 then
			-- Average
			Unfilter:Average(scanline, bitmap, bpp, row)
		elseif filterType == 4 then
			-- Paeth
			Unfilter:Paeth(scanline, bitmap, bpp, row)
		end
	end
	
	return setmetatable(file, PNG)
end

return PNG