Flutter Image File Upload - Base64 x MultiPart Form
Published: 2021-01-11 14:34:34

Recentemente comecei a pesquisar diferentes temas que poderiam ser utilizados para escrever algum conteúdo, foi aí que um amigo escreveu o primeiro artigo e utilizou de um problema que aconteceu em seu dia a dia para transformá-lo em uma ideia de artigo, para escrever esse pequeno artigo resolvi tentar da mesma maneira.

Passamos por uns erros no quesito de upload de uma imagem para a api via Base64, resolvi então mostrar aqui alguns problemas dessa abordagem e uma alternativa para a mesma.

Base64 é um método para codificação de dados para transferência na Internet. É utilizado frequentemente para transmitir dados binários por meios de transmissão que lidam apenas com texto, como por exemplo para enviar arquivos anexos por e-mail.

Para converter um arquivo para Base64 no flutter é muito simples vide código baixo:
```javascript 
File file = await ImagePicker.pickImage(source: ImageSource.camera);
String base64 = base64Encode(file.readAsBytesSync());
```
*¹ ImagePicker - Plugin Flutter para iOS e Android para selecionar imagens da galeria ou tirar uma nova foto com a câmera. [Link](https://pub.dev/packages/image_picker)*

Obtido o Base64, o mesmo pode ser enviado no *body* de uma requisição *post* por exemplo.

#Problemas com Base64

###Respostas de API ficam muito grandes

Respostas muito grandes tendem a levar mais tempo para serem processadas dando mais tempo para uma possível falha na rede e aumentando o consumo de dados do dispositivo.

###Oversizing

O tamanho da imagem codificada em Base64 é aproximadamente 30% maior do que a imagem binária original.

###A experiência do usuário é afetada negativamente.

Incluindo os retornos junto com outras respostas da API, o aplicativo irá esperar carregar todos os dados antes de exibir informações na tela, afetando assim a experiência do usuário que verá uma tela de carregamento por mais tempo.

###O armazenamento em cache de imagens no dispositivo não é mais possível.

Imagens enviadas para o dispositivo via Base64 tornará irrelevante qualquer implementação de serviços de cache de armazenamento de imagens.

Recursos nativos do flutter como o precacheImage tornam-se inutilizáveis nesta situação, já que toda vez será necessário fazer o decode do base64.

Outra implementação que se torna inutilizável seria o cachedNetworkImage, outra implementação nativa do flutter, mas que não pode ser  aplicada ao contexto de um Base64.

Para aplicativos que possam funcionar tanto online quanto offline, a utilização de cache de imagens é um recurso bem eficaz para melhor experiência do usuário.

#Vantagens do Base64

* Remover a necessidade de múltiplos request, para obtenção de dados. ²
* Imagens codificadas como Base64 podem ser armazenadas em bancos de dados e gerados novos arquivos.
² Como foi mostrado antes, essa abordagem pode ser uma vantagem ou uma desvantagem a depender do contexto e da implementação

#Multipart Form Data

* É uma de três formas de codificação existentes no HTML sendo elas: 

1.application/x-www-form-urlencoded 
2.multipart/form-data
3.text/plain
 
* Deve-se utilizar esta forma de codificação quando a requisição possuir algum arquivo que deve fazer upload 
* É compatível com todos os navegadores.
* Suporta arquivos com tamanhos muito grandes.
 
##Utilizando multipart com Flutter
```javascript 
File file = await ImagePicker.pickImage(source: ImageSource.camera);
final multiPartdata = await MultipartFile.fromFile(file.path);
final formData = FormData.fromMap({
     "file": multiPartdata,
});
```

Desta maneira o servidor da API deve estar preparado para receber requisições com o cabeçalho multipart/form-data, já que o conteúdo não irá junto com o body da requisição caso o mesmo exista.

Alguns servidores de storage como **_aws.s3_**, **_cloudinary_**, **_firebase cloud storage_**, estão preparados para receberem requisições nesse formato, possuindo libs para integração direta em Flutter, dispensando a necessidade da criação de uma api própria.

#Resolvendo o Oversizing

Algumas estratégias podem ser admitidas a fim de reduzir o oversizing, a mais comum são os famosos thumbnails, algumas alternativas mais recentes que têm grande aplicabilidade a depender do contexto seriam o blurHash e a Dominant color  abaixo explico o funcionamento de ambas.

###Thumbnails

Uma thumbnail é uma imagem comprimida que prevê a imagem original. Elas são mais leves e podem ser utilizadas para diversos fins. Por exemplo, um dos propósitos da utilização dessa thumb é reduzir o tempo de carregamento de alguma pagina na internet, para tornar o acesso mais rápido ao usuário. Então, uma thumbnail de uma foto maior, seria uma versão reduzida dela mesma.

Em essência, a principal função de uma miniatura é trazer uma informação ao usuário de maneira mais rápida.

###[Blurhash](https://github.com/woltapp/blurhash)

*“BlurHash is a compact representation of a placeholder for an image”.*

Blurhash é uma representação compacta de um espaço reservado para uma imagem. Esta é a definição dada pelos desenvolvedores. Trata-se de uma biblioteca que converte uma imagem para uma versão ofuscada e compactada de sua versão.
Essa biblioteca possui implementações para diversas linguagens, typescript, kotlin, swift, python, C, entre outras. Segue abaixo uma visão da mesma.

![](https://dev-to-uploads.s3.amazonaws.com/i/hjznmr681n753svu8qh7.JPG)

###Dominant color

Trata-se apenas de pegar a cor de maior incidência na imagem, e utilizá-la no local da mesma. Estratégia bastante parecida com o blurHash, a diferença seria apenas o resultado final da imagem.

![](https://dev-to-uploads.s3.amazonaws.com/i/nylgnpitcxgk8wpqp1wb.JPG)

#Referencial Bibliográfico

https://medium.com/snapp-mobile/dont-use-base64-encoded-images-on-mobile-13ddeac89d7c

https://pt.wikipedia.org/wiki/Base64

https://pub.dev/packages/image_picker

https://medium.com/snapp-mobile/dont-use-base64-encoded-images-on-mobile-13ddeac89d7c

http://www.coderiddles.com/base64-images/

https://neilpatel.com/br/blog/thumbnail-o-que-e/

https://github.com/woltapp/blurhash

https://lokeshdhakar.com/projects/color-thief/

https://flutter.dev/docs/cookbook/images/cached-images