Converting multipart file to an image object in golang - go

I'm attempting to upload an image, resize it and then upload it to Amazon S3 in go, however I'm struggling to figure out how to convert the image from multipart.File to image.Image
package controllers
import (
"github.com/gin-gonic/gin"
"github.com/mitchellh/goamz/aws"
"github.com/mitchellh/goamz/s3"
"github.com/nfnt/resize"
_ "image/jpeg"
"log"
"os"
"strconv"
)
type ResizeController struct {
}
func NewResizeController() *ResizeController {
return &ResizeController{}
}
func (rc ResizeController) Resize(c *gin.Context) {
auth, err := aws.EnvAuth()
if err != nil {
log.Fatal(err)
}
client := s3.New(auth, aws.EUWest)
bucket := client.Bucket(os.Getenv("AWS_BUCKET_NAME"))
file, header, err := c.Request.FormFile("file")
filename := header.Filename
height := c.Query("height")
width := c.Query("width")
h64, err := strconv.ParseUint(height, 10, 32)
w64, err := strconv.ParseUint(width, 10, 32)
h := uint(h64)
w := uint(w64)
m := resize.Resize(w, h, file, resize.Lanczos3)
err = bucket.Put("/content/"+filename, m, "content-type", s3.Private)
c.JSON(200, gin.H{"filename": header.Filename})
}
I'm getting the error controllers/resize_controller.go:43: cannot use file (type multipart.File) as type image.Image in argument to resize.Resize:

Figured it out, I just needed to use
image, err := jpeg.Decode(file)

Related

Sending a CSV file Server to Client

I've just recently started trying to learn Go and I'm trying to write a small server/client application for sending a csv file, from a server to a client. I'm running into an invalid type error when trying to encode a struct into BigEndian binary. My struct seems to already be in a binary format, I'm unsure why I get the following error:
Error writing binary buffer to big endian binary.Write: invalid type *main.DataPack
Also, I'd like to keep the TCP connection open after sending the file, that's why I'm not using io.Copy.
Currently I'm triggering the handling of the file upload through by sending a '\x00' byte:
// Server
package main
import (
"path/filepath"
"fmt"
"io/ioutil"
"net"
"os"
"encoding/binary"
"bytes"
)
type DataPack struct {
Length int64
Contents []byte
}
func main() {
absPath, _ := filepath.Abs("./progs.csv")
data, _ := ioutil.ReadFile(absPath)
fmt.Println("%s",data)
tel, err := net.Listen("tcp", "0.0.0.0:23")
if err != nil {
fmt.Println(err)
return
}
for {
conn, err := tel.Accept()
if err != nil {
break
}
fmt.Println("above filehandler")
go fileHandler(conn)
}
}
func fileHandler(conn net.Conn) {
buf := make([]byte, 0)
buf = append(buf, '\x00')
conn.Write(buf)
absPath, _ := filepath.Abs("./progs.csv")
file, err := os.Open(absPath)
defer file.Close()
fi, err := file.Stat()
if err != nil {
fmt.Println("Fatal error reading file: ", err)
}
fmt.Println("This is the length of the file: ", fi.Size())
data := &DataPack{Length: fi.Size()} // , Contents: }
data.Contents = make([]byte, data.Length)
n, err := file.Read(data.Contents)
if err != nil {
fmt.Println("error reading contents into struct: ", err)
}
fmt.Println("tried to read file contents: ", n)
fmt.Println("DataPack: %+v", data)
buf1 := new(bytes.Buffer)
err = binary.Write(buf1, binary.BigEndian, &data)
if err != nil {
fmt.Println("Error writing binary buffer to big endian ", err)
}
conn.Write(buf1.Bytes())
}
Here is the client
package main
import (
"log"
"fmt"
"net"
"strings"
"strconv"
"bufio"
)
const (
host = "127.0.0.1"
port = 23
)
func main() {
addr := strings.Join([]string{host, strconv.Itoa(port)}, ":")
client := NewClient()
var err error
client.socket, err = net.Dial("tcp", addr)
if err != nil {
log.Println("error setting up socket: %s", err)
}
for {
m := bufio.NewReader(client.socket)
b, err := m.ReadByte()
if err != nil {
fmt.Println("here is the error: ", err)
}
if b == '\x00'{
fmt.Println("about to receive a file!!!")
b, _ := m.ReadByte()
fmt.Println("just got another byte ", b )
}
}
log.Printf("Over")
}
why you get the error
Visit https://golang.org/pkg/encoding/binary/#Write
Write writes the binary representation of data into w. Data must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
type DataPack struct {
Length int64
Contents []byte
}
Contents isn't a fixed-size value, so you got the invalid type error.
how to solve it
go binary
json
others

