Seite 1 von 2

QPixmap über QDataStream schicken

Verfasst: 8. Januar 2008 16:25
von kochi
Hallo alle!

Ich bin verzweifelt am versuchen eine QPixmap über ein QDataStream zu schicken, aba das was dann am Ende aus dem Stream rauskommt lässt sich weder abspeichern noch anzeigen :cry:

will nähmlich ein Bild übers Netzwerk vom Server zu Client schicken, QStrings usw. lässt sich alles wunderbar übertragen, nur die QPixmap oda auch QImage net.

am Server sieht das ganze so aus:

Code: Alles auswählen

Worker.cpp
...
    QPixmap image("Logo.PNG");
    cout << "speicher Test: " << image.save("dasISTDERtest.png", "PNG") << endl;
    stream << image;
	if (!proband.waitForBytesWritten(TIMEOUT)) {
		//fehlerBehandeln(pServer->error());
		return;
	}
...
Am Server lässt sich die Pixmap abspeichern, liefert "1"

Jetzt da Client:

Code: Alles auswählen

DerConnect.cpp
...
if (!pServer->waitForReadyRead(SERVER_TIMEOUT)) {
		//fehlerBehandeln(pServer->error());
		return;
	}
	QPixmap image;
	stream >> image;
	cout << "speicher Test: " << image.save("here.png", "png") << endl;
...
Hier speichert er es nicht, liefert "0"

Gibt es andre Möglichkeiten ein Bild pbers Netzwerk zu übertragen oda mache ich was falsch? bitte um hilfe

lg Kochi

Verfasst: 8. Januar 2008 16:49
von Christian81
Einfach mit QFile laden und als QByteArray wäre sinnvoller.
Wie kannst Du sicher sein dass schon alle Daten am Client angekommen sind?

Verfasst: 8. Januar 2008 17:20
von kochi
Hey, danke mal,

also ich schaffs irgendwie net aus dem QFile ein QByteArray zu bekommen xD
find keine Funktion die mir eine QByteArray liefert oder so..


Stimmt, i glaub aba das der Stream solang empfängt bis er fertig is, hab jetzt hinterher noch ein stream.atEnd() und da kommt dann true raus, also er is fertig, alle daten sind drüben

lg kochi

Verfasst: 8. Januar 2008 17:40
von kochi
Hab das jetzt doch hingebkommen zu nem QByteArray

das ganze sieht jetzt so aus:

Code: Alles auswählen

Worker.cpp
...
  QFile myPicture("Logo.PNG");
  myPicture.open(QIODevice::ReadWrite);
  QByteArray myArray;
  myArray = myPicture.readAll();
  stream << myArray;
  if (!proband.waitForBytesWritten(TIMEOUT)) {
	return;
  }
...

Code: Alles auswählen

DerConnect.cpp
...
  if (!pServer->waitForReadyRead(SERVER_TIMEOUT)) {
	return;
  }
  QPixmap image;
  QByteArray myArray;
  stream >> myArray;
  image.loadFromData(myArray, "png");
  cout << stream.atEnd() <<" <-- Fertig?      speicher Test: " << image.save("here.png", "png") << endl;
...

es geht trotzdem nicht =/, hoffe es kann mir wer helfen

lg Kochi

Verfasst: 9. Januar 2008 19:12
von kochi
*push* kann mir keiner helfen? i schaffs einfach nicht :roll:

bidde um hilfe wie kann ich ein Bild übers netzwerk schicken
:?

lg Kochi

Verfasst: 9. Januar 2008 19:36
von Christian81
Da man nicht sieht wie Du die Daten empfängst - nein

Verfasst: 9. Januar 2008 19:49
von ObeliX
hallo,

also so richtig schlau werd ich aus der sache auch nicht.
ich hab da mal etwas rumprobiert, weils mich interessiert hat. und weil ich nicht extra was mit netzwerk und client/server machen wollte, hab ich ein QBuffer als IODevice für den stream genommen.

