Convert Base64 to PNG-File and save on Ktor Backende - kotlin

I need to save an image from the Client App as PNG on the Backend.
Im sending the Image as Base64 with Post to the Backend.
I cant find a way to convert the Base64 String to an PNG File and dont know, how I could save them as File on the Server.
Thats the function I use to get the Data from the client. In val picture I get the Image as Base64.
fun savepicture(data: getpicture) =
transaction {
val userid= data.userid
val date = data.date
val time = data.time
val picture= data.picture
println("$picture")
try {
decodeImage(aufnahme)
}
catch(e: Exception) {
println("Fehler: $e")
}
if (picture.isNotEmpty()) {
return#transaction true
}
return#transaction false
}
fun decodeImage(image: String) {
val pictureBytes = Base64.getDecoder().decode(image)
val path = Path("Path/to/destination")
path.writeBytes(pictureBytes)
}
With this function i create the Base64 String. The Bitmap is created of a picture taken form the Device.
fun encodeImage(bm: Bitmap): String? {
val baos = ByteArrayOutputStream()
bm.compress(Bitmap.CompressFormat.PNG, 90, baos)
val b = baos.toByteArray()
return java.util.Base64.getEncoder().encodeToString(b)
}
I hope someone could help me to convert and save my image.

You can use java.util.Base64 to decode your base64 string into bytes. Then you'll need to write the bytes into a file.
For instance:
val picture: String = "the base64 data here as a string"
// decode the base64 text into bytes
val pictureBytes = Base64.getDecoder().decode(picture)
// write the bytes to a file
val path = Path("the/path/to/the/file.png")
path.writeBytes(pictureBytes)

Related

Read the Gz file from S3 Kotlin

I am trying to get the gz file from S3 that is gz encoded using s3Client.
Unfortunately, I am get
UncheckedIOException "Cannot encode string." exception
when using
s3u.getObject(srcBucket, srcKey).await().asUtf8String()
The code for upload is
val gzip = key.endsWith(".gz")
val contentAsBytes: ByteArray = if (gzip) {
val baos = ByteArrayOutputStream()
GZIPOutputStream(baos).bufferedWriter(StandardCharsets.UTF_8)
.use { it.write(content) }
baos.toByteArray()
} else {
content.toByteArray(StandardCharsets.UTF_8)
}
val metadata = ObjectMetadata()
metadata.contentLength = contentAsBytes.size.toLong()
metadata.contentType = "text/plain; charset=utf-8"
if (gzip) {
metadata.contentEncoding = "gzip"
}
Can anyone help me know how to get the gzip file using s3?

How to stream a big zip file until end?

I am trying to stream a big zip file with Multi through GRPC service as follows:
#GrpcService
class HelloGrpcService : HelloGrpc {
override fun source(request: Empty?): Multi<SourceResponse> {
val file = File("/Users/developer/Downloads/Archive.zip")
val res = SourceResponse.newBuilder().setData(ByteString.readFrom(file.inputStream())).build()
return Multi.createFrom().item(res)
}
}
Unfortunately, I have received the following exception:
System.ArgumentException: The JSON value of length 212507417 is too large and not supported.
My goal is to stream the file and not to send it once.
The question is how to stream a big file in GRPC?
Here is the proto file:
syntax = "proto3";
import "google/protobuf/empty.proto";
option java_multiple_files = true;
option java_package = "io.acme";
option java_outer_classname = "HelloGrpcProto";
package hello;
service HelloGrpc {
rpc Source(google.protobuf.Empty) returns (stream SourceResponse) {}
}
message SourceResponse {
bytes data = 1;
}

How to send file using Chopper?

In my kotlin project, I use retrofit and it works well.
suspend fun createPlan(
context: Context?,
name: String,
file: File?
): ABC? {
val fileSignImage = file?.let {
MultipartBody.Part.createFormData(
"image",
it.getName(),
RequestBody.create("image/*".toMediaTypeOrNull(), it)
)
}
return RetrofitFactory.apiCall(context) {
RetrofitFactory.makeRetrofitService().createPlan(
name.toRequestBody("text/plain".toMediaTypeOrNull()),
fileSignImage
)
}}
RetrofitService
#Multipart
#POST("create_plan")
fun createPlan(
#Part("name") name: RequestBody,
#Part image: MultipartBody.Part?
): Deferred<Response<WebApiResponse.ABCs>>
If I want to use Chopper, what is the correct way?
This is what I have tried
Future<Response> createPlan(
BuildContext context, String name,String path) async {
Response response;
try {
response = await _service.createPlan(
name,path);
return response;
} catch (e) {
rethrow;
}
}
Service
#Post(path: "create_plan")
#multipart
Future<Response> createPlan(
#Field('name') String name,#PartFile('image') String imagePath);
How can I convert the imagePath to file so I can pass it as file to server using Chopper?
Anyone?
Looking at the documentation for Chopper, the PartFile annotation supports three data types:
List<int>
String (path of your file)
MultipartFile (from package:http)
You are currently using String, but for reasons unknown it is not working for you. The first option would probably be the most straightforward, but the third option would be the most similar to what you currently have in Retrofit, so we could try that.
import 'package:http/http.dart';
...
Future<Response> createPlan(BuildContext context, String name, String path) async {
Response response;
try {
final bytes = (await File(path).readAsBytes()).toList();
final file = MultipartFile.fromBytes('image', bytes);
response = await _service.createPlan(
name,
file,
);
return response;
} catch (e) {
rethrow;
}
}
Service
#Post(path: "create_plan")
#multipart
Future<Response> createPlan(
#Field('name') String name,
#PartFile('image') MultipartFile image,
);
I was managed to upload file using http instead of Chopper.
Future<http.Response> createPlan(String name, String path) async {
var request = http.MultipartRequest(
"POST",
Uri.parse(
"http://xxx"));
request.fields['name'] = name;
request.files.add(await http.MultipartFile.fromPath(
'image',
path,
));
try {
var streamedResponse = await request.send();
var response = http.Response.fromStream(streamedResponse);
return response;
} catch (e) {
rethrow;
}
}

asp.net web api file upload without saving

Ok, so I am writing a service to recieve file uploads from an iPhone application through phonegap. They send me a file and I am trying to grab the actual file without saving it to any type of file system. Currently this is what I have
[HttpPost]
public string processRequest()
{
string ext = "Entered";
Request.Content.ReadAsMultipartAsync<MultipartMemoryStreamProvider>(new MultipartMemoryStreamProvider()).ContinueWith((tsk) =>
{
ext = "Request";
MultipartMemoryStreamProvider prvdr = tsk.Result;
foreach (HttpContent ctnt in prvdr.Contents)
{
ext = "Foreach";
// You would get hold of the inner memory stream here
Stream stream = ctnt.ReadAsStreamAsync().Result;
if (stream == null)
{
ext = "Null Stream";
}
Image img = Image.FromStream(stream);
if (ImageFormat.Jpeg.Equals(img.RawFormat))
{
ext = "jpeg";
}
else if (ImageFormat.Png.Equals(img.RawFormat))
{
ext = "Png";
}
else if (ImageFormat.Gif.Equals(img.RawFormat))
{
ext = "Gif";
}
// do something witht his stream now
}
});
return ext;
}
I have put various responses in there so I can see where the function is getting to. Right now it always returns "Entered" which means its not even reading the content of the request, the end game is for me to grab the file object, convert it into an image and then to base 64. Any direction would be appreciated. Remember I want to do this without any file system so no solutions that involve mapping a path to a server folder.
Ok so a little update, I have edited my code according to my first response and at least it attempts to execute now but it just gets infinitely stuck inside the code. This happens during the ReadAsMultipartAsync function
[HttpPost]
public string processRequest()
{
string ext = "Entered";
Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider()).ContinueWith((tsk) =>
{
ext = "Request";
MultipartMemoryStreamProvider prvdr = tsk.Result;
foreach (HttpContent ctnt in prvdr.Contents)
{
ext = "Foreach";
// You would get hold of the inner memory stream here
Stream stream = ctnt.ReadAsStreamAsync().Result;
if (stream == null)
{
ext = "Null Stream";
}
Image img = Image.FromStream(stream);
if (ImageFormat.Jpeg.Equals(img.RawFormat))
{
ext = "jpeg";
}
else if (ImageFormat.Png.Equals(img.RawFormat))
{
ext = "Png";
}
else if (ImageFormat.Gif.Equals(img.RawFormat))
{
ext = "Gif";
}
// do something witht his stream now
}
}).Wait();
return ext;
}
The block inside ContinueWith also runs asynchronously (if you look at the signature for ContinueWith, you'll see that it returns a Task as well). So, with the above code, essentially you're returning before any of that has a chance to execute.
Try doing:
Request.Content.ReadAsMultipartAsync().ContinueWith(...).Wait();
Also, not sure you need to go to the trouble of doing Request.Content.ReadAsMultipartAsync<MultipartMemoryStreamProvider>(new MultipartMemoryStreamProvider()); I believe Request.Content.ReadAsMultipartAsync() should suffice.
Hope that helps!

base64 encoded PNG to Blob

I am fiddling around with creating a Blob out of a base64 encoded PNG...
final FormData formData = new FormData();
final String base64Image = "data:image/png;base64,iVBORw0K<reduced the data.....>gg==";
final Blob blob = new Blob([base64Image],"image/png");
formData.append('file', blob, "android.png");
req.send(formData);
I don't know what I a doing wrong but the contents of blob is something but not the png I would like it to be.
thx in advance...
[Update]
final FormData formData = new FormData();
final String base64Image = "iVBORw0KGgo<...reduce data...>kJggg==";
// BTW: I used the Base64 from dart-sdk/io/base64.dart
final List<int> intList = Base64.decode(base64Image);
final Int8Array int8array = new Int8Array.fromList(intList);
final String atobString = window.atob(base64Image);
// Does not work
// final Blob blob = new Blob([atobString]);
// The same...
// final Blob blob = new Blob([int8array]);
formData.append('file', blob, "android.png");
//formData.append('new-filename', "icon-share.png");
req.send(formData);
I think the number of bytes generated by Base64.decode are OK. The filesize was 1003 bytes and decoding also produces 1003 bytes.
[Update 2]
Here is the source I am talking about:
https://github.com/MikeMitterer/AndroidIconGenerator.DART/blob/master/test/src/restserver.dart
OK, here is the answer to my own question:
import 'dart:convert'
...
test(' -> Upload File to REST-Server', () {
final HttpRequest req = new HttpRequest();
loadEnd(HttpRequest request) {
if (request.readyState == HttpRequest.DONE) {
switch(request.status) {
case HttpStatus.HTTP_200_OK:
expect(response['path'].endsWith("android.png"),true);
break;
case HttpStatus.HTTP_0_COMMUNICATION_FAILED:
expect(request.status,HttpStatus.HTTP_200_OK);
break;
default:
expect(request.status,HttpStatus.HTTP_200_OK);
break;
}
}
}
req.open("POST", uriprovider.forUpload().toString());
// REST returns JSON Data
req.setRequestHeader('Accept', 'application/json');
req.onLoadEnd.listen(expectAsync1((ProgressEvent e) => loadEnd(req)));
final FormData formData = new FormData();
final String base64Image = "data:image/png;base64,iVBORw0KG<code reduce for sample>RU5ErkJggg==";
final String raw = "iVBORw0KG<code reduce for sample>RU5ErkJggg==";
final String contenttype = "image/png";
// Base64 is a modified version of dart-sdk/lib/io/base64.dart
final List<int> intList = BASE64.decode(raw);
final Int8Array int8array = new Int8Array.fromList(intList);
// Converting to Uint8Array brought the solution!
final Uint8Array uint8array = new Uint8Array(intList.length);
// does not work!
//var binary = window.atob(raw);
final Blob blob = new Blob([uint8array]);
formData.append('file', blob, "android.png");
req.send(formData);
});
Thanks to everyone pushing me in the right direction!
Need decode base64 (i.e. atob) url, before you encode to Blob. It's easy! Try it!