Introdução à programação
com Python em um contexto visual


Como exportar uma imagem

Um quadro (frame) é o resultado visual produzido na área de desenho do sketch no Processing em um determinado momento. Para salvar um quadro em um arquivo bitmap/raster, como por exemplo PNG, TIF ou JPG, usamos a função save_frame().

Passamos como argumento o nome do arquivo que deve ser salvo, e a extensão de três letras após o ponto no nome do arquivo indica o formato que deve ser salvo. Por exemplo save_frame("imagem.jpg") salva um arquivo JPG na pasta do sketch. Se utilizarmos alguns caracteres “#” no nome do arquivo eles serão substituídos pelo número do frame.

Um exemplo simples

O código abaixo exemplifica como salvar uma imagem PNG de um quadro. Quando uma tecla é pressionada, é executada a função key_pressed() e se for identificada a tecla “s” (key == 's') é execuatada a função save_frame(), que grava uma imagem.

def setup():
    size(500, 500)

def draw():
    background(0, 0, 200)
    x, y = random(width), random(height)
    circle(x, y, 100)


def keyPressed():
    if key == 's':     
        save_frame('frame#####.png')   # os ##### viram o número do frame no nome do arquivo
        print(f'PNG do frame {frame_count} salvo')

Resulta em arquivo semelhante a este “frame421.png” na pasta do sketch:

frame421.png

save_frame() dentro do draw()

Usar save_frame()dentro do laço principal draw() torna o sketch muito mais lento, pois salva uma imagem a cada frame do draw. Se o nome do arquivo for sempre o mesmo, ele vai ser sobreescrito, mas podemos acrescentar alguns carateres # no nome do arquivo, que serão substitúidos pelo número do quadro, e dessa maneira, um número grande de quadros pode ser salvo em alguns segundos, o que deve ser feito com cuidado (pode entupir o disco do seu computador).

Normalmente é criada uma condição que interrompe o sketch com exit() ou que só permite salvar um certo número de imagens (no exemplo abaixo, um quadro a cada 5 com frame_count % 5 == 0 e também fazemos um limite com frame_count <= 100).

def draw():
    # desenho
    ...
    # salva só a cada 5 frames até o frame 100
    if frame_count % 5 == 0 and frame_count <= 100:
        save_frame("imagem#####.png")

Neste outro exemplo, data e horário no nome do arquivo, e interrupção do sketch com exit() ao final.

nome_output = '{}-{}-{}-{}-{}-{}-frame#####.png'.format(
    year(), month(), day(), hour(), minute(), second())


def draw():
    # desenho
    ...
    save_frame(nome_output)
    if frame_count > 100:
        exit()  # interrompe a execução do sketch

Exportando em resolução maior do que a da tela

Um objeto * Py5Graphics * é uma espécie de tela virtual que pode gravar o resultado do desenho em paralelo à área de desenho normal, podendo também receber ajustes especiais aplicados apenas a esse objeto-tela, como .scale() no exemplo abaixo, o que permite exportar uma imagem 10 vezes maior do que a mostrada na tela. Outro ponto interessante deste método é que permite exportar imagens com o fundo transparente.

Exportando um sketch estático

def setup():
    size(50, 50)
    # preparo da gravação
    fator_escala = 10  # um número que multiplica a largura e altura da imagem
    f = create_graphics(width * fator_escala, height * fator_escala)
    begin_record(f)    # início da gravação
    # ajustes que só afetam o arquivo sendo gravado
    f.scale(fator_escala)
    f.stroke_weight(0.5)
    # instruções que aparecem na tela e no arquivo
    background(0, 200, 0)  # não use background() se quiser o fundo transparente
    circle(6, 6, 10)
    end_record()  # fim da gravação
    # se acrescentar instruções de desenho daqui em diante aparecerem só na tela
    f.save('imagem_ampliada.png')  # finalmente salva o arquivo
    # use f.save('imagem_ampliada.png', drop_alpha=False) para exportar um png com fundo transparente  

Repare que a espessura de linha está sendo ajustada para um valor diferente com f.strokeWeight(). Sem o ajuste ela ficaria 10 vezes maior no arquivo do que na área de desenho normal(acompanhando e resto da imagem) e desta maneira ela fica apenas 5 vezes maior no arquivo.