das ging bei mir auch nicht. wenn man das pixmap in den stream sendet, dann landet es auch im QBuffer (.size() meldet die größe). QBuffer.bytesAvaliable() berichtet hingegen weiter 0.
wenn man dann versucht aus dem stream zu lesen, wird einfach nichts gelesen, weil es offensichtlich nichts zu lesen gibt. deshalb schlägt auch das QPixmap.save() fehl. es wurde beim stream >> image; ein Null-pixmap erzeugt, daß man nicht saven kann.

all meine versuche den stream 'lesefähig' zu machen halfen nichts .QDataStrem hat ja kein flush oder sowas und der <<-operator kennt auch weder flush, noch endl, noch ends oder eof. auch das QIODevice bzw. den QBuffer 'unbufferd' zu machen brachte nichts.

letztendlich hab ich nach stream << image; einfach buffer.close(); gerufen - und sieheda, jetzt meldet buffer.bytesAvaliable() die buffergröße. wenn ich dann den buffer wieder mit open() öffne, dann klappt auch das stream >> image; und man kann es wie gewollt speichern.

natürlich macht es nun aber keinen sinn den TcpSocket (den du wohl verwendest) dauern zu- und wiederaufzumachen. aber die Socket-klasse hat ja eine flush()-funktion. ich vermute mal, wenn du die dann rufst, wird ein danach folgendes stream >> image; auch erfolgreich das pixmap lesen.
aber wie schon gesagt, das wollt ich dann nicht extra testen.


hoffe das hilft. berichte mal ob es geklappt hat. :)


gespannt ... Obel

Verfasst: 9. Januar 2008 19:51
von kochi
naja ich empfange über den QTcpSocket dem der QDataStream "stream" zugewiesen ist, also quasi das "stream >>" is das empfangen, oben in der if bedingung wartet er bis der Server etwas schickt, das readyRead und dann empfängt er es über den stream.

wie würdest du empfangen? kenne nur diese eine Methode

lg Kochi

Verfasst: 9. Januar 2008 20:11
von kochi
hoi, mein letzter post galt noch Christian81, hab mein absenden deinen post übersehn @ obel =)

Danke mal für deine antwort ;)


hab das auch gleich mal ausprobiert aber leider geht es trotzdem nicht =/

