diff --git a/apps/sandbox/test/flutter_test_config.dart b/apps/sandbox/test/flutter_test_config.dart
index 20daee9..04ffe4c 100644
--- a/apps/sandbox/test/flutter_test_config.dart
+++ b/apps/sandbox/test/flutter_test_config.dart
@@ -2,10 +2,14 @@ import 'dart:async';
 
 import 'package:alchemist/alchemist.dart';
 import 'package:alchemist_test_reporter/alchemist_test_reporter.dart';
+import 'package:allure_report/allure_report.dart';
 
 Future<void> testExecutable(FutureOr<void> Function() testMain) {
   const isRunningInCi = bool.fromEnvironment('CI', defaultValue: false);
-  goldenTestRunner = GoldenTestRunnerWithReports(inner: goldenTestRunner);
+  goldenTestRunner = GoldenTestRunnerWithReports(
+    inner: goldenTestRunner,
+    onAttachmentCreated: Allure.diff,
+  );
 
   return AlchemistConfig.runWithConfig(
     config: AlchemistConfig(
diff --git a/packages/alchemist_test_reporter/CHANGELOG.md b/packages/alchemist_test_reporter/CHANGELOG.md
index 5df4c7c..7fcde1f 100644
--- a/packages/alchemist_test_reporter/CHANGELOG.md
+++ b/packages/alchemist_test_reporter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.1.0
+
+- **feat:** add diff file generation
+
 ## 1.0.1
 
 - lower dart sdk version bound
diff --git a/packages/alchemist_test_reporter/lib/src/golden_test_runner_with_reports.dart b/packages/alchemist_test_reporter/lib/src/golden_test_runner_with_reports.dart
index a322cd0..93f8ba8 100644
--- a/packages/alchemist_test_reporter/lib/src/golden_test_runner_with_reports.dart
+++ b/packages/alchemist_test_reporter/lib/src/golden_test_runner_with_reports.dart
@@ -1,18 +1,30 @@
 // ignore_for_file: implementation_imports
 
 import 'dart:io';
+import 'dart:math';
 
 import 'package:path/path.dart' as p;
 import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:alchemist/alchemist.dart';
 import 'package:alchemist/src/golden_test_runner.dart';
+import 'package:image/image.dart' as img;
+import 'package:diff_image2/diff_image2.dart';
+
+typedef AttachmentCallback = void Function(
+  String expected,
+  String actual,
+  String diff,
+);
 
 class GoldenTestRunnerWithReports extends GoldenTestRunner {
   final GoldenTestRunner _inner;
+  final AttachmentCallback? onAttachmentCreated;
 
-  GoldenTestRunnerWithReports({required GoldenTestRunner inner})
-      : _inner = inner;
+  GoldenTestRunnerWithReports({
+    required GoldenTestRunner inner,
+    this.onAttachmentCreated,
+  }) : _inner = inner;
 
   @override
   Future<void> run({
@@ -61,8 +73,15 @@ class GoldenTestRunnerWithReports extends GoldenTestRunner {
         'failures',
         '${name}_testImage$extension',
       ));
+      final diffFile = File(p.join(
+        Directory.current.path,
+        'test',
+        'failures',
+        '${name}_maskedDiff$extension',
+      ));
 
       if (masterFile.existsSync() && testFile.existsSync()) {
+        final time = DateTime.now();
         final subfolder =
             p.dirname(goldenPath.toString()).replaceAll('goldens/', '');
 
@@ -77,13 +96,69 @@ class GoldenTestRunnerWithReports extends GoldenTestRunner {
             subfolder, p.basename(masterFile.path));
         final test = p.join(Directory.current.path, 'reports', 'failures',
             subfolder, p.basename(testFile.path));
+        final diff = p.join(Directory.current.path, 'reports', 'failures',
+            subfolder, p.basename(diffFile.path));
 
         masterFile.copySync(base);
         testFile.copySync(test);
 
-        print('event:attachment:$base');
-        print('event:attachment:$test');
+        try {
+          if (diffFile.existsSync()) {
+            diffFile.copySync(diff);
+          } else {
+            _fitImages(base, test);
+            _writeDiff(base, test, diff);
+          }
+
+          print('Elapsed - ${DateTime.now().difference(time)}');
+
+          if (onAttachmentCreated case AttachmentCallback onAttachmentCreated) {
+            onAttachmentCreated(base, test, diff);
+          } else {
+            print('event:attachment:$base');
+            print('event:attachment:$test');
+            print('event:attachment:$diff');
+          }
+        } catch (e) {
+          print(e.toString());
+        }
       }
     }
   }
 }
+
+Future<void> _fitImages(String left, String right) async {
+  var (leftImage, rightImage) = (
+    img.decodePng(File(left).readAsBytesSync()),
+    img.decodePng(File(right).readAsBytesSync()),
+  );
+
+  if (leftImage == null || rightImage == null) return;
+
+  final newLeftImage = img.copyExpandCanvas(
+    leftImage,
+    newWidth: max(leftImage.width, rightImage.width),
+    newHeight: max(leftImage.height, rightImage.height),
+    position: img.ExpandCanvasPosition.topLeft,
+    backgroundColor: img.ColorRgba8(255, 255, 255, 255),
+  );
+  final newRightImage = img.copyExpandCanvas(
+    rightImage,
+    newWidth: max(leftImage.width, rightImage.width),
+    newHeight: max(leftImage.height, rightImage.height),
+    position: img.ExpandCanvasPosition.topLeft,
+    backgroundColor: img.ColorRgba8(255, 255, 255, 255),
+  );
+
+  File(left).writeAsBytesSync(img.encodePng(newLeftImage));
+  File(right).writeAsBytesSync(img.encodePng(newRightImage));
+}
+
+void _writeDiff(String left, String right, String diff) {
+  final leftFile = img.decodePng(File(left).readAsBytesSync());
+  final rightFile = img.decodePng(File(right).readAsBytesSync());
+
+  var diffResult = DiffImage.compareFromMemory(leftFile!, rightFile!);
+  final png = img.encodePng(diffResult.diffImage);
+  File(diff).writeAsBytesSync(png);
+}
diff --git a/packages/alchemist_test_reporter/pubspec.yaml b/packages/alchemist_test_reporter/pubspec.yaml
index 405e814..39ecb4e 100644
--- a/packages/alchemist_test_reporter/pubspec.yaml
+++ b/packages/alchemist_test_reporter/pubspec.yaml
@@ -1,6 +1,6 @@
 name: alchemist_test_reporter
 description: Alchemist Test Reporter Addon
-version: 1.0.1
+version: 1.1.0
 homepage: https://github.com/rIIh/dart_test_reporter
 issue_tracker: https://github.com/rIIh/dart_test_reporter/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+%5Balchemist_test_reporter%5D
 
@@ -17,6 +17,8 @@ dependencies:
   alchemist: ^0.7.0
   test: ^1.24.0
   path: ^1.0.0
+  image: ^4.2.0
+  diff_image2: ^1.2.1
 
 
 dev_dependencies:
diff --git a/packages/allure_report/CHANGELOG.md b/packages/allure_report/CHANGELOG.md
index 9c51f4d..e3f42c3 100644
--- a/packages/allure_report/CHANGELOG.md
+++ b/packages/allure_report/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.2.0
+
+- **feat:** add diff comparison support
+
+
 ## 1.1.1
 
 - lower dart sdk version bound
diff --git a/packages/allure_report/lib/src/allure.dart b/packages/allure_report/lib/src/allure.dart
index fa8849d..14f34cf 100644
--- a/packages/allure_report/lib/src/allure.dart
+++ b/packages/allure_report/lib/src/allure.dart
@@ -23,6 +23,9 @@ abstract final class Allure {
 
   // #endregion
 
+  static void diff(String expected, String actual, String diff) =>
+      print('allure:event:diff:$expected:$actual:$diff');
+
   static void severity(Severity severity) =>
       print('allure:event:severity:${severity.name}');
 
diff --git a/packages/allure_report/lib/src/allure_reporter.dart b/packages/allure_report/lib/src/allure_reporter.dart
index 3b60f37..3ee89d4 100644
--- a/packages/allure_report/lib/src/allure_reporter.dart
+++ b/packages/allure_report/lib/src/allure_reporter.dart
@@ -1,9 +1,11 @@
 import 'dart:async';
 import 'dart:convert';
 
+import 'package:allure_report/src/events/diff_event.dart';
 import 'package:allure_report/src/models/allure_link.dart';
 import 'package:allure_report/src/models/severity.dart';
 import 'package:allure_report/src/test_report.dart';
+import 'package:mime/mime.dart';
 import 'package:test_reporter/test_reporter.dart';
 import 'package:universal_io/io.dart';
 import 'package:uuid/data.dart';
@@ -36,7 +38,7 @@ class AllureReporter implements TestReporter {
   }
 
   @override
-  FutureOr<void> onEvent(TestEvent event) {
+  Future<void> onEvent(TestEvent event) async {
     switch (event) {
       case TestSuiteEvent event:
         suites[event.suite.id] = event.suite;
@@ -59,6 +61,33 @@ class AllureReporter implements TestReporter {
           ],
         );
 
+      case TestMessageEvent event
+          when event.messageType == 'print' &&
+              DiffEvent.isEligible(event.message):
+        try {
+          final diffEvent = DiffEvent.fromMessage(event.message);
+          final expectedBytes = await File(diffEvent.expected).readAsBytes();
+          final actualBytes = await File(diffEvent.actual).readAsBytes();
+          final diffBytes = await File(diffEvent.diff).readAsBytes();
+
+          final id = Uuid().v4();
+          final allureDiff = p.join(Directory.systemTemp.path, '$id.imagediff');
+          File(allureDiff).writeAsString(jsonEncode({
+            'expected': 'data:image/png;base64,${base64.encode(expectedBytes)}',
+            'actual': 'data:image/png;base64,${base64.encode(actualBytes)}',
+            'diff': 'data:image/png;base64,${base64.encode(diffBytes)}',
+          }));
+
+          tests[event.testID] = tests[event.testID]!.copyWith(
+            attachments: [
+              ...tests[event.testID]!.attachments,
+              allureDiff,
+            ],
+          );
+        } catch (e) {
+          print("[E]: Failed to create diff: $e");
+        }
+
       case TestMessageEvent event
           when event.messageType == 'print' &&
               event.message.startsWith('allure:event:') &&
@@ -141,6 +170,11 @@ class AllureReporter implements TestReporter {
       attachments.add({
         'name': p.basenameWithoutExtension(path),
         'source': p.basename(path),
+        'type': switch (p.basename(path)) {
+          String filename when filename.endsWith('.imagediff') =>
+            'application/vnd.allure.image.diff',
+          String filename => lookupMimeType(filename)
+        },
       });
     }
 
diff --git a/packages/allure_report/lib/src/events/diff_event.dart b/packages/allure_report/lib/src/events/diff_event.dart
new file mode 100644
index 0000000..656e181
--- /dev/null
+++ b/packages/allure_report/lib/src/events/diff_event.dart
@@ -0,0 +1,22 @@
+class DiffEvent {
+  static const kTag = 'allure:event:diff';
+
+  static bool isEligible(String message) {
+    return message.startsWith('$kTag:') &&
+        ':'.allMatches(message.replaceAll('$kTag:', '')).length == 2;
+  }
+
+  DiffEvent(this.expected, this.actual, this.diff);
+
+  factory DiffEvent.fromMessage(String message) {
+    final [expected, actual, diff] = message //
+        .replaceAll('$kTag:', '')
+        .split(':');
+
+    return DiffEvent(expected, actual, diff);
+  }
+
+  final String expected;
+  final String actual;
+  final String diff;
+}
diff --git a/packages/allure_report/pubspec.yaml b/packages/allure_report/pubspec.yaml
index a4f8259..4186cd6 100644
--- a/packages/allure_report/pubspec.yaml
+++ b/packages/allure_report/pubspec.yaml
@@ -1,6 +1,6 @@
 name: allure_report
 description: Allure Report Adapter. Use it with [test_reporter](https://pub.dev/packages/test_reporter) package
-version: 1.1.1
+version: 1.2.0
 repository: https://github.com/rIIh/dart_test_reporter
 issue_tracker: https://github.com/rIIh/dart_test_reporter/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+%5Ballure_report%5D
 
@@ -13,6 +13,7 @@ dependencies:
   test_reporter: ^1.0.0
   universal_io: ^2.2.2
   uuid: ^4.4.0
+  mime: ^1.0.5
 
 dev_dependencies:
   build_runner: ^2.4.11