» »

[Pillow] Kako shranit PNG (mode P) sliko v JPEG?

[Pillow] Kako shranit PNG (mode P) sliko v JPEG?

HotBurek ::

Dobro zgodnje jutro.

Evo, fantje in dekline, nov dan, nov izziv.

Source image je tole:

Zdej me pa zanima, kako konvertat to sliko v jpeg format, in to tako, da tist "transparenten" background okrog konzerve ne postane zelen (ali črn)?

Trenutni sample:

import io;
import PIL.Image;

image = PIL.Image.open("/home/sepultura/arise/minerva_in.png");

print("image mode [1]: " + str(image.mode));
print("image format [1]: " + str(image.format));

plan = "a";

if image.mode in ["1", "8", "L", "P", "CMYK", "RGBA", "LA"]:

    # plan a
    if plan == "a":

        image = image.convert("RGB");

    # plan b
    elif plan == "b":

        if image.format == "PNG":

            image = image.convert("RGBA");

        else:

            image = image.convert("RGB");

    print("image mode [2]: " + str(image.mode));
    print("image format [2]: " + str(image.format));

image.save("/home/sepultura/arise/minerva_out.jpeg", format="JPEG", optimize=True);

image.close();

Če grem plan a, dobim na output-u warning:

UserWarning: Palette images with Transparency expressed in bytes should be converted to RGBA images

Print:

image mode [1]: P
image format [1]: PNG
image mode [2]: RGB
image format [2]: None

In končno sliko:



Če grem plan b, dobim na output-u error:

OSError: cannot write mode RGBA as JPEG

Print:

image mode [1]: P
image format [1]: PNG
image mode [2]: RGBA
image format [2]: None

Že od prej imam link na tole: PIL remove error "UserWarning: Palette images with Transparency expressed in bytes should be converted to RGBA images"

No, zdej moram to nekako rešit. Kako PNG sliko, ki je v mode P, shranit v JPEG format? Pa da bo lepo zgledalo, kot na izvoru.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
  • spremenilo: HotBurek ()

socialec ::

jpeg podpira transparenco?
kolikor vidim, hitri queryji pravijo, da ne...
menda je rešitev, da zmergaš na fiksen background image

Liker ::

if image.format == "PNG":
    image = image.convert("RGBA");
    bg = Image.new('RGBA', image.size, (0, 155, 0, 0))
    final_image = Image.alpha_composite(bg,image)
    ...

