Move images to shared namespace

This commit is contained in:
Andrea Maria Piana 2023-02-02 17:59:48 +00:00
parent 242c85cd6a
commit 1c660c3525
10 changed files with 145 additions and 128 deletions

View File

@ -1 +1 @@
0.128.2
0.128.3

62
images/adjust.go Normal file
View File

@ -0,0 +1,62 @@
package images
import (
"bytes"
"errors"
"image"
"io/ioutil"
"os"
)
const (
maxChatMessageImageSize = 400000
resizeTargetImageSize = 350000
idealTargetImageSize = 50000
)
func OpenAndAdjustImage(inputImage CroppedImage, crop bool) ([]byte, error) {
file, err := os.Open(inputImage.ImagePath)
if err != nil {
return nil, err
}
defer file.Close()
payload, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}
img, err := Decode(inputImage.ImagePath)
if err != nil {
return nil, err
}
if crop {
cropRect := image.Rectangle{
Min: image.Point{X: inputImage.X, Y: inputImage.Y},
Max: image.Point{X: inputImage.X + inputImage.Width, Y: inputImage.Y + inputImage.Height},
}
img, err = Crop(img, cropRect)
if err != nil {
return nil, err
}
}
bb := bytes.NewBuffer([]byte{})
err = CompressToFileLimits(bb, img, FileSizeLimits{Ideal: idealTargetImageSize, Max: resizeTargetImageSize})
if err != nil {
return nil, err
}
// We keep the smallest one
if len(payload) > len(bb.Bytes()) {
payload = bb.Bytes()
}
if len(payload) > maxChatMessageImageSize {
return nil, errors.New("image too large")
}
return payload, nil
}

View File

