Okay I figured it out.
Took a little tinkering but got image creation working pixel by pixel. This works great for an overworld preview. I also am going to try using this as the base map layer in game, and just spawning entities, waves, and other details on top of it. For example, most games like this have grass cluster tiles every so often instead of regular grass tiles. However, I can just do the clusters randomly and not have to have a sprite for each tile. I can now have the entire map (or a large area) loaded as a single sprite and keep a great frame rate.
Saved the map preview to disk and then used it later as a sprite2d resource. Also will later let the player look at their creations and stuff.
function InitImage()
img = Image:new()
local sz = SizeIndexToSize(worldgen.mapSize)
img:SetSize(sz,sz,4)
return img
end
function AddPixel(x,y,tile)
local col = spriteColors[tile]
img:SetPixel(x-1,y-1,col)
end
function AddImage()
local sz = SizeIndexToSize(worldgen.mapSize)
local texture = Texture2D:new()
texture:SetFilterMode(FILTER_NEAREST)
texture:SetNumLevels(1)
texture:SetSize(sz,sz,graphics:GetRGBAFormat(),TEXTURE_STATIC)
texture:SetData(img)
local sprite = ui.root:CreateChild("Sprite")
sprite:SetTexture(texture)
local m = graphics.width*.007 * (1/(sz*.02))
sprite:SetSize(sz*m,sz*m)
sprite:SetPosition(graphics.width/2 - sz*m/2,graphics.height/2 - sz*m/2)
sprite:SetBlendMode(BLEND_ALPHA)
img:SavePNG("Data/Art/map.png")
end