Чтение изображения из тела HTTP-запроса в Go - PullRequest
3 голосов
/ 27 декабря 2011

Я играю с 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

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

GET / cut HTTP / 1.1Пользователь-агент: 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.3Host: 127.0.0.1:8080Принять: /

HTTP / 1.1 200 OKДлина контента: 7007Тип контента: изображение / PNGДата: вторник, 27 декабря 2011 г. 19:51:53 GMT

[данные PNG]

Как вы думаете, что я здесь не так делаю?

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

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

Ответы [ 2 ]

8 голосов
/ 03 января 2012

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

Сосредоточьтесь на первом шаге, загрузив изображение .

Здесьу вас есть небольшая программа, которая загружает это изображение в память.
Она работает на моей еженедельной версии 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!")
}

Вуаля!

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

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

8 голосов
/ 28 декабря 2011

Я попробовал ваш код и заметил, что изображение, которое вы обслуживаете, имело правильный размер, но содержимое файла после определенной точки было 0x00.1004 *.Важно помнить, что 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 */
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...