2011-12-27 3 views
1

Je joue avec Go (première fois) et je veux construire un outil pour récupérer des images d'Internet et les couper (même redimensionner) mais je suis bloqué sur la première étape .Lire l'image du corps de la requête HTTP dans Go

package main 

import (
    "fmt" 
    "http" 
) 

var client = http.Client{} 

func cutterHandler(res http.ResponseWriter, req *http.Request) { 
    reqImg, err := client.Get("http://www.google.com/intl/en_com/images/srpr/logo3w.png") 
    if err != nil { 
    fmt.Fprintf(res, "Error %d", err) 
    return 
    } 
    buffer := make([]byte, reqImg.ContentLength) 
    reqImg.Body.Read(buffer) 
    res.Header().Set("Content-Length", fmt.Sprint(reqImg.ContentLength)) /* value: 7007 */ 
    res.Header().Set("Content-Type", reqImg.Header.Get("Content-Type")) /* value: image/png */ 
    res.Write(buffer) 
} 

func main() { 
    http.HandleFunc("/cut", cutterHandler) 
    http.ListenAndServe(":8080", nil) /* TODO Configurable */ 
} 

Je suis en mesure de demander une image (utilisons le logo Google) et d'obtenir son genre et sa taille. En fait, je ne fais que réécrire l'image (regardez cela comme un jouet "proxy"), en définissant Content-Length et Content-Type et en écrivant la tranche d'octets, mais je me trompe quelque part. Voir à quoi il ressemble l'image finale rendue le chrome 12.0.742.112 (90304):

Grotesque result

J'ai également vérifié le fichier téléchargé et il est une image PNG 7007 octets. Il devrait fonctionner correctement si nous regardons à la demande:

GET/cut HTTP/1.1
User-Agent: curl/7.22.0 (i486-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.0e zlib/1.2.3.4 libidn/1,23 libssh2/1.2.8 librtmp/2.3
hôte: 127.0.0.1:8080
Accept: /

HTTP/1.1 200 OK
Longueur du contenu: 7007
Content-Type: image/png
Date: Mar 27 décembre 2011 19:51:53 GMT

[données PNG]

Que pensez-vous que je fais mal ici? Je suis en train de gratter mes propres démangeaisons, donc probablement je n'utilise pas le bon outil :) Quoi qu'il en soit, je peux l'implémenter sur Ruby mais avant de vouloir essayer Go.

Mise à jour: gratte encore les démangeaisons mais ... Je pense que ça va être un bon projet de side-of-side donc je l'ouvre https://github.com/imdario/go-lazor Si ce n'est pas utile, au moins quelqu'un peut trouver l'utilité avec les références utilisé pour le développer. Ils étaient pour moi.

Répondre

8

J'ai essayé votre code et j'ai remarqué que l'image que vous diffusiez était de la bonne taille, mais le contenu du fichier après un certain point était tout 0x00.

Passez en revue le. La chose importante à retenir est que Read lit jusqu'à le nombre d'octets que vous demandez. Il peut lire moins sans erreur retournée. (Vous devriez aussi vérifier l'erreur, mais ce n'est pas un problème ici.)

Si vous voulez vous assurer que votre tampon est complètement plein, utilisez io.ReadFull. Dans ce cas, il est plus simple de copier tout le contenu du Reader avec io.Copy.

Il est également important de ne pas oublier de fermer les corps de requête HTTP.

Je réécrire le code de cette façon:

package main 

import (
    "fmt" 
    "http" 
    "io" 
) 

var client = http.Client{} 

func cutterHandler(res http.ResponseWriter, req *http.Request) { 
    reqImg, err := client.Get("http://www.google.com/intl/en_com/images/srpr/logo3w.png") 
    if err != nil { 
     fmt.Fprintf(res, "Error %d", err) 
     return 
    } 
    res.Header().Set("Content-Length", fmt.Sprint(reqImg.ContentLength)) 
    res.Header().Set("Content-Type", reqImg.Header.Get("Content-Type")) 
    if _, err = io.Copy(res, reqImg.Body); err != nil { 
     // handle error 
    } 
    reqImg.Body.Close() 
} 

func main() { 
    http.HandleFunc("/cut", cutterHandler) 
    http.ListenAndServe(":8080", nil) /* TODO Configurable */ 
} 
+0

Je vais vérifier cela plus tard. Ce que vous avez dit a l'air correct (je ne pensais pas en 0x0 octets possibles dans l'image). Merci! –

+0

io.Copie ne fonctionne pas comme prévu. La requête tronque après avoir écrit les en-têtes et je ne trouve aucune erreur. Quoi qu'il en soit, j'ai résolu avec le ReadFull: https://gist.github.com/1528886 Si vous le souhaitez, modifiez votre solution avec ce que j'ai utilisé, juste pour référence. J'accepte votre réponse comme vous l'avez indiqué de la bonne façon. Merci! –

+0

Désolé, il y avait une faute de frappe qui l'a empêché de fonctionner (confusion entre req et reqImg). J'ai corrigé le code et cela fonctionne avec io.Copy. –

7

Je pense que vous êtes allé trop vite pour la servir les choses partie.

Concentrez-vous sur la première étape, en téléchargeant l'image.

Ici, vous avez un petit programme qui télécharge cette image en mémoire.
Cela fonctionne sur ma version hebdomadaire 2011-12-22, pour r60.3 vous avez juste besoin de gofix les importations.

package main 

import (
    "log" 
    "io/ioutil" 
    "net/http" 
) 

const url = "http://www.google.com/intl/en_com/images/srpr/logo3w.png" 

func main() { 
    // Just a simple GET request to the image URL 
    // We get back a *Response, and an error 
    res, err := http.Get(url) 

    if err != nil { 
     log.Fatalf("http.Get -> %v", err) 
    } 

    // We read all the bytes of the image 
    // Types: data []byte 
    data, err = ioutil.ReadAll(res.Body) 

    if err != nil { 
     log.Fatalf("ioutil.ReadAll -> %v", err) 
    } 

    // You have to manually close the body, check docs 
    // This is required if you want to use things like 
    // Keep-Alive and other HTTP sorcery. 
    res.Body.Close() 

    // You can now save it to disk or whatever... 
    ioutil.WriteFile("google_logo.png", data, 0666) 

    log.Println("I saved your image buddy!") 
} 

Voilá!

Ceci va mettre l'image en mémoire à l'intérieur data.
Une fois que vous l'avez, vous pouvez le décoder, le recadrer et le renvoyer au navigateur.

Espérons que cela aide.

Questions connexes