local L={}local w=require(script.HuffmanTable)local I=require(script.BitStream)local j=game:GetService("\082\117\110\083\101\114\118\105\099\101")local V=50 local J={[192]=true,[193]=true;[194]=true;[195]=false,[197]=false,[198]=false;[199]=false;[201]=false,[202]=false;[203]=false;[205]=false;[206]=false,[207]=false}local u={}local function W(L)if L==0 then return math.sqrt(.125)else return math.sqrt(.25)end end for L=0,7,1 do for w=0,7,1 do local I={}for j=0,7,1 do for V=0,7,1 do local J=W(w)*math.cos(((w*math.pi)*(V+.5))/8)local u=W(L)*math.cos(((L*math.pi)*(j+.5))/8)I[(V*8+j)+1]=J*u end end u[(L*8+w)+1]=I end end local S={1;2;9,17;10;3,4;11,18;25,33;26,19;12;5;6,13;20,27;34;41,49;42;35,28,21,14;7,8,15;22;29;36,43,50,57,58;51,44,37,30,23,16;24,31,38,45;52;59;60,53;46,39;32;40,47,54;61;62,55,48;56,63;64}local H={{1,2,6,7,15;16;28;29},{3;5,8;14;17,27,30;43};{4,9,13,18;26,31,42,44},{10,12,19;25;32,41,45;54};{11,20,24,33;40,47,53,55};{21,23;34,39;47,52;56,61};{22;35;38,48,51,57;60,62};{36,37;49;50,58,59;63;64}}local function D(L,w)return bit32.lshift(L,8)+w end local function d(L,w)local I=math.pow(2,L-1)if w>=I then return w else return w-(2*I-1)end end local function r(L)if L>4000000000 then return L-4294967296 else return L end end function L.CreateJPEGfromBytes(L,W,s,b)if not(L[1]==255 and(L[2]==216 and L[3]==255))then warn("\073\109\097\103\101 \105\115 \110\111\116 \097 \074\080\069\071\046")return nil end local n={}n.ImageData={}n.QuantisationTables={}n.HuffmanDCTables={}n.HuffmanACTables={}n.ImageWidth=0 n.ImageHeight=0 n.MCUCountX=0 n.MCUCountY=0 n.MaxVerticalSampleFactor=0 n.MaxHorizontalSampleFactor=0 n.FrameType=0 n.RestartInterval=0 n.Precision=8 n.ComponentCount=0 n.ColorComponents={}local f=0 local m={}local y=0 local l={0,0;0,0}local X=false local function P(L,w,I)local j=D(I[w-2],I[w-1])local V="\048\120\070\070"..string.upper(string.format("\037\120",L))if W then print("                    ")print("--------------------")print("   \065\080\080"..(L-224 ..(" \091"..(V.."\093"))))print("   \080\097\121\108\111\097\100 \076\101\110\103\116\104\058 "..j)print("--------------------")end if L==238 and j>=12 then local L=w local j=0 if I[L]==65 and(I[L+1]==100 and(I[L+2]==111 and(I[L+3]==98 and I[L+4]==101)))then f=I[L+11]if W then if f==0 then print("\067\111\108\111\114 \116\114\097\110\115\102\111\114\109\058 \048 \040\085\110\107\110\111\119\110\044 \082\071\066 \111\114 \067\077\089\075 \097\115\115\117\109\101\100\041")elseif f==1 then print("\067\111\108\111\114 \116\114\097\110\115\102\111\114\109\058 \049 \040\089\067\098\067\114\041")elseif f==2 then print("\067\111\108\111\114 \116\114\097\110\115\102\111\114\109\058 \050 \040\089\067\067\075\041")end end end end return j end local function z(L,w,I)local j=D(I[w-2],I[w-1])if W then print("                    ")print("--------------------")print("   \067\079\077 \091\048\120\070\070\070\069\093     ")print("   \080\097\121\108\111\097\100 \076\101\110\103\116\104\058 "..j)print("--------------------")end return j end local function A(L,w,I)local j=D(I[w-2],I[w-1])if W then print("                    ")print("--------------------")print("   \068\081\084 \091\048\120\070\070\068\066\093     ")print("   \080\097\121\108\111\097\100 \076\101\110\103\116\104\058 "..j)print("--------------------")end local V=0 while I[w+V]~=255 do local L=bit32.rshift(I[w+V],4)local j=bit32.band(I[w+V],15)local J={}if L==1 then for L=1,64,1 do local j=I[(w+V)+1]local u=I[(w+V)+2]local W=D(j,u)table.insert(J,W)V=V+2 end else for L=1,64,1 do V=V+1 table.insert(J,I[w+V])end end if W then if j==0 then print("\068\101\115\116\105\110\097\116\105\111\110\058 "..(j.." \091\076\117\109\105\110\097\110\099\101\093"))elseif j==1 then print("\068\101\115\116\105\110\097\116\105\111\110\058 "..(j.." \091\067\104\114\111\109\105\110\097\110\099\101\093"))end for L=0,7,1 do local w=""for I=0,7,1 do local j=(I*8+L)+1 local V=J[H[L+1][I+1]]local u=string.rep(" ",4-string.len(V))w=w..(V..u)end print("  \082\111\119 "..(L..("\058  "..w)))end end n.QuantisationTables[j+1]=J V=V+1 end return j end local function E(L,I,j)local V=D(j[I-2],j[I-1])if W then print("                    ")print("--------------------")print("   \068\072\084 \091\048\120\070\070\067\052\093     ")print("   \080\097\121\108\111\097\100 \076\101\110\103\116\104\058 "..V)end local function J(L)local w={}local I=0 for j=1,#L,1 do local V=L[j]for L=1,V,1 do table.insert(w,{I,j})I=I+1 end I=bit32.lshift(I,1)end return w end local u=0 while u<V-2 do local L=j[I+u]local V=bit32.band(bit32.rshift(L,4),15)local S=bit32.band(L,15)local H={}local D={}local d={}for L=1,16,1 do u=u+1 table.insert(D,j[I+u])end for L,w in pairs(D)do d[L]={}for w=1,w,1 do u=u+1 local V=j[I+u]table.insert(H,V)d[L][w]=V end end u=u+1 if W then print("--------------------")print("\068\101\115\116\105\110\097\116\105\111\110\058 "..S)print("\067\108\097\115\115\058 "..V)for L=1,#d,1 do local w=string.format("  \067\111\100\101\115 \111\102 \108\101\110\103\116\104 \037\105 \098\105\116\115 \040\037\105 \116\111\116\097\108\041\058 ",L,#d[L])for I=1,#d[L],1 do local j=string.upper(string.format("\037\120",d[L][I]))if string.len(j)==1 then j="\048"..j end w=w..(j.." ")end print(w)end end if W then print("\083\121\109\098\111\108\115 \097\110\100 \116\104\101\105\114 \099\111\100\101\115\058")end local r={}for L,w in pairs(J(D))do local I=w[1]local j=w[2]local V=""local J=I for L=1,j,1 do local w=bit32.band(J,1)J=bit32.rshift(J,1)V=V..w end if W then print("  "..(H[L]..(" \061 "..(string.reverse(V)..(" \091"..(I.."\093"))))))end r[L]={H[L];I;j}end local s=w.CreateHuffmanTable()w.ConstructTree(s,D,H)if V==0 then n.HuffmanDCTables[S+1]=s elseif V==1 then n.HuffmanACTables[S+1]=s end end return V end local function U(L,w,I)local j=D(I[w-2],I[w-1])local V=D(I[w],I[w+1])if W then print("                    ")print("--------------------")print("   \068\082\073 \091\048\120\070\070\068\068\093    ")print("   \080\097\121\108\111\097\100 \076\101\110\103\116\104\058 "..j)print("--------------------")print("\073\110\116\101\114\118\097\108\058 "..V)end n.RestartInterval=V return j end local function g(L,w,I)if not J[L]then return"\078\111\116 \115\117\112\112\111\114\116\101\100\046"end local j=D(I[w-2],I[w-1])local V="\048\120\070\070"..string.upper(string.format("\037\120",L))if W then print("                    ")print("--------------------")print("   \083\079\070"..(L-192 ..(" \091"..(V.."\093"))))print("   \080\097\121\108\111\097\100 \076\101\110\103\116\104\058 "..j)print("--------------------")end local u=I[w]local S=D(I[w+1],I[w+2])local H=D(I[w+3],I[w+4])local d=I[w+5]n.ImageWidth=H n.ImageHeight=S n.Precision=u n.ComponentCount=d n.FrameType=L n.MCUCountX=math.floor((n.ImageWidth-1)/8)n.MCUCountY=math.floor((n.ImageHeight-1)/8)for L=1,n.ImageWidth,1 do n.ImageData[L]={}for w=1,n.ImageHeight,1 do n.ImageData[L][w]={0;0,0}end end for L=1,n.MCUCountX+8,1 do m[L]={}for w=1,n.MCUCountY+8,1 do m[L][w]={}for I=1,d,1 do m[L][w][I]=table.create(64,0)end end end if W then print("\073\109\097\103\101 \082\101\115\111\108\117\116\105\111\110\058 "..(n.ImageWidth..("\120"..n.ImageHeight)))print("\080\114\101\099\105\115\105\111\110\058 "..u)print("\067\111\109\112\111\110\101\110\116\115\058 "..d)end for L=0,d-1,1 do local j=I[(w+6)+L*3]local V=I[(w+7)+L*3]local J=I[(w+8)+L*3]if X then j=j+1 end if j==0 then X=true j=j+1 end local u=bit32.band(bit32.rshift(V,4),15)local S=bit32.band(V,15)n.MaxHorizontalSampleFactor=math.max(n.MaxHorizontalSampleFactor,u)n.MaxVerticalSampleFactor=math.max(n.MaxVerticalSampleFactor,S)n.ColorComponents[j]={}n.ColorComponents[j].ID=L+1 n.ColorComponents[j].HorizontalSamplingFactor=u n.ColorComponents[j].VerticalSamplingFactor=S n.ColorComponents[j].QuantSelection=J if W then print(string.format("  \067\111\109\112\111\110\101\110\116 \037\105\058 \091\083\101\108\101\099\116\105\111\110\058 \037\105\093 \091\083\097\109\112\108\101 \070\097\099\116\111\114\058 \037\105\093 \091\081\117\097\110\116 \073\068\058 \037\105\093",L+1,j,V,J))print("   - \088 \083\097\109\112\108\105\110\103 \070\097\099\116\111\114\058 "..u)print("   - \089 \083\097\109\112\108\105\110\103 \070\097\099\116\111\114\058 "..S)end end return j end local function x(L,J,u)local S=D(u[J-2],u[J-1])local H=u[J]local s=1 if W then print("                    ")print("--------------------")print("   \083\079\083 \091\048\120\070\070\068\065\093     ")print("   \080\097\121\108\111\097\100 \076\101\110\103\116\104\058 "..S)print("--------------------")print("\067\111\109\112\111\110\101\110\116 \067\111\117\110\116\058 "..H)end local f={}for L=0,H-1,1 do local w=u[J+s]local I=u[(J+s)+1]local j=bit32.band(bit32.rshift(I,4),15)local V=bit32.band(I,15)if X then w=w+1 end local S={}S.ID=w S.HuffmanDCTableID=j+1 S.HuffmanACTableID=V+1 S.HorizontalSample=n.ColorComponents[w].HorizontalSamplingFactor S.VerticalSample=n.ColorComponents[w].VerticalSamplingFactor local H=n.ColorComponents[w].QuantSelection+1 S.QuantisationTable=n.QuantisationTables[H]table.insert(f,S)if W then print(" \067\111\109\112\111\110\101\110\116\091"..(L+1 ..("\093\058 \115\101\108\101\099\116\111\114\061"..(w..("\044 \116\097\098\108\101\061"..(j..("\040\068\067\041\044"..(V.."\040\065\067\041"))))))))end s=s+2 end local P=u[(J+s)+2]local z=u[J+s]local A=u[(J+s)+1]local E=bit32.band(bit32.rshift(P,4),15)local U=bit32.band(P,15)if W then print("\083\112\101\099\116\114\097\108 \083\101\108\101\099\116\105\111\110\058 "..(z..(" \046\046 "..A)))print("\083\117\099\099\101\115\115\105\118\101 \065\112\112\114\111\120\105\109\097\116\105\111\110\058 "..P)print("\083\117\099\099\101\115\115\105\118\101 \072\105\103\104 \080\097\114\116\058 "..E)print("\083\117\099\099\101\115\115\105\118\101 \076\111\119 \080\097\114\116\058 "..U)end local g={}do local L=(J+s)+2 local w=0 while true do L=L+1 if w>0 then w=w-1 continue end local I=u[L]local j=u[L+1]if I==255 then if j>=208 and j<=215 then w=w+1 continue elseif j==0 then w=w+1 table.insert(g,I)continue else break end end table.insert(g,I)if j==nil then break end end end local x=I.CreateBitStream(g)local o=math.floor((n.ImageWidth-1)/8)local C=math.floor((n.ImageHeight-1)/8)local q=n.MaxHorizontalSampleFactor local F=n.MaxVerticalSampleFactor local a=n.RestartInterval local k=a local B=0 local function O(L,I)local j=w.GetCode(n.HuffmanDCTables[I.HuffmanDCTableID],x)local V=n.ColorComponents[I.ID].ID local J=l[V]if J==nil then J=0 end local u=x.ReadBits(j)local W=d(j,u)+J l[V]=W L[1]=W local S=n.HuffmanACTables[I.HuffmanACTableID]local H=1 while H<64 do j=w.GetCode(S,x)if j==0 then return end if j>16 then H=H+bit32.rshift(j,4)j=bit32.band(j,15)end u=x.ReadBits(j)if H<64 then H=H+1 local w=d(j,u)L[H]=w end end end local function R(L,w)local I=r(bit32.lshift(1,w-1))if L<I then return(L+r(bit32.lshift(-1,w)))+1 else return L end end local function M(L)if L>0 then if x.ReadBit()==1 then return L+r(bit32.lshift(1,U))end elseif L<0 then if x.ReadBit()==1 then return L+r(bit32.lshift(-1,U))end end return L end local function v(L,I)local j=w.GetCode(n.HuffmanDCTables[I.HuffmanDCTableID],x)local V=x.ReadBits(j)local J=R(V,j)+l[I.ID]l[I.ID]=J L[1]=r(bit32.lshift(J,U))end local function N(L,w)local I=x.ReadBit()local j=r(bit32.lshift(I,U))L[1]=r(bit32.bor(L[1],j))end local function i(L,I)if y>0 then y=y-1 return end local j=n.HuffmanACTables[I.HuffmanACTableID]local V=z while V<=A do local I=w.GetCode(j,x)local J=bit32.rshift(I,4)local u=bit32.band(I,15)if u==0 then if J==15 then V=V+16 else y=(x.ReadBits(J)+math.pow(2,J))-1 return end else V=(V+J)+1 local w=x.ReadBits(u)local I=R(w,u)I=bit32.lshift(I,U)I=r(I)L[V]=I end end end local function G(L,I)local j=z if y>0 then while j<=A do if L[j+1]~=0 then L[j+1]=M(L[j+1])end j=j+1 end y=y-1 return end local V=n.HuffmanACTables[I.HuffmanACTableID]while j<=A do local I=w.GetCode(V,x)local J=bit32.rshift(I,4)local u=I%16 if u==1 then local w=R(x.ReadBits(u),u)w=r(bit32.lshift(w,U))while(J>0 or L[j+1]~=0)and j<A do j=j+1 if L[j]~=0 then L[j]=M(L[j])else J=J-1 end end j=j+1 L[j]=w elseif u==0 then if J<15 then local w=x.ReadBits(J)+r(bit32.lshift(1,J))while j<=A and j<A do j=j+1 if L[j]~=0 then L[j]=M(L[j])end end y=w-1 return else while J>=0 and j<A do j=j+1 if L[j]~=0 then L[j]=M(L[j])else J=J-1 end end end else j=j+1 end end end local function h()if H>1 then for L=0,C,F do for w=0,o,q do for I,j in pairs(f)do for I=0,j.VerticalSample-1,1 do for V=0,j.HorizontalSample-1,1 do local J=(w+V)+1 local u=(L+I)+1 v(m[J][u][j.ID],j)end end end end if b then if L%V==0 then j.Stepped:Wait()end end end else local L=f[1]for w=0,C,3-L.VerticalSample do for I=0,o,3-L.HorizontalSample do local j=I+1 local V=w+1 v(m[j][V][L.ID],L)end if b then if w%V==0 then j.Stepped:Wait()end end end end end local function Z()for L=0,C,F do for w=0,o,q do for I,j in pairs(f)do local V=j.VerticalSample local J=j.HorizontalSample for I=0,V-1,1 do for V=0,J-1,1 do local J=(w+V)+1 local u=(L+I)+1 N(m[J][u][j.ID],j)end end end end if b then if L%V==0 then j.Stepped:Wait()end end end end local function c()local L=f[1]local w=2 local I=2 if q==2 then w=3 end if F==2 then I=3 end for I=0,C,I-L.VerticalSample do for w=0,o,w-L.HorizontalSample do local j=w+1 local V=I+1 i(m[j][V][L.ID],L)end if b then if I%V==0 then j.Stepped:Wait()end end end end local function t()local L=f[1]local w=2 local I=2 if q==2 then w=3 end if F==2 then I=3 end for I=0,C,I-L.VerticalSample do for w=0,o,w-L.HorizontalSample do local j=w+1 local V=I+1 G(m[j][V][L.ID],L)end if b then if I%V==0 then j.Stepped:Wait()end end end end if n.FrameType==192 then for L=0,C,F do for w=0,o,q do for I,j in pairs(f)do local V=I local J=j.QuantisationTable local u=j.HorizontalSample local W=j.VerticalSample for I=0,W-1,1 do for J=0,u-1,1 do local u=(w+J)+1 local W=(L+I)+1 O(m[u][W][V],j)end end B=B+W*u end if a~=0 then k=k-1 if k==0 then k=a l={0;0,0}x.Align()end end end if b then if L%V==0 then j.Stepped:Wait()end end end if W then print("\084\111\116\097\108 \077\067\085\115 \100\101\099\111\100\101\100\058 "..B)end end if n.FrameType==194 then if z==0 and A~=0 then warn("\083\112\101\099\116\114\097\108 \115\101\108\101\099\116\105\111\110 \115\116\097\114\116 \105\115 \122\101\114\111 \097\110\100 \101\110\100 \105\115 \110\111\116 \122\101\114\111\046")end if A==0 and z~=0 then warn("\083\112\101\099\116\114\097\108 \115\101\108\101\099\116\105\111\110 \101\110\100 \105\115 \122\101\114\111 \097\110\100 \115\116\097\114\116 \105\115 \110\111\116 \122\101\114\111\046")end if z>A then warn("\083\112\101\099\116\114\097\108 \115\101\108\101\099\116\105\111\110 \115\116\097\114\116 \105\115 \103\114\101\097\116\101\114 \116\104\097\110 \115\112\101\099\116\114\097\108 \115\101\108\101\099\116\105\111\110 \101\110\100\046")end if z~=0 and#f>1 then warn("\083\112\101\099\116\114\097\108 \115\101\108\101\099\116\105\111\110 \115\116\097\114\116 \105\115 \110\111\116 \122\101\114\111 \097\110\100 \108\111\111\112 \099\111\109\112\111\110\101\110\116\115 \105\115 \103\114\101\097\116\101\114 \116\104\097\110 \111\110\101\046")end if E>13 then warn("\083\117\099\099\101\115\115\105\118\101 \112\114\111\120\105\109\097\116\105\111\110 \104\105\103\104 \052 \098\105\116\115 \105\115 \103\114\101\097\116\101\114 \116\104\097\110 \049\051\046")end if U>13 then warn("\083\117\099\099\101\115\115\105\118\101 \112\114\111\120\105\109\097\116\105\111\110 \108\111\119 \052 \098\105\116\115 \105\115 \103\114\101\097\116\101\114 \116\104\097\110 \049\051\046")end if E~=0 then if E-U~=1 then warn("\097\104 \105\115 \110\111\116 \122\101\114\111 \097\110\100 \097\104 - \097\108 ~\061 \049")end end if z==0 and A==0 then if E==0 then h()else Z()end else if E==0 then c()else t()end end end end local o={[192]=g,[193]=g;[194]=g;[195]=g;[196]=E;[197]=g;[198]=g,[199]=g,[200]="\080\114\105\110\116",[201]=g,[202]=g;[203]=g;[204]="\080\114\105\110\116";[205]=g;[206]=g,[207]=g;[208]="\080\114\105\110\116",[209]="\080\114\105\110\116",[210]="\080\114\105\110\116";[211]="\080\114\105\110\116";[212]="\080\114\105\110\116",[213]="\080\114\105\110\116",[214]="\080\114\105\110\116";[215]="\080\114\105\110\116",[216]="\080\114\105\110\116";[217]="\080\114\105\110\116";[218]=x,[219]=A;[220]="\080\114\105\110\116",[221]=U;[222]="\080\114\105\110\116",[223]="\080\114\105\110\116";[224]=P;[225]=P;[226]=P,[227]=P,[228]=P;[229]=P;[230]=P;[231]=P;[232]=P,[233]=P;[234]=P;[235]=P;[236]=P;[237]=P;[238]=P,[239]=P;[240]="\080\114\105\110\116";[241]="\080\114\105\110\116",[242]="\080\114\105\110\116";[243]="\080\114\105\110\116",[244]="\080\114\105\110\116";[245]="\080\114\105\110\116",[246]="\080\114\105\110\116",[247]="\080\114\105\110\116";[248]="\080\114\105\110\116";[249]="\080\114\105\110\116";[250]="\080\114\105\110\116";[251]="\080\114\105\110\116";[252]="\080\114\105\110\116";[253]="\080\114\105\110\116";[254]=z}local C=tick()local q=tick()local F=L local a=0 local k=0 for L=1,#F-1,1 do local w=F[L]local I=F[L+1]if a>0 then a=a-1 continue end if w~=255 then continue end if I==0 then continue end local j=o[I]if j==nil then continue elseif type(j)=="\115\116\114\105\110\103"then continue end local V=j(I,L+4,F)if V then if V=="\078\111\116 \115\117\112\112\111\114\116\101\100\046"then return"\078\111\116 \115\117\112\112\111\114\116\101\100\046"elseif type(V)=="\110\117\109\098\101\114"then a=a+V end end if I==218 then k=k+1 end if k==1000000 then break end end local B=tick()if s then print("")print("\068\069\067\079\068\069\068 \073\078\058 "..(B-q.."\115"))end q=tick()local O=8*n.MaxVerticalSampleFactor-1 local R=8*n.MaxHorizontalSampleFactor-1 local M=2 local v=2 if n.MaxHorizontalSampleFactor==2 then M=3 end if n.MaxVerticalSampleFactor==2 then v=3 end for L,w in pairs(n.ColorComponents)do local I=n.ColorComponents[L].ID local J=n.ColorComponents[L].HorizontalSamplingFactor local W=n.ColorComponents[L].VerticalSamplingFactor local H=n.ColorComponents[L].QuantSelection local D=n.QuantisationTables[H+1]for L=0,n.MCUCountY,n.MaxVerticalSampleFactor do for w=0,n.MCUCountX,n.MaxHorizontalSampleFactor do for j=0,W-1,1 do for V=0,J-1,1 do local H=(w+V)+1 local d=(L+j)+1 local r=table.create(64,0)for L,w in pairs(m[H][d][I])do if w==0 then continue end if L>64 then break end local I=S[L]local j=w*D[L]local V=u[I]for L=1,64,1 do r[L]=r[L]+V[L]*j end end for L=0,O,1 do for w=0,R,1 do local j=((H-1)*8+w)+1 local V=((d-1)*8+L)+1 if j<=n.ImageWidth and V<=n.ImageHeight then local u=math.floor(L/(v-W))local S=math.floor(w/(M-J))local H=(S*8+u)+1 n.ImageData[j][V][I]=r[H]end end end end end end if b then if L%V==0 then j.Stepped:Wait()end end end end B=tick()if s then print("\080\069\082\070\079\082\077\069\068 \073\068\067\084 \073\078\058 "..(B-q.."\115"))end q=tick()for L=1,n.ImageWidth,1 do for w=1,n.ImageHeight,1 do if n.ComponentCount==3 then local I=n.ImageData[L][w][1]local j=n.ImageData[L][w][2]local V=n.ImageData[L][w][3]local J=(I+1.402*V)+128 local u=((I-.34414*j)-.71414*V)+128 local W=(I+1.772*j)+128 J=math.clamp(J,0,255)u=math.clamp(u,0,255)W=math.clamp(W,0,255)n.ImageData[L][w][1]=J n.ImageData[L][w][2]=u n.ImageData[L][w][3]=W elseif n.ComponentCount==4 then local I=n.ImageData[L][w][1]local j=n.ImageData[L][w][2]local V=n.ImageData[L][w][3]local J=n.ImageData[L][w][4]local u,W,S if f==2 or f==1 then u=(I+1.402*V)+128 W=((I-.34414*j)-.71414*V)+128 S=(I+1.772*j)+128 u=math.clamp(u,0,255)W=math.clamp(W,0,255)S=math.clamp(S,0,255)u=(255-u)*((J+128)/255)W=(255-W)*((J+128)/255)S=(255-S)*((J+128)/255)elseif f==0 then u=(I+128)*((J+128)/255)W=(j+128)*((J+128)/255)S=(V+128)*((J+128)/255)end n.ImageData[L][w][1]=u n.ImageData[L][w][2]=W n.ImageData[L][w][3]=S n.ImageData[L][w][4]=nil end end if b then if L%V==0 then j.Stepped:Wait()end end end B=tick()if s then print("\067\079\078\086\069\082\084\069\068 \084\079 \082\071\066\058 "..(B-q.."\115"))end local N=tick()if s then print("\070\073\078\073\083\072\069\068 \068\069\067\079\068\073\078\071 \074\080\069\071 \073\078\058 "..(N-C.."\115"))end function n.GetPixel(L,w)local I=n.ImageData[L][w][1]local j=n.ImageData[L][w][2]local V=n.ImageData[L][w][3]return I,j,V end return n end return L
--!nocheck
local module = {}

