2011-12-27 2 views
1

Я играю с Go (первый раз когда-либо), и я хочу создать инструмент для извлечения изображений из Интернета и разрезать их (даже изменить размер), но я застрял на первом шаге ,Чтение изображения из тела запроса HTTP в 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 */ 
} 

Я могу запросить изображение (давайте использовать логотип Google) и получить его вид и размер.

Действительно, я просто переписываю изображение (посмотрите на это как на игрушку «прокси»), установив Content-Length и Content-Type, и напишите байтовый фрагмент, но я где-то ошибаюсь. Посмотрите, как это выглядит финальное изображение, вынесенное Chromium 12.0.742.112 (90304):

Grotesque result

Также я проверил загруженный файл, и это 7007 байт PNG изображения. Он должен работать должным образом, если посмотреть по запросу:

GET/вырезать HTTP/1.1
User-Agent: завиток/7.22.0 (i486-ПК-Linux-гну) Libcurl/7.22.0 OpenSSL/1.0.0e Zlib/1.2.3.4 libidn/1,23 libssh2/1.2.8 librtmp/2,3
Хост: 127.0.0.1:8080
Accept: /

HTTP/1.1 200 OK
Контент-длина: 7007
Content-Type: изображение/PNG
Дата: Вт, 27 декабря 2011 19:51:53 GMT

[данные PNG]

Что вы думаете, что я здесь делаю неправильно?

Отказ от ответственности: я почесываю свой собственный зуд, поэтому, возможно, я использую неправильный инструмент :) Во всяком случае, я могу реализовать его на Ruby, но прежде чем я хочу дать попробовать.

Обновление: по-прежнему царапины зуда, но ... Я думаю, что это будет хороший побочный проект, поэтому я его открываю https://github.com/imdario/go-lazor Если это не полезно, по крайней мере, кто-то может найти полезность со ссылками используется для его развития. Они были для меня.

ответ

8

Я пробовал свой код и заметил, что изображение, которое вы обслуживали, было правильного размера, но содержимое файла, прошедшего через определенную точку, было 0x00.

Отзыв io.Reader documentation. Важно помнить, что Read читает до количество байтов, которое вы запрашиваете. Он может читать меньше, без ошибок. (Вы также должны проверить ошибку, но это не проблема.)

Если вы хотите, чтобы ваш буфер был полностью заполнен, используйте io.ReadFull. В этом случае проще всего скопировать все содержимое Reader с помощью io.Copy.

Также важно помнить о закрытии объектов запроса HTTP.

Я бы переписать код так:

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

Я собираюсь проверить это позже. То, что вы сказали, выглядит правильно (я не думал о возможных 0x0 байтах на изображении). Благодаря! –

+0

io.Copy не работает должным образом. Запрос усекает после записи заголовков, и я не обнаружил ошибок. В любом случае, я решил с помощью ReadFull: https://gist.github.com/1528886 Если вы хотите, отредактируйте свое решение с помощью того, что я использовал, только для справки. Я принимаю ваш ответ, когда вы указали правильный путь. Благодаря! –

+0

Извините, была опечатка, из-за которой он не работал (перепутал req и reqImg). Я исправил код, и он работает с io.Copy. –

7

Я думаю, что вы зашли слишком быстро к служить вещи часть.

Фокус на первом шаге, Скачивание изображения.

Здесь у вас есть небольшая программа, которая загружает это изображение в память.
Он работает на моей еженедельной версии 2011-12-22, для r60.3 вам просто нужно устранить импорт.

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á!

Это изображение будет отображаться внутри data.
После этого вы можете его декодировать, обрезать и вернуться в браузер.

Надеюсь, это поможет.

Смежные вопросы