Adicionar texto na imagem usando PIL

93

Tenho um aplicativo que carrega uma imagem e quando o usuário clica nela, aparece uma área de texto para essa imagem (usando jquery), onde o usuário pode escrever algum texto na imagem. Que deve ser adicionado na imagem.

Depois de fazer algumas pesquisas sobre isso, descobri que PIL(Python Imaging Library) pode me ajudar a fazer isso. Tentei alguns exemplos para ver como funciona e consegui escrever um texto em uma imagem. Mas acho que há alguma diferença quando tento usar Python Shelle em ambiente web. Quero dizer, o texto na textarea é muito grande em px. Como posso obter o mesmo tamanho de texto ao usar PIL como aquele na área de texto?

O texto é multilinha. Como posso torná-lo multilinha na imagem também, usando PIL?

Existe uma maneira melhor do que usar PIL? Não tenho certeza se esta é a melhor implementação.

html:

<img src="images/test.jpg"/>

é a imagem sendo editada

var count = 0;
$('textarea').autogrow();
$('img').click(function(){
    count = count + 1;
    if (count > 1){
        $(this).after('<textarea />');
        $('textarea').focus();
    }   
});

o jquery para adicionar a textarea. Além disso, a área de texto é a posição: tamanho absoluto e fixo.

Devo colocá-lo dentro de um formulário para obter as coordenadas da textarea na imagem? Quero escrever um texto na imagem quando o usuário clicar e salvá-lo na imagem.

Apostolos
fonte
Por que você deseja escrever um texto em uma imagem usando PIL (e não tenho certeza se PIL ajuda nisso). Não é bom o suficiente para você mostrar o texto sobreposto, que é usado mais comumente em controles deslizantes.
lalit
1
Eu preciso disso para um projeto em que quero que a imagem seja salva. Pil pode desenhar texto em uma imagem usando ImageDraw, não sei se existe outra maneira.
Apostolos
Será útil, se você puder fornecer o código Python que está usando?
lalit
ainda não implementado no Django. Tentei ver como o PIL funciona no console Python interativo. Deseja ver se funciona primeiro e depois transferi-lo para Django.
Apostolos
Qual é o símbolo $ em seu código?
Mugen,

Respostas:

171

Acho que o módulo ImageFont disponível em PILdeve ser útil para resolver o problema do tamanho da fonte do texto. Apenas verifique qual tipo e tamanho de fonte é apropriado para você e use a seguinte função para alterar os valores da fonte.

# font = ImageFont.truetype(<font-file>, <font-size>)
# font-file should be present in provided path.
font = ImageFont.truetype("sans-serif.ttf", 16)

Portanto, seu código será semelhante a:

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw 

img = Image.open("sample_in.jpg")
draw = ImageDraw.Draw(img)
# font = ImageFont.truetype(<font-file>, <font-size>)
font = ImageFont.truetype("sans-serif.ttf", 16)
# draw.text((x, y),"Sample Text",(r,g,b))
draw.text((0, 0),"Sample Text",(255,255,255),font=font)
img.save('sample-out.jpg')

Você pode precisar fazer um esforço extra para calcular o tamanho da fonte. Caso você queira alterá-lo com base na quantidade de texto que o usuário forneceu TextArea.

Para adicionar quebra automática de texto (coisa de multilinha), basta ter uma ideia aproximada de quantos caracteres podem vir em uma linha, então você provavelmente pode escrever uma função de pré-processamento para o seu texto, que basicamente encontra o caractere que será o último em cada linha e converte o espaço em branco antes desse caractere em nova linha.

lalit
fonte
1
Esse é o meu pensamento inicial. Então, preciso que minhas fontes estejam em uma pasta específica no meu servidor web para funcionar? Acho que sim. Quebra automática de texto? Existe uma maneira padrão ou devo implementar uma?
Apostolos
Você pode manter o arquivo de fonte em qualquer lugar do seu servidor web. Apenas certifique-se de que o caminho fornecido está correto.
lalit
7
@lalit Tentei seu código em uma máquina Windows e recebi um erro para a fonte self.font = core.getfont(file, size, index, encoding) IOError: cannot open resource. Como posso fornecer o caminho para o arquivo de fonte?
LWZ
3
@LWZ, para executar o código acima, apenas certifique-se de que o arquivo de fonte está no diretório atual no qual você está executando o código acima. Caso você esteja usando em seu programa, apenas especifique o caminho completo para seu arquivo, por exemplo, 'C: \ Windows \ Fonts \ sans-serif.ttf'. Outra coisa que você precisa ter certeza aqui é dar as permissões de leitura apropriadas ao arquivo.
lalit
3
font = ImageFont.truetype ("./ arial.ttf", 30); draw.textsize (msg, font = font);
WeizhongTu
16

