Is it possible to customize Gif generation frame-rate with image package? - flutter

I've managed to generate an animated GIF image from a set of images on a temporary directory on my storage, with the image package. But I don't if it is possible to customize the frame-rate of the generated GIF image.
This my current generation code :
void _mergeScreenshotsIntoGif({
required int gameStepsCount,
required String tempStorageDirPath,
required String baseFilename,
}) async {
final animation = image.Animation();
final imageDecoder = image.PngDecoder();
for (var stepIndex = 1; stepIndex <= gameStepsCount; stepIndex++) {
final currentFile = File(
'$tempStorageDirPath${Platform.pathSeparator}${baseFilename}_$stepIndex.png');
final currentImageBytes = await currentFile.readAsBytes();
final currentImage = imageDecoder.decodeImage(currentImageBytes)!;
animation.addFrame(currentImage);
}
final gifData = image.encodeGifAnimation(animation);
if (gifData == null) {
//TODO handle gif generation error
return;
}
final destinationFile =
File('$tempStorageDirPath${Platform.pathSeparator}$baseFilename.gif');
await destinationFile.writeAsBytes(gifData);
}
I've looked at the documentation of the package, but did not manage to reach my needs.
So is it possible ?

Maybe a naive implementation, but I managed to "slow" the animation. By adding the different images several times.
Replacing
animation.addFrame(currentImage);
with
for (var frameRepetitionIndex = 0;
frameRepetitionIndex < 10;
frameRepetitionIndex++) {
animation.addFrame(currentImage);
}

Related

How do I scrape images using beautifulsoup in flutter?

So I successfully scraped the text from the card that im scraping from but for some reason i cant scrape the image within the card in the website.
class ScraperService{static List<PackageModel> run(String html){
try{
final soup = BeautifulSoup(html);
final items = soup.findAll('div', class_: 'card content-card');
List<PackageModel> packages = [];
for(var item in items){
final dest = item.find('h3', class_: 'card-heading')?.text??'';
final desc = item.find('p', class_: 'card-text')?.text??'';
final img = item.find('img', class_: 'card-img-top lazy slick-slide slick-current slick-active');
//final imgUrl = img!['src'];
//print(imgUrl);
PackageModel model = PackageModel(
destination: dest.substring(4),
description: desc,
image: img!['src'],
);
packages.add(model);
}
return packages;
} catch (e){
print('ScraperService $e');
return [];
}}}
When I write this code it does not show the cards in my app. I tried printing the text i extracted from the img tag
final img = item.find('img', class_: 'card-img-top lazy slick-slide slick-current slick-active');
The cards in my app did show,however the elements in the img tag did not show.
I also tried
final img = item.find('img', class_: 'card-img-top lazy slick-slide slick-current slick-active')!['src'];
Same thing happened above, these means that I did not get the elements from the img tag right? Then what should I do

Image not displaying in .NET MAUI Mac Catalyst

