Forum Archive

Image.UI gets color inverted if photo is PNG

FuckingNerd

So I am working on something that involves the photo and scene modules. I take a photo from the photoalbum and display it as SpriteNode on the screen through Texture. However, I noticed that some pictures get displayed color inverted this way. I figured out that it seemed to be when the images are PNGs, JPEGs are just fine. To solve this, I could run an color inversion filter if the asset is PNG, but I would like to know where the problem comes from in the first place. Any advice ?

cvp

@FuckingNerd never seen that. Just tried with a png, no problem. Possible to post your png?

FuckingNerd

here is the image from my album and a screenshot from my app

FuckingNerd

relevant code

def prev_image(self):
        if self.current_album_pic_id <= 0:
            return
        self.current_album_pic_id -= 1

        self.canvasSprite.texture = Texture( self.get_current_image() )
        self.rescale_canvas() 

def get_current_image(self):
        image = self.get_current_asset().get_ui_image()
        return image
cvp

@FuckingNerd I see it correctly, non inverted colors, but not as an asset, as a downloaded file

FuckingNerd

The file is fine. The display as SpriteNode is the issue. JPG gets rendered correctly PNG not. I have many other PNGs, all seem to be color inverted when displayed as a spritenode.

cvp

@FuckingNerd Weird. I use a SpriteNode with texture = your .png, without colors inversion
iPadOS 15.6.1

FuckingNerd

Can you change the texture with .yourSpriteNode.texture = Texture( image ) ? I suspect it might be the assignment where it happens. Not during initialization.

cvp

@FuckingNerd that's what I did. I use an old script where I put your png as texture

from scene import *
import sound
import random
import math

class MyScene (Scene):
    def setup(self):
        self.background_color = 'midnightblue'
        self.ship = SpriteNode()#'spc:PlayerShip1Orange')
        self.ship.texture = Texture('1 - 97f7tRn.png')
        self.ship.position = self.size / 2
        self.add_child(self.ship)
        self.lasers=[]
    def updatex(self):
        x, y, z = gravity()
        pos = self.ship.position
        pos += (x * 15, y * 15)
        # Don't allow the ship to move beyond the screen bounds:
        pos.x = max(0, min(self.size.w, pos.x))
        pos.y = max(0, min(self.size.h, pos.y))
        self.ship.position = pos


    def touch_began(self, touch):

        laser_animation=Action.repeat_forever(Action.sequence(Action.call(self.fire_laser), Action.wait(0.1) ) )
        self.run_action(laser_animation, 'laser')

    def touch_ended(self,touch):
           self.remove_action('laser')
    def remove_laser(self,laser):
        del self.lasers[laser]
    def fire_laser(self):
        a=random.random()*500-250
        laser = SpriteNode('spc:LaserBlue9', position=self.ship.position, z_position=-1, parent=self)
        self.lasers.append(laser)
        laser.run_action(Action.sequence(Action.move_by(a, 1000), Action.remove(), Action.call(lambda:self.remove_laser(laser))))
        sound.play_effect('arcade:Laser_1')

run(MyScene(), show_fps=True)
FuckingNerd

So the photo module as asset is the issue.

cvp

@FuckingNerd No idea, try to import your photo as a local Pythonista file and then use it as texture

FuckingNerd

I have no idea how to access those imported files(never done it). This is not the way it seems. Can you help me out ?

cvp

@FuckingNerd I think you have correctly imported some images and you can replace in my little script my 1 - 97f7tRn.png by one of your IMG_xxxx.PNG

FuckingNerd

Did that. No color invert. So it’s the asset.

cvp

@FuckingNerd I guess, sorry, I can't help more 😢

FuckingNerd

Helps for the effort man!

cvp

@FuckingNerd Perhaps, you could
- get the asset as an ui.Image
- write it as a local (temporary) file
- use it as Texture
- remove the local file

FuckingNerd

I was able to solve the problem.

Instead of using asset.get_ui_image() and pass it on to SpriteNode(Texture(..ui_image..)) I got a PIL image directly with asset.get_image() and transformed it with the scripts found here to and ui image.

relevant from above link:
```

pil <=> ui

def pil2ui(imgIn):
with io.BytesIO() as bIO:
imgIn.save(bIO, 'PNG')
imgOut = ui.Image.from_data(bIO.getvalue())
del bIO
return imgOut
```

I hope you find this useful google hero from the future. This solves “weird false inverted colors for PNG ui.image from assets in photo module”.

cvp

@FuckingNerd 👍

cvp

@FuckingNerd you could try Asset.get_image_data which could be quicker

Asset.get_image_data(original=False)
Fetch the asset’s image data, and return it as a io.BytesIO object. 
You can use io.BytesIO.getvalue() to get the image data as a byte string.

By default, the most recent version of the image is returned; 
pass original=True to get the image without any adjustments/edits.

If you only need the image for saving it as a file, 
this is more efficient than Asset.get_image(). 
The returned io.BytesIO has an additional uti attribute 
that can be used to determine the file type of the image data.