diff --git a/api/geth_backend.go b/api/geth_backend.go index ab5597a2b..e233e4753 100644 --- a/api/geth_backend.go +++ b/api/geth_backend.go @@ -1270,11 +1270,16 @@ func (b *GethStatusBackend) SignHash(hexEncodedHash string) (string, error) { return hexEncodedSignature, nil } +// GetProfileImages returns an array of base64 encoded images related to the user's profile func (b *GethStatusBackend) GetProfileImages() (string, error) { // TODO return "", nil } +// SaveProfileImage takes the filepath of an image, crops it as per the rect coords and finally resizes the image. +// The resulting image(s) will be stored in the DB along with other user account information. +// aX and aY represent the pixel coordinates of the upper left corner of the image's cropping area +// bX and bY represent the pixel coordinates of the lower right corner of the image's cropping area func (b *GethStatusBackend) SaveProfileImage(filepath string, aX, aY, bX, bY int) (string, error) { imgs, err := images.GenerateProfileImages(filepath, aX, aY, bX, bY) diff --git a/appdatabase/migrations/sql/0013_identity_images.up.sql b/appdatabase/migrations/sql/0013_identity_images.up.sql index 91ec84741..0a7395ec1 100644 --- a/appdatabase/migrations/sql/0013_identity_images.up.sql +++ b/appdatabase/migrations/sql/0013_identity_images.up.sql @@ -6,4 +6,3 @@ CREATE TABLE IF NOT EXISTS identity_images( file_size int, resize_target int ) WITHOUT ROWID; - diff --git a/images/decode.go b/images/decode.go index 78821dfcb..68025ca61 100644 --- a/images/decode.go +++ b/images/decode.go @@ -2,6 +2,7 @@ package images import ( "errors" + "github.com/davecgh/go-spew/spew" "image" "image/gif" "image/jpeg" @@ -31,6 +32,9 @@ func prepareFileForDecode(file *os.File) ([]byte, error) { // Read the first 14 bytes, used for performing image type checks before parsing the image data fb := make([]byte, 14) _, err := file.Read(fb) + + spew.Dump(fb) + if err != nil { return nil, err } @@ -45,7 +49,7 @@ func prepareFileForDecode(file *os.File) ([]byte, error) { } func decodeImageData(buf []byte, r io.Reader) (img image.Image, err error) { - switch GetFileType(buf) { + switch GetType(buf) { case JPEG: img, err = jpeg.Decode(r) case PNG: @@ -66,7 +70,7 @@ func decodeImageData(buf []byte, r io.Reader) (img image.Image, err error) { return img, nil } -func GetFileType(buf []byte) FileType { +func GetType(buf []byte) ImageType { switch { case isJpeg(buf): return JPEG @@ -81,6 +85,21 @@ func GetFileType(buf []byte) FileType { } } +func GetMimeType(buf []byte) (string, error) { + switch { + case isJpeg(buf): + return "jpeg", nil + case isPng(buf): + return "png", nil + case isGif(buf): + return "gif", nil + case isWebp(buf): + return "webp", nil + default: + return "", errors.New("image format not supported") + } +} + func isJpeg(buf []byte) bool { return len(buf) > 2 && buf[0] == 0xFF && diff --git a/images/decode_test.go b/images/decode_test.go index 1503bed9c..845fac28a 100644 --- a/images/decode_test.go +++ b/images/decode_test.go @@ -1,6 +1,7 @@ package images import ( + "errors" "image" "testing" @@ -11,6 +12,14 @@ const ( path = "../_assets/tests/" ) +var ( + testJpegBytes = []byte{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x50, 0x37, 0x3c, 0x46, 0x3c, 0x32, 0x50} + testPngBytes = []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48} + testGifBytes = []byte{0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x00, 0x01, 0x00, 0x01, 0x84, 0x1f, 0x00, 0xff} + testWebpBytes = []byte{0x52, 0x49, 0x46, 0x46, 0x90, 0x49, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, 0x56, 0x50} + testAacBytes = []byte{0xff, 0xf1, 0x50, 0x80, 0x1c, 0x3f, 0xfc, 0xda, 0x00, 0x4c, 0x61, 0x76, 0x63, 0x35} +) + func TestDecode(t *testing.T) { cs := []struct { @@ -82,3 +91,45 @@ func TestDecode(t *testing.T) { require.Exactly(t, c.Bounds, img.Bounds()) } } + +func TestGetType(t *testing.T) { + cs := []struct{ + Buf []byte + Value ImageType + }{ + {testJpegBytes, JPEG}, + {testPngBytes, PNG}, + {testGifBytes, GIF}, + {testWebpBytes, WEBP}, + {testAacBytes, UNKNOWN}, + } + + for _, c := range cs { + require.Exactly(t, c.Value, GetType(c.Buf)) + } +} + +func TestGetMimeType(t *testing.T) { + cs := []struct{ + Buf []byte + Value string + Error error + }{ + {testJpegBytes, "jpeg", nil}, + {testPngBytes, "png", nil}, + {testGifBytes, "gif", nil}, + {testWebpBytes, "webp", nil}, + {testAacBytes, "", errors.New("image format not supported")}, + } + + for _, c := range cs { + mt, err := GetMimeType(c.Buf) + if c.Error == nil { + require.NoError(t, err) + } else { + require.EqualError(t, err, c.Error.Error()) + } + + require.Exactly(t, c.Value, mt) + } +} diff --git a/images/meta.go b/images/meta.go index 9764ad073..75d201e8b 100644 --- a/images/meta.go +++ b/images/meta.go @@ -1,7 +1,7 @@ package images const ( - UNKNOWN FileType = 1 + iota + UNKNOWN ImageType = 1 + iota // Raster image types JPEG @@ -37,5 +37,5 @@ type DimensionLimits struct { Max int } -type FileType uint +type ImageType uint type ResizeDimension uint diff --git a/protocol/common/message.go b/protocol/common/message.go index 455251ba3..87b5caab0 100644 --- a/protocol/common/message.go +++ b/protocol/common/message.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/status-im/status-go/images" "strings" "unicode" "unicode/utf8" @@ -269,7 +270,7 @@ func (m *Message) parseImage() error { e64.Encode(encBuf, payload) - mime, err := getImageMessageMIME(image) + mime, err := images.GetMimeType(image.Payload) if err != nil { return err @@ -356,20 +357,6 @@ func (m *Message) PrepareContent() error { return m.parseAudio() } -func getImageMessageMIME(i *protobuf.ImageMessage) (string, error) { - switch i.Type { - case protobuf.ImageType_PNG: - return "png", nil - case protobuf.ImageType_JPEG: - return "jpeg", nil - case protobuf.ImageType_WEBP: - return "webp", nil - case protobuf.ImageType_GIF: - return "gif", nil - } - return "", errors.New("image format not supported") -} - func getAudioMessageMIME(i *protobuf.AudioMessage) (string, error) { switch i.Type { case protobuf.AudioMessage_AAC: diff --git a/protocol/common/message_test.go b/protocol/common/message_test.go index eee5f461d..8d845c035 100644 --- a/protocol/common/message_test.go +++ b/protocol/common/message_test.go @@ -35,32 +35,6 @@ func TestPrepareContentImage(t *testing.T) { require.Equal(t, expectedJPEG, message.Base64Image) } -func TestGetImageMessageMIME(t *testing.T) { - jpeg := &protobuf.ImageMessage{Type: protobuf.ImageType_JPEG} - mime, err := getImageMessageMIME(jpeg) - require.NoError(t, err) - require.Equal(t, "jpeg", mime) - - png := &protobuf.ImageMessage{Type: protobuf.ImageType_PNG} - mime, err = getImageMessageMIME(png) - require.NoError(t, err) - require.Equal(t, "png", mime) - - webp := &protobuf.ImageMessage{Type: protobuf.ImageType_WEBP} - mime, err = getImageMessageMIME(webp) - require.NoError(t, err) - require.Equal(t, "webp", mime) - - gif := &protobuf.ImageMessage{Type: protobuf.ImageType_GIF} - mime, err = getImageMessageMIME(gif) - require.NoError(t, err) - require.Equal(t, "gif", mime) - - unknown := &protobuf.ImageMessage{Type: protobuf.ImageType_UNKNOWN_IMAGE_TYPE} - _, err = getImageMessageMIME(unknown) - require.Error(t, err) -} - func TestPrepareContentAudio(t *testing.T) { file, err := os.Open("../../_assets/tests/test.aac") require.NoError(t, err) @@ -91,10 +65,6 @@ func TestGetAudioMessageMIME(t *testing.T) { mime, err = getAudioMessageMIME(amr) require.NoError(t, err) require.Equal(t, "amr", mime) - - unknown := &protobuf.ImageMessage{Type: protobuf.ImageType_UNKNOWN_IMAGE_TYPE} - _, err = getImageMessageMIME(unknown) - require.Error(t, err) } func TestPrepareContentMentions(t *testing.T) { diff --git a/protocol/images/type.go b/protocol/images/type.go index 1908980dd..fc2b9ff7f 100644 --- a/protocol/images/type.go +++ b/protocol/images/type.go @@ -6,7 +6,7 @@ import ( ) func ImageType(buf []byte) protobuf.ImageType { - switch images.GetFileType(buf){ + switch images.GetType(buf){ case images.JPEG: return protobuf.ImageType_JPEG case images.PNG: