image file is truncated ?

Fragen zu Tkinter.
Antworten
gorba
User
Beiträge: 100
Registriert: Freitag 28. Juli 2006, 14:58

Hallo

Ich möchte an tkinter einen string übergeben, der mir dann das bild darstellt:

Code: Alles auswählen

	def update_label(self, buffer):
		im = Image.open( str.StringIO(buffer) ) 			
		im.thumbnail((280, 300), Image.ANTIALIAS)
		self.photo = ImageTk.PhotoImage(im)
		self.label.config(image = self.photo)
Diese funktion gibt mir folgenden Fehler aus:

Code: Alles auswählen

  File "P:\Projekte\Eyetec_gp\Python\PythonSchnittstelle\picSplit.py", line 188, in updateGuiImage
    GUI.update_label(self.receivedDataString)
  File "betterGUI.py", line 172, in update_label
    self.photo = ImageTk.PhotoImage(im)
  File "C:\Python24\Lib\site-packages\PIL\ImageTk.py", line 116, in __init__
    self.paste(image)
  File "C:\Python24\Lib\site-packages\PIL\ImageTk.py", line 166, in paste
    im.load()
  File "C:\Python24\Lib\site-packages\PIL\ImageFile.py", line 192, in load
    raise IOError("image file is truncated (%d bytes not processed)" % len(b))
IOError: image file is truncated (6 bytes not processed)
Wenn ich den string aber auf meine HD schreibe (als jpg) und ihn dann mit einem bildbearbeitungsprogramm anzeige, funktioniert das ganze...
Wie kann das sein?
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi Gorba,

was soll das hier bewirken?
im = Image.open( str.StringIO(buffer) )
Was ist str? StringIO simuliert doch schon einen Dateihandler, den Du nur an Image.open übergeben brauchst:

Code: Alles auswählen

from Tkinter import *
from StringIO import StringIO
import Image
from ImageTk import PhotoImage

def lade_bilddaten(sBild):
    fileBild = open(sBild, "rb")
    sData = fileBild.read()
    fileBild.close()
    return sData
    
tk = Tk()

SIO = StringIO(lade_bilddaten("test.jpg"))  ##  erstelle StringIO Instanz
im = Image.open(SIO)                        ##  lade aus StringIO Instanz als Dateirepraesentation
## entspricht: im = Image.open("test.jpg")

ph = PhotoImage(im)
Label(tk, image = ph).grid()
tk.mainloop()
Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
gorba
User
Beiträge: 100
Registriert: Freitag 28. Juli 2006, 14:58

Code: Alles auswählen

import StringIO as str
=) Das Problem hatt sich von selber gelöst. Ich vermute ich hatte im header des jpg files noch unnötige Daten. Auf jeden Fall tritt das Problem nicht mehr auf, obwohl ich nicht sagen kann wieso... =S
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

gorba hat geschrieben:

Code: Alles auswählen

import StringIO as str
Davon ist abzuraten, da es die eingebaute Funktion str() überdeckt. Und str() ist ja öfter mal notwendig.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
gorba
User
Beiträge: 100
Registriert: Freitag 28. Juli 2006, 14:58

danke für die info. Habs gleich geändert. War mir nicht bewusst.
gorba
User
Beiträge: 100
Registriert: Freitag 28. Juli 2006, 14:58

Ich habs. Das Problem war, dass im Header des Bildes eine andere Grösse stand, als ich wirklich hatte. Somit dachte mein tkinter, das bild sei so noch nicht komplett.

Hab gleich die nächste Frage =)
Ich möchte, wenn ich einen Teil des Bildes empfangen habe, den gleich darstellen. Ich nehme also meine Bilddaten, fülle den rest mit 0 auf (damit tkinter mit der grösse zufrieden ist) und zeige dann das ganze an:

Code: Alles auswählen

class MyClass(Frame):
	sImage = ""         ##    Pfad des aktuell geladenen Bildes
	photo = None        ##    aktuell geladenes Bild (Raster)

	def __init__(self, parent, master=None):
		Frame.__init__(self, master)
		self.grid()
		self.create_gui()

	def create_gui(self):
		Button(root,text="Quit",command=self.quit).grid()
		Button(root,text="Bild",command=self.send_em).grid()
		self.label = Label(root, image=self.photo)
		self.label.grid()

	def update_label(self, buffer):
		im = Image.open( strIO.StringIO(buffer) ) 			# im = Image.open('test123.jpg')
		im.thumbnail((380, 400), Image.ANTIALIAS)
		self.photo = ImageTk.PhotoImage(im)
		self.label.config(image = self.photo)
	
	def send_em(self):
		#~ plc.plc_remote_write_uart_no_ack(MASTER,10,11,data=[], repetitions = 0,debug = 0)
		#~ RecvData()
		f = open('hw0.bmp','rb')
		self.fd = f.read()
		f.close()
		size = len(self.fd)
		x = 1000
		datSize = x
		padSize = size - x
		new = ''
		new += self.fd[0:x]
		new += '0' * padSize
		self.update_label(new)
		print '------------------------------------------'
		time.sleep(0.5)
		x = 2000
		datSize = x
		padSize = size - x
		new = ''
		new += self.fd[0:x]
		new += '0' * padSize
		print '------------------------------------------'
		self.update_label(new)

root=Tk()
root.title("Viewer")
my_class = MyClass(root)
GUIFD = my_class
root.mainloop()
Komisch finde ich nun, dass tkinter den ersten aufruf von self.update_label(new) "ignoriert". Dass heisst, er zeigt mir erst das Bild beim letzten self.update_label(new) an. Egal wiviele zwischenschritte ich habe.

Gibt es sowas wie ein refresh() für tkinter? Oder kann mir jemand sagen, wiso sich tkinter so verhält?
Bin für jeden input dankbar.

greez
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Die Darstellung beginnt erst nach Aufruf von mainloop(). Du mußt die Ausgabe also nach mainloop() z.B. in einem eigenen Thread, der ein Event an Tkinter sendet, aktualisieren oder vielleicht einfacher über einen Tkinter-Timer (after()), der in MyClass.__init__() gestartet wird.
MfG
HWK
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi Gorba,

ich lasse mich gern verbessern, aber ich denke nicht dass das (in jedem Fall) so funktioniert. Denn es gibt verschiedene Arten der JPEG-Komprimierung, einige bauen das Bild z.B. in mehreren Verfeinerungsstufen auf. Ich weiß nicht was passiert, wenn plötzlich Daten von Blöcken fehlen. Zumindest wird das Bild mit Deinem Verfahren ziemlich sicher zur Unkenntlichkeit verunstaltet.

Sorry,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
gorba
User
Beiträge: 100
Registriert: Freitag 28. Juli 2006, 14:58

genau das habe ich auch festgestellt. bei bmp funktionier es (logischerweise) bei jpg schaut die ganze sache wesentlich komplizierter aus. Hab noch keinen weg gefunden, das Bild wider sauber darzustellen, nachdem irgendwo (header ausgeschlossen) bytes fehlen..

edit: das iterative anzeigen funktioniert so (mit auffüllen der leeren bytes). allerdings funktioniert sowas in der art nur bei bmp:

Code: Alles auswählen

			lastImage = self.ImageNr
			image = header[0]
			lastBlock = self.CurrentBlockNo
			nextBlock = header[1]
			expectedBlock = lastBlock + 1
			
			if(lastBlock == 255):					# dirty fixing..
				expectedBlock = 1
			
			if(lastImage == image):
				if(nextBlock == expectedBlock):		# everything is great! The best case ever..
					result = wordList
					self.appendBlock(result)
				elif(nextBlock == expectedBlock+1):	# one block is lost in space. Not so good..
					print 'One Block is lost in space. Padding with raw data'
					size = len(wordList)
					print 'Lenght of wordList = %d' % size
					rawData = [0]
					rawData = size * rawData
					print 'Lenght of white RAW data = %d' % len(rawData)
					i = 0
					for words in wordList:
						rawData.append(wordList[i])
						i += 1
					print 'Lengh of both: %d' % len(rawData)
					result = rawData
					self.appendBlock(result)

Dies ist nur ein teilausschnitt einer Funktion. Allerdings, wenn der Fall:
elif(nextBlock == expectedBlock+1):
eintritt, klappt das mit dem padding '0' nicht bez. es funkttioniert, allerdings ist das Bild verschoben und die Fraben stimmen nicht mehr.
Antworten