No comment ... :(

HotBurek ::

Tvoj sample ne dela, ker:

OSError: cannot write mode RGBA as JPEG

Delujočo rešitev sem našel tule:

How to Covert PNG to JPEG using Pillow while image color is black?

To z "background" rešitvijo že imam za resize. Zdej pa še za PNG P situacijo. Moram dodelat še, da RGBA konverta v RGB, ter LA v L.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

cekr ::

Uporabljaj raje TIFF.
Sinclair ZX Spectrum [Zilog Z80A - 3.5 MHz, 48kB, dvojni kasetofon,
TV-OUT, radirke, Sinclair-Basic], Sinclair ZX-81 [Z80A, 3.25MHZ, 1kB]

no comment ::

Nekateri formati se uporabljajo z razlogom. Če moraš imeti tranparency oz. alpha layer, izbereš ustrezen format.

Liker ::

*sigh*

Sem prebral, da želiš zeleno ozadje. JPEG ne podpira prosojnosti, saj to veš, ne?
In moja koda ni bila popolna. Če želiš shraniti JPEG, moraš najprej narediti nazaj convert v RGB mode. Na primer:
>>> from PIL import Image
>>> img = Image.open("Minerva-in.png")
>>> img = img.convert("RGBA")
>>> bg = Image.new("RGBA",img.size,(255,255,255,255))
>>> end = Image.alpha_composite(bg,img)
>>> end_jpg = end.convert("RGB")
>>> end_jpg.save("Minerva-out.jpeg")

To naredi JPG z belim ozadjem, kar si si verjetno želel.

Je pa python koda s podpičji res zakon. Thumbs up!

HotBurek ::

Ja ja, to. Da se transparentnost iz PNG zamenja v belo "ozadje" pri shranjevanju v JPEG.

Takole imam sedaj. Sem potestiral in dela, kot je željeno. Verjamem pa, da so še tudi druge/drugačne rešitve.

# UserWarning: Palette images with Transparency expressed in bytes should be converted to RGBA images
# https://stackoverflow.com/questions/70839890/pil-remove-error-userwarning-palette-images-with-transparency-expressed-in-byt
if image.format == "PNG":

    # set new mode for background
    new_mode = "RGB";

    # check if this is LA
    if image.mode == "LA":

        # set new mode to L
        new_mode = "L";

    # logging
    logging(loginfo, "PIL > new_mode: " + str(new_mode));

    # logging
    logging(loginfo, "PIL > Convert image from " + str(image.mode) + " mode to RGBA");

    # convert image from x to RGBA
    image = image.convert("RGBA");

    # make white background
    background = PIL.Image.new(new_mode, (image.width, image.height), (255, 255, 255));

    # put all together
    # https://stackoverflow.com/questions/50739732/how-to-covert-png-to-jpeg-using-pillow-while-image-color-is-black
    background.paste(image, image);

    # save back as image
    image = background;
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

socialec ::

Odlično.

HotBurek ::

Dobro jutro.

Evo, update. Zadevo sem še mel dodelal, ker sem naletel na PNG v LA mode.

Tisti, ki bi želel potestirat, gre za tole sliko:

qs-favicon-32x32.png

Razlika je v barvi: pri RGB je (255, 255, 255), pri L pa 255.

Trenutni working sample je takšen:

if image.format in ["PNG", "ICO"]:

    if image.mode == "RGBA":

        new_mode = "RGB";

        background = PIL.Image.new(new_mode, (image.width, image.height), (255, 255, 255));

        background.paste(image, image);

        image = background;

    elif image.mode == "LA":

        new_mode = "L";

        background = PIL.Image.new(new_mode, (image.width, image.height), 255);

        background.paste(image, image);

        image = background;

else:

    image = image.convert("RGB");
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

HotBurek ::

Me pa ena reč en mal, a kvalitetno, matra.

Spodnji ukaz ne znam prestavit v karkoli drugega, da bi bilo meni bolj razumljivo in da bi zadevo razumel:

# dela kot je treba
background.paste(image, image);

# naredi črno sliko (iz zgornjega LA primera)
background.paste(image, (0, 0));
background.paste(image, (0, 0, image.width, image.height));
background.paste(image, (0, 0), 0);
background.paste(image, (0, 0), "L");

Skratka, ta drugi parameter (image, image) mi ni jasen, kako bi ga "pretvoril" v nekaj drugega (koordinate in /ali mask). Tako, da bi bilo vsaj meni bolj jasno kaj drugi parameter "vnaša" (koordinate, mask, ???).
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

socialec ::

background.paste(image, image) pomeni: prilepi image na background, ampak upoštevaj alfa kanal iz image, da ohraniš prosojnost.

HotBurek ::

Takole imam končno verzijo:

background.paste(image, (0, 0), image);

Več pa ne bom zdej kompliciral z mask-om.

Zdejle sem imel 2 ure in 40 minut tegale: 5 hours Set: From TECHNO to HARDTECHNO w/ Fernanda Martins SPAIN JUL/2016

Vem vem, pussz, ker nisem zdržal celih 5 ur.

Pa še neki sem parser vmes pofiksal. Fak d fakin šiiiit... Greeeemoooo. Lets go!

Zdej bo treba dat volume dol, da se bo slišal cerkev zvonit... ker bo ura vsak cajt ... upugn. :O
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

HotBurek ::

Evo, naslednji primer.

Izvorna slika v formatu PNG, mode I (32-bit signed integer pixels).

Tule je seznam: https://pillow.readthedocs.io/en/stable...

Kako to skonvertat v JPEG?

Dodal sem mode I, delam po zgornjem primeru, in na koncu dobim belo sliko.

Krneki...

Slika:
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

Liker ::

Evo, naslednja rešitev.
Tvoj primer ni 32 biten PNG, ampak 16 biten.
kavcar@biric:~$ file coltello.png 
coltello.png: PNG image data, 596 x 768, 16-bit grayscale, non-interlaced
kavcar@biric:~$ 


PIL je imel bug, kjer je to napačno javljal.
Verjetno boš potreboval novejšo verzijo PIL knjižnice, če pa ne gre, si pa poglej PR iz linka in implementiraj workaround.

HotBurek ::

Ok, hvala za info.

Kot omenjeno, se zadeva dogaja v:

Fajl: /usr/lib/python3/dist-packages/PIL/PngImagePlugin.py

Linija: 65

Cotntent:

_MODES = {
    # supported bits/color combinations, and corresponding modes/rawmodes
    # Greyscale
    (1, 0): ("1", "1"),
    (2, 0): ("L", "L;2"),
    (4, 0): ("L", "L;4"),
    (8, 0): ("L", "L"),
>>> #(16, 0): ("I", "I;16B"),
    (16, 0): ("I;16B", "I;16B"),
    # Truecolour
    (8, 2): ("RGB", "RGB"),
    (16, 2): ("RGB", "RGB;16B"),
    # Indexed-colour
    (1, 3): ("P", "P;1"),
    (2, 3): ("P", "P;2"),
    (4, 3): ("P", "P;4"),
    (8, 3): ("P", "P"),
    # Greyscale with alpha
    (8, 4): ("LA", "LA"),
    (16, 4): ("RGBA", "LA;16B"),  # LA;16B->LA not yet available
    # Truecolour with alpha
    (8, 6): ("RGBA", "RGBA"),
    (16, 6): ("RGBA", "RGBA;16B"),
}

Jst sem malenkost telovadil (označil zgoraj), ampak je tole ... hm... mogoče izven okvirja mojih zmožnosti.

Na srečo je do sedaj od miljon slik tole bil prvi, in zaenkrat, tudi edini tak primer.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

Liker ::

Ja, morda ni najlažje za popravit knjižnico, ni panike.
Obstaja workaround, ki ga ti dejansko lahko implementiraš, ker imaš itak if za vsak PNG mode ločeno.
Torej rabiš nekaj takega:
if img.mode == "I":
 if "16-bit" in subprocess.check_output(["file",path_to_file]):
  max_value = 2**16 - 1
  img_arr = (numpy.array(img) / max_value) * 255.0
  img = Image.fromarray(img_arr.astype(numpy.uint8))
  img = img.convert("RGBA")
  ...

To bi moralo delovati, rabiš pa seveda še "import subprocess" in pa "import numpy".

HotBurek ::

Ful kul debest žur. Zadeva dela v nulo, zato bom lepo dal eno večerno sliko na ogled.

Dodal sem sicer eno malenkost. In to je, da se vsebino, ki jo vrne subprocesa, konverta iz byte v string. Ostalo pa je isto.

Je pa situacija taka, da trenutno verjetno zadeve še ne bom čisto končal.

Tisto, kar me je zmatral, je to, da subprocess za ta drugi input vzame pot_do_slike, jst pa izvorne slike (to govorim na serverju) nikoli ne shranim na disk (ostane v RAM-u, pol gre pa ven).

Tu moram še dodelat, da bo, v kolikor bo šel v tist "if I", da bo sliko shranil nekam na disk, in potem naredil subprocess ukaz. Ter, da bo to izvorno slikov v temp-u potem tudi zbrisal.

Sicer pa ja, it works. Hvala za input. 8-)