I'm trying to display an image to make my own custom splash screen using .NET MAUI. It is made in C# and does not use XAML. Here is my code:
SplashScreenActivity.cs:
using System;
using System.Text;
namespace LiveEditorHTML
{
public partial class SplashScreenActivity : ContentPage
{
Image splashScreenImage;
public async Task<string> ShowMsg(string title,
string msg, bool isQuestion, bool isInput,
int? num, string[]? question)
{
bool answer;
if (isQuestion && !isInput)
{
answer = await DisplayAlert(title, msg, "Yes", "No");
return answer.ToString();
}
else if (!isQuestion && !isInput)
{
await DisplayAlert(title, msg, "OK");
}
else if (!isQuestion && isInput)
{
string action = await DisplayActionSheet(
title + msg, "Cancel",
null, question
);
}
else
{
await DisplayAlert(title, msg, "OK");
}
return null;
}
public SplashScreenActivity()
{
var uiView = new ScrollView();
var stackLayout = new VerticalStackLayout();
var img = AssetsHelper.LoadMauiAsset("logo.png").Result;
Task.Run(() =>
{
string output = ShowMsg("Debug", img, false, false, 0, null).Result;
});
byte[] byteArray = Encoding.UTF8.GetBytes(img);
MemoryStream stream = new MemoryStream(byteArray);
splashScreenImage = new Image()
{
Source = ImageSource.FromStream(() => stream)
};
stackLayout.Children.Add(splashScreenImage);
this.Content = uiView;
}
}
}
AssetsHelper.cs:
using System;
namespace LiveEditorHTML
{
public class AssetsHelper
{
public static async Task<string> LoadMauiAsset(string fileName)
{
using var stream = await FileSystem.OpenAppPackageFileAsync(fileName);
using var reader = new StreamReader(stream);
var contents = reader.ReadToEndAsync();
return contents.Result;
}
}
}
Here is the image I used, created with GIMP, the image size is 456x456 (the same as the image sizes of the appicon.svg and appiconfg.svg files located at: Resources\AppIcon):
The ShowMsg() function is used to create a MessageBox like C# Winforms, in addition, it is also used for the cases of creating a Yes No questionnaire, and creating a questionnaire that requires the user to enter text. Currently, I just use the simplest feature, like the MessageBox in C# Winforms, which is to print a debug message, with the title Debug and the content as an image file that is read with the help of the AssetsHelper.cs support class.
When I run the program, the Debug window for printing information pops up, indicating that it is working, the file logo.png (with path at Resources\Raw) has been read successfully:
But then nothing is displayed:
I highly suspected that there might be an error, but no exceptions occurred, so I used the built-in image: dotnet_bot.svg to test (link at: Resources\Images). I replaced the following line in SplashScreenActivity.cs:
ImageSource.FromStream(() => stream)
Fort:
"dotnet_bot.svg"
The code becomes:
splashScreenImage = new Image()
{
Source = "dotnet_bot.svg"
};
to test. When I turn on the app and go through the Debug screen (since I haven't dropped the code that shows the Debug dialog), they don't work either:
And no exception is thrown. The app doesn't crash either.
All versions of .NET MAUI and VS are updated and VS is the latest Preview version. The computer I'm using is a Macbook Pro running macOS Monterey 12.5.1
So what's going on?
I had create a sample to test your code and the image can't show either. I found that you have changed the image file to the string, and then changed the string to the byte array.
You can try to convert the image to the byte array or set the image as the source directly. In addition, you didn't add the stacklayout into the scrollview. So you should add it or set the stacklayout as the page.content.
Set the image as the source directly
splashScreenImage = new Image()
{
Source = "test" // the test.png is in the /Resource/Image folder
};
stackLayout.Children.Add(splashScreenImage);
this.Content = stackLayout;
2.Convert the image to the byte array directly
public static async Task<byte[]> LoadMauiAsset(string fileName)
{
using var stream = await FileSystem.OpenAppPackageFileAsync(fileName);
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
return buffer;
}
MemoryStream stream = new MemoryStream(AssetsHelper.LoadMauiAsset("test").Result);
splashScreenImage = new Image()
{
Source = ImageSource.FromStream(() => stream)
};
stackLayout.Children.Add(splashScreenImage);
this.Content = stackLayout;

Paginated Flutter SfDataGrid Exporting All Data

I am using SfDataGrid with pagination and I would like to export all data not only the current page but I couldn't achieve it correctly.
My current code is below.
final excel.Workbook workbook = excel.Workbook();
for (var i = 0; i < viewModel.pagedRows.length; i++) {
final page = viewModel.pagedRows[i];
final excel.Worksheet worksheet = i == 0 ? workbook.worksheets[0] : workbook.worksheets.addWithName(i.toString());
key.currentState!.exportToExcelWorksheet(worksheet, rows: page);
}
final List<int> bytes = workbook.saveAsStream();
workbook.dispose();
writeToFile('DataGrid.xlsx', bytes);
Share.shareFiles([await getFilePath('DataGrid.xlsx')],
subject: 'Exported Excel',
mimeTypes: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-excel']);
With this code, I can correctly export paginated data to related worksheets. But the problem is summary rows because the export system uses the current visible datagrid's page's summary values while exporting and this causes data errors in the exported file.
I think I should use DataGridToExcelConverter and intervene exporting process however I didn't find a way to do it.
After taking a good sleep I solved my problem and as I guessed it was solved by using DataGridToExcelConverter.
CustomDataGridToExcelConverter converter = CustomDataGridToExcelConverter();
final excel.Workbook workbook = excel.Workbook();
workbook.worksheets[0].name = "1";
for (var i = 0; i < viewModel.pagedRows.length; i++) {
final page = viewModel.pagedRows[i];
final excel.Worksheet worksheet = i == 0 ? workbook.worksheets[0] : workbook.worksheets.addWithName((i + 1).toString());
converter.page = i;
key.currentState!.exportToExcelWorksheet(excludeColumns: ['id'], worksheet, rows: page, converter: converter,
cellExport: (details) async {
details.excelRange.cellStyle.hAlign = excel.HAlignType.center;
});
}
final List<int> bytes = workbook.saveAsStream();
workbook.dispose();
writeToFile('excel.xlsx', bytes);
And my CustomDataGridToExcelConverter class is like below
class CustomDataGridToExcelConverter extends DataGridToExcelConverter {
int page = 0;
#override
void exportToExcelWorksheet(SfDataGrid dataGrid, List<DataGridRow>? rows, Worksheet worksheet) {
(dataGrid.source as LogbookViewModel).silentHandlePageChange(page == 0 ? 0 : page - 1, page);
super.exportToExcelWorksheet(dataGrid, rows, worksheet);
}
silentHandlePageChange method is an alternate of handlePageChange which doesn't notify listeners.
void silentHandlePageChange(int oldPageIndex, int newPageIndex) async {
_dataGridRows = _pagedRows[newPageIndex];
_currentPage = newPageIndex;
}
In my opinion, paged excel export should be in the box but I managed to work it somehow

How to make this kind of animation in Flutter?

Video reference
please check the link above to see the animation.
The one in the video is made in Java, An imageView changing images using UniversalImageLoader in 2500 milliseconds interval with a Handler.
JavaCode:
int imgs[] = {R.drawable.efone, R.drawable.eftwo, R.drawable.efthree, R.drawable.effour, R.drawable.effive};
backgroundSlide = (ImageView) findViewById(R.id.bgSlide);
backgroundSlide.setImageResource(R.drawable.efone);
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
int i = 0;
#Override
public void run() {
if (i > imgs.length - 1)
i = 0;
backgroundSlide.startAnimation(animAlpha);
ImageLoader.getInstance().displayImage("drawable://" + imgs[i], backgroundSlide);
i++;
handler.postDelayed(runnable, 2500);
}
};
Xml:
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:id="#+id/bgSlide"
android:src="#drawable/efone" />
Giving you hint:
First add
import 'dart:async';
Suppose you have List of Images.
List<String> imgURLs = ['img1', img2, img3.....N];
Below code for change images:
int index = 0;
const duration = const Duration(seconds:2); // change time as per your requirement
new Timer.periodic(duration, (timer){
setState(){
imageObj = imgURLs[index];
}
if(index >= imgURLs.lenght-1) {
timer.cancel();
}
index++;
});
Put this code at your place might be in initState method and use imageObj to set your image on the screen.
imageObj might be Image type or whatever type based on your image list

javafx8 candle stick chart can't getrid of the stale data

I used the sample candle stick chart code to draw chart. When I worked in the java7 ,the chart worked fine. But when I tried in the Java8. there is a problem.
I tracked the problem like this:this code is from the sample code of Ensemble :CandlStickChart.java
#Override protected void layoutPlotChildren() {
// we have nothing to layout if no data is present
if(getData() == null) return;
// update candle positions
for (int seriesIndex=0; seriesIndex < getData().size(); seriesIndex++) {
Series<Number,Number> series = getData().get(seriesIndex);
Iterator<Data<Number,Number>> iter = getDisplayedDataIterator(series);
Path seriesPath = null;
if (series.getNode() instanceof Path) {
seriesPath = (Path)series.getNode();
seriesPath.getElements().clear();
}
while(iter.hasNext()) {
System.out.println(i++); // the different place
Data<Number,Number> item = iter.next();
double x = getXAxis().getDisplayPosition(getCurrentDisplayedXValue(item));
double y = getYAxis().getDisplayPosition(getCurrentDisplayedYValue(item));
Node itemNode = item.getNode();
CandleStickExtraValues extra = (CandleStickExtraValues)item.getExtraValue();
if (itemNode instanceof Candle && extra != null) {
Candle candle = (Candle) itemNode;
this is part of the code.the problem is with the "the different palce"
for the iter.hasNext() will preserve the stale value.so, every time I set in new data。the list is further long .
the setdata code like :
ObservableList<XYChart.Data<Number, Number>> newData
= FXCollections.<XYChart.Data<Number, Number>>observableArrayList();
for (int j = 1; j <= leno; j++) {
newData.add(。。。。。。。);//
series.getData().clear();
series.setData(newData);
When I remove the stale data by Iter.remove the exception is:we don't support removeing items from the diplayed data list.
You have to add two calls to removeDataItemFromDisplay to the dataItemRemoved method.
Note: I made series and item final in the example code.
#Override
protected void dataItemRemoved(final Data<Number, Number> item,
final Series<Number, Number> series) {
final Node candle = item.getNode();
if (shouldAnimate()) {
// fade out old candle
FadeTransition ft = new FadeTransition(Duration.millis(500), candle);
ft.setToValue(0);
ft.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
getPlotChildren().remove(candle);
removeDataItemFromDisplay(series, item);
}
});
ft.play();
} else {
getPlotChildren().remove(candle);
removeDataItemFromDisplay(series, item);
}
}