Difference between []uint8 && []byte (Golang Slices) - go

One of the functions I am running: image.Decode()
The image.Decode function takes in an io.Reader && and the io.Reader function takes in a []byte.
When I pass in a []uint8, if gives me this error:
panic: image: unknown format
How do I convert the []uint8 to []byte?
UPDATE
The error is happening at the starred area because image.Decode can't read the variable xxx.
package main
import (
"github.com/nfnt/resize"
"image"
"image/jpeg"
"fmt"
"launchpad.net/goamz/aws"
"launchpad.net/goamz/s3"
"bytes"
"encoding/json"
"io/ioutil"
"os"
"reflect"
)
type Data struct {
Key string
}
func main() {
useast := aws.USEast
connection := s3.New(auth, useast)
mybucket := connection.Bucket("bucketName")
image_data, err := mybucket.Get("1637563605030")
if err != nil {
panic(err.Error())
} else {
fmt.Println("success")
}
xxx := []byte(image_data)
******* THIS IS WHERE THE ERROR OCCURS **************
original_image, _, err := image.Decode(bytes.NewReader(xxx))
******* THIS IS WHERE THE ERROR OCCURS END **************
if err != nil {
fmt.Println("Shit")
panic(err.Error())
} else {
fmt.Println("Another success")
}
new_image := resize.Resize(160, 0, original_image, resize.Lanczos3)
if new_image != nil {
fmt.Println("YAY")
}
}

The Go Programming Language Specification
Numeric types
uint8 the set of all unsigned 8-bit integers (0 to 255)
byte alias for uint8
package main
import "fmt"
func ByteSlice(b []byte) []byte { return b }
func main() {
b := []byte{0, 1}
u8 := []uint8{2, 3}
fmt.Printf("%T %T\n", b, u8)
fmt.Println(ByteSlice(b))
fmt.Println(ByteSlice(u8))
}
Output:
[]uint8 []uint8
[0 1]
[2 3]
You have misdiagnosed your problem.

As the other answers have explained, there's no problem passing a []uint8 where a []byte is required. If this was your problem, you'd be getting a compile time error. You aren't. A panic is a runtime error, and it's being thrown by the image library when it reads the data in the slice.
In fact, the image library is only partially your problem. See http://golang.org/src/pkg/image/format.go. It's returning an error message because it doesn't recognize the image format of the data in the slice. Your code, which calls image.Decode() is calling panic when image.Decode() returns the error message.

If you have a variable imageData that is []uint8 you may pass []byte(imageData)
See http://golang.org/ref/spec#Conversions

Related

What happen when field value string is unmarshalled into []byte

What happens to my original data in the variable str here?
After converting to the struct the length of bytes is 6
And the value of byte don't match ascii code of 1, 2, 3, 4, 5, 6, 7, 8 at all
package main
import (
"encoding/json"
"fmt"
)
type Encrypt struct {
Bytes []byte `json:"bytes"`
}
func main(){
str := "12345678"
raw := fmt.Sprintf("{\"bytes\":%s}", str)
var encrypt = Encrypt{}
fmt.Println([]byte(raw)[0])
err := json.Unmarshal([]byte(raw), &encrypt)
if err != nil{
fmt.Println(err)
return
}
fmt.Println("final result")
fmt.Println(len(encrypt.Bytes))
fmt.Println(string(encrypt.Bytes))
for _, b := range encrypt.Bytes{
fmt.Print(b)
fmt.Print(" ")
}
fmt.Print("\n")
}
As per the documentation https://pkg.go.dev/encoding/json#Unmarshal:
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
As you can see there is no place for []byte. Also, in you code raw := fmt.Sprintf("{\"bytes\":%s}", str) you are sending str as a number. You can send it as string as in the following code.
package main
import (
"encoding/json"
"fmt"
)
type Encrypt struct {
ByteString string `json:"bytes"`
}
func main() {
str := "12345678"
raw := fmt.Sprintf("{\"bytes\":\"%s\"}", str)
fmt.Println(raw)
var encrypt = Encrypt{}
fmt.Println([]byte(str))
err := json.Unmarshal([]byte(raw), &encrypt)
if err != nil {
panic(err)
}
fmt.Println("final result ", []byte(encrypt.ByteString))
}

