【问题标题】:Add Text on Image using PIL使用 PIL 在图像上添加文本
【发布时间】:2013-04-28 17:07:55
【问题描述】:

我有一个加载图像的应用程序,当用户单击它时,该图像会出现一个文本区域(使用jquery),用户可以在其中在图像上写一些文本。应该在图片上添加。

在做了一些研究之后,我认为PIL(Python Imaging Library)可以帮助我做到这一点。所以我尝试了几个例子来看看它是如何工作的,我设法在图像上写了文字。但是我认为当我使用Python Shell 和在网络环境中尝试它时会有一些不同。我的意思是 textarea 上的文本在 px 中非常大。使用 PIL 时如何实现与 textarea 上相同大小的文本?

文本是多行的。如何使用PIL 使其成为多行图像?

有没有比使用 PIL 更好的方法?我不完全确定,如果这是最好的实现。

html:

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

它正在编辑的图像

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

jquery 添加文本区域。 文本区域也是位置:绝对和固定大小。

我应该把它放在一个表单中,这样我就可以在图像上获取 textarea 的坐标了吗? 我想在用户点击时在图像上写文字并将其保存在图像上。

【问题讨论】:

  • 为什么要使用 PIL 在图像上写入文本(我不确定 PIL 是否有帮助)。在滑块中最常用的叠加层中显示文本还不够好。
  • 我需要它用于我想要保存图像的项目。 pil可以使用ImageDraw在图片上绘制文字,不知道有没有其他方法。
  • 会有所帮助,如果你能提供你正在使用的Python代码?
  • 尚未在 django 中实现。我试图看看 PIL 在交互式 python 控制台中是如何工作的。想先看看能不能用,然后在django中调出来。
  • 代码中的 $ 符号是什么?

标签: python django image python-imaging-library


【解决方案1】:

我最近不得不实施同样的事情。我在pypi 上创建了一个包,它可能会派上用场:pynter

您可以通过以下步骤向图像添加文本:

  1. 下载图片:curl https://i.imgur.com/XQCKcC9.jpg -o ./image.jpg

  2. 下载字体:curl https://fonts.google.com/download?family=Roboto -o ./roboto.zip ; unzip ./roboto.zip -d ./Roboto

  3. pip install pynter

from pynter.pynter import generate_captioned
font_path = './Roboto/Roboto-Regular.ttf'
image_path = './image.jpg'
im = generate_captioned('China lands rover on Mars'.upper(), image_path=image_path, size=(1080, 1350),
                        font_path=font_path, filter_color=(0, 0, 0, 40))
im.show()
im.convert('RGB').save('drawn_image.jpg')

这将是结果:

【讨论】:

    【解决方案2】:

    先安装枕头

    pip install pillow
    

    示例

    from PIL import Image, ImageDraw, ImageFont
    
    image = Image.open('Focal.png')
    width, height = image.size 
    
    draw = ImageDraw.Draw(image)
    
    text = 'https://devnote.in'
    textwidth, textheight = draw.textsize(text)
    
    margin = 10
    x = width - textwidth - margin
    y = height - textheight - margin
    
    draw.text((x, y), text)
    
    image.save('devnote.png')
    
    # optional parameters like optimize and quality
    image.save('optimized.png', optimize=True, quality=50)
    

    【讨论】:

      【解决方案3】:

      要在图像文件上添加文本,只需复制/粘贴下面的代码

      <?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>
      

      【讨论】:

        【解决方案4】:

        其他答案中未提及的一件事是检查文本大小。通常需要确保文本适合图像(例如,如果文本过大,则缩短文本)或确定绘制文本的位置(例如,对齐文本顶部居中)。 Pillow/PIL 提供了两种检查文本大小的方法,一种是通过 ImageFont,另一种是通过 ImageDraw。如下图,字体不处理多行,而 ImageDraw 可以。

        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)) 
        

        【讨论】:

        • 感谢您强调这一差异。我确实在寻找在多行中获得正确的文本大小。
        【解决方案5】:

        首先,您必须下载字体类型...例如:https://www.wfonts.com/font/microsoft-sans-serif

        之后,使用此代码绘制文本:

        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')
        

        【讨论】:

          【解决方案6】:

          借助 Pillow,您还可以使用 ImageDraw 模块在图像上绘图。您可以绘制线、点、椭圆、矩形、圆弧、位图、弦、扇形片、多边形、形状和文本。

          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')
          

          我们使用 new() 方法创建一个 Image 对象。这将返回一个没有加载图像的 Image 对象。然后,我们在保存之前向图像添加一个矩形和一些文本。

          【讨论】:

            【解决方案7】:

            更简单的示例(用黑色绘制“Hello world!”,并在图像的左上角使用默认字体):

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

            【讨论】:

            • 我也意识到可以使用没有指定字体的 .text。但是在没有指定字体的情况下有没有办法指定大小?
            • load_default 似乎没有办法指定字体大小。 ://
            【解决方案8】:

            我认为PIL 中提供的ImageFont 模块应该有助于解决文本字体大小问题。只需检查适合您的字体类型和大小,然后使用以下功能更改字体值。

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

            所以你的代码看起来类似于:

            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')
            

            您可能需要付出一些额外的努力来计算字体大小。如果您想根据用户在TextArea 中提供的文本数量来更改它。

            要添加文本换行(多行),只需大致了解一行中可以包含多少个字符,然后您可以为您的文本编写一个预处理函数,它基本上可以找到最后一个字符每行并将此字符之前的空格转换为换行符。

            【讨论】:

            • 这是我最初的想法。那么我需要我的字体在我的网络服务器的特定文件夹中才能工作吗?我想是的。环绕文本?有标准方法还是必须实现?
            • 您可以将字体文件保存在 Web 服务器的任何位置。只要确保您提供的路径是正确的。
            • @lalit 我在 Windows 机器上尝试了您的代码,但字体 self.font = core.getfont(file, size, index, encoding) IOError: cannot open resource 出现错误。如何提供字体文件的路径?
            • @LWZ,要运行上述代码,只需确保字体文件位于执行上述代码的当前目录中。如果您在程序中使用它,只需指定文件的完整路径,例如'C:\Windows\Fonts\sans-serif.ttf'。您需要在此处确保的其他事项是为文件提供适当的读取权限。
            • font = ImageFont.truetype("./arial.ttf", 30);draw.textsize(msg, font=font);
            【解决方案9】:

            您可以在项目的根目录中创建一个目录“字体”并将您的字体 (sans_serif.ttf) 文件放在那里。然后你可以做这样的事情:

            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)
            

            【讨论】:

              猜你喜欢
              • 2021-08-23
              • 2012-03-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-10-06
              • 1970-01-01
              • 2019-01-17
              • 1970-01-01
              相关资源
              最近更新 更多