## Espaço de Tecnologias e Artes - Sesc Avenida Paulista
### `hackmd.io/@sesc-av-paulista/estudos-em-python-21-maio`
# Grupo de estudos em Python
## 21/5 Convertendo e redimensionando Imagens
### O que eu preciso para começar?
- Vamos usar o **Thonny IDE**, que é livre já com um interpretador Python, você pode baixar em https://thonny.org
- Como instalar bibliotecas no Thonny?
- **Usando a interface gráfica** menu *Tools/Ferramentas > Manage Packages/Gerenciar Pacotes*
- **Usando o shell aberto pelo Thonny** em *Tools > Open System Shell*
- Como se faz em geral no Python: `pip install <nome da lib>`, mas idealmente você deve usar um "virtual environment" antes, só que no caso do Thonny provê já esse env
### Algumas bibliotecas
- Pillow - Python Image Library - PIL (Fork)
- https://pypi.org/project/pillow/
- [Documentação oficial](https://pillow.readthedocs.io/en/stable/)
### Exemplos
#### Convertendo PNGs em JPGs em uma pasta
Salva arquivos convertidos na mesma pasta que os originais.
obs: pode não reconhecer alguns .png salvado da web.
```python=
from tkinter.filedialog import askdirectory
from pathlib import Path
from PIL import Image
# Abre uma janela para selecionar uma pasta
string_pasta = askdirectory() # '' se for cancelada a seleção
if string_pasta: # só executa se a pasta foi selecionada
caminho_pasta = Path(string_pasta)
# iterando pela pasta escolhida
for caminho_arquivo in caminho_pasta.iterdir():
if caminho_arquivo.suffix == '.png': # checa sufixo .png
# constroi path de saída
caminho_saida = caminho_pasta / (caminho_arquivo.stem + '.jpg')
try: # bloco try, pra se der problema ...
with Image.open(caminho_arquivo) as im: # carrega imagem
im.save(caminho_saida) # salva imagem
print(f'Salvei {caminho_saida.name}')
except OSError: # ... trata exceção
print(f'Não foi possível converter {caminho_arquivo}!')
print('Terminei de olhar a pasta!')
else:
print('Cancelado!')
```
### Gerador de thumbnails
Cria uma pasta nova ao lado da original escolhida, acrescentando "_thumbs" no nome.
obs: percorre toda a pasta selecionada salvando arquivos de imagem em thumbnails. Gera imagens com tamanho diferentes.
```python=
from tkinter.filedialog import askdirectory
from pathlib import Path
from PIL import Image
# Abre uma janela para selecionar uma pasta
string_pasta = askdirectory() # '' se for cancelada a seleção
if string_pasta: # só executa se a pasta foi selecionada
caminho_pasta = Path(string_pasta) # transforma str em objeto Path
# constroi caminho para a pasta de saída com '_thumbs' no final do nome
caminho_thumbs = caminho_pasta.parent / (caminho_pasta.name + '_thumbs')
caminho_thumbs.mkdir(exist_ok=True) # cria pasta, ok se já existir
# iterando pela pasta escolhida com as imagens
for caminho_arquivo in caminho_pasta.iterdir():
# constroi path de saída
caminho_saida = caminho_thumbs / caminho_arquivo.name
# bloco try, pra se der problema ... vai pular o que não for imagem
try:
with Image.open(caminho_arquivo) as im: # carrega imagem
largura_maxima = 25
altura_maxima = 255
im.thumbnail((largura_maxima, altura_maxima))
im.save(caminho_saida) # salva imagem
print(f'Salvei {caminho_saida.name}')
except OSError: # ... trata exceção
print(f'Não foi possível criar thubnail de {caminho_arquivo}!')
print('Terminei de olhar a pasta!')
else:
print('Cancelado!')
```
### Convertendo um arquivo em grayscale
obs: Selecione um arquivo por vez
```python=
from tkinter.filedialog import askopenfilename
from pathlib import Path
from PIL import Image
# Abre uma janela para selecionar um arquivo só numa pasta
string_arquivo = askopenfilename() # '' se cancelada
if string_arquivo: # só executa se a arquivo foi selecionad0o
caminho_arquivo = Path(string_arquivo) # transforma str em objeto Path
novo_nome = caminho_arquivo.stem + '_alterado' + caminho_arquivo.suffix
caminho_saida = caminho_arquivo.parent / novo_nome
try:
with Image.open(caminho_arquivo) as im: # carrega imagem
# converte em grayscale ('LA' preserva alpha, mas não rola em JPG por exemplo)
convertida = im.convert('L')
convertida.save(caminho_saida) # salva imagem
print(f'Salvei {caminho_saida.name}')
except Exception as erro: # ... trata exceção
print(erro)
```
### Convertendo um arquivo em rgb
obs: Selecione um arquivo por vez
```python=
from tkinter.filedialog import askopenfilename
from pathlib import Path
from PIL import Image
# Abre uma janela para selecionar um arquivo só numa pasta
string_arquivo = askopenfilename() # '' se cancelada
if string_arquivo: # só executa se a arquivo foi selecionad0o
caminho_arquivo = Path(string_arquivo) # transforma str em objeto Path
novo_nome = caminho_arquivo.stem + '_alterado' + caminho_arquivo.suffix
caminho_saida = caminho_arquivo.parent / novo_nome
try:
with Image.open(caminho_arquivo) as im: # carrega imagem
rgb2xyz = (
0.412453, 0.357580, 0.180423, 0, # vermelho 0 A 255 / Ultimo parametro opacidade
0.212671, 0.715160, 0.072169, 0, # verde 0 A 255
0.019334, 0.119193, 0.950227, 0) # azul 0 A 255
convertida = im.convert("RGB", rgb2xyz) # converte em RGB
convertida.save(caminho_saida) # salva imagem
print(f'Salvei {caminho_saida.name}')
except Exception as erro: # ... trata exceção
print(erro)
```
### PNGs -> GIF usando `imageio`
Este script para rodar na linha de comando converte PNGs em um pasta em um GIF usando a biblioteca `imageio`
- https://pypi.org/project/imageio/
Importante: todos os PGNs precisam ter as mesmas dimensões e estar localizado no mesmo arquivo que o .py. (para ajustar as dimensções pode usar o https://www.iloveimg.com/pt/redimensionar-imagem#resize-options,pixels)
```python=
"""
Cria GIF from PNGs em um diretório/pasta!
Imagens precisam ser todas do mesmo tamanho em pixels
"""
from pathlib import Path
import argparse
import imageio
# usando argparse para definir os comandos
parser = argparse.ArgumentParser(
prog='PNG frames to GIF animation'
)
parser.add_argument(
'-i', '--input',
help='Input folder containing the PNG images'
)
parser.add_argument(
'-o', '--output', default='output.gif',
help='Output GIF file name'
)
parser.add_argument(
'-d', '--duration', default=200, type=int,
help='Frame duration in milliseconds',
)
parser.add_argument(
'-l', '--loop', default=0, type=int,
help='Number of loops (default=0, keep looping)',
)
args = parser.parse_args()
# define path da pasta de entrada (ou diretório atual)
input_dir = Path(args.input or Path.cwd())
if input_dir.is_dir(): # se for mesmo um diretório
try: # tenta fazer uma lista de imagens .png
images = [imageio.v3.imread(file_path)
for file_path in sorted(input_dir.iterdir())
if file_path.suffix.lower() == '.png']
if images: # se tiver imagens na lista
# monta caminho do arquivo de saída
output_path = input_dir / args.output
imageio.v3.imwrite(
output_path,
images,
duration=int(args.duration),
loop=args.loop,
)
print(f'Animation saved at:\n{output_path}\n')
else: # não tinha imagens
print(f'No PNG images found at:\n{input_dir}')
except Exception as e: # algum outro erro
if str(e).startswith('all input arrays'):
print('Select only images of same size.')
else:
print(str(e))
else:
print(f'{input_dir}\nis not a valid input dir.')