Image not showing after Base 64 Conversion - flutter

I am few months into Flutter, Ran into this issue where I have gotten a base64 String from an API, I have decoded the base 64 string and converted it to bytes. When I try to display it on an image widget I get nothing. Below is my code. and a snippet from my console. Thank you.
if (imgString != null) {
_bytesImage = base64.decode(imgString.toString());
print(_bytesImage);
return ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.memory(
_bytesImage,
width: 300,
height: 250,
fit: BoxFit.cover,
));
} else {
print("Image String is null");
return SizedBox.shrink();
}

I had the same issue. I just did this.
Added this under Build Widget.
I stored the base64 string in var called _imgString. It was containing some new line characters in it. So I used split function and joined them to get a proper format.
Uint8List _image = base64.decode(_imgString.split('\n').join());
image = Image.memory(
_image,
fit: BoxFit.cover,
);
You can call this image object in your widget tree wherever you want.
For eg.
Container(
margin: const EdgeInsets.all(15.0),
padding: const EdgeInsets.all(3.0),
height: 250.0,
width: 400,
child: SingleChildScrollView(
// for Vertical scrolling
scrollDirection: Axis.vertical,
child: image,
),
),

You can convert a Uint8List to a Flutter Image..
if (imgString != null) {
_bytesImage = BASE64.encode(imgString.toString());
Uint8List bytes = BASE64.decode(_bytesImage);
print(bytes);
return ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.memory(
bytes,
width: 300,
height: 250,
fit: BoxFit.cover,
));
} else {
print("Image String is null");
return SizedBox.shrink();
}

Related

asset image not appearing in flutter

