brendan-duncan / image

Dart Image Library for opening, manipulating, and saving various different image file formats.
MIT License
1.17k stars 263 forks source link

multi_frame_codec.cc(109) Could not getPixels for frame 1 #682

Open hanyuzheng opened 1 week ago

hanyuzheng commented 1 week ago

How to solve this problem?please help me.

import 'package:image/image.dart' as img;s
import 'dart:typed_data';

img.Image? image = await img.decodeGifFile(BgImageController.to.imageUri);
Uint8List imageData = img.GifEncoder().encode(image!);

ERROR message

[ERROR:flutter/lib/ui/painting/multi_frame_codec.cc(109)] Could not getPixels for frame 1

════════ Exception caught by image resource service ════════════════════════════
The following _Exception was thrown resolving an image frame:
Exception: Could not getPixels for frame 1

When the exception was thrown, this was the stack:
════════════════════════════════════════════════════════════════════════════════
ajee10x commented 1 day ago

What i understand simply...

Try these solutions, as I’m currently working on an open source application that handles this kind of stuff in my @openlab-x, and I will launch it soon. Of course, @brendan-duncan will get a lot of credit for his hard work on https://pub.dev/packages/image :) Everything is working on my end!

import 'package:image/image.dart' as img;
import 'dart:io';

void main() async {
  // Load the GIF image file
  var gifImage = await File('your_gif_image.gif').readAsBytes();

  // Decode the GIF image file
  var decodedImage = img.decodeGif(gifImage);

  if (decodedImage != null) {
    // Perform operations on the decoded image if needed
    Uint8List imageData = img.encodeGif(decodedImage);

    // Save the result back as a GIF
    await File('output_image.gif').writeAsBytes(imageData);
  } else {
    print('Failed to decode GIF image');
  }
}

And here i made the prefect example for what you want to achieve:

# The following section is specific to Flutter packages.
flutter:
  assets:
    - assets/SampleGIFImage_350kbmb.gif
import 'package:flutter/material.dart';
import 'dart:typed_data';
import 'package:image/image.dart' as img;
import 'package:flutter/services.dart' show rootBundle;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'GIF Processing Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Uint8List? _originalImage;
  Uint8List? _modifiedImage;
  String _decodingStatus = "Decoding...";
  String _grayscaleStatus = "Converting to Grayscale...";
  String _encodingStatus = "Encoding...";
  bool _isProcessing = false;

  Future<void> _processImage() async {
    setState(() {
      _isProcessing = true;
      _decodingStatus = "Decoding...";
      _grayscaleStatus = "Converting to Grayscale...";
      _encodingStatus = "Encoding...";
    });

    try {
      // Step 1: Decoding the GIF
      print('Step 1: Decoding...');
      final byteData =
          await rootBundle.load('assets/SampleGIFImage_350kbmb.gif');
      final Uint8List bytes = byteData.buffer.asUint8List();

      img.Image? decodedImage = img.decodeGif(bytes);
      if (decodedImage != null) {
        setState(() {
          _originalImage = bytes;
          _decodingStatus = "Decoding... Done"; // Turn green when done
        });
        print('Step 1: Decoding Done.');

        // Step 2: Convert to Grayscale
        print('Step 2: Converting to Grayscale...');
        img.Image grayscaleImage = img.grayscale(decodedImage);
        setState(() {
          _grayscaleStatus = "Converting to Grayscale... Done"; // Turn green
        });
        print('Step 2: Converting to Grayscale Done.');

        // Step 3: Re-encode the image
        print('Step 3: Encoding...');
        Uint8List modifiedBytes =
            Uint8List.fromList(img.encodeGif(grayscaleImage));
        setState(() {
          _modifiedImage = modifiedBytes;
          _encodingStatus = "Encoding... Done"; // Turn green
        });
        print('Step 3: Encoding Done.');
      } else {
        print('Failed to decode the image.');
      }
    } catch (e) {
      print('Error during image processing: $e');
    } finally {
      setState(() {
        _isProcessing = false;
      });
    }
  }

  Widget _buildStatus(String status) {
    // Check if the step is done
    bool isDone = status.endsWith("Done");

    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        children: [
          // Step status (turn green if done)
          Expanded(
            child: Text(
              status,
              style: TextStyle(
                color: isDone ? Colors.green : Colors.black,
                fontSize: 16,
              ),
            ),
          ),
          // Show a check mark when step is done
          if (isDone) Icon(Icons.check_circle, color: Colors.green),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('GIF to Grayscale Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Padding(
              padding: EdgeInsets.all(16.0),
              child: Text(
                'This button will load a GIF, decode it, convert it into a grayscale version, and then re-encode it as a new GIF. You will see both the original and modified images below.',
                textAlign: TextAlign.center,
                style: TextStyle(fontSize: 16),
              ),
            ),
            ElevatedButton(
              onPressed: _isProcessing
                  ? null
                  : _processImage, // Disable button during processing
              style: ElevatedButton.styleFrom(
                padding:
                    const EdgeInsets.symmetric(horizontal: 40, vertical: 20),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10),
                ),
              ),
              child: const Text(
                'Process GIF Image',
                style: TextStyle(fontSize: 18),
              ),
            ),
            const SizedBox(height: 20),

            // Display loading steps
            _buildStatus(_decodingStatus),
            _buildStatus(_grayscaleStatus),
            _buildStatus(_encodingStatus),

            const SizedBox(height: 20),

            // Show loading indicator while processing
            if (_isProcessing) const CircularProgressIndicator(),

            // Display images when processing is complete
            if (_originalImage != null && !_isProcessing) ...[
              const Text('Original Image:', style: TextStyle(fontSize: 16)),
              Image.memory(_originalImage!),
              const SizedBox(height: 20),
              const Text('Grayscale Image:', style: TextStyle(fontSize: 16)),
              Image.memory(_modifiedImage!),
            ],
          ],
        ),
      ),
    );
  }
}
PS C:\Users\XXX\XXX\XXX\OpenLabX\XXX\flutter_packages_image> flutter run -d chrome
Launching lib\main.dart on Chrome in debug mode...
Waiting for connection from debug service on Chrome...              9.1s
This app is linked to the debug service: ws://127.0.0.1:64300/B99EyLDA850=/ws
Debug service listening on ws://127.0.0.1:64300/B99EyLDA850=/ws

🔥  To hot restart changes while running, press "r" or "R".
For a more detailed help message, press "h". To quit, press "q".

A Dart VM Service on Chrome is available at: http://127.0.0.1:64300/B99EyLDA850=
The Flutter DevTools debugger and profiler on Chrome is available at:
http://127.0.0.1:9101?uri=http://127.0.0.1:64300/B99EyLDA850=
Step 1: Decoding...
Step 1: Decoding Done.
Step 2: Converting to Grayscale...
Step 2: Converting to Grayscale Done.
Step 3: Encoding...
Step 3: Encoding Done.

Result:

image

image

Cheers :)