local HUFFMAN_MODULE = require(script.HuffmanTable)
local BITSTREAM_MODULE = require(script.BitStream)

local RUN_SERVICE = game:GetService("RunService")

local PREVENT_TIMEOUT_INTERVAL = 50

-- Supported modes
local supportedModes = { -- If a mode is not supported (set to false) then the module will simply return and say that the mode isn't supported, in short, it won't bother decoding it.
	[0xC0] = true, -- "Start Of Frame 0"
	[0xC1] = true, -- "Start Of Frame 1"
	[0xC2] = true, -- "Start Of Frame 2"
	[0xC3] = false, -- "Start Of Frame 3"
	[0xC5] = false, -- "Start Of Frame 5"
	[0xC6] = false, -- "Start Of Frame 6"
	[0xC7] = false, -- "Start Of Frame 7"
	[0xC9] = false, -- "Start Of Frame 9"
	[0xCA] = false, -- "Start Of Frame 10"
	[0xCB] = false, -- "Start Of Frame 11"
	[0xCD] = false, -- "Start Of Frame 13"
	[0xCE] = false, -- "Start Of Frame 14"
	[0xCF] = false, -- "Start Of Frame 15"
}

-- Create idct LUT
local idctTable = {}

local function NormCoeff(n)
	if n == 0 then
		return math.sqrt(1 / 8)
	else
		return math.sqrt(2 / 8)
	end