root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

Liker ::

Če imaš png že v "ramu", potem lahko pogledaš vrednost byta na offsetu 24 - tam notru je zapisan bit_depth direktno.
>>> f = open("coltello.png","rb")
>>> img_data = f.read()
>>> img_data[24]
16
>>> 

HotBurek ::

In to je sedaj končna rešitev.

"content" pride iz:

import requests;
response = requests.get(url, ...);
content = response.content;

# this is some nasty fix for I;16 images and the way python handles this stuff
# https://github.com/python-pillow/Pillow/issues/3796
if image.format == "PNG" and image.mode == "I":

    # init bit depth
    bit_depth = 0;

    # check if content length is at least 25
    if len(content) > 24:

        # read byte at position 24 where bit depth value is
        bit_depth = content[24];

    # logging
    logging(loginfo, "PIL > bit_depth=" + str(bit_depth));

    # check if bit depth is 16
    if bit_depth == 16:

        # some magic i dont know how it works... but it does
        max_value = 2 ** 16 - 1;
        img_arr = (numpy.array(image) / max_value) * 255.0;
        image = PIL.Image.fromarray(img_arr.astype(numpy.uint8));
        image = image.convert("RGBA");
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[Python] PIL.Image resize in slaba kvaliteta

Oddelek: Programiranje
5723 (516) DamijanD
»

CSS3 - Transparentnost + Text Problem

Oddelek: Izdelava spletišč
22940 (769) Tydek
»

uporaba C++ unmanaged kode v C#.NET projektu

Oddelek: Programiranje
112010 (1733) krho
»

image/png .......(prikaz!!)?

Oddelek: Izdelava spletišč
181245 (1136) Ziga Dolhar
»

[java] transparentnost

Oddelek: Programiranje
91298 (1072) jpzoky1

Več podobnih tem