Exportando um único frame de um sketch interativo

fator_escala = 10
salvar_png = False

def setup():
    size(200, 200)  # com fator 10, vira 2000px x 2000px

def draw():
    global salvar_png
    if salvar_png:
        output_buffer = create_graphics(width * fator_escala,
                                        height * fator_escala)
        begin_record(output_buffer)
        output_buffer.scale(fator_escala)   
        file_name = f'{frame_count}.png'    # outra maneira 
    # seu desenho vai aqui
    background(0, 100, 0) 
    circle(mouse_x, mouse_y, width / 2)
    if salvar_png:
        salvar_png = False
        end_record()
        output_buffer.save(file_name)
        print(f'{file_name} salvo.')

def key_pressed():
    global salvar_png
    if key == 'h':
        salvar_png = True

3069

Gravando frames acumulados de um sketch

Este exemplo começa a gravar a acumulação de frames quando se aperta a tecla ‘r’. O resultado é um PNG com fundo transparente e escalado 10 vezes em relação ao que vemos na tela.

fator_escala = 10
gravando = False

def setup():
    size(200, 200)  # com fator 10, vira 2000px x 2000px

def draw():
    # Este exemplo não usa background no draw(), e na tele se vê um fundo cinza
    # mas no PNG gravado o fundo ficará transparente
    if gravando:
        output_buffer.scale(fator_escala) # precisa escalar novamente a cada frame
    circle(mouse_x, mouse_y, width / 5)        
        
def key_pressed():
    global gravando, file_name, output_buffer
    if key == 'r':   # a tecla 'r' liga e desliga a gravação (recording)
        if not gravando:
            gravando = True
            background(200) # limpa a tela (mas não entra na gravação)
            output_buffer = create_graphics(width * fator_escala,
                                        height * fator_escala)
            begin_record(output_buffer)
            file_name = f'{frame_count}.png' 
            print(f'iniciando a gravação de {file_name}')
        else:
            gravando = False
            end_record()
            # drop_alpha=False é necessário no momento para salvar fundo transparente
            output_buffer.save(file_name, drop_alpha=False)  
            print(f'{file_name} gravado.')

126

Exportando apenas parte da tela (e em um local selecionado!)

No exemplo a seguir, vamos usar a estratégia de desenhar em um objeto Py5Graphics como no exemplo anterior, e demonstrar também as seguintes possibilidades:

image

Ambos os textos da imagem acima, em preto e em branco, não estarão presentes no arquivo salvo, assim como toda a àrea cinza em volta ou qualquer elemento nela desenhado.

salvar = False

def setup():
    size(500, 500)
    global w, h, margem, f
    # dimensões da imagem e um deslocamento / margem
    w, h, margem = 400, 400, 50
    f = create_graphics(w, h)

def draw():
    global salvar
    translate(margem, margem)  # 0, 0 no canto da imagem a ser salva
    # instruções antes do beginRecord só aparecem na tela
    # Se não for criado fundo depois de beginRecord, no arquivo fundo
    # transparente
    background(100)  # fundo geral na tela apenas
    fill(0)
    text('Só na tela', 0, -20)
    # início da gravação
    if salvar:
        begin_record(f)  # início da gravação
    # As instruções aqui aparecem na tela e no arquivo
    no_stroke()
    fill(0, 0, 200)
    rect(0, 0, w, h)  # fundo no arquivo usando um retângulo
    fill(0, 200, 0)
    circle(100, 100, 100)
    # fim da gravação
    if salvar:
        # instruções com 'f.' aparecem só na gravação
        f.fill(255, 0, 0)
        f.text('Só na gravação', 20, 300)
        end_record()
        salvar = False
        # em vez de f.save("arquivo_na_pasta_do_sketch.png")
        # vamos usar esta função selectOtuput que chama por nós salva_arquivo()
        select_output("Escolha onde Salvar", salva_arquivo)
    # instruções depois do end_record também aparecem só na tela
    fill(255)
    text('Também só na tela', 10, 20)

Note o texto em vermelho que só aparece no arquivo salvo.

Assuntos relacionados