end

for i = 0, 7 do
	for j = 0, 7 do
		local grid = {}

		for y = 0, 7 do
			for x = 0, 7 do
				local nn = NormCoeff(j) * math.cos(j * math.pi * (x + 0.5) / 8)
				local mm = NormCoeff(i) * math.cos(i * math.pi * (y + 0.5) / 8)

				grid[x * 8 + y + 1] = nn * mm
			end
		end

		idctTable[i * 8 + j + 1] = grid
	end
end

-- Zigzag LUTs
local zigzag1D = {
	1,
	2,
	9,
	17,
	10,
	3,
	4,
	11,
	18,
	25,
	33,
	26,
	19,
	12,
	5,
	6,
	13,
	20,
	27,
	34,
	41,
	49,
	42,
	35,
	28,
	21,
	14,
	7,
	8,
	15,
	22,
	29,
	36,
	43,
	50,
	57,
	58,
	51,
	44,
	37,
	30,
	23,
	16,
	24,
	31,
	38,
	45,
	52,
	59,
	60,
	53,
	46,
	39,
	32,
	40,
	47,
	54,
	61,
	62,
	55,
	48,
	56,
	63,
	64,
}

local zigzag2D = {
	{ 1, 2, 6, 7, 15, 16, 28, 29 },
	{ 3, 5, 8, 14, 17, 27, 30, 43 },
	{ 4, 9, 13, 18, 26, 31, 42, 44 },
	{ 10, 12, 19, 25, 32, 41, 45, 54 },
	{ 11, 20, 24, 33, 40, 47, 53, 55 },
	{ 21, 23, 34, 39, 47, 52, 56, 61 },
	{ 22, 35, 38, 48, 51, 57, 60, 62 },
	{ 36, 37, 49, 50, 58, 59, 63, 64 },
}

