Changing pixels in image

Hi, I’m trying to create a program that reads a PNG image (finds the RGBA values of each pixel) and then changes them (for example, sets all red values to maximum and the original image gets a red tint). So far, I’m just trying to read all the pixels and then set them unchanged as the texture of the sprite to which the original PNG image belonged. The problem is that instead of the program drawing the image the way it read it, it transforms it very strangely (you can see it in the attached images). Does anyone know what I’m doing wrong?


Here is my code:

function set_pixel(stream, width, x, y, color)
	local index = 4 * (x + y * width) + 1
	stream[index + 0] = color.x
	stream[index + 1] = color.y
	stream[index + 2] = color.z
	stream[index + 3] = color.w
end

function get_pixel_rgba(pixels, width, x, y)
	local index = 4 * (x + y * width) + 1
	local r = pixels[index + 0]
	local g = pixels[index + 1]
	local b = pixels[index + 2]
	local a = pixels[index + 3]
	return r,g,b,a
end

function init(self)
	msg.post(".", "acquire_input_focus")
	local file = io.open("images\\kraken.png", "rb")
	local file = file:read("*a")

	local buf, w, h = png.decode_rgba(file, true)
	local pixels = buffer.get_stream(buf, hash("pixels"))

	self.buffer = buffer.create(w * h, {{name = hash("rgba"), type = buffer.VALUE_TYPE_UINT8, count = 4}})
	local stream = buffer.get_stream(self.buffer, hash("rgba"))

	tables = {}
	for x = 0, w-1 do
		for y = 0, h-1 do
			r,g,b,a = get_pixel_rgba(pixels, w, x, y)
			table.insert(tables,vmath.vector4(r,g,b,a))
		end
	end

	b = 1
	for x = 0, w-1 do
		for y = 0, h-1 do
			clr = tables[b]
			set_pixel(stream, w, x, y, clr)
			b = b+1
		end
	end
	local resource_path = go.get("#sprite", "texture0")
	local header = {width = w, height = h, type = resource.TEXTURE_TYPE_2D, format = resource.TEXTURE_FORMAT_RGBA, num_mip_maps = 1}
	resource.set_texture(resource_path, header, self.buffer)
 end

Thank you

2 Likes

If you can upload a small functional project where it’s not working as a zip and include an image of what you would expect it to look like when working properly it can be easier to see what is wrong and give you a solution.

I think problem with sprite and it atlas.
Sprite image region is smaller then all atlas.

It better to do that work with model and it texture.

Or make atlas where image is fill atlas. Image 1x1 and atlas 1x1.

3 Likes

Yes, this is likely the problem. If you use a sprite and an atlas you must make sure that you take into account the size of the atlas (which has a width and height that is a power of two).

2 Likes

If you just need to display the image with some effects - shaders is what you need.

2 Likes

You are right! …but I’m not sure I understand well how the model works. I created the model in go and set the PNG picture as its texture (mesh - quad.dae, material - model.material). I expected, that the picture shows in main collection or something like this, but nothing…

Did you add model predicate and render target to render script or is it available?

No, how can I do it?

You can find more details here:

more about render:

Thank you but reading this was the first thing I did. I ask because I am a Defold-beginner and I don’t understand its system yet… In addition, the whole documentation is only about 3D models, which is a bit confusing for me, because I’m trying to use it instead of an atlas (if I understand correctly).

This tutorial by @Pawel is a great starting point: https://defold.com/2020/10/19/Shaders-for-beginners/

For post processing (ie full screen effects) you render your game to an offscreen buffer (instead of directly to the screen). This is basically like taking a screenshot of your screen. And in a second step you draw this screenshot together with a shader post processing effect to a 3D quad (rectangle) that covers the entire screen.

For tinting of an image or doing special effects on an individual sprite or similar you can use a custom shader… A custom shader can add additional steps when drawing, for instance replacing or shifting colors.

4 Likes

This tutorial operates on a sprite, instead of model, but if you want only to display your picture with some effects on it - the tutorial will show you exactly how to do it and it is a great solution for you :slight_smile: Fragment program is what you are actually trying to do - operation on each pixel of the sprite/image.

If you would like to export your image with those effects in the future - that is another story :slight_smile:

4 Likes

Thank you so much, perfect article (I really enjoyed it :eye:)! Exactly what I needed. (Only in the first example of FP code did you put the third line in the comment and when I did it too, the sprite disappeared because of that. When I wrote it back, everything worked almost better than it should :D)

3 Likes

Oo, thank you! I’ll take a look into this part and fix it :wink:

EDIT: Do you mean this line @kovarskic?
/3+4/ gl_FragColor = texture2D(texture_sampler, var_texcoord0.xy); // * tint_pm;

1 Like

No no, I really meant the third line (//uniform lowp vec4 tint; //vector representing a color in RGBA (red, green, blue, alpha)), but (now I don’t understand anything) I tried it again and suddenly everything works as it should, even without the third line… I had to do something wrong…

I checked it and the whole fp is working, so I think there must have been some other mistake by some chance :wink:

I commented it out on purpose, as I wanted to focus on the 4 points. Tint (which was in default fp I wanted users to use there) is an additional operation here that was not needed for this explanation :wink:

2 Likes