hab beim Server, das is die worker.cpp den flush dazugetan, der liefert auch ein true aber leider lässt es sich am client noch immer nicht speichern :(

Code: Alles auswählen

Worker.cpp
...
    QPixmap image("Logo.PNG");
    
    stream << image;
   cout << "QTcpSocket flush: " << stream.flush() << endl;

   if (!proband.waitForBytesWritten(TIMEOUT)) {
      //fehlerBehandeln(pServer->error());
      return;
   }
...
der client is wie bei meinem ersten post

hab ich das richtig verstanden mit dem flush? oda hab ich an schwachsinn ausprobiert? :D

PS: hab beim QT-Assistent das gefunden:

Related Non-Members
QDataStream & operator<< ( QDataStream & stream, const QPixmap & pixmap )

This is an overloaded member function, provided for convenience.
Writes the given pixmap to the the given stream as a PNG image. Note that writing the stream to a file will not produce a valid image file.
See also QPixmap::save() and Format of the QDataStream Operators.


kann sein das man bilder noch nicht übertragen kann? xD wozu gibt es diesen Non member wenn er am schluss eh nicht funktioniert? ^^

Verfasst: 9. Januar 2008 21:16
von ObeliX
hmm, schwer zu sagen ohne dein konzept zu kennen.

ich nehme mal an sowohl der send-block alsauch der receive-block stammen aus eigenen send-/receive-threads ? weil beide aufrufe ja blockierend arbeiten (zumindest für die timeout-dauer). und beim waitForReadyRead() macht es ja eigentlich nur mit -1 wirklich sinn, sonst ist es ja auch nur ein polling mit wartezeit.

mich verwirrt auch die doku zu den beiden funktionen. da wird erklärt wann true und wann false zurück gegeben wird und am ende steht, daß die default-implementierung nichts macht und immer false meldet. ja was denn nun ? ich steh da wohl etwas auf'm schlauch.
ich interpretiere das mal so, daß QIODevice nichts macht und die abgeleiteteten klassen (Q3Socket, Q3SocketDevice, QAbstractSocket, QBuffer, QFile und QProcess) sich so wie beschrieben verhalten. ist dann zwar schwachsinn, daß diese beschreibungen in der QIODevice-doku steh`n ... aber die trolle werden sich schon was dabei gedacht haben.

ich würd nach dem

Code: Alles auswählen

 
if (!proband.waitForBytesWritten(TIMEOUT)) {
  //fehlerBehandeln(pServer->error());
  return;
}
einfach mal ein proband.flush(); einfügen (ich unterstell mal, daß proband dein TcpSocket ist).

das wär's schon. sollte dann funzen, wenn ich mein QBuffer-testbeispiel richtig umorakelt habe :wink: . falls es nicht klappt mal davor einfügen. ansonsten weiß ich auch nicht weiter.

laß dir dann mal beim absenden vor und nach stream << image; proband.size() und proband.bytesAvaliable() ausgeben und auch nochmal nach dem waitForBytesWritten() und nach dem flush().
und beim empfangen ensprechend vor waitForReadyRead() und vor und nach stream >> image;.

ich wette in deiner anfangspost-version (also ohne flush()) wird zwar size() was zeigen aber avaliable() nichts. sodaß auch beim lesezugriff nichts passiert. das wird sich erst durchs flush() ändern.

ansonsten versteh ich das auch nicht :roll:


viel erfolg
Obel

Verfasst: 9. Januar 2008 21:26
von ObeliX
äh, siehste jetzt hab ich dein posting erst gesehn nachdem ich bereits geantwortet habe.

und ich bin ein wenig verwirrt. du hast stream.flush() compiliert bekommen ? was für einen stream hast du denn da ? ich dachte QDataStream. aber der hat doch garkeine flush()-funktion (oder hab ich was übersehn ?) !

das flush() war für das IODevice bestimmt, mit welchem dein (QData)Stream arbeitet.
Note that writing the stream to a file will not produce a valid image file.
heißt, daß du nicht << nutzen kannst um in einen file-stream zu schreiben. genauer gesagt kannst du das schon, aber das was dann auf der platte landet ist kein PNG-file (sondern nur binärdaten).


Obel

Verfasst: 9. Januar 2008 23:29
von kochi
Hello,

ahh sorry hab mich verschrieben, wollt eh den proband.flush() schreiben, hab ich auf im Programm, nur das Programm war am Laptop das Forum am Tower, un war zu faul am laptop kabel anstecken usw. xD

hab jetzt die size() und bytesAvailable() funktionen dazugehaut:


Code: Alles auswählen

Server:
---------
QPixmap image("Logo.PNG");
cout << "1: QTcpSocket Size: " << proband.size() << "   Bytes am Socket: " << proband.bytesAvailable() << endl;
stream << image;
cout << "2: QTcpSocket Size: " << proband.size() << "   Bytes am Socket: " << proband.bytesAvailable() << endl;
cout << "TCPFlush: " << proband.flush() << endl;
cout << "3: QTcpSocket Size: " << proband.size() << "   Bytes am Socket: " << proband.bytesAvailable() << endl;
if (!proband.waitForBytesWritten(TIMEOUT)) {
   //fehlerBehandeln(pServer->error());
   return;
}

Code: Alles auswählen

Client:
-------
cout << "1: QTcpSocket Size: " << pServer->size() << "   Bytes am Socket: " << pServer->bytesAvailable() << endl;
	
if (!pServer->waitForReadyRead(SERVER_TIMEOUT)) {
   //fehlerBehandeln(pServer->error());
   return;
}
	
QPixmap image;
cout << "2: QTcpSocket Size: " << pServer->size() << "   Bytes am Socket: " << pServer->bytesAvailable() << endl;
stream >> image;
   cout << "3: QTcpSocket Size: " << pServer->size() << "   Bytes am Socket: " << pServer->bytesAvailable() << endl;
   cout << stream.atEnd() <<" <-- Fertig?      speicher Test: " << image.save("here.png", "png") << endl;

un raus kommt dann:

Server Console:

Server bereit an
Verbunden mit neuem Client
1: QTcpSocket Size: 0 Bytes am Socket: 0
2: QTcpSocket Size: 0 Bytes am Socket: 0
TCPFlush: 1
3: QTcpSocket Size: 0 Bytes am Socket: 0



Client Console:

1: QTcpSocket Size: 0 Bytes am Socket: 0
2: QTcpSocket Size: 4380 Bytes am Socket: 4380
3: QTcpSocket Size: 0 Bytes am Socket: 0
1 <-- Fertig? speicher Test: 0

merkwürdig das er am server immer 0 hat aber am client dann vorm auslesen bytes hat, also übertragen wird was

er wills net speichern =/ und auch net anzeigen hmmmm

wenn ich die Pixmap auf nem Label anzeigen will kommt auf da console folgendes:
libpng error: Read Error

lg kochi

Verfasst: 10. Januar 2008 11:29
von ObeliX
hmm ??? :roll:

poste doch mal wie du das IODevice und den DataStream anlegst.

mglw. sind die 4380 bytes nur der overhead der zu nem leeren pixmap gehört ... ich weiß auch nicht. stell doch nach dem empfang mal fest wie groß (width and height) das pixmap ist und ob das null-flag gesetzt ist. kannst ja auch mal das client-image mit ner größe anlegen konstruktor(300,200) und abspeichern (sollte nen schwarzes rechteck rauskommen). ich denke nach dem stream >> image; ist das dann wieder 0,0 groß.

und das flush() würd ich erst nach dem waitForBytesWritten(); machen.


MfG Obel

Verfasst: 10. Januar 2008 20:19
von kochi
hab den flush jetzt hinter das waitfor gesetzt,

es speichert jetzt auch das Bild, aber nicht immer!! :shock:


hab mal 4 test verbindungen, hmm da server rennt und da client verbindet sich immer neu

1: QTcpSocket Size: 0 Bytes am Socket: 0
2: QTcpSocket Size: 4380 Bytes am Socket: 4380
3: QTcpSocket Size: 0 Bytes am Socket: 0
Breite: 0 Höhe: 0
1 <-- Fertig? speicher Test: 0

1: QTcpSocket Size: 0 Bytes am Socket: 0
2: QTcpSocket Size: 12938 Bytes am Socket: 12938
3: QTcpSocket Size: 0 Bytes am Socket: 0
Breite: 400 Höhe: 400
1 <-- Fertig? speicher Test: 1

1: QTcpSocket Size: 0 Bytes am Socket: 0
2: QTcpSocket Size: 7300 Bytes am Socket: 7300
3: QTcpSocket Size: 0 Bytes am Socket: 0
Breite: 0 Höhe: 0
1 <-- Fertig? speicher Test: 0

1: QTcpSocket Size: 0 Bytes am Socket: 0
2: QTcpSocket Size: 12938 Bytes am Socket: 12938
3: QTcpSocket Size: 0 Bytes am Socket: 0
Breite: 400 Höhe: 400
1 <-- Fertig? speicher Test: 1

ist hier nur zufall das es jedes 2 mal ging, es ist willkürlich, hmmm irgenwie ka woran das liegen könnt ...

aja noch meine definitionen vom stream und iodevice

Code: Alles auswählen

QTcpSocket proband;
proband.setSocketDescriptor(socketDesc);
QDataStream stream(&proband);
die zeilen stehn am Anfang von da run methode beim run(){...} block vom Server

am client schaut das so aus:

Code: Alles auswählen

pServer = new QTcpSocket(naechster); // im Konstruktor
...
void DerConnect::verbinde() {

  pServer->abort();
  pServer->connectToHost(server->text(), port->text().toInt());
  if (!pServer->waitForConnected(SERVER_TIMEOUT)) {
	//fehlerBehandeln(pServer->error());
	cout << "mislungen" << endl;
	return;
  }
  QDataStream stream(pServer);
  ...
lg kochi

Verfasst: 10. Januar 2008 23:26
von ObeliX
ok ... jetzt gehn mir aber wirklich die ideen aus :lol:

laß den waitfor...-kram doch einfach mal weg - zumindest beim senden. denn ich denke das brauchste garnicht (genauso wie das flush() eigentlich nicht nötig ist) und guck was passiert.

alternativ kannstes dann auch nochmal testweise durch ein while(proband.bytesToWrite()) usleep(50000); ersetzen.


Obel