-- Useful functions
local function CombineTwoBytes(high, low)
	return bit32.lshift(high, 8) + low
end

local function DecodeNumber(code, bits)
	local l = math.pow(2, code - 1)

	if bits >= l then
		return bits
	else
		return bits - (2 * l - 1)
	end
end

local function BitwiseHandleOverflow(x)
	if x > 4000000000 then
		return x - 4294967296
	else
		return x
	end
end

function module.CreateJPEGfromBytes(rawInputBytes, printDebugInformation, printProgress, preventTimeouts)
	-- Verify it's a JPEG
	if not (rawInputBytes[1] == 0xFF and rawInputBytes[2] == 0xD8 and rawInputBytes[3] == 0xFF) then
		warn("Image is not a JPEG.")
		return nil
	end

	local jpeg = {}

	jpeg.ImageData = {}

	jpeg.QuantisationTables = {}
	jpeg.HuffmanDCTables = {}
	jpeg.HuffmanACTables = {}

	jpeg.ImageWidth = 0
	jpeg.ImageHeight = 0

	jpeg.MCUCountX = 0
	jpeg.MCUCountY = 0

	jpeg.MaxVerticalSampleFactor = 0
	jpeg.MaxHorizontalSampleFactor = 0

	jpeg.FrameType = 0 -- The marker from start of frame, e.g 0xC0 = SOF0 (baseline), 0xC2 = SOF2 (progressive)
	jpeg.RestartInterval = 0
	jpeg.Precision = 8

	jpeg.ComponentCount = 0
	jpeg.ColorComponents = {}

	local colorTransform = 0

	local mcus = {}
	local eobRun = 0
	local previousDCs = { 0, 0, 0, 0 }

	local addOneToSelector = false -- Prevents zero index because this is Lua

	-- 'pos' will index the first byte in 'bytes' after the length information

	local function APPn(marker, pos, bytes)
		local payloadLength = CombineTwoBytes(bytes[pos - 2], bytes[pos - 1])
		local markerString = "0xFF" .. string.upper(string.format("%x", marker))

		if printDebugInformation then
			print("                    ")
			print("--------------------")
			print("   APP" .. marker - 0xE0 .. " [" .. markerString .. "]") -- tostring incase nil
			print("   Payload Length: " .. payloadLength)
			print("--------------------")
		end

		if marker == 0xEE and payloadLength >= 12 then
			local i = pos
			local _lastByte = 0

			if bytes[i] == 65 and bytes[i + 1] == 100 and bytes[i + 2] == 111 and bytes[i + 3] == 98 and bytes[i + 4] == 101 then
				colorTransform = bytes[i + 11]

				if printDebugInformation then
					if colorTransform == 0 then
						print("Color transform: 0 (Unknown, RGB or CMYK assumed)")
					elseif colorTransform == 1 then
						print("Color transform: 1 (YCbCr)")
					elseif colorTransform == 2 then
						print("Color transform: 2 (YCCK)")
					end
				end
			end
		end

		return payloadLength
	end

	local function COM(marker, pos, bytes)
		local payloadLength = CombineTwoBytes(bytes[pos - 2], bytes[pos - 1])

		if printDebugInformation then
			print("                    ")
			print("--------------------")
			print("   COM [0xFFFE]     ")
			print("   Payload Length: " .. payloadLength)
			print("--------------------")
		end

		return payloadLength
	end

	local function DQT(marker, pos, bytes)
		local payloadLength = CombineTwoBytes(bytes[pos - 2], bytes[pos - 1])

		if printDebugInformation then
			print("                    ")
			print("--------------------")
			print("   DQT [0xFFDB]     ")
			print("   Payload Length: " .. payloadLength)
			print("--------------------")
		end

		local i = 0
		while bytes[pos + i] ~= 0xFF do
			local precision = bit32.rshift(bytes[pos + i], 4)
			local identifier = bit32.band(bytes[pos + i], 0x0F)

			local quant = {}

			if precision == 1 then
				for j = 1, 64 do
					local highByte = bytes[pos + i + 1]
					local lowByte = bytes[pos + i + 2]

					local value = CombineTwoBytes(highByte, lowByte)
					table.insert(quant, value)

					i = i + 2
				end
			else
				for j = 1, 64 do
					i = i + 1
					table.insert(quant, bytes[pos + i])
				end
			end

			-- Print
			if printDebugInformation then
				if identifier == 0 then
					print("Destination: " .. identifier .. " [Luminance]")
				elseif identifier == 1 then
					print("Destination: " .. identifier .. " [Chrominance]")
				end

				for x = 0, 7 do
					local str = ""

					for y = 0, 7 do
						local _index = y * 8 + x + 1

						local word = quant[zigzag2D[x + 1][y + 1]]
						local spaces = string.rep(" ", 4 - string.len(word))

						str = str .. word .. spaces
					end

					print("  Row " .. x .. ":  " .. str)
				end
			end

			-- Add it to the global variable
			jpeg.QuantisationTables[identifier + 1] = quant

			i = i + 1
		end

		return payloadLength
	end

	local function DHT(marker, pos, bytes)
		local payloadLength = CombineTwoBytes(bytes[pos - 2], bytes[pos - 1])

		if printDebugInformation then
			print("                    ")
			print("--------------------")
			print("   DHT [0xFFC4]     ")
			print("   Payload Length: " .. payloadLength)
		end

		-- Create huffman table
		local function GetCodesFromLengths(lengths) -- Creates the codes used to traverse the huffman tree given the lengths in the jpeg binary
			local codes = {}

			local codeCandidate = 0

			for bitLength = 1, #lengths do
				local length = lengths[bitLength]

				for i = 1, length do
					table.insert(codes, { codeCandidate, bitLength })

					codeCandidate = codeCandidate + 1
				end

				codeCandidate = bit32.lshift(codeCandidate, 1)
			end

			return codes
		end

		-- Extract class and destination
		local i = 0

		while i < payloadLength - 2 do -- Subtract 2 because payload length includes length information
			local classAndDestination = bytes[pos + i] -- This will be used to index jpeg.HuffmanTables

			local class = bit32.band(bit32.rshift(classAndDestination, 4), 0x0F) -- 0 = DC, 1 = AC
			local destination = bit32.band(classAndDestination, 0x0F) -- 0 = Luminace, 1 = Chrominance

			-- Extract information
			local symbols = {}
			local lengths = {}
			local symbolsSorted = {}

			-- Extract lengths
			for j = 1, 16 do
				i = i + 1
				table.insert(lengths, bytes[pos + i])
			end

			-- Extract symbols
			for j, length in pairs(lengths) do
				symbolsSorted[j] = {}

				for k = 1, length do
					i = i + 1
					local symbol = bytes[pos + i]

					table.insert(symbols, symbol)
					symbolsSorted[j][k] = symbol
				end
			end

			i = i + 1

			-- Print
			if printDebugInformation then
				print("--------------------")
				print("Destination: " .. destination)
				print("Class: " .. class)

				for j = 1, #symbolsSorted do
					local str = string.format("  Codes of length %i bits (%i total): ", j, #symbolsSorted[j])

					for k = 1, #symbolsSorted[j] do
						local x = string.upper(string.format("%x", symbolsSorted[j][k]))

						if string.len(x) == 1 then
							x = "0" .. x
						end

						str = str .. x .. " "
					end

					print(str)
				end
			end

			if printDebugInformation then
				print("Symbols and their codes:")
			end

			local symbolsAndCodes = {}

			for ii, info in pairs(GetCodesFromLengths(lengths)) do
				local code = info[1]
				local bitLength = info[2]

				local str = ""
				local c = code

				for _ = 1, bitLength do
					local bit = bit32.band(c, 1)
					c = bit32.rshift(c, 1)

					str = str .. bit
				end

				if printDebugInformation then
					print("  " .. symbols[ii] .. " = " .. string.reverse(str) .. " [" .. code .. "]")
				end

				symbolsAndCodes[ii] = {
					symbols[ii],
					code,
					bitLength,
				}
			end

			local huffmanTable = HUFFMAN_MODULE.CreateHuffmanTable()
			HUFFMAN_MODULE.ConstructTree(huffmanTable, lengths, symbols)

			if class == 0 then -- DC
				jpeg.HuffmanDCTables[destination + 1] = huffmanTable
			elseif class == 1 then -- AC
				jpeg.HuffmanACTables[destination + 1] = huffmanTable
			end
		end

		return payloadLength
	end

	local function DRI(marker, pos, bytes)
		local payloadLength = CombineTwoBytes(bytes[pos - 2], bytes[pos - 1])

		local interval = CombineTwoBytes(bytes[pos], bytes[pos + 1]) --CombineTwoBytes(bytes[2], bytes[3])

		if printDebugInformation then
			print("                    ")
			print("--------------------")
			print("   DRI [0xFFDD]    ")
			print("   Payload Length: " .. payloadLength)
			print("--------------------")
			print("Interval: " .. interval)
		end

		jpeg.RestartInterval = interval

		return payloadLength
	end

	local function SOFn(marker, pos, bytes)
		if not supportedModes[marker] then
			return "Not supported."
		end

		local payloadLength = CombineTwoBytes(bytes[pos - 2], bytes[pos - 1])

		local markerString = "0xFF" .. string.upper(string.format("%x", marker))

		if printDebugInformation then
			print("                    ")
			print("--------------------")
			print("   SOF" .. marker - 0xC0 .. " [" .. markerString .. "]") -- tostring incase nil
			print("   Payload Length: " .. payloadLength)
			print("--------------------")
		end

		-- Read information
		local precision = bytes[pos]
		local lineNumber = CombineTwoBytes(bytes[pos + 1], bytes[pos + 2]) -- aka height
		local samplesPerLine = CombineTwoBytes(bytes[pos + 3], bytes[pos + 4]) -- aka width
		local componentCount = bytes[pos + 5]

		jpeg.ImageWidth = samplesPerLine
		jpeg.ImageHeight = lineNumber
		jpeg.Precision = precision
		jpeg.ComponentCount = componentCount
		jpeg.FrameType = marker

		jpeg.MCUCountX = math.floor((jpeg.ImageWidth - 1) / 8)
		jpeg.MCUCountY = math.floor((jpeg.ImageHeight - 1) / 8)

		-- Fill in image with blank data
		for x = 1, jpeg.ImageWidth do
			jpeg.ImageData[x] = {}

			for y = 1, jpeg.ImageHeight do
				jpeg.ImageData[x][y] = { 0, 0, 0 }
			end
		end

		-- Create mcus
		for x = 1, jpeg.MCUCountX + 8 do
			mcus[x] = {}
			for y = 1, jpeg.MCUCountY + 8 do
				mcus[x][y] = {}
				for i = 1, componentCount do
					mcus[x][y][i] = table.create(64, 0)
				end
			end
		end

		if printDebugInformation then
			print("Image Resolution: " .. jpeg.ImageWidth .. "x" .. jpeg.ImageHeight)
			print("Precision: " .. precision)
			print("Components: " .. componentCount)
		end

		for id = 0, componentCount - 1 do
			local componentId = bytes[pos + 6 + (id * 3)]
			local sampleFactor = bytes[pos + 7 + (id * 3)]
			local quantTableId = bytes[pos + 8 + (id * 3)]

			if addOneToSelector then
				componentId = componentId + 1
			end

			if componentId == 0 then
				addOneToSelector = true
				componentId = componentId + 1
			end

			local horizontalSample = bit32.band(bit32.rshift(sampleFactor, 4), 0x0F)
			local verticalSample = bit32.band(sampleFactor, 0x0F)

			jpeg.MaxHorizontalSampleFactor = math.max(jpeg.MaxHorizontalSampleFactor, horizontalSample)
			jpeg.MaxVerticalSampleFactor = math.max(jpeg.MaxVerticalSampleFactor, verticalSample)

			jpeg.ColorComponents[componentId] = {}
			jpeg.ColorComponents[componentId].ID = id + 1
			jpeg.ColorComponents[componentId].HorizontalSamplingFactor = horizontalSample
			jpeg.ColorComponents[componentId].VerticalSamplingFactor = verticalSample
			jpeg.ColorComponents[componentId].QuantSelection = quantTableId

			if printDebugInformation then
				print(string.format("  Component %i: [Selection: %i] [Sample Factor: %i] [Quant ID: %i]", id + 1, componentId, sampleFactor, quantTableId))
				print("   - X Sampling Factor: " .. horizontalSample)
				print("   - Y Sampling Factor: " .. verticalSample)
			end
		end

		return payloadLength
	end

	local function SOS(marker, pos, bytes)
		local payloadLength = CombineTwoBytes(bytes[pos - 2], bytes[pos - 1])

		local componentCount = bytes[pos]
		local offset = 1

		if printDebugInformation then
			print("                    ")
			print("--------------------")
			print("   SOS [0xFFDA]     ")
			print("   Payload Length: " .. payloadLength)
			print("--------------------")
			print("Component Count: " .. componentCount)
		end

		local loopComponents = {}

		for i = 0, componentCount - 1 do
			local selector = bytes[pos + offset]

			local huffmanId = bytes[pos + offset + 1]
			local DCTableID = bit32.band(bit32.rshift(huffmanId, 4), 0x0F)
			local ACTableID = bit32.band(huffmanId, 0x0F)

			if addOneToSelector then
				selector = selector + 1
			end

			local component = {}
			component.ID = selector
			component.HuffmanDCTableID = DCTableID + 1
			component.HuffmanACTableID = ACTableID + 1
			component.HorizontalSample = jpeg.ColorComponents[selector].HorizontalSamplingFactor
			component.VerticalSample = jpeg.ColorComponents[selector].VerticalSamplingFactor

			local quantSelection = jpeg.ColorComponents[selector].QuantSelection + 1
			component.QuantisationTable = jpeg.QuantisationTables[quantSelection]

			table.insert(loopComponents, component)

			if printDebugInformation then
				print(" Component[" .. i + 1 .. "]: selector=" .. selector .. ", table=" .. DCTableID .. "(DC)," .. ACTableID .. "(AC)")
			end

			offset = offset + 2
		end

		local successiveApproximation = bytes[pos + offset + 2] -- NOT NEEDED
		local ss = bytes[pos + offset] -- Spectral start NOT NEEDED
		local se = bytes[pos + offset + 1] -- Spectral end NOT NEEDED
		local ah = bit32.band(bit32.rshift(successiveApproximation, 4), 0x0F) -- Successive Approximation low part of byte NOT NEEDED
		local al = bit32.band(successiveApproximation, 0x0F) -- Successive Approximation low part of byte NOT NEEDED

		if printDebugInformation then
			print("Spectral Selection: " .. ss .. " .. " .. se)
			print("Successive Approximation: " .. successiveApproximation)

			print("Successive High Part: " .. ah)
			print("Successive Low Part: " .. al)
		end

		-- Create scan data by removing stuff bytes and restart markers from inside it
		local scanData = {}

		do
			local i = pos + offset + 2
			local bytesToSkip = 0

			while true do
				i = i + 1

				if bytesToSkip > 0 then
					bytesToSkip = bytesToSkip - 1
					continue
				end

				local byte = bytes[i]
				local nextByte = bytes[i + 1]

				if byte == 0xFF then
					if nextByte >= 0xD0 and nextByte <= 0xD7 then
						bytesToSkip = bytesToSkip + 1
						continue
					elseif nextByte == 0x00 then
						bytesToSkip = bytesToSkip + 1
						table.insert(scanData, byte)
						continue
					else -- Probably another marker
						break
					end
				end

				table.insert(scanData, byte)

				if nextByte == nil then
					break
				end
			end
		end

		-- Make bit stream from scan data that will be used for huffman decoding
		local bitStream = BITSTREAM_MODULE.CreateBitStream(scanData)

		local mcuCountX = math.floor((jpeg.ImageWidth - 1) / 8)
		local mcuCountY = math.floor((jpeg.ImageHeight - 1) / 8)

		local maxHorizontalSample = jpeg.MaxHorizontalSampleFactor
		local maxVerticalSample = jpeg.MaxVerticalSampleFactor

		local restartInterval = jpeg.RestartInterval
		local restartCount = restartInterval

		local decodedMCUCount = 0

		-- Function used for decoding individual MCUs in baseline mode
		local function BaselineDecodeMCUComponent(mcu, component)
			-- Decode DC component
			local code = HUFFMAN_MODULE.GetCode(jpeg.HuffmanDCTables[component.HuffmanDCTableID], bitStream)

			local actualID = jpeg.ColorComponents[component.ID].ID
			local prevDC = previousDCs[actualID]

			if prevDC == nil then
				prevDC = 0
			end

			local bits = bitStream.ReadBits(code)
			local dccoeff = DecodeNumber(code, bits) + prevDC

			previousDCs[actualID] = dccoeff -- Set previous DC

			mcu[1] = dccoeff

			local huffmanTable = jpeg.HuffmanACTables[component.HuffmanACTableID]

			-- Decode AC components
			local i = 1
			while i < 64 do
				code = HUFFMAN_MODULE.GetCode(huffmanTable, bitStream)

				if code == 0 then
					return
				end

				if code > 16 then -- AC table
					i = i + bit32.rshift(code, 4) -- Num zeros which we skip
					code = bit32.band(code, 0x0F)
				end

				bits = bitStream.ReadBits(code)

				if i < 64 then
					i = i + 1

					local accoeff = DecodeNumber(code, bits)
					mcu[i] = accoeff
				end
			end
		end

		-- Functions used for decoding parts of individual MCUs in progressive mode
		local function Extend(additional, magnitude)
			local vt = BitwiseHandleOverflow(bit32.lshift(1, magnitude - 1))

			if additional < vt then
				return additional + BitwiseHandleOverflow(bit32.lshift(-1, magnitude)) + 1
			else
				return additional
			end
		end

		local function RefineAC(coeff)
			if coeff > 0 then
				if bitStream.ReadBit() == 1 then
					return coeff + BitwiseHandleOverflow(bit32.lshift(1, al))
				end
			elseif coeff < 0 then
				if bitStream.ReadBit() == 1 then
					return coeff + BitwiseHandleOverflow(bit32.lshift(-1, al))
				end
			end

			return coeff
		end

		local function DecodeDCProgressiveFirstPerBlock(mcu, component)
			local size = HUFFMAN_MODULE.GetCode(jpeg.HuffmanDCTables[component.HuffmanDCTableID], bitStream)
			local bits = bitStream.ReadBits(size)

			local dcValue = Extend(bits, size) + previousDCs[component.ID]
			previousDCs[component.ID] = dcValue -- Set previous DC

			mcu[1] = BitwiseHandleOverflow(bit32.lshift(dcValue, al))
		end

		local function DecodeDCProgressiveRefinePerBlock(mcu, component)
			local bit = bitStream.ReadBit()

			local leftShiftedBit = BitwiseHandleOverflow(bit32.lshift(bit, al))
			mcu[1] = BitwiseHandleOverflow(bit32.bor(mcu[1], leftShiftedBit))
		end

		local function DecodeACProgressiveFirstPerBlock(mcu, component)
			if eobRun > 0 then
				eobRun = eobRun - 1
				return
			end

			local huffmanTable = jpeg.HuffmanACTables[component.HuffmanACTableID]

			local i = ss
			while i <= se do
				local symbol = HUFFMAN_MODULE.GetCode(huffmanTable, bitStream)

				local runLength = bit32.rshift(symbol, 4)
				local size = bit32.band(symbol, 0x0F)

				if size == 0 then
					if runLength == 15 then
						i = i + 16
					else
						eobRun = bitStream.ReadBits(runLength) + math.pow(2, runLength) - 1
						return
					end
				else
					i = i + runLength + 1

					local bits = bitStream.ReadBits(size)

					local value = Extend(bits, size)
					value = bit32.lshift(value, al)
					value = BitwiseHandleOverflow(value)

					mcu[i] = value
				end
			end
		end

		local function DecodeACProgressiveRefinePerBlock(mcu, component)
			local i = ss

			if eobRun > 0 then
				while i <= se do
					if mcu[i + 1] ~= 0 then
						mcu[i + 1] = RefineAC(mcu[i + 1])
					end

					i = i + 1
				end

				eobRun = eobRun - 1
				return
			end

			local huffmanTable = jpeg.HuffmanACTables[component.HuffmanACTableID]

			while i <= se do
				local symbol = HUFFMAN_MODULE.GetCode(huffmanTable, bitStream)

				local runLength = bit32.rshift(symbol, 4)
				local size = symbol % 16

				if size == 1 then
					local value = Extend(bitStream.ReadBits(size), size)
					value = BitwiseHandleOverflow(bit32.lshift(value, al))

					while (runLength > 0 or mcu[i + 1] ~= 0) and i < se do
						i = i + 1

						if mcu[i] ~= 0 then
							mcu[i] = RefineAC(mcu[i])
						else
							runLength = runLength - 1
						end
					end

					i = i + 1
					mcu[i] = value
				elseif size == 0 then
					if runLength < 15 then
						local newEOBrun = bitStream.ReadBits(runLength) + BitwiseHandleOverflow(bit32.lshift(1, runLength))

						while i <= se and i < se do
							i = i + 1

							if mcu[i] ~= 0 then
								mcu[i] = RefineAC(mcu[i])
							end
						end

						eobRun = newEOBrun - 1
						return
					else
						while runLength >= 0 and i < se do
							i = i + 1

							if mcu[i] ~= 0 then
								mcu[i] = RefineAC(mcu[i])
							else
								runLength = runLength - 1
							end
						end
					end
				else
					i = i + 1
				end
			end
		end

		-- Main progressive jpeg decoding functions
		local function DecodeDCProgressiveFirst()
			if componentCount > 1 then -- Interleaved
				for y = 0, mcuCountY, maxVerticalSample do
					for x = 0, mcuCountX, maxHorizontalSample do
						for _, component in pairs(loopComponents) do
							for v = 0, component.VerticalSample - 1 do
								for h = 0, component.HorizontalSample - 1 do
									local mcuX = x + h + 1
									local mcuY = y + v + 1

									DecodeDCProgressiveFirstPerBlock(mcus[mcuX][mcuY][component.ID], component)
								end
							end
						end
					end

					if preventTimeouts then
						if y % PREVENT_TIMEOUT_INTERVAL == 0 then
							RUN_SERVICE.Stepped:Wait()
						end
					end
				end
			else -- For non-interleaved (one component) we do this
				local component = loopComponents[1]

				for y = 0, mcuCountY, 3 - component.VerticalSample do
					for x = 0, mcuCountX, 3 - component.HorizontalSample do
						local mcuX = x + 1
						local mcuY = y + 1

						DecodeDCProgressiveFirstPerBlock(mcus[mcuX][mcuY][component.ID], component)
					end

					if preventTimeouts then
						if y % PREVENT_TIMEOUT_INTERVAL == 0 then
							RUN_SERVICE.Stepped:Wait()
						end
					end
				end
			end
		end

		local function DecodeDCProgressiveRefine()
			for y = 0, mcuCountY, maxVerticalSample do
				for x = 0, mcuCountX, maxHorizontalSample do
					for _, component in pairs(loopComponents) do
						local verticalSample = component.VerticalSample
						local horizontalSample = component.HorizontalSample

						for v = 0, verticalSample - 1 do
							for h = 0, horizontalSample - 1 do
								local mcuX = x + h + 1
								local mcuY = y + v + 1

								DecodeDCProgressiveRefinePerBlock(mcus[mcuX][mcuY][component.ID], component)
							end
						end
					end
				end

				if preventTimeouts then
					if y % PREVENT_TIMEOUT_INTERVAL == 0 then
						RUN_SERVICE.Stepped:Wait()
					end
				end
			end
		end

		local function DecodeACProgressiveFirst()
			local component = loopComponents[1]

			local subtractFromX = 2
			local subtractFromY = 2

			if maxHorizontalSample == 2 then
				subtractFromX = 3
			end
			if maxVerticalSample == 2 then
				subtractFromY = 3
			end

			for y = 0, mcuCountY, subtractFromY - component.VerticalSample do
				for x = 0, mcuCountX, subtractFromX - component.HorizontalSample do
					local mcuX = x + 1
					local mcuY = y + 1

					DecodeACProgressiveFirstPerBlock(mcus[mcuX][mcuY][component.ID], component)
				end

				if preventTimeouts then
					if y % PREVENT_TIMEOUT_INTERVAL == 0 then
						RUN_SERVICE.Stepped:Wait()
					end
				end
			end
		end

		local function DecodeACProgressiveRefine()
			local component = loopComponents[1]

			local subtractFromX = 2
			local subtractFromY = 2

			if maxHorizontalSample == 2 then
				subtractFromX = 3
			end
			if maxVerticalSample == 2 then
				subtractFromY = 3
			end

			for y = 0, mcuCountY, subtractFromY - component.VerticalSample do
				for x = 0, mcuCountX, subtractFromX - component.HorizontalSample do
					local mcuX = x + 1
					local mcuY = y + 1

					DecodeACProgressiveRefinePerBlock(mcus[mcuX][mcuY][component.ID], component)
				end

				if preventTimeouts then
					if y % PREVENT_TIMEOUT_INTERVAL == 0 then
						RUN_SERVICE.Stepped:Wait()
					end
				end
			end
		end

		-- Decode baseline jpegs
		if jpeg.FrameType == 0xC0 then
			for y = 0, mcuCountY, maxVerticalSample do
				for x = 0, mcuCountX, maxHorizontalSample do
					for i, component in pairs(loopComponents) do
						local componentId = i
						local _quantisationTable = component.QuantisationTable
						local horizontalSample = component.HorizontalSample
						local verticalSample = component.VerticalSample

						for v = 0, verticalSample - 1 do
							for h = 0, horizontalSample - 1 do
								local mcuX = x + h + 1
								local mcuY = y + v + 1

								BaselineDecodeMCUComponent(mcus[mcuX][mcuY][componentId], component)
							end
						end

						decodedMCUCount = decodedMCUCount + (verticalSample * horizontalSample)
					end

					-- Restart Interval
					if restartInterval ~= 0 then
						restartCount = restartCount - 1

						if restartCount == 0 then
							restartCount = restartInterval

							previousDCs = { 0, 0, 0 }
							bitStream.Align()
						end
					end
				end

				if preventTimeouts then
					if y % PREVENT_TIMEOUT_INTERVAL == 0 then
						RUN_SERVICE.Stepped:Wait()
					end
				end
			end

			if printDebugInformation then
				print("Total MCUs decoded: " .. decodedMCUCount)
			end
		end

		-- Decode progressive jpegs
		if jpeg.FrameType == 0xC2 then
			-- Validation checks
			if ss == 0 and se ~= 0 then
				warn("Spectral selection start is zero and end is not zero.")
			end

			if se == 0 and ss ~= 0 then
				warn("Spectral selection end is zero and start is not zero.")
			end

			if ss > se then
				warn("Spectral selection start is greater than spectral selection end.")
			end

			if ss ~= 0 and #loopComponents > 1 then
				warn("Spectral selection start is not zero and loop components is greater than one.")
			end

			if ah > 13 then
				warn("Successive proximation high 4 bits is greater than 13.")
			end

			if al > 13 then
				warn("Successive proximation low 4 bits is greater than 13.")
			end

			if ah ~= 0 then
				if ah - al ~= 1 then
					warn("ah is not zero and ah - al ~= 1")
				end
			end

			-- Decode
			if ss == 0 and se == 0 then
				if ah == 0 then
					DecodeDCProgressiveFirst()
				else
					DecodeDCProgressiveRefine()
				end
			else
				if ah == 0 then
					DecodeACProgressiveFirst()
				else
					DecodeACProgressiveRefine()
				end
			end
		end
	end

	local markerProcedures = {
		[0xC0] = SOFn, -- SOF0  [Baseline DCT]
		[0xC1] = SOFn, -- SOF1  [Extended Sequential DCT]
		[0xC2] = SOFn, -- SOF2  [Progressive DCT]
		[0xC3] = SOFn, -- SOF3  [Lossless (sequential)]
		[0xC4] = DHT, -- DHT   [Define Huffman Table]
		[0xC5] = SOFn, -- SOF5  [Differential sequential DCT]
		[0xC6] = SOFn, -- SOF6  [Differential progressive DCT]
		[0xC7] = SOFn, -- SOF7  [Differential lossless (sequential)]
		[0xC8] = "Print", -- JPG   [Reserved for JPEG extensions]
		[0xC9] = SOFn, -- SOF9  [Extended sequential DCT]
		[0xCA] = SOFn, -- SOF10 [Progressive DCT]
		[0xCB] = SOFn, -- SOF11 [Lossless (sequential)]
		[0xCC] = "Print", -- DAC   [Define arithmetic coding conditioning(s)]
		[0xCD] = SOFn, -- SOF13 [Differential sequential DCT]
		[0xCE] = SOFn, -- SOF14 [Differential progressive DCT]
		[0xCF] = SOFn, -- SOF15 [Differential lossless (sequential)]
		[0xD0] = "Print", -- RSTm* [Restart with modulo 8 count "m"]
		[0xD1] = "Print", -- RSTm* [Restart with modulo 8 count "m"]
		[0xD2] = "Print", -- RSTm* [Restart with modulo 8 count "m"]
		[0xD3] = "Print", -- RSTm* [Restart with modulo 8 count "m"]
		[0xD4] = "Print", -- RSTm* [Restart with modulo 8 count "m"]
		[0xD5] = "Print", -- RSTm* [Restart with modulo 8 count "m"]
		[0xD6] = "Print", -- RSTm* [Restart with modulo 8 count "m"]
		[0xD7] = "Print", -- RSTm* [Restart with modulo 8 count "m"]
		[0xD8] = "Print", -- SOI  [Start of image]
		[0xD9] = "Print", -- EOI  [End of image]
		[0xDA] = SOS, -- SOS   [Start of scan]
		[0xDB] = DQT, -- DQT   [Define quantisation table(s)]
		[0xDC] = "Print", -- DNL   [Define number of lines]
		[0xDD] = DRI, -- DRI   [Define restart interval]
		[0xDE] = "Print", -- DHP   [Define hierarchical progression]
		[0xDF] = "Print", -- EXP   [Expand reference components(s)]
		[0xE0] = APPn, -- APP0  [Application segments 0xE0->0xEF]
		[0xE1] = APPn, -- APP1
		[0xE2] = APPn, -- APP2
		[0xE3] = APPn, -- APP3
		[0xE4] = APPn, -- APP4
		[0xE5] = APPn, -- APP5
		[0xE6] = APPn, -- APP6
		[0xE7] = APPn, -- APP7
		[0xE8] = APPn, -- APP8
		[0xE9] = APPn, -- APP9
		[0xEA] = APPn, -- APP10
		[0xEB] = APPn, -- APP11
		[0xEC] = APPn, -- APP12
		[0xED] = APPn, -- APP13
		[0xEE] = APPn, -- APP14
		[0xEF] = APPn, -- APP15
		[0xF0] = "Print", -- JPG0  [JPG segments 0xF0->0xFD]
		[0xF1] = "Print", -- JPG1
		[0xF2] = "Print", -- JPG2
		[0xF3] = "Print", -- JPG3
		[0xF4] = "Print", -- JPG4
		[0xF5] = "Print", -- JPG5
		[0xF6] = "Print", -- JPG6
		[0xF7] = "Print", -- JPG7
		[0xF8] = "Print", -- JPG8
		[0xF9] = "Print", -- JPG9
		[0xFA] = "Print", -- JPG10
		[0xFB] = "Print", -- JPG11
		[0xFC] = "Print", -- JPG12
		[0xFD] = "Print", -- JPG13
		[0xFE] = COM, -- COM [Comment]
	}

	-- Decode
	local totalTimingStart = tick()
	local timingStart = tick()

	local bytes = rawInputBytes
	local skipCount = 0

	local scanCount = 0

	for pos = 1, #bytes - 1 do
		local byte = bytes[pos]
		local nextByte = bytes[pos + 1]

		if skipCount > 0 then
			skipCount = skipCount - 1
			continue
		end

		if byte ~= 0xFF then -- Skip unless there is a possible marker, scanning and stuff will be dealt with inside functions
			continue
		end

		if nextByte == 0x00 then
			continue
		end

		-- nextByte is the marker
		local procedure = markerProcedures[nextByte]

		if procedure == nil then
			continue
		elseif type(procedure) == "string" then
			continue
		end

		-- Procedure
		local returnValue = procedure(nextByte, pos + 4, bytes)

		if returnValue then
			-- Return incase jpeg is not supported
			if returnValue == "Not supported." then
				return "Not supported."
			elseif type(returnValue) == "number" then
				-- Skip bytes
				skipCount = skipCount + returnValue
			end
		end

		-- For debugging
		if nextByte == 0xDA then
			scanCount = scanCount + 1
		end

		if scanCount == 1000000 then
			break
		end
	end

	local timingEnd = tick()

	if printProgress then
		print("")
		print("DECODED IN: " .. timingEnd - timingStart .. "s")
	end

	-- Perform IDCT
	timingStart = tick()

	local iLimit = (8 * jpeg.MaxVerticalSampleFactor) - 1
	local jLimit = (8 * jpeg.MaxHorizontalSampleFactor) - 1

	local subtractFromX = 2
	local subtractFromY = 2

	if jpeg.MaxHorizontalSampleFactor == 2 then
		subtractFromX = 3
	end
	if jpeg.MaxVerticalSampleFactor == 2 then
		subtractFromY = 3
	end

	for component, _ in pairs(jpeg.ColorComponents) do
		local actualID = jpeg.ColorComponents[component].ID
		local componentHorizontalSample = jpeg.ColorComponents[component].HorizontalSamplingFactor
		local componentVerticalSample = jpeg.ColorComponents[component].VerticalSamplingFactor
		local quantSelection = jpeg.ColorComponents[component].QuantSelection
		local quantisationTable = jpeg.QuantisationTables[quantSelection + 1]

		for y = 0, jpeg.MCUCountY, jpeg.MaxVerticalSampleFactor do
			for x = 0, jpeg.MCUCountX, jpeg.MaxHorizontalSampleFactor do
				for v = 0, componentVerticalSample - 1 do
					for h = 0, componentHorizontalSample - 1 do
						local mcuX = x + h + 1
						local mcuY = y + v + 1

						-- IDCT
						local decodedMCU = table.create(64, 0)

						for i, influence in pairs(mcus[mcuX][mcuY][actualID]) do
							if influence == 0 then
								continue
							end

							if i > 64 then
								break
							end

							local zigzagIndex = zigzag1D[i]
							local quantisedInfluence = influence * quantisationTable[i]

							local idctLUT = idctTable[zigzagIndex]

							for j = 1, 64 do
								decodedMCU[j] = decodedMCU[j] + (idctLUT[j] * quantisedInfluence)
							end
						end

						-- Fill in pixel image
						for i = 0, iLimit do
							for j = 0, jLimit do
								local pixelX = (mcuX - 1) * 8 + j + 1
								local pixelY = (mcuY - 1) * 8 + i + 1

								if pixelX <= jpeg.ImageWidth and pixelY <= jpeg.ImageHeight then
									local ii = math.floor(i / (subtractFromY - componentVerticalSample))
									local jj = math.floor(j / (subtractFromX - componentHorizontalSample))

									local index = jj * 8 + ii + 1

									jpeg.ImageData[pixelX][pixelY][actualID] = decodedMCU[index]
								end
							end
						end
					end
				end
			end

			-- Stop script from timing out
			if preventTimeouts then
				if y % PREVENT_TIMEOUT_INTERVAL == 0 then
					RUN_SERVICE.Stepped:Wait()
				end
			end
		end
	end

	timingEnd = tick()

	if printProgress then
		print("PERFORMED IDCT IN: " .. timingEnd - timingStart .. "s")
	end

	-- Convert to RGB
	timingStart = tick()

	for x = 1, jpeg.ImageWidth do
		for y = 1, jpeg.ImageHeight do
			if jpeg.ComponentCount == 3 then
				local lum = jpeg.ImageData[x][y][1]
				local cb = jpeg.ImageData[x][y][2]
				local cr = jpeg.ImageData[x][y][3]

				local r = lum + 1.402 * cr + 128
				local g = lum - 0.34414 * cb - 0.71414 * cr + 128
				local b = lum + 1.772 * cb + 128

				r = math.clamp(r, 0, 255)
				g = math.clamp(g, 0, 255)
				b = math.clamp(b, 0, 255)

				jpeg.ImageData[x][y][1] = r
				jpeg.ImageData[x][y][2] = g
				jpeg.ImageData[x][y][3] = b
			elseif jpeg.ComponentCount == 4 then
				local c = jpeg.ImageData[x][y][1]
				local m = jpeg.ImageData[x][y][2]
				local Y = jpeg.ImageData[x][y][3]
				local k = jpeg.ImageData[x][y][4]

				local r, g, b

				if colorTransform == 2 or colorTransform == 1 then
					r = c + 1.402 * Y + 128
					g = c - 0.34414 * m - 0.71414 * Y + 128
					b = c + 1.772 * m + 128

					r = math.clamp(r, 0, 255)
					g = math.clamp(g, 0, 255)
					b = math.clamp(b, 0, 255)

					r = (255 - r) * ((k + 128) / 255)
					g = (255 - g) * ((k + 128) / 255)
					b = (255 - b) * ((k + 128) / 255)
				elseif colorTransform == 0 then
					r = (c + 128) * ((k + 128) / 255)
					g = (m + 128) * ((k + 128) / 255)
					b = (Y + 128) * ((k + 128) / 255)
				end

				jpeg.ImageData[x][y][1] = r
				jpeg.ImageData[x][y][2] = g
				jpeg.ImageData[x][y][3] = b
				jpeg.ImageData[x][y][4] = nil
			end
		end

		-- Stop script from timing out
		if preventTimeouts then
			if x % PREVENT_TIMEOUT_INTERVAL == 0 then
				RUN_SERVICE.Stepped:Wait()
			end
		end
	end

	timingEnd = tick()

	if printProgress then
		print("CONVERTED TO RGB: " .. timingEnd - timingStart .. "s")
	end

	local totalTimingEnd = tick()

	if printProgress then
		print("FINISHED DECODING JPEG IN: " .. totalTimingEnd - totalTimingStart .. "s")
	end

	-- Other API functions
	function jpeg.GetPixel(x, y)
		local r = jpeg.ImageData[x][y][1]
		local g = jpeg.ImageData[x][y][2]
		local b = jpeg.ImageData[x][y][3]

		return r, g, b
	end

	return jpeg
end

return module
