เพิ่มข้อความในภาพโดยใช้ PIL


94

ฉันมีแอพพลิเคชั่นที่โหลดรูปภาพและเมื่อผู้ใช้คลิกที่มันพื้นที่ข้อความจะปรากฏขึ้นสำหรับรูปภาพนี้ (โดยใช้jquery) ซึ่งผู้ใช้สามารถเขียนข้อความบางอย่างบนรูปภาพได้ ซึ่งควรเพิ่มใน Image

หลังจากทำการค้นคว้าเกี่ยวกับเรื่องนี้ฉันพบว่าPIL(Python Imaging Library) สามารถช่วยฉันทำสิ่งนี้ได้ ดังนั้นฉันจึงลองสองสามตัวอย่างเพื่อดูว่ามันทำงานอย่างไรและฉันสามารถเขียนข้อความบนรูปภาพได้ แต่ฉันคิดว่ามีความแตกต่างบางอย่างเมื่อฉันลองใช้Python Shellและในสภาพแวดล้อมของเว็บ ฉันหมายถึงข้อความบนพื้นที่ข้อความมีขนาดใหญ่มากเป็นพิกเซล ฉันจะทำให้ข้อความมีขนาดเท่ากันได้อย่างไรเมื่อใช้ PIL เป็นขนาดเดียวกับพื้นที่ข้อความ

ข้อความคือ Multiline ฉันจะทำให้เป็นหลายเส้นในภาพได้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 พื้นที่ข้อความยังเป็นตำแหน่ง: ขนาดที่แน่นอนและคงที่

ฉันควรวางไว้ในแบบฟอร์มเพื่อให้ได้พิกัดของ textarea บนรูปภาพหรือไม่? ฉันต้องการเขียนข้อความบนภาพเมื่อผู้ใช้คลิกและบันทึกลงในภาพ


ทำไมคุณถึงต้องการเขียนข้อความบนภาพโดยใช้ PIL (และฉันไม่แน่ใจว่า PIL ช่วยได้หรือไม่) ไม่ดีพอที่คุณจะแสดงข้อความในภาพซ้อนทับซึ่งใช้กันมากที่สุดในแถบเลื่อน
lalit

1
ฉันต้องการมันสำหรับโครงการฉันต้องการบันทึกภาพ Pil สามารถวาดข้อความบนรูปภาพโดยใช้ ImageDraw ไม่ทราบว่ามีวิธีอื่นหรือไม่
Apostolos

จะเป็นประโยชน์หากคุณสามารถระบุรหัส Python ที่คุณใช้อยู่?
lalit

ยังไม่ได้ใช้ใน django ฉันพยายามดูว่า PIL ทำงานอย่างไรในคอนโซล python แบบโต้ตอบ ต้องการดูว่าใช้งานได้หรือไม่ก่อนแล้วจึงโอนใน Django
Apostolos

สัญลักษณ์ $ ในรหัสของคุณคืออะไร?
Mugen

คำตอบ:


173

ฉันคิดว่าโมดูลImageFont ที่มีอยู่PILควรมีประโยชน์ในการแก้ปัญหาขนาดตัวอักษรของข้อความ เพียงตรวจสอบประเภทและขนาดแบบอักษรที่เหมาะสมสำหรับคุณและใช้ฟังก์ชันต่อไปนี้เพื่อเปลี่ยนค่าแบบอักษร

# 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ไว้

หากต้องการเพิ่มการตัดข้อความ (สิ่งหลายบรรทัด) เพียงแค่ใช้ความคิดคร่าวๆว่าหนึ่งบรรทัดสามารถมีอักขระได้กี่ตัวจากนั้นคุณอาจเขียนฟังก์ชัน pre-pprocessing สำหรับข้อความของคุณซึ่งโดยทั่วไปจะพบอักขระที่จะอยู่สุดท้ายในแต่ละบรรทัดและ แปลงช่องว่างก่อนอักขระนี้เป็นบรรทัดใหม่


1
นั่นคือความคิดเริ่มต้นของฉัน ดังนั้นฉันจำเป็นต้องให้ฟอนต์ของฉันอยู่ในโฟลเดอร์เฉพาะในเว็บเซิร์ฟเวอร์ของฉันเพื่อให้ทำงานได้หรือไม่ฉันคิดว่าใช่ การตัดข้อความมีวิธีมาตรฐานหรือไม่หรือต้องใช้วิธีใด
Apostolos

คุณสามารถเก็บไฟล์ฟอนต์ไว้ที่ใดก็ได้ในเว็บเซิร์ฟเวอร์ของคุณ ตรวจสอบให้แน่ใจว่าเส้นทางที่คุณระบุถูกต้อง
lalit

7
@lalit ฉันพยายามรหัสของคุณบนเครื่อง Windows self.font = core.getfont(file, size, index, encoding) IOError: cannot open resourceและฉันได้ข้อผิดพลาดสำหรับตัวอักษรที่ ฉันจะให้พา ธ ไปยังไฟล์ฟอนต์ได้อย่างไร
LWZ

3
@LWZ ในการรันโค้ดด้านบนตรวจสอบให้แน่ใจว่าไฟล์ฟอนต์อยู่ในไดเร็กทอรีปัจจุบันที่คุณใช้งานโค้ดด้านบน ในกรณีที่คุณใช้ในโปรแกรมของคุณเพียงระบุเส้นทางแบบเต็มสำหรับไฟล์ของคุณเช่น 'C: \ Windows \ Fonts \ sans-serif.ttf' สิ่งอื่นที่คุณต้องตรวจสอบให้แน่ใจคือการให้สิทธิ์ในการอ่านไฟล์ที่เหมาะสม
lalit

3
font = ImageFont.truetype ("./ arial.ttf", 30); draw.textsize (msg, font = font);
WeizhongTu

16

คุณสามารถสร้างไดเร็กทอรี "ฟอนต์" ในรูทของโปรเจ็กต์ของคุณและใส่ไฟล์ฟอนต์ (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)

15

ตัวอย่างที่เรียบง่ายยิ่งขึ้น (วาด "Hello world!" เป็นสีดำและมีแบบอักษรเริ่มต้นที่ด้านซ้ายบนของภาพ):

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

8

ครั้งแรกที่คุณจะต้องดาวน์โหลดแบบตัวอักษรที่ ... ตัวอย่างเช่น: 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')

เราสร้างออบเจ็กต์รูปภาพด้วยเมธอด () ใหม่ สิ่งนี้ส่งคืนออบเจ็กต์รูปภาพโดยไม่มีรูปภาพที่โหลด จากนั้นเราจะเพิ่มสี่เหลี่ยมผืนผ้าและข้อความบางส่วนลงในภาพก่อนบันทึก


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

ขอขอบคุณที่เน้นย้ำความแตกต่างนี้ ฉันกำลังมองหาขนาดตัวอักษรที่เหมาะสมในหลายบรรทัด
fcole90

-9

หากต้องการเพิ่มข้อความในไฟล์รูปภาพเพียงแค่คัดลอก / วางโค้ดด้านล่าง

<?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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.