Convert Image from Buffer to display in Frontend (Flutter) - database

I have a backend based on NodeJS and using mongodb as the database. Images with the field name photo is saved as object Type Buffer. I have successfully sent Images from the app using form data but I am not able to display the image in frontend.
This is the function used to get the data from API
Future<User> userWithId() async {
User result;
try {
final response = await http.get(
'api link',
headers: <String, String>{
'Authorization': 'Bearer $token',
},
);
if (response.statusCode == 200) {
result = User.fromJson(jsonDecode(response.body));
}
} catch (e) {
print(e.toString());
}
return result;
}
This is the fromJson function of the class User. The photo field here returns the image as buffer.
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['_id'] as String ?? "",
email: json['email'] as String ?? "",
// profilePhoto: json["photo"] ?? null,
// profilePhoto: base64.encode(jsonDecode(json["photo"])) ?? null,
);
}
This is the data from the photo field
This is the data from MongoDB database

For those who are facing this issue as well, this is a multi-part problem:
Converting List to List.
Using converted List to read/display image.
In OP's case, to get buffer List would be profilePhoto: json["photo"]["data"]["data"].
For step 1, To convert List to List:
List<dynamic> bufferDynamic = profilePhoto: json["photo"]["data"]["data"];
List<int> bufferInt = buffer.map((e) => e as int).toList();
For step 2 as some have already mention, use Image.memory class provided by Flutter.
Image.memory(Uint8List.fromList(bufferInt))
Hope this helps for those who need to read/display image from buffer. (:

you can use base64Decode method from dart:convert
store your image binary in string format:
factory User.fromJson(Map<String, dynamic> json) {
return User(
...
profilePhoto: json["photo"] ?? null,
...
);
}
and use the following code in UI:
Image.memory(base64Decode(user.profilePhoto))
also, don't forget to add an if statement to check if the photo is null or not
Hope, it helps

json['photo']['data']['data'];
By doing this you are getting this error List' is not a subtype of type 'String'. So may be your return type for profilePhoto is String. Change it to dynamic then try again.

Thanks to the great article bellow explaining about bytes in dart, you can convert your response data which is as List of integers, to Uint8List data type and pass it to Image.memory to render image.
Image.memory(Uint8List.fromList(// pass image data array here));
https://medium.com/flutter-community/working-with-bytes-in-dart-6ece83455721

Try like this
List<int> imageData = user.profilePhoto['data'] as List<int>
////
Image.memory(Uint8List.fromList(imageData));

Image type
You should modify your class User, currently you have something like:
class User {
final String id;
final String email;
final ? profilePhoto
}
I am not sure which type you are currently using but you need to change it accordingly to the data you get in your response. Your image is, in your computer, a list of bytes (uint8, meaning unsigned integer of 8 bits, so 1 byte), ranging from 0 to 255 in value (0 to 0xFF).
Images header
You can read about EXIF to understand better how the standard specifies the formats for images
Every JPEG file starts from binary value '0xFFD8', ends by binary value '0xFFD9'.
The first eight bytes of a PNG file always contain the following (decimal) values: 137 80 78 71 13 10 26 10
Fix
Change the type of your profilePhoto to Uint8List, full code:
class User {
final String id;
final String email;
String profilePhoto // I don't know which type you use
User({this.id, this.email, this.profilePhoto});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
id: json['_id'] as String ?? "",
email: json['email'] as String ?? "",
profilePhoto: json["photo"] ?? null,
);
}
}
And then load the image in your widget with Image.memory while being cautious as its value could be null:
return user.profilePhoto != null ? Image.memory(user.profilePhoto) : Container();
NB: Image.memory is a shorthand of an Image widget backed by MemoryImage.

Related

How to iterate through a dynamic list of objects in dart

I have this dynamic list which I am decoding from a json response, it goes as
[{Calcium: [47.92, mg, Red, 0.00169033008, ounce]}, {Choline: [71.88, mg, Red, 0.00253549512, ounce]}, {Copper: [0.08, mg, Red, 0.00000282192, ounce]}, {Crude fat: [70.28, g, Green, 2.47905672, ounce]}, {Folate: [23.96, mcg, Red, 0.00000084516504, ounce]}...]
In that I need to check whether a given key exists. for an example check key "Calcium" exists and if so I need to fetch the value of index 0 and index 2 of the array belongs to that key,
I want to perform this in an iterative way.
how can I achieve this in dart?
I have tried this but it does not work , maybe I'm doing it in a wrong way.
nutrientList.forEach((element) {
if(nutrientList.contains("Calcium")) {
valCalcium = element.calcium[0];
calciumClr = element.calcium[2];
} else {}
You can create an Object that maps the Json object to the values you need. Let Calcium be an object that parses "Calcium". Since the Map has dynamic as its values, it can handle a List value.
class Calcium {
final List<String> content;
Calcium({
required this.content,
});
factory Calcium.fromJson(Map<String, dynamic> json) {
return Calcium(
content: json['Calcium'],
);
}
}
Then to fetch the details inside the Object, parse the json response with Calcium.fromJson() then get List by calling Calcium.content
Calcium calcium = Calcium.fromJson(json);
List<String> calciumDetails = calcium.content;

How to pass an Encoded ("application/x-www-form-urlencoded") object with array within a query string in HttpClient?

I am trying to encode ("application/x-www-form-urlencoded") an object in Angular using HttpParameterCodec.
This object has a field as object which in turn has array of string. object structure as mentioned below.
export class SearchRequest {id: string = undefined;partnerIds: PartnerIds = undefined;}
export class PartnerIds { partnerId: string[] = undefined;}
Now when I am trying encode this object with utility code (which works fine with plain object) mentioned below, It is not in correct format due to list of string in it.
generateQueryParams(searchRequest) {
let httpParams: HttpParams = new HttpParams({encoder: new CustomEncoderComponent()});
Object.keys(searchRequest).forEach(key => {
httpParams = httpParams.append(key, searchRequest[key]);
});
return httpParams;
}
I tried with below query params format but it did not work.
1. id=123&partnerIds=XYZ&partnerIds=ABC
2. id=123&partnerId[]=XYZ&partnerId[]=ABC
3. id=123&partnerId=XYZ&partnerId=ABC
Please suggest How to pass this (SearchRequest) object within a query string in HttpClient?

how to retrieve values of the map returned by jsonPath().getMap methods of rest assured

how to retrieve values of the map returned by jsonPath().getMap methods of rest assured
I am trying to get the response on below api in Map, which I am able to successfully get but when I try to access the value of key "id" in the below code, I get cast Error on line "String id = test.get("id");"
public void testRestAssured() {
Response apiResponse = RestAssured.given().get("https://reqres.in/api/user/2");
Map<String, String> test = apiResponse.jsonPath().getMap("data");
System.out.println(test);
String id = test.get("id");
System.out.println("ID : " + id);
}
Error
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
I tried to do many things like
String id = test.get("id").toString();
or
String id = String.valueOf(test.get("id"));
but nothing helped in resolution
api response is as follows
{
"data": {
"id": 2,
"name": "fuchsia rose",
"year": 2001,
"color": "#C74375",
"pantone_value": "17-2031"
}
}
Try the below code, it is working fine for me:
Response apiResponse = RestAssured.given().get("http://reqres.in/api/user/2");
Map<Object, Object> test = apiResponse.jsonPath().getMap("data");
System.out.println(test);
String id = test.get("id").toString();
System.out.println("ID : " + id);
The changes I have done is: change Map of (String, String) to Map (Object, Object) because we know that each key of map is string but value could be of any data type.
I hope it will solve your problem.
Correct code is
Response apiResponse = RestAssured.given().get("http://reqres.in/api/user/2");
Map<Object, Object> test = apiResponse.jsonPath().getMap("data");
System.out.println(test);
for (Object e : test.keySet()) {
System.out.println(" Key is " + e + " , value is " + test.get(e));
simply try this:
import com.jayway.restassured.path.json.JsonPath;
JsonPath extractor = JsonPath.from(apiResponse.toString());
String id = extractor.getString("data.id");
You should define Object for map value. Because your json values are different types (String and int).
// define Object type for map values
Map<String, Object> test = apiResponse.jsonPath().getMap("data");
// use casting for assigning
int id = (int) test.get("id");
Do you really need to make from your response map object?
If not you can use this one:
String id = RestAssured.given().get("https://reqres.in/api/user/2")
.then().extract().jsonPath().getString("data.id");

Insert multiple records into database with Vapor3

I want to be able to bulk add records to a nosql database in Vapor 3.
This is my Struct.
struct Country: Content {
let countryName: String
let timezone: String
let defaultPickupLocation: String
}
So I'm trying to pass an array of JSON objects but I'm not sure how to structure the route nor how to access the array to decode each one.
I have tried this route:
let countryGroup = router.grouped("api/country")
countryGroup.post([Country.self], at:"bulk", use: bulkAddCountries)
with this function:
func bulkAddCountries(req: Request, countries:[Country]) throws -> Future<String> {
for country in countries{
return try req.content.decode(Country.self).map(to: String.self) { countries in
//creates a JSON encoder to encode the JSON data
let encoder = JSONEncoder()
let countryData:Data
do{
countryData = try encoder.encode(country) // encode the data
} catch {
return "Error. Data in the wrong format."
}
// code to save data
}
}
}
So how do I structure both the Route and the function to get access to each country?
I'm not sure which NoSQL database you plan on using, but the current beta versions of MongoKitten 5 and Meow 2.0 make this pretty easy.
Please note how we didn't write documentation for these two libraries yet as we pushed to a stable API first. The following code is roughly what you need with MongoKitten 5:
// Register MongoKitten to Vapor's Services
services.register(Future<MongoKitten.Database>.self) { container in
return try MongoKitten.Database.connect(settings: ConnectionSettings("mongodb://localhost/my-db"), on: container.eventLoop)
}
// Globally, add this so that the above code can register MongoKitten to Vapor's Services
extension Future: Service where T == MongoKitten.Database {}
// An adaptation of your function
func bulkAddCountries(req: Request, countries:[Country]) throws -> Future<Response> {
// Get a handle to MongoDB
let database = req.make(Future<MongoKitten.Database>.self)
// Make a `Document` for each Country
let documents = try countries.map { country in
return try BSONEncoder().encode(country)
}
// Insert the countries to the "countries" MongoDB collection
return database["countries"].insert(documents: documents).map { success in
return // Return a successful response
}
}
I had a similar need and want to share my solution for bulk processing in Vapor 3. I’d love to have another experienced developer help refine my solution.
I’m going to try my best to explain what I did. And I’m probably wrong.
First, nothing special in the router. Here, I’m handling a POST to items/batch for a JSON array of Items.
router.post("items", "batch", use: itemsController.handleBatch)
Then the controller’s handler.
func createBatch(_ req: Request) throws -> Future<HTTPStatus> {
// Decode request to [Item]
return try req.content.decode([Item].self)
// flatMap will collapse Future<Future<HTTPStatus>> to [Future<HTTPStatus>]
.flatMap(to: HTTPStatus.self) { items in
// Handle each item as 'itm'. Transforming itm to Future<HTTPStatus>
return items.map { itm -> Future<HTTPStatus> in
// Process itm. Here, I save, producing a Future<Item> called savedItem
let savedItem = itm.save(on: req)
// transform the Future<Item> to Future<HTTPStatus>
return savedItem.transform(to: HTTPStatus.ok)
}
// flatten() : “Flattens an array of futures into a future with an array of results”
// e.g. [Future<HTTPStatus>] -> Future<[HTTPStatus]>
.flatten(on: req)
// transform() : Maps the current future to contain the new type. Errors are carried over, successful (expected) results are transformed into the given instance.
// e.g. Future<[.ok]> -> Future<.ok>
.transform(to: HTTPStatus.ok)
}
}

FullCalendar JSON not populating calendar

I think I am missing something. I have set up Full Calendar, and have the default version working, but now am adding my own JSON, and it is not.
Code in the calendar page is
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay,listWeek'
},
defaultDate: '2017-09-12',
editable: true,
navLinks: true, // can click day/week names to navigate views
eventLimit: true, // allow "more" link when too many events
events: {
url: 'php/get-events.php',
error: function() {
$('#script-warning').show();
}
},
loading: function(bool) {
$('#loading').toggle(bool);
}
});
});
I am learning how to encode JSON as I go along, and I found a tutorial online that gave me some code that seems to work. I have amended the original code in get-events.php to read like this (snippet with DB details taken out)...
// Require our Event class and datetime utilities
require dirname(__FILE__) . '/utils.php';
// Short-circuit if the client did not give us a date range.
if (!isset($_GET['start']) || !isset($_GET['end'])) {
die("Please provide a date range.");
}
// Parse the start/end parameters.
// These are assumed to be ISO8601 strings with no time nor timezone, like "2013-12-29".
// Since no timezone will be present, they will parsed as UTC.
$range_start = parseDateTime($_GET['start']);
$range_end = parseDateTime($_GET['end']);
// Parse the timezone parameter if it is present.
$timezone = null;
if (isset($_GET['timezone'])) {
$timezone = new DateTimeZone($_GET['timezone']);
}
class Emp {
public $id = "";
public $title = "";
public $start = "";
public $url = "";
}
while(!$JAN->atEnd()) {
e = new Emp();
$e->id = $JAN->getColumnVal("ID");
$e->title = $JAN->getColumnVal("TITLE");
$e->start = $JAN->getColumnVal("DATE")."T".$JAN->getColumnVal("TIME");
$e->url = "meeting_info.php?ID=".$JAN->getColumnVal("ID");
echo json_encode($e);
$JAN->moveNext();
}
$JAN->moveFirst(); //return RS to first record
// Read and parse our events JSON file into an array of event data arrays.
$json = file_get_contents(dirname(__FILE__) . '/../json/events.json');
$input_arrays = json_decode($json, true);
// Accumulate an output array of event data arrays.
$output_arrays = array();
foreach ($input_arrays as $array) {
// Convert the input array into a useful Event object
$event = new Event($array, $timezone);
// If the event is in-bounds, add it to the output
if ($event->isWithinDayRange($range_start, $range_end)) {
$output_arrays[] = $event->toArray();
}
}
// Send JSON to the client.
echo json_encode($output_arrays);
When I run the get-events.php page on it's own I get what I am assuming to be a correctly encoded JSON returned, one example in the array is ...
{"id":20,"title":"Executive Committee Meeting","start":"2017-05-01T00:00:00","url":"meeting_info.php?ID=20"}
Can anybody tell me what I have done wrong?
You need to run json_encode() on a complete array of PHP objects, not on each one individually. In your loop, add each Emp to an array, and then encode the array, when the loop ends.
If you look in your browser's network tab at the result of your ajax request, I think you're very likely to see a string of individual objects, but not wrapped in array (square) brackets, and not separated by commas, meaning the JSON is invalid. There's also a good chance there's an error message in your browser's console about the invalid data format. It's best to check this rather than assuming your JSON is correct. There are also online JSON validator tools you can paste it into, to validate the JSON in isolation.
Something like this should work better:
$events = array();
while(!$JAN->atEnd()) {
e = new Emp();
$e->id = $JAN->getColumnVal("ID");
$e->title = $JAN->getColumnVal("TITLE");
$e->start = $JAN->getColumnVal("DATE")."T".$JAN->getColumnVal("TIME");
$e->url = "meeting_info.php?ID=".$JAN->getColumnVal("ID");
$events[] = $e; //add event to the array
$JAN->moveNext();
}
echo json_encode($events); //encode the whole array as a coherent piece of JSON
//P.S. no need to run moveFirst really, since the request is going to end, and discard the resultset anyhow. Depending on your data access technique, you possibly need to close the recordset though, to avoid locking etc.
What you need your code to generate (and what fullCalendar is expecting), is a JSON array - here's a simple example containing 2 elements (representing events):
[
{ "id":20, "title":"Executive Committee Meeting", "start":"2017-05-01T00:00:00", "url":"meeting_info.php?ID=20" },
{ "id":21, "title":"Another Boring Committee Meeting", "start":"2017-05-02T00:00:00", "url":"meeting_info.php?ID=21" }
]
The example code I've given above should generate an array which is in the same format as this JSON sample.

Resources