Skip to content

Commit

Permalink
Merge pull request #32 from fluttercandies/mix-image
Browse files Browse the repository at this point in the history
mix image
  • Loading branch information
CaiJingLong authored May 26, 2020
2 parents bedca54 + e871c04 commit 9d4b067
Show file tree
Hide file tree
Showing 19 changed files with 508 additions and 87 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
.pub/

build/
.settings
.settings
.idea/
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ The version of readme pub and github may be inconsistent, please refer to [githu
- [Color](#color)
- [ScaleOption](#scaleoption)
- [AddTextOption](#addtextoption)
- [MixOption](#mixoption)
- [BlendMode](#blendmode)
- [OutputFormat](#outputformat)
- [Common issue](#common-issue)
- [iOS](#ios)
Expand Down Expand Up @@ -148,6 +150,32 @@ textOption.addText(
);
```

#### MixOption

##### BlendMode

Support next BlendMode, other will be ignored.

| iOS | android(PorterDuff.Mode) | flutter(BlendMode) |
| --------------------------- | ------------------------ | ------------------ |
| kCGBlendModeClear | CLEAR | clear |
|   | SRC | src |
|   | DST | dst |
| kCGBlendModeNormal | SRC_OVER | srcOver |
| kCGBlendModeDestinationOver | DST_OVER | dstOver |
| kCGBlendModeSourceIn | SRC_IN | srcIn |
| kCGBlendModeDestinationIn | DST_IN | dstIn |
| kCGBlendModeSourceOut | SRC_OUT | srcOut |
| kCGBlendModeDestinationOver | DST_OUT | dstOut |
| kCGBlendModeSourceAtop | SRC_ATOP | srcATop |
| kCGBlendModeDestinationAtop | DST_ATOP | dstATop |
| kCGBlendModeXOR | XOR | xor |
| kCGBlendModeDarken | DARKEN | darken |
| kCGBlendModeLighten | LIGHTEN | lighten |
| kCGBlendModeMultiply | MULTIPLY | multiply |
| kCGBlendModeScreen | SCREEN | screen |
| kCGBlendModeOverlay | OVERLAY | overlay |

### OutputFormat

```dart
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,31 @@ class ImageHandler(private var bitmap: Bitmap) {
is ColorOption -> bitmap = handleColor(option)
is ScaleOption -> bitmap = handleScale(option)
is AddTextOpt -> bitmap = handleText(option)
is MixImageOpt -> bitmap = handleMixImage(option)
}
}
}

private fun handleMixImage(option: MixImageOpt): Bitmap {
val newBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, bitmap.config)
val canvas = Canvas(newBitmap)
canvas.drawBitmap(bitmap, 0F, 0F, null)

val src = BitmapFactory.decodeByteArray(option.img, 0, option.img.count())

val paint = Paint()
paint.xfermode = PorterDuffXfermode(option.porterDuffMode)

// val srcRect = Rect(option.x, option.y, option.x + option.w, option.y + option.h)
// val dstRect = Rect(0, 0, bitmap.width, bitmap.height)

val dstRect = Rect(option.x, option.y, option.x + option.w, option.y + option.h)
val srcRect = Rect(0, 0, bitmap.width, bitmap.height)
canvas.drawBitmap(src, srcRect, dstRect, paint)

return newBitmap
}

private fun handleScale(option: ScaleOption): Bitmap {
val w = min(bitmap.width, option.width)
val h = min(bitmap.height, option.height)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package top.kikt.flutter_image_editor.option

import android.graphics.PorterDuff
import top.kikt.flutter_image_editor.util.ConvertUtils

class MixImageOpt(map: Map<*, *>) : Option {

val img: ByteArray = (map["target"] as Map<*, *>)["memory"] as ByteArray

val x = map["x"] as Int
val y = map["y"] as Int
val w = map["w"] as Int
val h = map["h"] as Int

private val type = map["mixMode"] as String

val porterDuffMode: PorterDuff.Mode
get() = ConvertUtils.convertToPorterDuffMode(type)

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package top.kikt.flutter_image_editor.util

import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import io.flutter.plugin.common.MethodCall
import top.kikt.flutter_image_editor.BitmapWrapper
import top.kikt.flutter_image_editor.option.*
Expand Down Expand Up @@ -33,6 +35,9 @@ object ConvertUtils {
}

val valueMap = optionMap["value"]
if (valueMap !is Map<*, *>) {
continue@loop
}
when (optionMap["type"]) {
"flip" -> {
val flipOption = getFlipOption(valueMap)
Expand All @@ -58,6 +63,10 @@ object ConvertUtils {
val addTextOption: AddTextOpt = getTextOption(valueMap) ?: continue@loop
list.add(addTextOption)
}
"mix_image" -> {
val mixImageOpt = MixImageOpt(valueMap)
list.add(mixImageOpt)
}
else -> {
}
}
Expand Down Expand Up @@ -151,6 +160,29 @@ object ConvertUtils {
return FlipOption(optionMap["h"] as Boolean, optionMap["v"] as Boolean)
}

fun convertToPorterDuffMode(type: String): PorterDuff.Mode {
return when (type) {
"clear" -> PorterDuff.Mode.CLEAR
"src" -> PorterDuff.Mode.SRC
"dst" -> PorterDuff.Mode.DST
"srcOver" -> PorterDuff.Mode.SRC_OVER
"dstOver" -> PorterDuff.Mode.DST_OVER
"srcIn" -> PorterDuff.Mode.SRC_IN
"dstIn" -> PorterDuff.Mode.DST_IN
"srcOut" -> PorterDuff.Mode.SRC_OUT
"dstOut" -> PorterDuff.Mode.DST_OUT
"srcATop" -> PorterDuff.Mode.SRC_ATOP
"dstATop" -> PorterDuff.Mode.DST_ATOP
"xor" -> PorterDuff.Mode.XOR
"darken" -> PorterDuff.Mode.DARKEN
"lighten" -> PorterDuff.Mode.LIGHTEN
"multiply" -> PorterDuff.Mode.MULTIPLY
"screen" -> PorterDuff.Mode.SCREEN
"overlay" -> PorterDuff.Mode.OVERLAY
else -> PorterDuff.Mode.SRC_OVER
}
}

@Suppress("UNCHECKED_CAST")
fun <T> Any.asValue(): T {
return this as T
Expand Down
Binary file added blendmode.numbers
Binary file not shown.
Binary file added example/assets/dst.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/src.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion example/lib/advanced_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'dart:typed_data';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_image_editor_example/const/resource.dart';
import 'package:image_editor/image_editor.dart';
import 'package:image_editor/image_editor.dart' hide ImageSource;
import 'package:image_picker/image_picker.dart';
import 'package:oktoast/oktoast.dart';

Expand Down
14 changes: 11 additions & 3 deletions example/lib/const/resource.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
/// generate by resouce_generator library, shouldn't edit.
/// Generate by [resource_generator](https://github.com/CaiJingLong/flutter_resource_generator) library.
/// PLEASE DO NOT EDIT MANUALLY.
class R {
/// ![preview](file:///Users/cai/Documents/GitHub/flutter_image_editor/example/./assets/have-exif-3.jpg)

/// ![preview](file:///Volumes/Samsung-T5/code/flutter/plugins/flutter_image_editor/example/./assets/dst.png)
static const String ASSETS_DST_PNG = "assets/dst.png";

/// ![preview](file:///Volumes/Samsung-T5/code/flutter/plugins/flutter_image_editor/example/./assets/have-exif-3.jpg)
static const String ASSETS_HAVE_EXIF_3_JPG = "assets/have-exif-3.jpg";

/// ![preview](file:///Users/cai/Documents/GitHub/flutter_image_editor/example/./assets/icon.png)
/// ![preview](file:///Volumes/Samsung-T5/code/flutter/plugins/flutter_image_editor/example/./assets/icon.png)
static const String ASSETS_ICON_PNG = "assets/icon.png";

/// ![preview](file:///Volumes/Samsung-T5/code/flutter/plugins/flutter_image_editor/example/./assets/src.png)
static const String ASSETS_SRC_PNG = "assets/src.png";
}
12 changes: 12 additions & 0 deletions example/lib/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_image_editor_example/advanced_page.dart';
import 'package:flutter_image_editor_example/mix_image_page.dart';
import 'package:flutter_image_editor_example/widget/scale_widget.dart';

import 'add_text_page.dart';
Expand Down Expand Up @@ -52,6 +53,11 @@ class _HomePageState extends State<HomePage> {
onPressed: _addText,
tooltip: "Add text",
),
IconButton(
icon: Icon(Icons.branding_watermark),
onPressed: _mixImage,
tooltip: "Mix image",
),
],
),
body: Column(
Expand Down Expand Up @@ -144,6 +150,12 @@ class _HomePageState extends State<HomePage> {
builder: (_) => AddTextPage(),
));
}

void _mixImage() {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => MixImagePage(),
));
}
}

Widget buildButton(String text, Function onTap) {
Expand Down
104 changes: 104 additions & 0 deletions example/lib/mix_image_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_image_editor_example/const/resource.dart';
import 'package:image_editor/image_editor.dart';

class MixImagePage extends StatefulWidget {
@override
_MixImagePageState createState() => _MixImagePageState();
}

class _MixImagePageState extends State<MixImagePage> {
ImageProvider image;

var blendMode = BlendMode.srcOver;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('mix image'),
),
body: Column(
children: <Widget>[
AspectRatio(
aspectRatio: 2 / 1,
child: Row(
children: <Widget>[
AspectRatio(
aspectRatio: 1,
child: Image.asset(R.ASSETS_SRC_PNG),
),
AspectRatio(
aspectRatio: 1,
child: Image.asset(R.ASSETS_DST_PNG),
),
],
),
),
Container(
width: 270,
height: 270,
child: image != null
? Image(
image: image,
)
: Container(),
),
DropdownButton<BlendMode>(
items: supportBlendModes.map((e) => _buildItem(e)).toList(),
onChanged: _onChange,
value: blendMode,
),
RaisedButton(
child: Text('mix'),
onPressed: () {
mix();
},
),
],
),
);
}

DropdownMenuItem<BlendMode> _buildItem(BlendMode e) {
return DropdownMenuItem(
child: Text(e.toString()),
value: e,
);
}

void _onChange(BlendMode value) {
setState(() {
this.blendMode = value;
});
}

void mix() async {
final src = await loadFromAsset(R.ASSETS_SRC_PNG);
final dst = await loadFromAsset(R.ASSETS_DST_PNG);
final optionGroup = ImageEditorOption();
optionGroup.outputFormat = OutputFormat.png();
optionGroup.addOption(
MixImageOption(
x: 300,
y: 300,
width: 150,
height: 150,
target: MemoryImageSource(src),
blendMode: blendMode,
),
);
final result =
await ImageEditor.editImage(image: dst, imageEditorOption: optionGroup);
this.image = MemoryImage(result);
setState(() {});
}

Future<Uint8List> loadFromAsset(String key) async {
final byteData = await rootBundle.load(key);
return byteData.buffer.asUint8List();
}
}
34 changes: 23 additions & 11 deletions ios/Classes/FIConvertUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN

#define kCGBlendModeSrc 12345
#define kCGBlendModeDst 12346

@class FIEditorOptionGroup;

@interface FIConvertUtils : NSObject
Expand Down Expand Up @@ -49,19 +52,28 @@ NS_ASSUME_NONNULL_BEGIN
@property(assign, nonatomic) int height;
@end

@interface FIAddText : NSObject<FIOption>
@property(nonatomic,copy) NSString *text;
@property(nonatomic,assign) int x;
@property(nonatomic,assign) int y;
@property(nonatomic,assign) int fontSizePx;
@property(nonatomic,assign) int r;
@property(nonatomic,assign) int g;
@property(nonatomic,assign) int b;
@property(nonatomic,assign) int a;
@interface FIAddText : NSObject <FIOption>
@property(nonatomic, copy) NSString *text;
@property(nonatomic, assign) int x;
@property(nonatomic, assign) int y;
@property(nonatomic, assign) int fontSizePx;
@property(nonatomic, assign) int r;
@property(nonatomic, assign) int g;
@property(nonatomic, assign) int b;
@property(nonatomic, assign) int a;
@end

@interface FIAddTextOption : NSObject <FIOption>
@property(nonatomic, strong) NSArray<FIAddText *> *texts;
@end

@interface FIAddTextOption : NSObject<FIOption>
@property(nonatomic,strong)NSArray<FIAddText*> *texts;
@interface FIMixImageOption : NSObject <FIOption>
@property(nonatomic, assign) int x;
@property(nonatomic, assign) int y;
@property(nonatomic, assign) int width;
@property(nonatomic, assign) int height;
@property(nonatomic, strong) NSData *src;
@property(nonatomic, strong) NSNumber *blendMode;
@end

@interface FIEditorOptionGroup : NSObject
Expand Down
Loading

0 comments on commit 9d4b067

Please sign in to comment.