hello, so i’ve been wondering is there a way to read images and return the color value of a pixel?
What kinds of images? And how do you want to get them into the game?
upload them to roblox, and im talking about height maps.
There might be some way of getting them with a HTTP request using the asset API https://api.roblox.com/docs#Assets
Haven’t used it so can’t tell you how.
Is this for letting players upload height maps for a game?
i want to create the earth (this sounds weird lmfao)
Would it be fine if you can only “get images into the game” through Studio? I.e. get the heightmap into a script running in Studio and generating the mesh from that?
https://developer.roblox.com/en-us/api-reference/function/StudioService/PromptImportFile
how do i read the height map though
Step 1 is to convert it to a simpler image format so you don’t have to decode PNG compression and other complicated stuff. I recommend a simple bitmap (.bmp), or even better raw rgb data (.data). Just open your image in GIMP or whatever and export as raw (.data). You should get an option between standard and planar, definitely go for planar (RRRGGGBBB instead of (RGBRGBRGB) if your heightmap is greyscale because that way you can just take the first 1/3rd of the data instead of having to get every 3rd byte of the data.
With this test image
I get this binary content:
Which corresponds to first a black (0% white) pixel, then a 50% white pixel, then a bunch of 100% white pixels (the image keeps going with some random drawing I did, that’s why it’s not ff’s all the way but also e.g. fc, f0, etc.). This is just to show that this way of exporting works as expected.
When you call File:GetBinaryContents you get a string, which you need to decode into numbers. Do yourself a favor and use 24 bit color depth = 1 byte per color channel, that way each character corresponds to the color value of exactly one pixel. You can turn a 1-character string into the corresponding number value by calling string.byte on it.
Hold on I gotta get to my windows computer to type the rest of this post xD
Here’s a sequence of commands you can type in the Command Bar in Studio to get hold of the image data:
imageFile = game:GetService("StudioService"):PromptImportFile({"data"})
imageString = imageFile:GetBinaryContents()
imageData = {} for i = 1, #imageString do imageData[i] = imageString:sub(i, i):byte() end
Since raw image files don’t have any metadata, there’s no way to see from the file what the dimensions (width and height) of the image are, but if you know ahead of time then that’s not an issue.
Aaaand here’s how you could use the imageData to generate part terrain from the height map:
for y = 1, 16 do
for x = 1, 16 do
local i = (y - 1) * 16 + x
local p = game.Workspace.Part:Clone()
p.CFrame = CFrame.new(x, imageData[i]/256, y)
p.Color = Color3.fromHSV(.33, .75, imageData[i]/255)
if imageData[i] == 0 then
p.Color = Color3.fromRGB(0, 0, 255)
end
p.Parent = game.Workspace.DaParts
end
end
PromptImportFile has a size limit of 100 MB, so you can only do about 5773x5773 images this way. If you want bigger images you’ll have to split them up and import the pieces separately.
im starting to understand, first i need to upload a .data or .bmp file by doing game:GetService('StudioService'):PromptImportFile()
in the command bar
It doesn’t actually upload the file anywhere, it just lets you manipulate the file in Studio. I updated my previous comment, it goes over the whole process
Actually, if you’re using GIMP you can set your image to only be greyscale so you don’t waste bytes by having all three channels and instead just have a single greyscale channel:
The Export dialog still asks you if you want normal or planar mode which doesn’t make sense when you have only 1 channel. It still worked though, with a 2x2 test image the exported file is only 4 bytes, exactly as expected. That means you can do 10000x10000 images!
EDIT: Oh, and the images of course don’t need to be square, you could do a 10 million times 1 pixel image if you wanted or anything in between, just multiply the dimensions to make sure you get a number less than or equal to 10 million.
EDIT 2: My Studio crashes at around 500x500 :c
Found a map of Europe (9000x6705)
A tiny region of the alps (200x200):
Generated using
imageFile = game:GetService("StudioService"):PromptImportFile({"data"})
imageString = imageFile:GetBinaryContents()
game.Workspace.DaParts:ClearAllChildren()
stopIt = false --Type stopIt = true in the Command Bar to stop generating
local w, h = 9000, 6705 --Heightmap dimensions
local x0, y0 = 4489, 3299 --Starting coordinates
local sx, sy = 200, 200 --Generated size, Studio crashes for me around 500, 500
for y = y0, y0 + sx do --
if stopIt then break end
wait()
for x = x0, x0 + sy do
local i = (y - 1) * w + x --(x, y) coordinate to offset into file
local height = imageString:sub(i, i):byte() / 255 --Convert to the range [0, 1]
local p = game.Workspace.Part:Clone()
p.CFrame = CFrame.new(x - x0, height * 50, y - y0)
p.Color = Color3.fromHSV(.33, 1 - height, 0.9 - height)
if height == 0 then
p.Color = Color3.fromRGB(0, 0, 255)
end
p.Parent = game.Workspace.DaParts
end
end