Você pode criar um diretório "fonts" em uma raiz de seu projeto e colocar seu arquivo de fontes (sans_serif.ttf) lá. Então você pode fazer algo assim:

fonts_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'fonts')
font = ImageFont.truetype(os.path.join(fonts_path, 'sans_serif.ttf'), 24)
svpp
fonte
15

Um exemplo ainda mais mínimo (desenha "Hello world!" Em preto e com a fonte padrão no canto superior esquerdo da imagem):

...
from PIL import ImageDraw
...
ImageDraw.Draw(
    image  # Image
).text(
    (0, 0),  # Coordinates
    'Hello world!',  # Text
    (0, 0, 0)  # Color
)
Solomon Ucko
fonte
6

Primeiro, você deve baixar um tipo de fonte ... por exemplo: https://www.wfonts.com/font/microsoft-sans-serif .

Depois disso, use este código para desenhar o texto:

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw 
img = Image.open("filename.jpg")
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(r'filepath\..\sans-serif.ttf', 16)
draw.text((0, 0),"Draw This Text",(0,0,0),font=font) # this will draw text with Blackcolor and 16 size

img.save('sample-out.jpg')
Kumar S
fonte
4

Com o Pillow, você também pode desenhar em uma imagem usando o módulo ImageDraw. Você pode desenhar linhas, pontos, elipses, retângulos, arcos, bitmaps, acordes, pieslices, polígonos, formas e texto.

from PIL import Image, ImageDraw
blank_image = Image.new('RGBA', (400, 300), 'white')
img_draw = ImageDraw.Draw(blank_image)
img_draw.rectangle((70, 50, 270, 200), outline='red', fill='blue')
img_draw.text((70, 250), 'Hello World', fill='green')
blank_image.save('drawn_image.jpg')

criamos um objeto Image com o método new (). Isso retorna um objeto Image sem imagem carregada. Em seguida, adicionamos um retângulo e algum texto à imagem antes de salvá-la.

Tamil Selvan S
fonte
3

Uma coisa não mencionada em outras respostas é verificar o tamanho do texto. Freqüentemente, é necessário certificar-se de que o texto se ajusta à imagem (por exemplo, encurtar o texto se for muito grande) ou para determinar o local para desenhar o texto (por exemplo, texto alinhado no centro). Pillow / PIL oferece dois métodos para verificar o tamanho do texto, um via ImageFont e outro via ImageDraw. Conforme mostrado abaixo, a fonte não lida com linhas múltiplas, enquanto ImageDraw sim.

In [28]: im = Image.new(mode='RGB',size=(240,240))                                                            
In [29]: font = ImageFont.truetype('arial')
In [30]: draw = ImageDraw.Draw(im)
In [31]: t1 = 'hello world!'
In [32]: t2 = 'hello \nworld!'
In [33]: font.getsize(t1), font.getsize(t2) # the height is the same
Out[33]: ((52, 10), (60, 10)) 
In [35]: draw.textsize(t1, font), draw.textsize(t2, font)  # handles multi-lined text
Out[35]: ((52, 10), (27, 24)) 
lange
fonte
-8

Para adicionar texto em um arquivo de imagem, basta copiar / colar o código abaixo

<?php
$source = "images/cer.jpg";
$image = imagecreatefromjpeg($source);
$output = "images/certificate".rand(1,200).".jpg";
$white = imagecolorallocate($image,255,255,255);
$black = imagecolorallocate($image,7,94,94);
$font_size = 30;
$rotation = 0;
$origin_x = 250;
$origin_y = 450;
$font = __DIR__ ."/font/Roboto-Italic.ttf";
$text = "Dummy";
$text1 = imagettftext($image,$font_size,$rotation,$origin_x,$origin_y,$black,$font,$text);
     imagejpeg($image,$output,99);
?> <img src="<?php echo $output; ?>"> <a href="<?php echo $output;    ?>" download="<?php echo $output; ?>">Download Certificate</a>
Ramsevak Kumar
fonte