I am using dhiwise to convert my figma prototype into flutter but the header is not appearing and is somehow above the screen. I tried moving it elsewhere but it just puts it outside the header.
current look
what it is supposed to look like
return SafeArea(
child: Scaffold(
backgroundColor: ColorConstant.whiteA700,
body: Container(
height: size.height,
width: size.width,
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: SingleChildScrollView(
child: Container(
height: size.height,
width: size.width,
child: Stack(
alignment: Alignment.topRight,
children: [
Align(
alignment: Alignment.center,
child: Container(
height: size.height,
width: size.width,
decoration: BoxDecoration(
color: ColorConstant.whiteA700,
),
child: Stack(
alignment: Alignment.bottomCenter,
children: [
Align(
alignment: Alignment.topCenter,
child: Container(
width: size.width,
padding: getPadding(
left: 11,
top: 7,
right: 11,
bottom: 7,
),
decoration: BoxDecoration(
color: ColorConstant.blue200,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
CustomIconButton(
height: 53,
width: 53,
margin: getMargin(
bottom: 276,
),
child: CustomImageView(
svgPath: ImageConstant.imgUser,
the custom image view code, this code was directly from the website itself and I have no idea what any of the code means to do
// ignore_for_file: must_be_immutable
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class CustomImageView extends StatelessWidget {
///[url] is required parameter for fetching network image
String? url;
///[imagePath] is required parameter for showing png,jpg,etc image
String? imagePath;
///[svgPath] is required parameter for showing svg image
String? svgPath;
///[file] is required parameter for fetching image file
File? file;
double? height;
double? width;
Color? color;
BoxFit? fit;
final String placeHolder;
Alignment? alignment;
VoidCallback? onTap;
EdgeInsetsGeometry? margin;
BorderRadius? radius;
BoxBorder? border;
///a [CustomImageView] it can be used for showing any type of images
/// it will shows the placeholder image if image is not found on network image
CustomImageView({
this.url,
this.imagePath,
this.svgPath,
this.file,
this.height,
this.width,
this.color,
this.fit,
this.alignment,
this.onTap,
this.radius,
this.margin,
this.border,
this.placeHolder = 'assets/images/image_not_found.png',
});
#override
Widget build(BuildContext context) {
return alignment != null
? Align(
alignment: alignment!,
child: _buildWidget(),
)
: _buildWidget();
}
Widget _buildWidget() {
return Padding(
padding: margin ?? EdgeInsets.zero,
child: InkWell(
onTap: onTap,
child: _buildCircleImage(),
),
);
}
///build the image with border radius
_buildCircleImage() {
if(radius!=null) {
return ClipRRect(
borderRadius: radius,
child: _buildImageWithBorder(),
);
}
else{
return _buildImageWithBorder();
}
}
///build the image with border and border radius style
_buildImageWithBorder(){
if(border!=null) {
return Container(
decoration: BoxDecoration(
border: border,
borderRadius: radius,
),
child: _buildImageView(),
);
}else{
return _buildImageView();
}
}
Widget _buildImageView() {
if (svgPath != null && svgPath!.isNotEmpty) {
return Container(
height: height,
width: width,
child: SvgPicture.asset(
svgPath!,
height: height,
width: width,
fit: fit ?? BoxFit.contain,
color: color,
),
);
} else if (file != null && file!.path.isNotEmpty) {
return Image.file(
file!,
height: height,
width: width,
fit: fit ?? BoxFit.cover,
color: color,
);
} else if (url != null && url!.isNotEmpty) {
return CachedNetworkImage(
height: height,
width: width,
fit: fit,
imageUrl: url!,
color: color,
placeholder: (context, url) => Container(
height: 30,
width: 30,
child: LinearProgressIndicator(
color: Colors.grey.shade200,
backgroundColor: Colors.grey.shade100,
),
),
errorWidget: (context, url, error) => Image.asset(
placeHolder,
height: height,
width: width,
fit: fit ?? BoxFit.cover,
),
);
} else if (imagePath != null && imagePath!.isNotEmpty) {
return Image.asset(
imagePath!,
height: height,
width: width,
fit: fit ?? BoxFit.cover,
color: color,
);
}
return SizedBox();
}
}
1- flutter clean
2- flutter pub get
And if it doesn't work with these instructions, I suggest you look at the link below
enter link description here
I hope you specified that image as an asset in the pubspec.yaml.
I mean...
Flutter uses the pubspec.yaml file, located at the root of your project, to identify assets required by an app.
flutter:
assets:
- assets/my_icon.png
- assets/background.png
To include all assets under a directory, specify the directory name with the / character at the end:
flutter:
assets:
- directory/
- directory/subdirectory/
If you already specify path of your image (sometimes you need to hot restart if you add new asset)
please check that svg image was fine by opening it via web. I face the same issues before with svg using SvgPicture I can open svg file on web but not readble in mobile apps. As I remember my error was not valid svg.
This library only supports <defs> and xlink:href references that are defined ahead of their references.
If do so, maybe you can try this one.
save image as PNG from Figma
Import image to Adobe XD
Export to SVG.
Replace current asset with this Adobe XD svg format.

Flutter: Image resizes weirdly

I have an app with a feature that allows users to upload images, and later these images are used at various points through the app. I use imagePicker to get the images, with the following method:
onTap: () async {
ImagePicker _picker = ImagePicker();
final XFile? _image = await _picker.pickImage(
source: ImageSource.gallery,
imageQuality: 50,
);
if (_image == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('No image was selected.')));
}
if (_image != null) {
print('Uploading ...');
Container(
child: Center(child: CircularProgressIndicator()),
);
StorageRepository().updateImage(user, _image, index);
}
},
One example of a widget with weird image resizing is the following:
SizedBox(
height: MediaQuery.of(context).size.height / 1.4,
width: MediaQuery.of(context).size.width,
child: Stack(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(3, 3),
blurRadius: 3,
spreadRadius: 3)
],
image: DecorationImage(
fit: BoxFit.fill,
image: NetworkImage(voteUser!
.imageUrls[state.imageUrlIndex]),
),
),
),
...
),
),
In this image, you can see the guy is stretched out, making the photo look weird.
My question is, how can I make an image that consistently looks good, but will not overflow the screen? I recognize cropping the image during the upload can help, however i would then have to set widgets with variable widths and heights rather than using mediaQuery, which runs the risk of overflowing the screen. Any ideas? thanks!
use Boxfit.cover it will work.
fit: BoxFit.cover

setState() does not update Image widget after data is passed back from another screen

I currently have a screen where if you type into a search field it navigates you to a 2nd screen (ImageResults()) that displays images based upon the search keyword. When you select an image on the 2nd screen, the image url is passed back to the 1st screen and the image should be displayed as a preview.
I did a print statement print(image) to check if the 2nd screen successfully passed the url to the 1st screen and it did. However, the image widget is not updating even after calling setState() and keeps displaying the image when image == null is true when the print statement indicates that image is not null and contains the selected image url.
Any thoughts on what's going on? Thanks!
Widget build(BuildContext context) {
String? image;
TextEditingController _searchInputController = TextEditingController();
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
TextField(
controller: _searchInputController,
textInputAction: TextInputAction.search,
onSubmitted: (String keyword) async {
var data = await getPics(_searchInputController.text);
final _image = await Navigator.of(context).push(createRoute(
ImageResults(_searchInputController.text, data['photos'])));
setState(() {
_searchInputController.text = '';
image = _image;
});
print(image);
},
),
image == null
? ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.asset(
'assets/activity.jpg',
height: 200,
width: MediaQuery.of(context).size.width * .6,
fit: BoxFit.cover,
),
)
: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
image!,
height: 200,
width: MediaQuery.of(context).size.width * .6,
fit: BoxFit.cover,
),
)
],
),
),
);
}
You need to move your variable declarations outside the build function. Because if your image variable is inside the build function, it will be set to null after your setState()
String? image;
Widget build(BuildContext context) {
//...
}
I'd recommend you do that for your TextEditingController as well

How can I make a Card height extend based on content?

I am creating a Card which has a header and a grid view of photos. Below is the code:
_getImageWidget(Post post, AppConfig config) {
if (post.photoPaths != null && post.photoPaths.length > 0) {
var url = config.imagePathDomain + post.photoPaths[0];
try {
return Expanded(
child: GridView.count(
crossAxisCount: 3,
shrinkWrap: false,
children: post.photoPaths.map<Widget>((String path) {
return CachedNetworkImage(
imageUrl: url,
);
}).toList()));
} catch (err) {
return Container();
}
}
return Container();
}
#override
Widget build(BuildContext context) {
var config = AppConfig.of(context);
return BlocBuilder<UserInfoBloc, UserInfo>(builder: (_, userInfo) {
return Container(
width: MediaQuery.of(context).size.width,
child: Card(
child: Column(children: <Widget>[
Row(
children: <Widget>[
IconButton(
iconSize: 30,
icon: roundImage(post.userPicture, Icon(Icons.person)),
onPressed: () {},
),
Text('#${userInfo.username}')
],
),
this._getImageWidget(post, config),
])));
});
}
The header in the Card is a Row includes a IconButton and Text.
The body of the Card is a gridview which includes a few photo.
Below is the screenshot when I run the code. You can see that the photo is shown only a half. And I can scroll vertically on the grid view. The number of photos is dynamic which means there could be many rows of photos in the GridView. How can I make the Card extend based on its children?
By simply setting your CachedNetwork image to use a fit: BoxFit.cover that will resize to fill the content while preserving ratio (this means you may lose some of its details) or fit: BoxFit.contain that will try to be as big as possible while containing the entire source (image) within the bounds.
If that doesn't help as well (as I'm not seeing the entire tree so I'm not sure about the ancestors of your Card) you can also replace the return of your BlocBuilder's child to be a FittedBox instead of a Container and apply the same logic for the fit property, but for the whole card instead.
Try using a fixed size container and using the BoxFit property on the container.
Something like this :
new Container(
width: 80.0,
height: 80.0,
decoration: new BoxDecoration(
shape: BoxShape.rectangle,
image: new DecorationImage(
fit: BoxFit.fill,
image: CachedNetworkImageProvider(url),
),
),
),
Edit : Try to remove itemExtent from ListView.builder

Assign an image dynamically in flutter

How can I assign an image dynamically in flutter ? For example:
final topContent = Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10.0),
height: MediaQuery.of(context).size.height * 0.5,
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(lesson.imagePath),
fit: BoxFit.cover,
),
)),
Container(
height: MediaQuery.of(context).size.height * 0.5,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
child: SingleChildScrollView(
controller: _scrollController,
child: Center(
child: topContentText,
),
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
Now the image at the start lesson.imagePath is what I want to change dynamically. I tried to use setState() but it gives me an error:
The expression here is a type of void and cannot be used
image: setState ((){
if (someCondition) {
return new AssetImage(lesson.imagePath);
}
}),
Your setState call is wrong! The most simple way is make your image as state of your widget and update this image inside a setState call. setState method does not returns nothing it just rebuilds your widget.
In your _WidgetState class you declare as member:
AssetImage _imageToShow;
You can provider a initial image inside initState method.
#override
initState(){
_imageToShow = AssetImage('youAssetImage');
}
Your Container widget should be declared as:
Container(
padding: EdgeInsets.only(left: 10.0),
height: MediaQuery.of(context).size.height * 0.5,
decoration: new BoxDecoration(
image: new DecorationImage(
image: _imageToShow,
fit: BoxFit.cover,
),
)),
),
And to update your image with setState call you just need:
void updateImage() {
setState ((){
if (someCondition) {
_imageToShow = new AssetImage(lesson.imagePath);
}
});
}
But remember that something has to call updateImage method.
The above solution can work also you can set an array of names and you can set the same image name in the assets folder and you can dynamically select the image where you want to use.
suppose in your case you have a list of lessons.
var lesson = ['a','b','c'];
In assets, folder give the same name to the images. (Don't forget to update the pubspec.yaml file)
Then in the AssetImage you can give the path which can be chosen dynamically.
image:AssetImage('assets/${lesson[index]}.jpg')
Remember to give the same name to the image like here a,b and c to the image.
Also the same extension to be given like here .jpg
image:AssetImage('assets/${lesson[index]}.jpg')