Convert binary value as string to uint32 in Golang

Hello i am trying to convert 00000000000000000000000000001011 to uint32 in golang using
var v = "00000000000000000000000000001011"
fmt.Printf("%T\n", v)
c := []byte(v)
u := binary.LittleEndian.Uint32(c)
However it is not working.
You can't use encoding/binary for this, as that is to serialize and deserialize the (memory) bytes of different values (e.g. numbers). What you have is the base 2 string representation of the number.
To get its integer value you have to parse it. For that, use strconv.ParseUint():
s := "00000000000000000000000000001011"
u, err := strconv.ParseUint(s, 2, 32)
if err != nil {
panic(err)
}
fmt.Println(u)
This outputs (try it on the Go Playground):
11
Note that strconv.ParseUint() returns a value of type uint64, so if you need uint32, you have to manually convert it, e.g.:
u32 := uint32(u)
There are more options for parsing numbers from strings, for an overview, check Convert string to integer type in Go?
For example,
package main
import (
"fmt"
"strconv"
)
func main() {
s := "00000000000000000000000000001011"
fmt.Println(s)
u64, err := strconv.ParseUint(s, 2, 32)
u32 := uint32(u64)
if err == nil {
fmt.Println(u32)
}
}
Playground: https://play.golang.org/p/yiicgWsb7B_M
Output:
00000000000000000000000000001011
11

Interface variable conversion in Golang

I have a variable which value can be string or int depend on the input. I use interface{} as the type. How to convert the value of that variable to int if the input is like "50", "45", or any string of int.
package main
import "fmt"
import "log"
import "strconv"
func main() {
var limit interface{}
limit = "50"
page := 1
offset := 0
if limit != "ALL" {
log.Println("INSIDE")
offset = limit.(int)*page - limit.(int)
}
fmt.Println(offset)
}
Above code got:
interface conversion: interface {} is string, not int
If I use this:
package main
import "fmt"
import "log"
import "strconv"
func main() {
var limit interface{}
limit = "50"
page := 1
offset := 0
if limit != "ALL" {
log.Println("INSIDE")
offset = strconv.Atoi(limit)*page - strconv.Atoi(limit)
}
fmt.Println(offset)
}
I got this
exit status 2
command-line-arguments
./main.go:14:24: cannot use limit (type interface {}) as type string in argument to strconv.Atoi: need type assertion
./main.go:14:24: multiple-value strconv.Atoi() in single-value context
./main.go:14:51: cannot use limit (type interface {}) as type string in argument to strconv.Atoi: need type assertion
./main.go:14:51: multiple-value strconv.Atoi() in single-value context
How to convert value of that variable to int?
In Go, in contrast to languages such as Python/JavaScript/Perl, the variables have strict types and strong boundaries. You have to write explicit code to make the conversion of a string from/to an integer. This is helpful to write safer and more performant programs.
In addition, if the variable is stored in an interface{} you have to use a type assertion (or a type switch) to further use the content with a specific type.
Here is your fixed code:
package main
import "fmt"
import "log"
import "strconv"
func main() {
var limit interface{}
limit = "50"
page := 1
offset := 3
if limit != "ALL" {
// Type assertion
s, isString := limit.(string)
if !isString {
log.Fatalf("limit is not a string but %T", limit)
}
// Conversion from string to int, with error handling
l, err := strconv.Atoi(s)
if err != nil {
log.Fatalf("%s: %v", limit, err)
}
offset = l*page - l
}
fmt.Println(offset)
}
However, I suggest that you just use the string type for the limit variable.
strconv package can use for this kind of conversion
package main
import (
"fmt"
"strconv"
)
func main() {
var lim interface{}
lim = "10"
fmt.Printf("Type is: %T\nValue is: %s \n", lim, lim.(string))
i, _ := strconv.Atoi(lim.(string))
fmt.Printf("After conversion value is: %d", i)
}
Output of the above code:
Type is: string, Value is: 10
After conversion value is: 10
As I understood your question, value of your limit in fact is always string, but in one case it's value == ALL, otherwise it's a string representation of an integer value.
If I'm right, then I would provide following solution:
import (
"errors"
"fmt"
"strconv"
)
func getOffset(limit string, page int64) (int64, error) {
lim, err := strconv.ParseInt(limit, 10, 64)
if err != nil {
if limit == "ALL" {
return 0, nil
}
return 0, errors.New(fmt.Sprintf("string '%v' doesn't fit requirements, error: %v", limit, err))
}
offset := lim*page - lim
return offset, nil
}
Full solution on playground: https://play.golang.org/p/fJv9_cw18R5