@ -3,34 +3,33 @@ package images
import (
"errors"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/protocol/protobuf"
)
func ImageType(buf []byte) protobuf.ImageType {
switch images.GetType(buf) {
case images.JPEG:
func GetProtobufImageType(buf []byte) protobuf.ImageType {
switch GetType(buf) {
case JPEG:
return protobuf.ImageType_JPEG
case images.PNG:
case PNG:
return protobuf.ImageType_PNG
case images.GIF:
case GIF:
return protobuf.ImageType_GIF
case images.WEBP:
case WEBP:
return protobuf.ImageType_WEBP
default:
return protobuf.ImageType_UNKNOWN_IMAGE_TYPE
}
}
func ImageMime(buf []byte) (string, error) {
switch images.GetType(buf) {
case images.JPEG:
func GetProtobufImageMime(buf []byte) (string, error) {
switch GetType(buf) {
case JPEG:
return "image/jpeg", nil
case images.PNG:
case PNG:
return "image/png", nil
case images.GIF:
case GIF:
return "image/gif", nil
case images.WEBP:
case WEBP:
return "image/webp", nil
default:
return "", errors.New("mime type not found")

View File

@ -7,6 +7,8 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
"unicode"
"unicode/utf8"
@ -19,6 +21,7 @@ import (
"github.com/status-im/status-go/api/multiformat"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/protocol/audio"
"github.com/status-im/status-go/protocol/protobuf"
)
@ -657,3 +660,39 @@ func (m *Message) GetSenderPubKey() (*ecdsa.PublicKey, error) {
return nil, errors.New("no Message.SigPubKey or Message.From set unable to get public key")
}
func (m *Message) LoadAudio() error {
file, err := os.Open(m.AudioPath)
if err != nil {
return err
}
defer file.Close()
payload, err := ioutil.ReadAll(file)
if err != nil {
return err
}
audioMessage := m.GetAudio()
if audioMessage == nil {
return errors.New("no audio has been passed")
}
audioMessage.Payload = payload
audioMessage.Type = audio.Type(payload)
m.Payload = &protobuf.ChatMessage_Audio{Audio: audioMessage}
return os.Remove(m.AudioPath)
}
func (m *Message) LoadImage() error {
payload, err := images.OpenAndAdjustImage(images.CroppedImage{ImagePath: m.ImagePath}, false)
if err != nil {
return err
}
imageMessage := m.GetImage()
imageMessage.Payload = payload
imageMessage.Type = images.GetProtobufImageType(payload)
m.Payload = &protobuf.ChatMessage_Image{Image: imageMessage}
return nil
}

View File

@ -8,8 +8,6 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"image"
"io/ioutil"
"math"
"math/rand"
"os"
@ -33,12 +31,11 @@ import (
"github.com/status-im/status-go/contracts"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
userimage "github.com/status-im/status-go/images"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/multiaccounts"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/protocol/anonmetrics"
"github.com/status-im/status-go/protocol/audio"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/communities"
"github.com/status-im/status-go/protocol/encryption"
@ -48,7 +45,6 @@ import (
"github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/protocol/identity/alias"
"github.com/status-im/status-go/protocol/identity/identicon"
"github.com/status-im/status-go/protocol/images"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/pushnotificationclient"
"github.com/status-im/status-go/protocol/pushnotificationserver"
@ -77,10 +73,6 @@ const (
publicChat chatContext = "public-chat"
privateChat chatContext = "private-chat"
maxChatMessageImageSize = 400000
resizeTargetImageSize = 350000
idealTargetImageSize = 50000
)
const messageResendMinDelay = 30
@ -922,7 +914,7 @@ func (m *Messenger) attachChatIdentity(cca *protobuf.ContactCodeAdvertisement) e
return err
}
img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, userimage.SmallDimName)
img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, images.SmallDimName)
if err != nil {
return err
}
@ -1002,7 +994,7 @@ func (m *Messenger) handleStandaloneChatIdentity(chat *Chat) error {
}
img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, userimage.SmallDimName)
img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, images.SmallDimName)
if err != nil {
return err
}
@ -1035,7 +1027,7 @@ func (m *Messenger) handleStandaloneChatIdentity(chat *Chat) error {
return nil
}
func (m *Messenger) getIdentityHash(displayName, bio string, img *userimage.IdentityImage, socialLinks *identity.SocialLinks) ([]byte, error) {
func (m *Messenger) getIdentityHash(displayName, bio string, img *images.IdentityImage, socialLinks *identity.SocialLinks) ([]byte, error) {
socialLinksData, err := socialLinks.Serialize()
if err != nil {
return []byte{}, err
@ -1053,7 +1045,7 @@ func (m *Messenger) shouldPublishChatIdentity(chatID string) (bool, error) {
}
// Check we have at least one image or a display name
img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, userimage.SmallDimName)
img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, images.SmallDimName)
if err != nil {
return false, err
}
@ -1134,11 +1126,11 @@ func (m *Messenger) createChatIdentity(context chatContext) (*protobuf.ChatIdent
}
// adaptIdentityImageToProtobuf Adapts a images.IdentityImage to protobuf.IdentityImage
func (m *Messenger) adaptIdentityImageToProtobuf(img *userimage.IdentityImage) *protobuf.IdentityImage {
func (m *Messenger) adaptIdentityImageToProtobuf(img *images.IdentityImage) *protobuf.IdentityImage {
return &protobuf.IdentityImage{
Payload: img.Payload,
SourceType: protobuf.IdentityImage_RAW_PAYLOAD, // TODO add ENS avatar handling to dedicated PR
ImageType: images.ImageType(img.Payload),
ImageType: images.GetProtobufImageType(img.Payload),
}
}
@ -1159,7 +1151,7 @@ func (m *Messenger) attachIdentityImagesToChatIdentity(context chatContext, ci *
case publicChat:
m.logger.Info(fmt.Sprintf("handling %s ChatIdentity", context))
img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, userimage.SmallDimName)
img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, images.SmallDimName)
if err != nil {
return err
}
@ -1170,7 +1162,7 @@ func (m *Messenger) attachIdentityImagesToChatIdentity(context chatContext, ci *
m.logger.Debug(fmt.Sprintf("%s images.IdentityImage '%s'", context, spew.Sdump(img)))
ciis[userimage.SmallDimName] = m.adaptIdentityImageToProtobuf(img)
ciis[images.SmallDimName] = m.adaptIdentityImageToProtobuf(img)
m.logger.Debug(fmt.Sprintf("%s protobuf.IdentityImage '%s'", context, spew.Sdump(ciis)))
ci.Images = ciis
@ -1944,53 +1936,6 @@ func (m *Messenger) SendChatMessages(ctx context.Context, messages []*common.Mes
return &response, nil
}
func (m *Messenger) OpenAndAdjustImage(inputImage userimage.CroppedImage, crop bool) ([]byte, error) {
file, err := os.Open(inputImage.ImagePath)
if err != nil {
return nil, err
}
defer file.Close()
payload, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}
img, err := userimage.Decode(inputImage.ImagePath)
if err != nil {
return nil, err
}
if crop {
cropRect := image.Rectangle{
Min: image.Point{X: inputImage.X, Y: inputImage.Y},
Max: image.Point{X: inputImage.X + inputImage.Width, Y: inputImage.Y + inputImage.Height},
}
img, err = userimage.Crop(img, cropRect)
if err != nil {
return nil, err
}
}
bb := bytes.NewBuffer([]byte{})
err = userimage.CompressToFileLimits(bb, img, userimage.FileSizeLimits{Ideal: idealTargetImageSize, Max: resizeTargetImageSize})
if err != nil {
return nil, err
}
// We keep the smallest one
if len(payload) > len(bb.Bytes()) {
payload = bb.Bytes()
}
if len(payload) > maxChatMessageImageSize {
return nil, errors.New("image too large")
}
return payload, nil
}
// SendChatMessage takes a minimal message and sends it based on the corresponding chat
func (m *Messenger) sendChatMessage(ctx context.Context, message *common.Message) (*MessengerResponse, error) {
displayName, err := m.settings.DisplayName()
@ -2001,16 +1946,10 @@ func (m *Messenger) sendChatMessage(ctx context.Context, message *common.Message
message.DisplayName = displayName
if len(message.ImagePath) != 0 {
payload, err := m.OpenAndAdjustImage(userimage.CroppedImage{ImagePath: message.ImagePath}, false)
err := message.LoadImage()
if err != nil {
return nil, err
}
imageMessage := message.GetImage()
imageMessage.Payload = payload
imageMessage.Type = images.ImageType(payload)
message.Payload = &protobuf.ChatMessage_Image{Image: imageMessage}
} else if len(message.CommunityID) != 0 {
community, err := m.communitiesManager.GetByIDString(message.CommunityID)
if err != nil {
@ -2029,25 +1968,7 @@ func (m *Messenger) sendChatMessage(ctx context.Context, message *common.Message
message.ContentType = protobuf.ChatMessage_COMMUNITY
} else if len(message.AudioPath) != 0 {
file, err := os.Open(message.AudioPath)
if err != nil {
return nil, err
}
defer file.Close()
payload, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}
audioMessage := message.GetAudio()
if audioMessage == nil {
return nil, errors.New("no audio has been passed")
}
audioMessage.Payload = payload
audioMessage.Type = audio.Type(payload)
message.Payload = &protobuf.ChatMessage_Audio{Audio: audioMessage}
err = os.Remove(message.AudioPath)
err := message.LoadAudio()
if err != nil {
return nil, err
}
@ -6084,6 +6005,10 @@ func chunkAttachmentsByByteSize(slice []*protobuf.DiscordMessageAttachment, maxF
return chunks
}
func (m *Messenger) ImageServerURL() string {
return m.httpServer.MakeImageServerURL()
}
func (m *Messenger) myHexIdentity() string {
return common.PubkeyToHex(&m.identity.PublicKey)
}

View File

@ -1260,8 +1260,6 @@ func (s *MessengerContactRequestSuite) TestPairedDevicesRemoveContact() {
s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState)
s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState)
alice2.logger.Info("MY KEY", zap.String("my-id", alice2.myHexIdentity()))
// Check on alice2 side
resp, err = WaitOnMessengerResponse(
alice2,

View File

@ -10,7 +10,7 @@ import (
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
userimage "github.com/status-im/status-go/images"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
v1protocol "github.com/status-im/status-go/protocol/v1"
@ -310,7 +310,7 @@ func (m *Messenger) ChangeGroupChatName(ctx context.Context, chatID string, name
return m.addMessagesAndChat(chat, buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations), &response)
}
func (m *Messenger) EditGroupChat(ctx context.Context, chatID string, name string, color string, image userimage.CroppedImage) (*MessengerResponse, error) {
func (m *Messenger) EditGroupChat(ctx context.Context, chatID string, name string, color string, image images.CroppedImage) (*MessengerResponse, error) {
logger := m.logger.With(zap.String("site", "EditGroupChat"))
logger.Info("Editing group chat details", zap.String("chatID", chatID), zap.String("name", name), zap.String("color", color))
@ -363,7 +363,7 @@ func (m *Messenger) EditGroupChat(ctx context.Context, chatID string, name strin
}
if len(image.ImagePath) > 0 {
payload, err := m.OpenAndAdjustImage(image, true)
payload, err := images.OpenAndAdjustImage(image, true)
if err != nil {
return nil, err

View File

@ -1,5 +0,0 @@
package protocol
func (m *Messenger) ImageServerURL() string {
return m.httpServer.MakeImageServerURL()
}

View File

@ -4,8 +4,7 @@ import (
"errors"
"github.com/ethereum/go-ethereum/log"
userimages "github.com/status-im/status-go/images"
"github.com/status-im/status-go/protocol/images"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/protocol/protobuf"
)
@ -40,18 +39,18 @@ type CreateCommunity struct {
ImageAy int `json:"imageAy"`
ImageBx int `json:"imageBx"`
ImageBy int `json:"imageBy"`
Banner userimages.CroppedImage `json:"banner"`
Banner images.CroppedImage `json:"banner"`
HistoryArchiveSupportEnabled bool `json:"historyArchiveSupportEnabled,omitempty"`
PinMessageAllMembersEnabled bool `json:"pinMessageAllMembersEnabled,omitempty"`
Encrypted bool `json:"encrypted,omitempty"`
Tags []string `json:"tags,omitempty"`
}
func adaptIdentityImageToProtobuf(img userimages.IdentityImage) *protobuf.IdentityImage {
func adaptIdentityImageToProtobuf(img images.IdentityImage) *protobuf.IdentityImage {
return &protobuf.IdentityImage{
Payload: img.Payload,
SourceType: protobuf.IdentityImage_RAW_PAYLOAD,
ImageType: images.ImageType(img.Payload),
ImageType: images.GetProtobufImageType(img.Payload),
}
}
@ -99,7 +98,7 @@ func (c *CreateCommunity) ToCommunityDescription() (*protobuf.CommunityDescripti
ciis := make(map[string]*protobuf.IdentityImage)
if c.Image != "" {
log.Info("has-image", "image", c.Image)
imgs, err := userimages.GenerateIdentityImages(c.Image, c.ImageAx, c.ImageAy, c.ImageBx, c.ImageBy)
imgs, err := images.GenerateIdentityImages(c.Image, c.ImageAx, c.ImageAy, c.ImageBx, c.ImageBy)
if err != nil {
return nil, err
}
@ -109,7 +108,7 @@ func (c *CreateCommunity) ToCommunityDescription() (*protobuf.CommunityDescripti
}
if c.Banner.ImagePath != "" {
log.Info("has-banner", "image", c.Banner.ImagePath)
img, err := userimages.GenerateBannerImage(c.Banner.ImagePath, c.Banner.X, c.Banner.Y, c.Banner.X+c.Banner.Width, c.Banner.Y+c.Banner.Height)
img, err := images.GenerateBannerImage(c.Banner.ImagePath, c.Banner.X, c.Banner.Y, c.Banner.X+c.Banner.Width, c.Banner.Y+c.Banner.Height)
if err != nil {
return nil, err
}

View File

@ -14,12 +14,12 @@ import (
"github.com/yeqown/go-qrcode/writer/standard"
"go.uber.org/zap"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/ipfs"
"github.com/status-im/status-go/multiaccounts"
"github.com/status-im/status-go/protocol/identity/colorhash"
"github.com/status-im/status-go/protocol/identity/identicon"
"github.com/status-im/status-go/protocol/identity/ring"
"github.com/status-im/status-go/protocol/images"
qrcodeutils "github.com/status-im/status-go/qrcode"
)
@ -110,7 +110,7 @@ func handleAccountImages(multiaccountsDB *multiaccounts.Database, logger *zap.Lo
logger.Error("empty image")
return
}
mime, err := images.ImageMime(payload)
mime, err := images.GetProtobufImageMime(payload)
if err != nil {
logger.Error("failed to get mime", zap.Error(err))
}
@ -173,7 +173,7 @@ func handleContactImages(db *sql.DB, logger *zap.Logger) http.HandlerFunc {
logger.Error("empty image")
return
}
mime, err := images.ImageMime(payload)
mime, err := images.GetProtobufImageMime(payload)
if err != nil {
logger.Error("failed to get mime", zap.Error(err))
}
@ -267,7 +267,7 @@ func handleDiscordAuthorAvatar(db *sql.DB, logger *zap.Logger) http.HandlerFunc
logger.Error("empty image")
return
}
mime, err := images.ImageMime(image)
mime, err := images.GetProtobufImageMime(image)
if err != nil {
logger.Error("failed to get mime", zap.Error(err))
}
@ -306,7 +306,7 @@ func handleDiscordAttachment(db *sql.DB, logger *zap.Logger) http.HandlerFunc {
logger.Error("empty image")
return
}
mime, err := images.ImageMime(image)
mime, err := images.GetProtobufImageMime(image)
if err != nil {
logger.Error("failed to get mime", zap.Error(err))
}
@ -339,7 +339,7 @@ func handleImage(db *sql.DB, logger *zap.Logger) http.HandlerFunc {
logger.Error("empty image")
return
}
mime, err := images.ImageMime(image)
mime, err := images.GetProtobufImageMime(image)
if err != nil {
logger.Error("failed to get mime", zap.Error(err))
}
@ -460,7 +460,7 @@ func handleQRCodeGeneration(multiaccountsDB *multiaccounts.Database, logger *zap
payload, _ = qrcodeutils.ResizeImage(payload, size, size)
}
}
mime, err := images.ImageMime(payload)
mime, err := images.GetProtobufImageMime(payload)
if err != nil {
logger.Error("could not generate image from payload", zap.Error(err))
}