How to upload file to amazon s3 using gin framework

I am trying to upload a file to Amazon S3 Using gin framework of Go. Since aws-sdc requires to read the file i need to open file using os.open('filename').But since i am getting the file from "formFile" I don't have the path of the file to open, so os.Open() is giving error
The system cannot find the file specified.
My approach is as follows
package controllers
import (
"bytes"
"log"
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
const (
S3_REGION = "MY REGION"
S3_BUCKET = "<MY BUCKET>"
)
func UploadDocument(c *gin.Context) {
var Buf bytes.Buffer
file, _ := c.FormFile("file")
creds := credentials.NewSharedCredentials("", "default")
s, err := session.NewSession(&aws.Config{
Region: aws.String(S3_REGION),
Credentials: creds,
})
if err != nil {
log.Fatal(err)
}
err = AddFilesToS3(s, file.fileName)
if err != nil {
log.Fatal(err)
}
}
func AddFilesToS3(s *session.Session, fileDir string) error {
file, err := os.Open(fileDir)
if err != nil {
return err
}
defer file.Close()
fileInfo, _ := file.Stat()
var size int64 = fileInfo.Size()
buffer := make([]byte, size)
file.Read(buffer)
_, err = s3.New(s).PutObject(&s3.PutObjectInput{
Bucket: aws.String(S3_BUCKET),
Key: aws.String("myfolder" + "/" + fileDir),
ACL: aws.String("private"),
Body: bytes.NewReader(buffer),
ContentLength: aws.Int64(size),
ContentType: aws.String(http.DetectContentType(buffer)),
ContentDisposition: aws.String("attachment"),
ServerSideEncryption: aws.String("AES256"),
})
return err
}
I am sending my file through POSTMAN like this
what I need to pass to my 'AddFilesToS3' function, since I am sending just the file name, os.Open(fileDir) is failing to look to the actual path of the file.
Where am I doing wrong or is there any better method available to do this?
You're not even reading the file from the form.
You need to call FileHeader.Open. This returns a multipart.File which implements the standard io.Reader interface.
You should change AddFilesToS3 to take a filename and io.Reader. This can then be called for files from gin as well as regular files.
fileHeader, err := c.FormFile("file")
// check err
f, err := fileHeader.Open()
// check err
err = AddFilesToS3(s, fileHeader.fileName, f)
And your AddFilesToS3 is now:
func AddFilesToS3(s *session.Session, fileDir string, r io.Reader) error {
// left as an exercise for the OP
You may need to pass fileHeader.Size() as well.

Not able to decode different image formats in GOLANG (assignment count mismatch)

I want to decode images of different formats and I'm running into problems calling image.Decode.
Here's my code and here's the error I'm seeing:
/myproject.go:21: assignment count mismatch: 2 = 3
package main
import (
"fmt"
"image"
"log"
"os"
)
func check(e error) {
if e != nil {
log.Fatal(e)
}
}
func loadanddeconde(filename string) image.Image {
reader, err := os.Open(filename)
check(err)
defer reader.Close()
/*21.line*/ img, err := image.Decode(reader)
check(err)
return img
}
func main() {
img := loadanddeconde("/home/gomok/Bureau/JSK.jpg")
fmt.Printf("IMAGE TYPE: %T \n", img)
}
So that's just the go compiler saying you're getting 3 values returned from image.Decode and you're only assigning 2 of them.
Do this:
img, format, err := image.Decode(reader)
fmt.Printf("Image Type: %s\n", format)

Golang AES decrypt video before streaming it though http

Im trying to stream AES encrypted video file; however we need to decrypt it on the fly before streaming it though http
how to write the output of decrypted data to http writer
package main
import (
"crypto/aes"
"crypto/cipher"
"io"
"log"
"net/http"
"os"
)
var key []byte = []byte("yourAESPrivateKey")
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
inFile, err := os.Open("2.ts")
if err != nil {
log.Fatal(err)
}
defer inFile.Close()
block, err := aes.NewCipher(key)
if err != nil {
log.Fatal(err)
return
}
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
w.Header().Set("Content-type", "video/mp4")
writer := &cipher.StreamWriter{S: stream, W: w}
if _, err := io.Copy(writer, inFile); err != nil {
log.Fatal(err)
return
}
//http.ServeContent(w, r, "video.mp4", time.Now(), inFile)
}
func main() {
http.HandleFunc("/", ServeHTTP)
http.ListenAndServe(":2020", nil)
}
i have enhanced my code
so if i requested an encrypted file, the server will decrypt it and serve it properly, however i have another problem as below
the problem now is that i get corrupted file if file exceeds certain size.
i have done some tests on text files for debugging purposes and so i can post data results here (big corrupted file) check the end of the file
package main
import (
"crypto/aes"
"crypto/cipher"
"log"
"net/http"
"os"
"time"
)
type cipherHttpWriter struct {
http.ResponseWriter
}
func (c cipherHttpWriter) Write(b []byte) (int, error) {
var key []byte = []byte("we!#09bsa$.a-ala.HJOqweK45aghf&A")
block, err := aes.NewCipher(key)
if err != nil {
return 0, err
}
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
streamWriter := &cipher.StreamWriter{S: stream, W: c.ResponseWriter}
defer streamWriter.Close()
return streamWriter.Write(b)
}
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
inFile, err := os.Open(string(r.URL.Path[1:]))
if err != nil {
log.Fatal(err)
}
defer inFile.Close()
writer := cipherHttpWriter{}
writer.ResponseWriter = w
http.ServeContent(writer, r, "", time.Now(), inFile)
}
func main() {
http.HandleFunc("/", ServeHTTP)
http.ListenAndServe(":2020", nil)
}

Save an image from url to file

Very new to Go (first simple project I'm working on).
Question: How do I get an image from URL and then save it to my computer?
Here's what I have so far:
package main
import (
"fmt"
"net/http"
"image"
"io/ioutil"
)
func main() {
url := "http://i.imgur.com/m1UIjW1.jpg"
// don't worry about errors
response, _ := http.Get(url);
defer response.Body.Close()
m, _, err := image.Decode(response.Body)
error := ioutil.WriteFile("/images/asdf.jpg", m, 0644)
}
However, when I run this code, I get cannot use m (type image.Image) as type []byte in function argument
I'm assuming I have to convert image.Image (variable m) into an undefined amount of bytes? Is that the correct way to go about this?
There is no need to decode the file. Simply copy the response body to a file you've opened. Here's the deal in the modified example:
response.Body is a stream of data, and implements the Reader interface - meaning you can sequentially call Read on it, as if it was an open file.
The file I'm opening here implements the Writer interface. This is the opposite - it's a stream you can call Write on.
io.Copy "patches" a reader and a writer, consumes the reader stream and writes its contents to a Writer.
This is one of my favorite things about go - implicit interfaces. You don't have to declare you're implementing an interface, you just have to implement it to be used in some context. This allows mixing and matching of code that doesn't need to know about other code it's interacting with.
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
)
func main() {
url := "http://i.imgur.com/m1UIjW1.jpg"
// don't worry about errors
response, e := http.Get(url)
if e != nil {
log.Fatal(e)
}
defer response.Body.Close()
//open a file for writing
file, err := os.Create("/tmp/asdf.jpg")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// Use io.Copy to just dump the response body to the file. This supports huge files
_, err = io.Copy(file, response.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println("Success!")
}
package main
import (
"io"
"net/http"
"os"
"fmt"
)
func main() {
img, _ := os.Create("image.jpg")
defer img.Close()
resp, _ := http.Get("http://i.imgur.com/Dz2r9lk.jpg")
defer resp.Body.Close()
b, _ := io.Copy(img, resp.Body)
fmt.Println("File size: ", b)
}
Try this:
package main
import (
"fmt"
"net/http"
"net/url"
"os"
"strings"
)
var (
fileName string
fullUrlFile string
)
func main() {
fullUrlFile = "https://i.imgur.com/m1UIjW1.jpg"
r, e := http.Get(fullUrlFile)
if e != nil {
panic(e)
}
defer r.Body.Close()
buildFileName()
// Create distination
f, e := os.Create(fileName) // "m1UIjW1.jpg"
if e != nil {
panic(e)
}
defer f.Close()
// Fill distination with content
n, e := f.ReadFrom(r.Body)
if e != nil {
panic(e)
}
fmt.Println("File size: ", n)
}
func buildFileName() {
fileUrl, e := url.Parse(fullUrlFile)
if e != nil {
panic(e)
}
path := fileUrl.Path
segments := strings.Split(path, "/")
fileName = segments[len(segments)-1]
println(fileName)
}
You can also use the ReadFrom method:
package main
import (
"net/http"
"os"
)
func main() {
r, e := http.Get("https://i.imgur.com/m1UIjW1.jpg")
if e != nil {
panic(e)
}
defer r.Body.Close()
f, e := os.Create("m1UIjW1.jpg")
if e != nil {
panic(e)
}
defer f.Close()
f.ReadFrom(r.Body)
}
https://golang.org/pkg/os#File.ReadFrom
What is the type of response.Body? You should just convert that into a []byte if it is not and write that to disk. There is no reason to use the image class unless you have some reason to treat the data as an image. Just treat the data as a series of bytes and write it to the disk.

Resources