วิธีการเขียนภาพ PNG เพื่อสตริงด้วย PIL


105

ผมได้สร้างภาพโดยใช้PIL ฉันจะบันทึกลงในสตริงในหน่วยความจำได้อย่างไร Image.save()วิธีการต้องใช้ไฟล์

ฉันต้องการเก็บภาพหลาย ๆ ภาพไว้ในพจนานุกรม

คำตอบ:


201

คุณสามารถใช้BytesIOคลาสเพื่อรับ wrapper รอบ ๆ สตริงที่ทำงานเหมือนไฟล์ BytesIOวัตถุให้อินเตอร์เฟซเดียวกันเป็นไฟล์ แต่จะช่วยประหยัดเนื้อหาเพียงในหน่วยความจำ:

import io

with io.BytesIO() as output:
    image.save(output, format="GIF")
    contents = output.getvalue()

คุณต้องระบุรูปแบบเอาต์พุตด้วยformatพารามิเตอร์อย่างชัดเจนมิฉะนั้น PIL จะเพิ่มข้อผิดพลาดเมื่อพยายามตรวจจับโดยอัตโนมัติ

หากคุณโหลดรูปภาพจากไฟล์มันมีformatพารามิเตอร์ที่มีรูปแบบไฟล์ต้นฉบับดังนั้นในกรณีนี้คุณสามารถformat=image.formatใช้ได้

ใน Python 2 เวอร์ชันเก่าก่อนที่จะเปิดตัวioโมดูลคุณจะต้องใช้StringIOโมดูลแทน


1
ใช่ นี่คือสิ่งที่ฉันกำลังมองหา ฉัน googled ทุกการรวมกันของ python, string, reader, writer, buffer และไม่ได้คิดอะไรเลย ขอบคุณ!
rik.the.vik

2
ไม่ได้ผลสำหรับฉัน :( ฉันได้รับ KeyError นี้ใน Imaging / PIL / Image.pyc บรรทัด 1423 -> เพิ่ม KeyError (ต่อ) # ส่วนขยายที่ไม่รู้จัก
Radian

6
@Radian เอกสาร PIL บนเมธอด save () กล่าวว่า: You can use a file object instead of a filename. In this case, you must always specify the format.ดังนั้นหากอาร์กิวเมนต์แรกเป็นอ็อบเจ็กต์ไฟล์คุณต้องส่งผ่านอาร์กิวเมนต์ที่สองซึ่งเป็นรูปแบบ (เช่น'PNG')
Su Zhang

1
ใน Python เวอร์ชันปัจจุบัน StringIO อยู่ในแพ็กเกจ io คุณต้องเขียน:from io import StringIO
Spoutnik16

4
คุณสามารถใช้งานได้ดีขึ้นimage.save(output, format=image.format)
reetesh11


24

วิธีแก้ปัญหาของ sth ไม่ได้ผลสำหรับฉัน
เพราะใน ...

Imaging / PIL / Image.pyc บรรทัด 1423 -> เพิ่ม KeyError (ext) # ส่วนขยายที่ไม่รู้จัก

กำลังพยายามตรวจหารูปแบบจากนามสกุลในชื่อไฟล์ซึ่งไม่มีอยู่ในกรณี StringIO

คุณสามารถข้ามการตรวจจับรูปแบบได้โดยตั้งค่ารูปแบบด้วยตัวคุณเองในพารามิเตอร์

import StringIO
output = StringIO.StringIO()
format = 'PNG' # or 'JPEG' or whatever you want
image.save(output, format)
contents = output.getvalue()
output.close()

14

save()สามารถใช้วัตถุคล้ายไฟล์เช่นเดียวกับเส้นทางดังนั้นคุณสามารถใช้บัฟเฟอร์ในหน่วยความจำเช่นStringIO:

buf = StringIO.StringIO()
im.save(buf, format='JPEG')
jpeg = buf.getvalue()

ขอบคุณ. StringIO - นั่นคือสิ่งที่ฉันต้องการ
maxp

อินเทอร์เฟซ save () นั้นสะอาดกว่าอินเทอร์เฟซ tostring () มากเมื่อต้องรับไฟล์ PNG, JPEG หรือรูปแบบไฟล์จริง
Kekoa

13

ด้วยความทันสมัย ​​(ณ กลางปี ​​2017 Python 3.5 และ Pillow 4.0):

ดูเหมือนว่า StringIO จะไม่ทำงานเหมือนเดิมอีกต่อไป คลาส BytesIO เป็นวิธีที่เหมาะสมในการจัดการสิ่งนี้ ฟังก์ชันบันทึกของ Pillow คาดว่าสตริงเป็นอาร์กิวเมนต์แรกและไม่น่าแปลกใจที่จะไม่เห็น StringIO เช่นนี้ สิ่งต่อไปนี้คล้ายกับโซลูชัน StringIO รุ่นเก่า แต่มี BytesIO แทน

from io import BytesIO
from PIL import Image

image = Image.open("a_file.png")
faux_file = BytesIO()
image.save(faux_file, 'png')

2
image_data = faux_file.getvalue () มีจุดประสงค์อะไร
Ryan

@Ryan จับดีไม่มีจุดมุ่งหมายใด ๆ มันเหลือจากการทดสอบและถูกลบออกในที่สุด
mightypile

9

เมื่อคุณพูดว่า "ฉันต้องการเก็บภาพจำนวนมากในพจนานุกรม" จะไม่ชัดเจนว่านี่เป็นโครงสร้างในหน่วยความจำหรือไม่

คุณไม่จำเป็นต้องทำสิ่งนี้เพื่อทำให้ภาพในความทรงจำเสื่อมลง เพียงแค่เก็บไฟล์imageวัตถุไว้ในพจนานุกรมของคุณ

หากคุณจะเขียนพจนานุกรมของคุณลงในไฟล์คุณอาจต้องการดู im.tostring()วิธีการและไฟล์Image.fromstring()ฟังก์ชัน

http://effbot.org/imagingbook/image.htm

im.tostring () => สตริง

ส่งคืนสตริงที่มีข้อมูลพิกเซลโดยใช้ตัวเข้ารหัส "raw" มาตรฐาน

Image.fromstring (โหมดขนาดข้อมูล) => รูปภาพ

สร้างหน่วยความจำภาพจากข้อมูลพิกเซลในสตริงโดยใช้ตัวถอดรหัส "raw" มาตรฐาน

"รูปแบบ" (.jpeg, .png ฯลฯ ) จะมีความสำคัญเฉพาะบนดิสก์เมื่อคุณแลกเปลี่ยนไฟล์ หากคุณไม่ได้แลกเปลี่ยนไฟล์รูปแบบก็ไม่สำคัญ


2
ดูเหมือนว่าเขาต้องการคงรูปแบบ PNG ไว้ไม่ใช่ลดขนาดเป็นข้อมูลพิกเซลดิบ
Ben Blank
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.