I cannot access err.Err from strconv package

I am probably missing something really simple here:
package main
import (
"fmt"
"strconv"
"reflect"
)
func main() {
s := "abd"
fmt.Println(s)
_, err := strconv.Atoi(s)
if err != nil {
fmt.Println(err)
}
fmt.Println(reflect.TypeOf(err))
fmt.Println(err.Err)
}
I am trying to extract the error itself e.g. ErrSyntax or ErrRange, but I am not able to do so.
After looking at:
https://golang.org/src/strconv/atoi.go?s=3604:3671#L16
I see that err is a pointer to strconv.NumError
15 // A NumError records a failed conversion.
16 type NumError struct {
17 Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat)
18 Num string // the input
19 Err error // the reason the conversion failed (ErrRange, ErrSyntax)
20 }
And Err is the field that holds either ErrRange of ErrSyntax. Therefore, I thought that err.Err would work, but I get:
err.Err undefined (type error has no field or method Err
Err is public, am I missing something with visibility rules?
What am I missing?
Use a type assertion to get the *strconv.NumError value:
if e, ok := err.(*strconv.NumError); ok {
fmt.Println("e.Err", e.Err)
}
playground example

How to decompress a []byte content in gzip format that gives an error when unmarshaling

I'm making a request to an API, which with I get a []byte out of the response (ioutil.ReadAll(resp.Body)). I'm trying to unmarshal this content, but seems to be not encoded on utf-8 format, as unmarshal returns an error. I'm trying this to do so:
package main
import (
"encoding/json"
"fmt"
"some/api"
)
func main() {
content := api.SomeAPI.SomeRequest() // []byte variable
var data interface{}
err := json.Unmarshal(content, &data)
if err != nil {
panic(err.Error())
}
fmt.Println("Data from response", data)
}
I get as an error that invalid character '\x1f' looking for beginning of value. For the record, the response includes in the header that Content-Type:[application/json; charset=utf-8].
How can I decode content to avoid these invalid characters when unmarshaling?
Edit
This is the hexdump of content: play.golang.org/p/oJ5mqERAmj
Judging by your hex dump you are receiving gzip encoded data so you'll need to use compress/gzip to decode it first.
Try something like this
package main
import (
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"io"
"some/api"
)
func main() {
content := api.SomeAPI.SomeRequest() // []byte variable
// decompress the content into an io.Reader
buf := bytes.NewBuffer(content)
reader, err := gzip.NewReader(buf)
if err != nil {
panic(err)
}
// Use the stream interface to decode json from the io.Reader
var data interface{}
dec := json.NewDecoder(reader)
err = dec.Decode(&data)
if err != nil && err != io.EOF {
panic(err)
}
fmt.Println("Data from response", data)
}
Previous
Character \x1f is the unit separator character in ASCII and UTF-8. It is never part of an UTF-8 encoding, however can be used to mark off different bits of text. A string with an \x1f can valid UTF-8 but not valid json as far as I know.
I think you need to read the API specification closely to find out what they are using the \x1f markers for, but in the meantime you could try removing them and see what happens, eg
import (
"bytes"
"fmt"
)
func main() {
b := []byte("hello\x1fGoodbye")
fmt.Printf("b was %q\n", b)
b = bytes.Replace(b, []byte{0x1f}, []byte{' '}, -1)
fmt.Printf("b is now %q\n", b)
}
Prints
b was "hello\x1fGoodbye"
b is now "hello Goodbye"
Playground link

Resources