WN

WN (https://www.wn.se/forum/index.php)
-   Serversidans teknologier (https://www.wn.se/forum/forumdisplay.php?f=4)
-   -   Ta emot bild via POST-anrop (https://www.wn.se/forum/showthread.php?t=30010)

etanders 2008-06-18 17:20

Jag kör C#/ASP.NET 3.5 och vill ta emot en uppladdad bild från en källa utanför C#-applikationen. Jag gör ett POST-anrop till en .ashx-sida där jag vill ta hand om bilden för att sedan kunna spara i databasen. Har försökt på olika sätt, men lyckas inte riktigt få till det.

Kod:

// ImageHandler.ashx

public class ImageHandler : IHttpHandler
{
  public void ProcessRequest(HttpContext context)
  {
    Stream stream = context.Request.InputStream;

    //Image image = Image.FromStream(stream);

    byte[] bytes = new byte[stream.Length];
    stream.Read(bytes, 0, bytes.Length);
    string str = Convert.ToBase64String(bytes);
  }
}

Den bortkommenterade raden ger ArgumentException, "Parametern är inte giltig", så det fungerar uppenbarligen inte.

Om jag tar innehållet i str och "decodar" på http://www.toastedspam.com/decode64 så får jag fram följande

Kod:

----------11a9bf2ff31--------21523374577461
Content-Disposition: form-data; name="myImage"; filename="theFilename.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: base64

/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABTAHQDASIA
AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
  (forts...)

Alltså lyckas ju överföringen i någon mening - det jag vill ha tag på "finns" ju... Men hur gör jag för att få ut datan (i det här fallet bilden) som är kodad här så att jag kan använda den i C#?

EDIT:
Använder man FileUpload-kontrollen i ASP.NET är det självklart inga problem att "hitta" bilden, då funkar det utmärkt med
Kod:

Image image = Image.FromStream(FileUpload1.PostedFile.InputStream);
Men i detta fall kommer alltså POST-anropet inte från ASP.NET-applikationen. Tips på lösningar på motsvarande problem i andra miljöer (t.ex. php) är också intressanta!

KarlRoos 2008-06-18 17:46

Jag har själv haft problem när jag inte fattat vad problemet varit (i PHP då).

Tillslut kom jag på att jag hade glömt <form enctype="multipart/form-data" action="?post" method="POST"> <_<

etanders 2008-06-18 17:51

context.Request.ContentType = "multipart/form-data; boundary=--------11a9bf2ff31--------21523374577461" så jag tror inte det är problemet.

Jake.Nu 2008-06-18 19:26

Ser ut som du gör om datan som kommer till base64 ytterligare en gång?

Kod:

string str = Convert.ToBase64String(bytes);
Filen som skickas från sändande part är väl redan i base64-format?

Kod:

string str = Convert.FromBase64String(bytes);
känns mer rätt (om den funktionen ens finns).

digiArt 2008-06-18 22:23

Rätt svar:


Kod:

    HttpPostedFile htf = context.Request.Files[0];
    System.IO.Stream stream = htf.InputStream;
    System.Drawing.Image im = System.Drawing.Image.FromStream(stream);


etanders 2008-06-19 00:01

digiArt:
Det är ju en rätt naturlig lösning, så jag har redan försökt. Problemet är att context.Request.Files är tom...


Jake.Nu:
Convert.ToBase64String() gör om en byte[] till en string.
Citat:

"Converts an array of 8-bit unsigned integers to its equivalent String representation encoded with base 64 digits. ...
The elements of inArray are taken as a numeric value and converted to a String representation encoded with base 64 digits."
http://msdn.microsoft.com/en-us/library/dhx0d524.aspx

Det finns också Convert.FromBase64String() som gör om en string till en byte[].
Citat:

"Converts the specified String, which encodes binary data as base 64 digits, to an equivalent 8-bit unsigned integer array."
http://msdn.microsoft.com/en-us/library/sy...se64string.aspx

Det jag får fram i variabeln str i mitt första inlägg är hela innehållet i post-anropet i kodad form. Convert.ToBase64String gör bara om det från binär form till en sträng. I klartext är det en massa tecken i en följd.
Kod:

LS0tLS0tLS0tLTExYTlkOWVhYmI5LS0tLS0tLS0yMTUyMzU0NzUyNTY3MQ0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJwYXN0ZWRJbWFnZSI7IGZpbGVuYW1lPSJ0aGVGaWxlbmFtZS5qcGciDQp (forts...)
Om jag, som jag beskrev i första inlägget, kör denna sträng i en base64-decoder (http://www.toastedspam.com/decode64) får jag det resultat som jag också visade i mitt första inlägg. Där ser man först i klartext headern med Content-Disposition, Content-Type m.m. Därefter kommer själva bilden kodad i base64. Och om jag klipper ut bara den texten och kör i http://www.toastedspam.com/decode64 igen så visas faktiskt bilden, så det stämmer.

För att sammanfatta, det jag får fram ur context.Request.InputStream måste först base64-decodas en gång för att skilja ut headers och själva datan. Denna data måste sedan base64-decodas en gång till för att få själva bilden. Det är lätt att tappa bort sig här...

Det konstiga är ju att ASP.NET lyckas tyda headerinformationen, för den finns med i bl.a. context.Request.ContentType och context.Request.Headers, men context.Request.Files är som sagt tom.

Någon funktion för konvertering motsvarande den som görs på http://www.toastedspam.com/decode64 har jag inte hittat i .NET, ännu i alla fall.

Någon som har fler bra idéer?

digiArt 2008-06-19 08:33

Jag hade också problem med att Request.Files var tom, men sätt ett namn på input-fältet så löser det sig.

etanders 2008-06-19 09:34

digiArt, tack för att du engagerar dig, men titta i mitt första inlägg. Efter ett par varv i base64-decodern får jag fram följande
Kod:

----------11a9bf2ff31--------21523374577461
Content-Disposition: form-data; name="myImage"; filename="theFilename.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: base64

/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABTAHQDASIA
AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
  (forts...)

Raden med Content-Disposition innehåller väl det som motsvarar namnet på inputfältet, här "myImage", eller?

Sedan är ju saken också den att anropet inte kommer från ett vanligt html-formulär, utan en javaapplet. Kan det vara i den änden problemet ligger?

funcall 2008-06-19 14:33

Borde inte detta funka?
Kod:

StreamReader sra = New StreamReader(context.Request.InputStream, System.Text.Encoding.UTF8);
System.Drawing.Image fullSizeImg = System.Drawing.Image.FromStream(sra.BaseStream);


etanders 2008-06-19 15:07

Tack för tipset, funcall! Jag får System.ArgumentException "Parametern är inte giltig." när jag provar ditt förslag, men det ger åtminstone några nya uppslag att experimentera vidare med.

Jag har i alla fall lyckats få in filen i context.Request.Files nu...

funcall 2008-06-19 15:52

Vad är det som felar? altså vilken rad?

etanders 2008-06-19 16:06

Just nu är läget detta...

Kod:

public void ProcessRequest(HttpContext context)
{
  var httpPostedFile = context.Request.Files[0];
  var path = ... // sökväg för att spara filen
  var streamReader = new StreamReader(httpPostedFile.InputStream, System.Text.Encoding.UTF8);
  var image = Image.FromStream(streamReader.BaseStream);

  try
  {
    image.Save(path);
  }
  catch (Exception e)
  {
    var bitmap = new Bitmap(image);
    bitmap.Save(path);
  }
}

image.Save() i try ger
Kod:

System.Runtime.InteropServices.ExternalException
"Ett allmänt fel uppstod i GDI+."

Däremot funkar bitmap.Save() i catch, och jag får en fil med rätt höjd och bredd, men innehållet är inte riktigt.

funcall 2008-06-19 16:11

Har du kollat så inputstreamen är UTF8 ?

etanders 2008-06-19 16:20

Nej, hur kan jag göra det?

Men jag har provat med alla varianter av Encoding; ASCII, BigEndianUnicode, Default, Unicode, UTF32, UTF7 och UTF8. Det är ingen skillnad alls.

funcall 2008-06-19 16:32

Ok du kan ju skriva ut och jämföra.

Annars kan du testa
var streamReader = new StreamReader(httpPostedFile.InputStream);
eller
var streamReader = new StreamReader(httpPostedFile.InputStream, true);

etanders 2008-06-19 17:04

Troligen fungerar C#-koden jag har nu, men frågan är om bilden kodas på rätt sätt när den sänds från javaappleten.

Jag använder java.awt.image.BufferedImage och beroende på vad jag sätter för imageType i konstruktorn, så får jag olika förvrängda resultat i .NET-applikationen...

Får läsa på och experimentera mera helt enkelt :)

digiArt 2008-06-19 17:09

Kod:


Image im = Bitmap.FromStream(stream);

im.Save(path);

Koden ovan är otestad, det är lite klipp och klistra från en funktion i min egen webbplats.

Det som återstår är att kolla vilken typ av bild som du egentligen tar emot (om det är en bild öht, någon kanske skickar ett worddokument) för att sätta rätt ImageFormat.

etanders 2008-06-19 17:29

digiArt, det funkar inte. Blir samma fel som jag beskrev i inlägget kl 16.06.

Provade just att läsa in en jpg-fil direkt
Kod:

var originalImage = Image.FromFile(context.Request.PhysicalApplicationPath + "image.jpg");
originalImage.Save(path);

Detta funkar fint.

Jämförde också formatet hos bilderna
Kod:

image.RawFormat.Guid == originalImage.RawFormat.Guid == ImageFormat.Jpeg.Guid
bitmap.RawFormat.Guid == ImageFormat.MemoryBmp.Guid

Tror som sagt att det återstående problemet ligger i javaappleten och hur bilden kodas där innan den skickas.

Vimp 2008-06-21 23:53

Kan du inte skapa upp din request mot sidan du postar till själv i java-applikationen och bara skicka med den informationen som behövs?

etanders 2008-06-23 11:37

Jo, det är just det jag vill göra (om jag förstår dig rätt).

Mitt första problem var att få till javakoden för requesten så att jag överhuvudtaget kom åt filen i .net-applikationen. Det lyckades till slut.

Mitt problem nu är hur jag ska omvandla mitt java.awt.Image-objekt till någon form av strängrepresentation som kan överföras i requesten och som jag kan lyckas omvandla tillbaka till ett System.Drawing.Image-objekt i .net.

Kod:

// Java
  private void postImage(Image image)
  {
    BufferedImage buffImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    ImageIcon imageIcon = new ImageIcon(image);
    ImageObserver observer = imageIcon.getImageObserver();

    buffImage.getGraphics().setColor(new Color(255, 255, 255));
    buffImage.getGraphics().fillRect(0, 0, width, height);
    buffImage.getGraphics().drawImage(imageIcon.getImage(), 0, 0, observer);

    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    JPEGImageEncoder jpeg = JPEGCodec.createJPEGEncoder(stream);
    jpeg.encode(buffImage);

    URL url = new URL(m_postUrl);
    URLConnection connection = url.openConnection();
     
    String boundary = "--------" + Long.toHexString(System.currentTimeMillis()) + "--------" + Long.toOctalString(System.currentTimeMillis());
   
    connection.setRequestProperty("method", "POST");
    connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
   
    String output =
        "--" + boundary + "\r\n"
        + "Content-Disposition: form-data; name=\"theFirst\"\r\n"
        + "Content-Type: text/plain\r\n"
        + "Content-Transfer-Encoding: quoted-printable\r\n\r\n"
        + "Testar ett litet meddelande.\r\n"
        + "--" + boundary + "\r\n"
        + "Content-Disposition: form-data; name=\"pastedImage\"; filename=\"theFilename.jpg\"\r\n"
        + "Content-Type: image/jpeg\r\n"
        + "Content-Transfer-Encoding: base64\r\n\r\n"
        + Base64.encode(stream.toByteArray())
        //+ new String(stream.toByteArray())
        + "\r\n"
        + "--" + boundary + "--\r\n";
   
    connection.setDoOutput(true);
    connection.getOutputStream().write(output.getBytes());
    connection.connect();
  }

Jag har provat både med och utan base64-kodning (rad 7 från slutet), men vad jag väljer för argument i första raden (BufferedImage.TYPE_INT_RGB) påverkar resultatet i filen jag till slut får ut i .net. Tips, någon?

Vimp 2008-06-23 11:41

Måste du posta den som en bild? Kan du inte bara posta som rådata och sedan låta .NET behandla den som en bild?

etanders 2008-06-23 15:02

Visst, vilken typ av "rådata" skulle du rekommendera?

Vimp 2008-06-23 16:04

Jag tänkte att du kanske bara kan plocka ner alla bytes och skicka direkt till nästa sida. Som det är nu skapar du upp ett nytt Image-objekt med bilden. Du kan t.ex. plocka ner streamen, lagra direkt som en base64-enkodad sträng utifrån din byte-array och sedan göra tvärtom i .NET-applikationen. Dvs skippa hela biten med att spara om den som en bild i java.

etanders 2008-06-23 16:27

Det jag har som utgångspunkt är Image-objektet i java. Hur konverterar man det bäst till en bytearray? Dessutom måste jag ju koda det som jpeg (eller annat bildformat) eftersom javas Image är en intern representation.

Vimp 2008-06-24 11:08

Måste du ta emot en Image i parametern? När du postar bilden till java-applikationen, får du då inte en byte-array? Den byte-arrayen kan du sedan skicka vidare utan modifikation och posta till nästa sida, antingen som den är, eller som t.ex. en base64-kodad sträng.

Genom att göra om den till ett objekt i java så måste du på något sätt serialisera den eller skapa en ny bild (som du gör nu). Det bästa är om du kan skicka vidare den som den är till .NET-applikationen.

etanders 2008-06-24 14:23

Fast grejen är att jag aldrig postar någon bild till javaapplikationen. "Originalet" är Image-objektet...

Vimp 2008-06-24 14:35

Ahaa, jag hade fått för mig att du laddade upp bilden till java-applikationen och bara skulle vidarebefordra den till ASP.NET-sidan. My mistake.

Om du tar base64-strängen direkt till ASP.NET-sidan och försöker visa (utan att posta från javan), kan du då visa upp bilden?

etanders 2008-06-24 14:56

Citat:

Originally posted by etanders@Jun 19 2008, 00:01
Det jag får fram i variabeln str i mitt första inlägg är hela innehållet i post-anropet i kodad form. Convert.ToBase64String gör bara om det från binär form till en sträng. I klartext är det en massa tecken i en följd.
Kod:

LS0tLS0tLS0tLTExYTlkOWVhYmI5LS0tLS0tLS0yMTUyMzU0NzUyNTY3MQ0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJwYXN0ZWRJbWFnZSI7IGZpbGVuYW1lPSJ0aGVGaWxlbmFtZS5qcGciDQp (forts...)
Om jag, som jag beskrev i första inlägget, kör denna sträng i en base64-decoder (http://www.toastedspam.com/decode64) får jag det resultat som jag också visade i mitt första inlägg. Där ser man först i klartext headern med Content-Disposition, Content-Type m.m. Därefter kommer själva bilden kodad i base64. Och om jag klipper ut bara den texten och kör i http://www.toastedspam.com/decode64 igen så visas faktiskt bilden, så det stämmer.

Se ovan från ett tidigare svar i denna tråd. I någon mening har jag ju tillgång till rätt data, det gäller bara att konvertera den mellan olika format tills det blir rätt...

Vimp 2008-06-24 15:33

Du kanske kan ha en web service som tar emot din base64-sträng?


Alla tider är GMT +2. Klockan är nu 07:44.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson