├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── CMakeLists.txt ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── src │ ├── main │ ├── AndroidManifest.xml │ └── kotlin │ │ └── com │ │ └── example │ │ └── bitmap │ │ └── BitmapPlugin.kt │ └── test │ └── kotlin │ └── com │ └── example │ └── bitmap │ └── BitmapPluginTest.kt ├── example ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ ├── doggo.jpeg │ └── street.jpg ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ ├── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ └── LaunchImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ └── README.md │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h │ └── RunnerTests │ │ └── RunnerTests.swift ├── lib │ └── main.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── BitmapPlugin.h │ ├── BitmapPlugin.m │ ├── SwiftBitmapPlugin.swift │ └── bitmap.cpp └── bitmap.podspec ├── lib ├── bitmap_flutter.dart └── src │ ├── bitmap.dart │ ├── ffi.dart │ └── operation │ ├── adjust_color.dart │ ├── brightness.dart │ ├── contrast.dart │ ├── crop.dart │ ├── flip.dart │ ├── operation.dart │ ├── resize.dart │ ├── rgb_overlay.dart │ └── rotation.dart ├── macos ├── Classes │ └── BitmapPlugin.swift └── bitmap.podspec ├── pubspec.lock ├── pubspec.yaml ├── test └── bitmap_test.dart └── transform.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | build/ 29 | ios/.generated/ 30 | android/.cxx/ 31 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "db7ef5bf9f59442b0e200a90587e8fa5e0c6336a" 8 | channel: "stable" 9 | 10 | project_type: plugin 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 17 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 18 | - platform: android 19 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 20 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 21 | - platform: ios 22 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 23 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 24 | 25 | # User provided section 26 | 27 | # List of Local paths (relative to this file) that should be 28 | # ignored by the migrate tool. 29 | # 30 | # Files that are not part of the templates will be ignored by default. 31 | unmanaged_files: 32 | - 'lib/main.dart' 33 | - 'ios/Runner.xcodeproj/project.pbxproj' 34 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.2.0 2 | 3 | * fix: Add support for android gradle version 8.1.3 4 | * feat: Implement RGB overlay operation 5 | 6 | ## 0.1.3 7 | 8 | * Bump ffi to 2.0.1 9 | 10 | ## 0.1.2 11 | 12 | * Fix wrong throw on resize image 13 | 14 | ## 0.1.1 15 | 16 | * Fix wrong assertion on resize image 17 | 18 | ## 0.1.0 19 | 20 | * Support FFI 1.0.0 21 | * Add crop operation 22 | * Add rotation operation 23 | * Change API to `bitmap.apply(Operation())` 24 | * Add batch operations 25 | * Update plugin to support Flutter 1.20.0 26 | 27 | ## 0.0.1 28 | 29 | * Initial release 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Renan C. Araújo 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![transform image dog](https://raw.githubusercontent.com/bluefireteam/bitmap/9cd10ebf04/transform.jpg) 3 | 4 | # Flutter Bitmap 5 | 6 | [![Pub](https://img.shields.io/pub/v/bitmap.svg?style=popout)](https://pub.dartlang.org/packages/bitmap) 7 | 8 | A minimalist [Flutter](https://flutter.dev/) package to perform fast bitmaps operations. 9 | The focus here is to provide a cool bitmap manipulation interface. 10 | 11 | The package standard format is [RGBA32](https://en.wikipedia.org/wiki/RGBA_color_space). 12 | 13 | Bitmap uses the Dart FFI to perform operations such as contrast, brightness, saturation, and exposure. 14 | 15 | For now, things like format encoding, EXIF and multi-frame images are not the concern of this package. If that is your need, check [`image`](https://pub.dartlang.org/packages/image). 16 | Some of the algorithms here are heavily inspired by this awesome lib. 17 | 18 | ## Why this exists? 19 | 20 | I started to use [dart image](https://pub.dartlang.org/packages/image) to create [LetsPicture](https://play.google.com/store/apps/details?id=app.letspicture.letspicture) (cool app, check it out) but since the beginning, I've noticed that the performance was really bad. 21 | [Dart image](https://pub.dartlang.org/packages/image) has its own Image format, so between decoding, putting some transformations and then displaying the result on the app you had to convert the image two times (at least). 22 | 23 | So this package is just this: We deal [bitmaps](https://en.wikipedia.org/wiki/BMP_file_format) (duh) and we focus only on Flutter use cases. 24 | 25 | `bitmap` takes some advantages from Flutter: 26 | - Every image is decoded to [RGBA32](https://en.wikipedia.org/wiki/RGBA_color_space) by the framework trough ImageStreamListener, so we can rely on Flutter to do the decoding job; 27 | - Dart FFI: we are porting some of our functions to C (or C++) making it blazing fast. 28 | - With this package, you can easily take advantage of stuff like [compute](https://api.flutter.dev/flutter/foundation/compute.html) ([Isolates](https://www.didierboelens.com/2019/01/futures---isolates---event-loop/)) on only the manipulations you want to free the UI thread of heavy computation. 29 | 30 | ## Alternatives 31 | 32 | #### Dart image 33 | 34 | As mentioned previously, [`check on pub`](https://pub.dartlang.org/packages/image). 35 | 36 | #### Flutter Built-in ColorFilter class 37 | 38 | Flutter has a powerful [ColorFilter](https://api.flutter.dev/flutter/dart-ui/ColorFilter-class.html) class (that came from [skia](https://skia.org/user/api/skpaint_overview#SkColorFilter)) which can be used to put some color corrections when painting stuff on canvas. You can use a matrix to correct color (Some matrix examples [here](https://docs.rainmeter.net/tips/colormatrix-guide/)). 39 | Not every color transformation can be done through the matrix, though. 40 | 41 | ## Basic usage 42 | 43 | ### 1. Image to Bitmap 44 | 45 | Everything is around the [Bitmap](https://pub.dev/documentation/bitmap/latest/bitmap/bitmap-library.html) class. You can get an instance of that from any [ImageProvider](https://api.flutter.dev/flutter/painting/ImageProvider-class.html). 46 | 47 | ```dart 48 | import 'package:bitmap/bitmap.dart'; 49 | 50 | Bitmap bitmap = await Bitmap.fromProvider(NetworkImage("http://pudim.com.br/pudim.jpg")); // Notice this is an async operation 51 | ``` 52 | 53 | ##### You can create from a headed [Uint8List](https://api.flutter.dev/flutter/dart-typed_data/Uint8List-class.html): 54 | 55 | ```dart 56 | import 'package:bitmap/bitmap.dart'; 57 | 58 | Bitmap bitmap = Bitmap.fromHeadful(imageWidth, imageHeight, theListOfInts); // Not async 59 | ``` 60 | 61 | ##### Or a headless: 62 | 63 | ```dart 64 | Bitmap bitmap = Bitmap.fromHeadless(imageWidth, imageHeight, theListOfInts); // Not async 65 | ``` 66 | This is useful when you are dealing with the [Uint8List](https://api.flutter.dev/flutter/dart-typed_data/Uint8List-class.html) that [ByteData](https://api.flutter.dev/flutter/dart-typed_data/ByteData-class.html) generates. 67 | 68 | ##### You can even create a blank one 69 | 70 | ```dart 71 | Bitmap bitmap = Bitmap.blank(imageWidth, imageHeight); 72 | ``` 73 | This creates a black, full transparent bitmap. 74 | 75 | ### 2. Applying some operations 76 | 77 | Let's put some contrast 78 | ```dart 79 | import 'package:bitmap/bitmap.dart'; 80 | 81 | Bitmap contrastedBitmap = bitmap.apply(BitmapContrast(0.2));; 82 | ``` 83 | 84 | It is possible to add several operations at once 85 | ```dart 86 | import 'package:bitmap/bitmap.dart'; 87 | Bitmap brightBitmap = bitmap.applyBatch([ 88 | BitmapBrightness(0.2), 89 | BitmapAdjustColor( 90 | saturation: 1.0 91 | ), 92 | ]); 93 | ``` 94 | 95 | ### 3. Displaying/painting/saving the output 96 | 97 | You can create two outputs from a `Bitmap` instance: 98 | - A `Uint8List` with no header, only the content of the file (`.content` property). 99 | - A `Uint8List` with a bitmap header, which Flutter can parse (`.buildHeaded()` method). 100 | 101 | ##### Displaying 102 | 103 | To easiest way to display an image is to getting the bitmap with header and then passing it to the widget `Image.memory`: 104 | ```dart 105 | // .. 106 | 107 | Uint8List headedBitmap = bitmap.buildHeaded(); 108 | 109 | // .. 110 | child: Image.memory(headedBitmap) 111 | // .. 112 | ``` 113 | 114 | ##### Painting 115 | 116 | The `Bitmap` class has also a helper function `buildImage` that uses Flutter's `decodeImageFromList` to build a [`dart:ui Image`](https://api.flutter.dev/flutter/dart-ui/Image-class.html). 117 | With an `Image`, you can [paint it in a canvas](https://api.flutter.dev/flutter/dart-ui/Canvas/drawImage.html) (in a [CustomPainter](https://api.flutter.dev/flutter/rendering/CustomPainter-class.html), for example). 118 | 119 | ```dart 120 | import 'dart:ui' as ui; 121 | // .. 122 | ui.Image outputImage = await bitmap.buildImage(); 123 | canvas.drawImage(outputImage, Offset.zero, ui.Paint()); 124 | ``` 125 | 126 | ##### Saving 127 | 128 | You can also save the image as a `.bmp` file (get the file content with the `.buildHeaded()` method). 129 | You can check also the [`image`](https://pub.dartlang.org/packages/image) lib where you can save the image in several formats. 130 | 131 | [How to save files with Flutter?](https://flutter.dev/docs/cookbook/persistence/reading-writing-files) 132 | 133 | ## Performance improvements and Dart FFI 134 | 135 | ### Dart FFI 136 | 137 | The capability of calling a `c` (or `c++`) function from dart can help us a lot in getter better performance times. 138 | 139 | ### Isolates 140 | 141 | Most of the manipulations on the bitmap take a long time to be completed. That's is because they have to iterate on every item of the bitmap. 142 | A picture with a 400px width and height sizes will generate a list of 640000 integers. This is a heavy computation. 143 | Those can be expensive. Sou you may use [Isolates](https://www.didierboelens.com/2019/01/futures---isolates---event-loop/) there to free the UI thread from all of this work. 144 | 145 | Check the [example app](https://github.com/renancaraujo/bitmap), where the transformations are applied through the compute function. 146 | 147 | **Important: it is noticed that the performance increases a lot when using release mode on your Flutter App** 148 | 149 | ## Apps using it (only one for now) 150 | 151 | - [Lets Picture](https://github.com/renancaraujo/letspicture) - [Play store](https://play.google.com/store/apps/details?id=app.letspicture.letspicture) and the [source code](https://github.com/renancaraujo/letspicture). 152 | 153 | ## Supported operations 154 | 155 | - Flip vertical 156 | - Flip horizontal 157 | - Rotation 158 | - Resize (nearest interpolation) 159 | - Contrast 160 | - Brightness 161 | - Saturation 162 | - Exposure 163 | - Crop 164 | 165 | ## Todo 166 | 167 | There is a lot of work to be done: 168 | 169 | - [ ] Resize with other interpolations 170 | - [ ] Set channel 171 | - [ ] White balance 172 | - [ ] Color blend 173 | - [ ] Noise 174 | - [ ] Tones 175 | - [ ] ??? The sky is the limit 176 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | errors: 3 | mixin_inherits_from_not_object: ignore 4 | linter: 5 | rules: 6 | - always_declare_return_types 7 | - always_put_control_body_on_new_line 8 | - always_require_non_null_named_parameters 9 | - annotate_overrides 10 | - avoid_as 11 | - avoid_classes_with_only_static_members 12 | - avoid_empty_else 13 | - avoid_field_initializers_in_const_classes 14 | - avoid_function_literals_in_foreach_calls 15 | - avoid_init_to_null 16 | - avoid_null_checks_in_equality_operators 17 | - avoid_relative_lib_imports 18 | - avoid_renaming_method_parameters 19 | - avoid_return_types_on_setters 20 | - avoid_slow_async_io 21 | - await_only_futures 22 | - camel_case_types 23 | - cancel_subscriptions 24 | - control_flow_in_finally 25 | - directives_ordering 26 | - empty_catches 27 | - empty_constructor_bodies 28 | - empty_statements 29 | - hash_and_equals 30 | - implementation_imports 31 | - iterable_contains_unrelated_type 32 | - library_names 33 | - library_prefixes 34 | - list_remove_unrelated_type 35 | - no_adjacent_strings_in_list 36 | - no_duplicate_case_values 37 | - non_constant_identifier_names 38 | - overridden_fields 39 | - package_api_docs 40 | - package_names 41 | - package_prefixed_library_names 42 | - prefer_adjacent_string_concatenation 43 | - prefer_asserts_in_initializer_lists 44 | - prefer_collection_literals 45 | - prefer_conditional_assignment 46 | - prefer_const_constructors 47 | - prefer_const_declarations 48 | - prefer_const_literals_to_create_immutables 49 | - prefer_contains 50 | - prefer_equal_for_default_values 51 | - prefer_final_fields 52 | - prefer_final_locals 53 | - prefer_foreach 54 | - prefer_initializing_formals 55 | - prefer_is_empty 56 | - prefer_is_not_empty 57 | - prefer_typing_uninitialized_variables 58 | - recursive_getters 59 | - slash_for_doc_comments 60 | - sort_unnamed_constructors_first 61 | - test_types_in_equals 62 | - throw_in_finally 63 | - type_init_formals 64 | - unnecessary_brace_in_string_interps 65 | - unnecessary_getters_setters 66 | - unnecessary_null_aware_assignments 67 | - unnecessary_null_in_if_null_operators 68 | - unnecessary_overrides 69 | - unnecessary_parenthesis 70 | - unnecessary_this 71 | - unrelated_type_equality_checks 72 | - use_rethrow_when_possible 73 | - unnecessary_new 74 | 75 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /android/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4.1) 2 | 3 | add_library( bitmap 4 | 5 | # Sets the library as a shared library. 6 | SHARED 7 | 8 | # Provides a relative path to your source file(s). 9 | ../ios/Classes/bitmap.cpp ) -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.example.bitmap' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '1.9.0' 6 | repositories { 7 | google() 8 | mavenCentral() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:8.1.3' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | rootProject.allprojects { 18 | repositories { 19 | google() 20 | mavenCentral() 21 | } 22 | } 23 | 24 | apply plugin: 'com.android.library' 25 | apply plugin: 'kotlin-android' 26 | 27 | android { 28 | if (project.android.hasProperty("namespace")) { 29 | namespace "com.example.bitmap" 30 | } 31 | 32 | compileSdkVersion 33 33 | 34 | sourceSets { 35 | main.java.srcDirs += 'src/main/kotlin' 36 | } 37 | defaultConfig { 38 | minSdkVersion 16 39 | } 40 | 41 | compileOptions { 42 | sourceCompatibility = JavaVersion.VERSION_1_8 43 | targetCompatibility = JavaVersion.VERSION_1_8 44 | } 45 | 46 | kotlinOptions { 47 | jvmTarget = '1.8' 48 | } 49 | 50 | externalNativeBuild { 51 | cmake { 52 | path "CMakeLists.txt" 53 | } 54 | } 55 | } 56 | 57 | dependencies { 58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 59 | } 60 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip 6 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'bitmap' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/example/bitmap/BitmapPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.example.bitmap 2 | 3 | import androidx.annotation.NonNull 4 | import io.flutter.embedding.engine.plugins.FlutterPlugin 5 | import io.flutter.plugin.common.MethodCall 6 | import io.flutter.plugin.common.MethodChannel 7 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 8 | import io.flutter.plugin.common.MethodChannel.Result 9 | 10 | /** BitmapPlugin */ 11 | class BitmapPlugin : FlutterPlugin, MethodCallHandler { 12 | 13 | private lateinit var channel: MethodChannel 14 | 15 | override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { 16 | channel = MethodChannel(flutterPluginBinding.binaryMessenger, "bitmap") 17 | channel.setMethodCallHandler(this) 18 | } 19 | 20 | override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { 21 | when (call.method) { 22 | "getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}") 23 | else -> result.notImplemented() 24 | } 25 | } 26 | 27 | override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { 28 | channel.setMethodCallHandler(null) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/example/bitmap/BitmapPluginTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.bitmap 2 | 3 | import io.flutter.plugin.common.MethodCall 4 | import io.flutter.plugin.common.MethodChannel 5 | import kotlin.test.Test 6 | import org.mockito.Mockito 7 | 8 | /* 9 | * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation. 10 | * 11 | * Once you have built the plugin's example app, you can run these tests from the command 12 | * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or 13 | * you can run them directly from IDEs that support JUnit such as Android Studio. 14 | */ 15 | 16 | internal class BitmapPluginTest { 17 | @Test 18 | fun onMethodCall_getPlatformVersion_returnsExpectedValue() { 19 | val plugin = BitmapPlugin() 20 | 21 | val call = MethodCall("getPlatformVersion", null) 22 | val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java) 23 | plugin.onMethodCall(call, mockResult) 24 | 25 | Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | 39 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "db7ef5bf9f59442b0e200a90587e8fa5e0c6336a" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 17 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 18 | - platform: android 19 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 20 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 21 | - platform: ios 22 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 23 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 24 | - platform: linux 25 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 26 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 27 | - platform: macos 28 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 29 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 30 | - platform: web 31 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 32 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 33 | - platform: windows 34 | create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 35 | base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # bitmap_example 2 | 3 | Demonstrates how to use the bitmap plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 25 | android { 26 | namespace "com.example.example" 27 | compileSdkVersion flutter.compileSdkVersion 28 | ndkVersion flutter.ndkVersion 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | 35 | kotlinOptions { 36 | jvmTarget = '1.8' 37 | } 38 | 39 | sourceSets { 40 | main.java.srcDirs += 'src/main/kotlin' 41 | } 42 | 43 | defaultConfig { 44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 45 | applicationId "com.example.example" 46 | // You can update the following values to match your application needs. 47 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 48 | minSdkVersion flutter.minSdkVersion 49 | targetSdkVersion flutter.targetSdkVersion 50 | versionCode flutterVersionCode.toInteger() 51 | versionName flutterVersionName 52 | } 53 | 54 | buildTypes { 55 | release { 56 | // TODO: Add your own signing config for the release build. 57 | // Signing with the debug keys for now, so `flutter run --release` works. 58 | signingConfig signingConfigs.debug 59 | } 60 | } 61 | } 62 | 63 | flutter { 64 | source '../..' 65 | } 66 | 67 | dependencies {} 68 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.9.0' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | google() 16 | mavenCentral() 17 | } 18 | } 19 | 20 | rootProject.buildDir = '../build' 21 | subprojects { 22 | project.buildDir = "${rootProject.buildDir}/${project.name}" 23 | } 24 | subprojects { 25 | project.evaluationDependsOn(':app') 26 | } 27 | 28 | tasks.register("clean", Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 6 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false 21 | } 22 | } 23 | 24 | plugins { 25 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 26 | id "com.android.application" version "7.3.0" apply false 27 | } 28 | 29 | include ":app" 30 | -------------------------------------------------------------------------------- /example/assets/doggo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/assets/doggo.jpeg -------------------------------------------------------------------------------- /example/assets/street.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/assets/street.jpg -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - bitmap (0.0.1): 3 | - Flutter 4 | - Flutter (1.0.0) 5 | 6 | DEPENDENCIES: 7 | - bitmap (from `.symlinks/plugins/bitmap/ios`) 8 | - Flutter (from `Flutter`) 9 | 10 | EXTERNAL SOURCES: 11 | bitmap: 12 | :path: ".symlinks/plugins/bitmap/ios" 13 | Flutter: 14 | :path: Flutter 15 | 16 | SPEC CHECKSUMS: 17 | bitmap: 591b0556efe6e811a263b8dfdc511fe1faa72315 18 | Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 19 | 20 | PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 21 | 22 | COCOAPODS: 1.12.1 23 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | C79DF2D43ED612EBB7C3903C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C9C63EE55E32E8A9F8219F0 /* Pods_Runner.framework */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = ""; 24 | dstSubfolderSpec = 10; 25 | files = ( 26 | ); 27 | name = "Embed Frameworks"; 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 0E09980A587ABB3C85121AAD /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 34 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 35 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 37 | 4AA7D1255AB78501A097F704 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 38 | 4C9C63EE55E32E8A9F8219F0 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 40 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 41 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 42 | 950A91CA40C20268F693704C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 43 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 44 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 45 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 47 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 48 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 49 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | C79DF2D43ED612EBB7C3903C /* Pods_Runner.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 30608FFB367171B4C72BF01C /* Frameworks */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 4C9C63EE55E32E8A9F8219F0 /* Pods_Runner.framework */, 68 | ); 69 | name = Frameworks; 70 | sourceTree = ""; 71 | }; 72 | 9740EEB11CF90186004384FC /* Flutter */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 76 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 77 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 78 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 79 | ); 80 | name = Flutter; 81 | sourceTree = ""; 82 | }; 83 | 97C146E51CF9000F007C117D = { 84 | isa = PBXGroup; 85 | children = ( 86 | 9740EEB11CF90186004384FC /* Flutter */, 87 | 97C146F01CF9000F007C117D /* Runner */, 88 | 97C146EF1CF9000F007C117D /* Products */, 89 | D7E953E155436CCC5E91988E /* Pods */, 90 | 30608FFB367171B4C72BF01C /* Frameworks */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | 97C146EF1CF9000F007C117D /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 97C146EE1CF9000F007C117D /* Runner.app */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 97C146F01CF9000F007C117D /* Runner */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 106 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 107 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 108 | 97C147021CF9000F007C117D /* Info.plist */, 109 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 110 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 111 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 112 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 113 | ); 114 | path = Runner; 115 | sourceTree = ""; 116 | }; 117 | D7E953E155436CCC5E91988E /* Pods */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 950A91CA40C20268F693704C /* Pods-Runner.debug.xcconfig */, 121 | 0E09980A587ABB3C85121AAD /* Pods-Runner.release.xcconfig */, 122 | 4AA7D1255AB78501A097F704 /* Pods-Runner.profile.xcconfig */, 123 | ); 124 | name = Pods; 125 | path = Pods; 126 | sourceTree = ""; 127 | }; 128 | /* End PBXGroup section */ 129 | 130 | /* Begin PBXNativeTarget section */ 131 | 97C146ED1CF9000F007C117D /* Runner */ = { 132 | isa = PBXNativeTarget; 133 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 134 | buildPhases = ( 135 | F3F12D9A66F64149ACC4CA8D /* [CP] Check Pods Manifest.lock */, 136 | 9740EEB61CF901F6004384FC /* Run Script */, 137 | 97C146EA1CF9000F007C117D /* Sources */, 138 | 97C146EB1CF9000F007C117D /* Frameworks */, 139 | 97C146EC1CF9000F007C117D /* Resources */, 140 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 142 | 9336C0CFC86F60BF2BE900C0 /* [CP] Embed Pods Frameworks */, 143 | ); 144 | buildRules = ( 145 | ); 146 | dependencies = ( 147 | ); 148 | name = Runner; 149 | productName = Runner; 150 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 151 | productType = "com.apple.product-type.application"; 152 | }; 153 | /* End PBXNativeTarget section */ 154 | 155 | /* Begin PBXProject section */ 156 | 97C146E61CF9000F007C117D /* Project object */ = { 157 | isa = PBXProject; 158 | attributes = { 159 | LastUpgradeCheck = 1430; 160 | ORGANIZATIONNAME = ""; 161 | TargetAttributes = { 162 | 97C146ED1CF9000F007C117D = { 163 | CreatedOnToolsVersion = 7.3.1; 164 | LastSwiftMigration = 1100; 165 | }; 166 | }; 167 | }; 168 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 169 | compatibilityVersion = "Xcode 9.3"; 170 | developmentRegion = en; 171 | hasScannedForEncodings = 0; 172 | knownRegions = ( 173 | en, 174 | Base, 175 | ); 176 | mainGroup = 97C146E51CF9000F007C117D; 177 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 178 | projectDirPath = ""; 179 | projectRoot = ""; 180 | targets = ( 181 | 97C146ED1CF9000F007C117D /* Runner */, 182 | ); 183 | }; 184 | /* End PBXProject section */ 185 | 186 | /* Begin PBXResourcesBuildPhase section */ 187 | 97C146EC1CF9000F007C117D /* Resources */ = { 188 | isa = PBXResourcesBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 192 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 193 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 194 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | }; 198 | /* End PBXResourcesBuildPhase section */ 199 | 200 | /* Begin PBXShellScriptBuildPhase section */ 201 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 202 | isa = PBXShellScriptBuildPhase; 203 | alwaysOutOfDate = 1; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | ); 207 | inputPaths = ( 208 | "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", 209 | ); 210 | name = "Thin Binary"; 211 | outputPaths = ( 212 | ); 213 | runOnlyForDeploymentPostprocessing = 0; 214 | shellPath = /bin/sh; 215 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 216 | }; 217 | 9336C0CFC86F60BF2BE900C0 /* [CP] Embed Pods Frameworks */ = { 218 | isa = PBXShellScriptBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | ); 222 | inputFileListPaths = ( 223 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", 224 | ); 225 | name = "[CP] Embed Pods Frameworks"; 226 | outputFileListPaths = ( 227 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", 228 | ); 229 | runOnlyForDeploymentPostprocessing = 0; 230 | shellPath = /bin/sh; 231 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 232 | showEnvVarsInLog = 0; 233 | }; 234 | 9740EEB61CF901F6004384FC /* Run Script */ = { 235 | isa = PBXShellScriptBuildPhase; 236 | alwaysOutOfDate = 1; 237 | buildActionMask = 2147483647; 238 | files = ( 239 | ); 240 | inputPaths = ( 241 | ); 242 | name = "Run Script"; 243 | outputPaths = ( 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | shellPath = /bin/sh; 247 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 248 | }; 249 | F3F12D9A66F64149ACC4CA8D /* [CP] Check Pods Manifest.lock */ = { 250 | isa = PBXShellScriptBuildPhase; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | ); 254 | inputFileListPaths = ( 255 | ); 256 | inputPaths = ( 257 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 258 | "${PODS_ROOT}/Manifest.lock", 259 | ); 260 | name = "[CP] Check Pods Manifest.lock"; 261 | outputFileListPaths = ( 262 | ); 263 | outputPaths = ( 264 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | shellPath = /bin/sh; 268 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 269 | showEnvVarsInLog = 0; 270 | }; 271 | /* End PBXShellScriptBuildPhase section */ 272 | 273 | /* Begin PBXSourcesBuildPhase section */ 274 | 97C146EA1CF9000F007C117D /* Sources */ = { 275 | isa = PBXSourcesBuildPhase; 276 | buildActionMask = 2147483647; 277 | files = ( 278 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 279 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | /* End PBXSourcesBuildPhase section */ 284 | 285 | /* Begin PBXVariantGroup section */ 286 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 287 | isa = PBXVariantGroup; 288 | children = ( 289 | 97C146FB1CF9000F007C117D /* Base */, 290 | ); 291 | name = Main.storyboard; 292 | sourceTree = ""; 293 | }; 294 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 295 | isa = PBXVariantGroup; 296 | children = ( 297 | 97C147001CF9000F007C117D /* Base */, 298 | ); 299 | name = LaunchScreen.storyboard; 300 | sourceTree = ""; 301 | }; 302 | /* End PBXVariantGroup section */ 303 | 304 | /* Begin XCBuildConfiguration section */ 305 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | ALWAYS_SEARCH_USER_PATHS = NO; 309 | CLANG_ANALYZER_NONNULL = YES; 310 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 311 | CLANG_CXX_LIBRARY = "libc++"; 312 | CLANG_ENABLE_MODULES = YES; 313 | CLANG_ENABLE_OBJC_ARC = YES; 314 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 315 | CLANG_WARN_BOOL_CONVERSION = YES; 316 | CLANG_WARN_COMMA = YES; 317 | CLANG_WARN_CONSTANT_CONVERSION = YES; 318 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 320 | CLANG_WARN_EMPTY_BODY = YES; 321 | CLANG_WARN_ENUM_CONVERSION = YES; 322 | CLANG_WARN_INFINITE_RECURSION = YES; 323 | CLANG_WARN_INT_CONVERSION = YES; 324 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 325 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 326 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 327 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 328 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 329 | CLANG_WARN_STRICT_PROTOTYPES = YES; 330 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 331 | CLANG_WARN_UNREACHABLE_CODE = YES; 332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 333 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 334 | COPY_PHASE_STRIP = NO; 335 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 336 | ENABLE_NS_ASSERTIONS = NO; 337 | ENABLE_STRICT_OBJC_MSGSEND = YES; 338 | GCC_C_LANGUAGE_STANDARD = gnu99; 339 | GCC_NO_COMMON_BLOCKS = YES; 340 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 341 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 342 | GCC_WARN_UNDECLARED_SELECTOR = YES; 343 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 344 | GCC_WARN_UNUSED_FUNCTION = YES; 345 | GCC_WARN_UNUSED_VARIABLE = YES; 346 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 347 | MTL_ENABLE_DEBUG_INFO = NO; 348 | SDKROOT = iphoneos; 349 | SUPPORTED_PLATFORMS = iphoneos; 350 | TARGETED_DEVICE_FAMILY = "1,2"; 351 | VALIDATE_PRODUCT = YES; 352 | }; 353 | name = Profile; 354 | }; 355 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 356 | isa = XCBuildConfiguration; 357 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 358 | buildSettings = { 359 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 360 | CLANG_ENABLE_MODULES = YES; 361 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 362 | ENABLE_BITCODE = NO; 363 | INFOPLIST_FILE = Runner/Info.plist; 364 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 365 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bitmapExample; 366 | PRODUCT_NAME = "$(TARGET_NAME)"; 367 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 368 | SWIFT_VERSION = 5.0; 369 | VERSIONING_SYSTEM = "apple-generic"; 370 | }; 371 | name = Profile; 372 | }; 373 | 97C147031CF9000F007C117D /* Debug */ = { 374 | isa = XCBuildConfiguration; 375 | buildSettings = { 376 | ALWAYS_SEARCH_USER_PATHS = NO; 377 | CLANG_ANALYZER_NONNULL = YES; 378 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 379 | CLANG_CXX_LIBRARY = "libc++"; 380 | CLANG_ENABLE_MODULES = YES; 381 | CLANG_ENABLE_OBJC_ARC = YES; 382 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 383 | CLANG_WARN_BOOL_CONVERSION = YES; 384 | CLANG_WARN_COMMA = YES; 385 | CLANG_WARN_CONSTANT_CONVERSION = YES; 386 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 387 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 388 | CLANG_WARN_EMPTY_BODY = YES; 389 | CLANG_WARN_ENUM_CONVERSION = YES; 390 | CLANG_WARN_INFINITE_RECURSION = YES; 391 | CLANG_WARN_INT_CONVERSION = YES; 392 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 393 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 394 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 396 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 397 | CLANG_WARN_STRICT_PROTOTYPES = YES; 398 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 399 | CLANG_WARN_UNREACHABLE_CODE = YES; 400 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 401 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 402 | COPY_PHASE_STRIP = NO; 403 | DEBUG_INFORMATION_FORMAT = dwarf; 404 | ENABLE_STRICT_OBJC_MSGSEND = YES; 405 | ENABLE_TESTABILITY = YES; 406 | GCC_C_LANGUAGE_STANDARD = gnu99; 407 | GCC_DYNAMIC_NO_PIC = NO; 408 | GCC_NO_COMMON_BLOCKS = YES; 409 | GCC_OPTIMIZATION_LEVEL = 0; 410 | GCC_PREPROCESSOR_DEFINITIONS = ( 411 | "DEBUG=1", 412 | "$(inherited)", 413 | ); 414 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 415 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 416 | GCC_WARN_UNDECLARED_SELECTOR = YES; 417 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 418 | GCC_WARN_UNUSED_FUNCTION = YES; 419 | GCC_WARN_UNUSED_VARIABLE = YES; 420 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 421 | MTL_ENABLE_DEBUG_INFO = YES; 422 | ONLY_ACTIVE_ARCH = YES; 423 | SDKROOT = iphoneos; 424 | TARGETED_DEVICE_FAMILY = "1,2"; 425 | }; 426 | name = Debug; 427 | }; 428 | 97C147041CF9000F007C117D /* Release */ = { 429 | isa = XCBuildConfiguration; 430 | buildSettings = { 431 | ALWAYS_SEARCH_USER_PATHS = NO; 432 | CLANG_ANALYZER_NONNULL = YES; 433 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 434 | CLANG_CXX_LIBRARY = "libc++"; 435 | CLANG_ENABLE_MODULES = YES; 436 | CLANG_ENABLE_OBJC_ARC = YES; 437 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 438 | CLANG_WARN_BOOL_CONVERSION = YES; 439 | CLANG_WARN_COMMA = YES; 440 | CLANG_WARN_CONSTANT_CONVERSION = YES; 441 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 442 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 443 | CLANG_WARN_EMPTY_BODY = YES; 444 | CLANG_WARN_ENUM_CONVERSION = YES; 445 | CLANG_WARN_INFINITE_RECURSION = YES; 446 | CLANG_WARN_INT_CONVERSION = YES; 447 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 448 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 449 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 450 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 451 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 452 | CLANG_WARN_STRICT_PROTOTYPES = YES; 453 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 454 | CLANG_WARN_UNREACHABLE_CODE = YES; 455 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 456 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 457 | COPY_PHASE_STRIP = NO; 458 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 459 | ENABLE_NS_ASSERTIONS = NO; 460 | ENABLE_STRICT_OBJC_MSGSEND = YES; 461 | GCC_C_LANGUAGE_STANDARD = gnu99; 462 | GCC_NO_COMMON_BLOCKS = YES; 463 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 464 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 465 | GCC_WARN_UNDECLARED_SELECTOR = YES; 466 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 467 | GCC_WARN_UNUSED_FUNCTION = YES; 468 | GCC_WARN_UNUSED_VARIABLE = YES; 469 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 470 | MTL_ENABLE_DEBUG_INFO = NO; 471 | SDKROOT = iphoneos; 472 | SUPPORTED_PLATFORMS = iphoneos; 473 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 474 | TARGETED_DEVICE_FAMILY = "1,2"; 475 | VALIDATE_PRODUCT = YES; 476 | }; 477 | name = Release; 478 | }; 479 | 97C147061CF9000F007C117D /* Debug */ = { 480 | isa = XCBuildConfiguration; 481 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 482 | buildSettings = { 483 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 484 | CLANG_ENABLE_MODULES = YES; 485 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 486 | ENABLE_BITCODE = NO; 487 | INFOPLIST_FILE = Runner/Info.plist; 488 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 489 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bitmapExample; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 492 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 493 | SWIFT_VERSION = 5.0; 494 | VERSIONING_SYSTEM = "apple-generic"; 495 | }; 496 | name = Debug; 497 | }; 498 | 97C147071CF9000F007C117D /* Release */ = { 499 | isa = XCBuildConfiguration; 500 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 501 | buildSettings = { 502 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 503 | CLANG_ENABLE_MODULES = YES; 504 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 505 | ENABLE_BITCODE = NO; 506 | INFOPLIST_FILE = Runner/Info.plist; 507 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 508 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bitmapExample; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 511 | SWIFT_VERSION = 5.0; 512 | VERSIONING_SYSTEM = "apple-generic"; 513 | }; 514 | name = Release; 515 | }; 516 | /* End XCBuildConfiguration section */ 517 | 518 | /* Begin XCConfigurationList section */ 519 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 520 | isa = XCConfigurationList; 521 | buildConfigurations = ( 522 | 97C147031CF9000F007C117D /* Debug */, 523 | 97C147041CF9000F007C117D /* Release */, 524 | 249021D3217E4FDB00AE95B9 /* Profile */, 525 | ); 526 | defaultConfigurationIsVisible = 0; 527 | defaultConfigurationName = Release; 528 | }; 529 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 530 | isa = XCConfigurationList; 531 | buildConfigurations = ( 532 | 97C147061CF9000F007C117D /* Debug */, 533 | 97C147071CF9000F007C117D /* Release */, 534 | 249021D4217E4FDB00AE95B9 /* Profile */, 535 | ); 536 | defaultConfigurationIsVisible = 0; 537 | defaultConfigurationName = Release; 538 | }; 539 | /* End XCConfigurationList section */ 540 | }; 541 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 542 | } 543 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | bitmap_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | @testable import bitmap 6 | 7 | // This demonstrates a simple unit test of the Swift portion of this plugin's implementation. 8 | // 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | 11 | class RunnerTests: XCTestCase { 12 | 13 | func testGetPlatformVersion() { 14 | let plugin = BitmapPlugin() 15 | 16 | let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) 17 | 18 | let resultExpectation = expectation(description: "result block must be called.") 19 | plugin.handle(call) { result in 20 | XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion) 21 | resultExpectation.fulfill() 22 | } 23 | waitForExpectations(timeout: 1) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bitmap/bitmap.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | void main() => runApp(MyApp()); 8 | 9 | class MyApp extends StatelessWidget { 10 | // This widget is the root of your application. 11 | @override 12 | Widget build(BuildContext context) { 13 | return MaterialApp( 14 | title: 'Image', 15 | theme: ThemeData( 16 | primarySwatch: Colors.orange, 17 | ), 18 | home: MyHomePage( 19 | title: "Pans", 20 | ), 21 | ); 22 | } 23 | } 24 | 25 | class MyHomePage extends StatefulWidget { 26 | MyHomePage({ 27 | Key? key, 28 | required this.title, 29 | }) : super(key: key); 30 | 31 | final String title; 32 | 33 | @override 34 | _MyHomePageState createState() => _MyHomePageState(); 35 | } 36 | 37 | class _MyHomePageState extends State { 38 | ImageValueNotifier imageValueNotifier = ImageValueNotifier(); 39 | 40 | @override 41 | void initState() { 42 | super.initState(); 43 | imageValueNotifier.loadImage(); 44 | } 45 | 46 | void flipHImage() { 47 | if (imageValueNotifier.value != null) { 48 | imageValueNotifier.flipHImage(); 49 | } 50 | } 51 | 52 | void flipVImage() { 53 | if (imageValueNotifier.value != null) { 54 | imageValueNotifier.flipVImage(); 55 | } 56 | } 57 | 58 | void rotateClockwiseImage() { 59 | if (imageValueNotifier.value != null) { 60 | imageValueNotifier.rotateClockwiseImage(); 61 | } 62 | } 63 | 64 | void rotateCounterClockwiseImage() { 65 | if (imageValueNotifier.value != null) { 66 | imageValueNotifier.rotateCounterClockwiseImage(); 67 | } 68 | } 69 | 70 | void rotate180Image() { 71 | if (imageValueNotifier.value != null) { 72 | imageValueNotifier.rotate180Image(); 73 | } 74 | } 75 | 76 | void contrastImage() { 77 | if (imageValueNotifier.value != null) { 78 | imageValueNotifier.contrastImage(); 79 | } 80 | } 81 | 82 | void brightnessImage() { 83 | if (imageValueNotifier.value != null) { 84 | imageValueNotifier.brightnessImage(); 85 | } 86 | } 87 | 88 | void adjustColorImage() { 89 | if (imageValueNotifier.value != null) { 90 | imageValueNotifier.adjustColorImage(); 91 | } 92 | } 93 | 94 | void batchOperations() { 95 | if (imageValueNotifier.value != null) { 96 | imageValueNotifier.batchOperations(); 97 | } 98 | } 99 | 100 | @override 101 | Widget build(BuildContext context) { 102 | return Scaffold( 103 | body: GestureDetector( 104 | onTap: () { 105 | imageValueNotifier.reset(); 106 | }, 107 | child: Center( 108 | child: ValueListenableBuilder( 109 | valueListenable: imageValueNotifier, 110 | builder: (BuildContext context, Bitmap? bitmap, Widget? child) { 111 | if (bitmap == null) { 112 | return const CircularProgressIndicator(); 113 | } 114 | return Column( 115 | children: [ 116 | SafeArea( 117 | top: true, 118 | child: Image.memory( 119 | bitmap.buildHeaded(), 120 | ), 121 | ), 122 | const Text("Tap image to reset"), 123 | Text("ImageSize ${bitmap.width}"), 124 | ], 125 | ); 126 | }, 127 | ), 128 | ), 129 | ), 130 | floatingActionButton: Buttons( 131 | flipHImage: flipHImage, 132 | flipVImage: flipVImage, 133 | rotateClockwiseImage: rotateClockwiseImage, 134 | rotateCounterClockwiseImage: rotateCounterClockwiseImage, 135 | rotate180Image: rotate180Image, 136 | contrastImage: contrastImage, 137 | brightnessImage: brightnessImage, 138 | adjustColorImage: adjustColorImage, 139 | batchOperations: batchOperations, 140 | ), // This trailing comma makes auto-formatting nicer for build methods. 141 | ); 142 | } 143 | } 144 | 145 | class Buttons extends StatelessWidget { 146 | const Buttons({ 147 | Key? key, 148 | required this.flipHImage, 149 | required this.flipVImage, 150 | required this.rotateClockwiseImage, 151 | required this.rotateCounterClockwiseImage, 152 | required this.rotate180Image, 153 | required this.contrastImage, 154 | required this.brightnessImage, 155 | required this.adjustColorImage, 156 | required this.batchOperations, 157 | }) : super(key: key); 158 | 159 | final VoidCallback flipHImage; 160 | final VoidCallback flipVImage; 161 | final VoidCallback rotateClockwiseImage; 162 | final VoidCallback rotateCounterClockwiseImage; 163 | final VoidCallback rotate180Image; 164 | final VoidCallback contrastImage; 165 | final VoidCallback brightnessImage; 166 | final VoidCallback adjustColorImage; 167 | final VoidCallback batchOperations; 168 | 169 | @override 170 | Widget build(BuildContext context) { 171 | return Container( 172 | padding: const EdgeInsets.symmetric(horizontal: 20), 173 | child: Column( 174 | mainAxisAlignment: MainAxisAlignment.end, 175 | children: [ 176 | Row( 177 | children: [ 178 | TextButton( 179 | onPressed: flipHImage, 180 | child: const Text( 181 | "Flip horizontal", 182 | style: TextStyle(fontSize: 10), 183 | ), 184 | ), 185 | TextButton( 186 | onPressed: flipVImage, 187 | child: const Text( 188 | "Flip vertical", 189 | style: TextStyle(fontSize: 10), 190 | ), 191 | ), 192 | TextButton( 193 | onPressed: contrastImage, 194 | child: const Text( 195 | "Contrast +", 196 | style: TextStyle(fontSize: 10), 197 | ), 198 | ), 199 | ], 200 | ), 201 | Row( 202 | children: [ 203 | TextButton( 204 | onPressed: brightnessImage, 205 | child: const Text( 206 | "Brightness +", 207 | style: TextStyle(fontSize: 10), 208 | ), 209 | ), 210 | TextButton( 211 | onPressed: adjustColorImage, 212 | child: const Text( 213 | "AdjustColor +", 214 | style: TextStyle(fontSize: 10), 215 | ), 216 | ), 217 | ], 218 | ), 219 | Row( 220 | children: [ 221 | TextButton( 222 | onPressed: rotateClockwiseImage, 223 | child: const Text( 224 | "Rotate Clock +", 225 | style: TextStyle(fontSize: 10), 226 | ), 227 | ), 228 | TextButton( 229 | onPressed: rotateCounterClockwiseImage, 230 | child: const Text( 231 | "Rotate Clock -", 232 | style: TextStyle(fontSize: 10), 233 | ), 234 | ), 235 | TextButton( 236 | onPressed: rotate180Image, 237 | child: const Text( 238 | "Rotate 180", 239 | style: TextStyle(fontSize: 10), 240 | ), 241 | ), 242 | ], 243 | ), 244 | Row( 245 | children: [ 246 | TextButton( 247 | onPressed: batchOperations, 248 | child: const Text( 249 | "Batch operations (saturation + crop)", 250 | style: TextStyle(fontSize: 10), 251 | ), 252 | ), 253 | ], 254 | ), 255 | ], 256 | ), 257 | ); 258 | } 259 | } 260 | 261 | // stores headless contents 262 | class ImageValueNotifier extends ValueNotifier { 263 | ImageValueNotifier() : super(null); 264 | 265 | late Bitmap initial; 266 | 267 | void reset() { 268 | value = initial; 269 | } 270 | 271 | void loadImage() async { 272 | const ImageProvider imageProvider = const AssetImage("assets/street.jpg"); 273 | 274 | value = await Bitmap.fromProvider(imageProvider); 275 | initial = value!; 276 | } 277 | 278 | void flipHImage() async { 279 | final temp = value!; 280 | value = null; 281 | 282 | final Uint8List converted = await compute( 283 | flipHImageIsolate, 284 | [temp.content, temp.width, temp.height], 285 | ); 286 | 287 | value = Bitmap.fromHeadless(temp.width, temp.height, converted); 288 | } 289 | 290 | void flipVImage() async { 291 | final temp = value!; 292 | value = null; 293 | 294 | final converted = await compute( 295 | flipVImageIsolate, 296 | [temp.content, temp.width, temp.height], 297 | ); 298 | 299 | value = Bitmap.fromHeadless(temp.width, temp.height, converted); 300 | } 301 | 302 | void rotateClockwiseImage() async { 303 | final temp = value!; 304 | value = null; 305 | 306 | final converted = await compute( 307 | rotateClockwiseImageIsolate, 308 | [temp.content, temp.width, temp.height], 309 | ); 310 | 311 | value = Bitmap.fromHeadless(temp.height, temp.width, converted); 312 | } 313 | 314 | void rotateCounterClockwiseImage() async { 315 | final temp = value!; 316 | value = null; 317 | 318 | final converted = await compute( 319 | rotateCounterClockwiseImageIsolate, 320 | [temp.content, temp.width, temp.height], 321 | ); 322 | 323 | value = Bitmap.fromHeadless(temp.height, temp.width, converted); 324 | } 325 | 326 | void rotate180Image() async { 327 | final temp = value!; 328 | value = null; 329 | 330 | final converted = await compute( 331 | rotate180ImageIsolate, 332 | [temp.content, temp.width, temp.height], 333 | ); 334 | 335 | value = Bitmap.fromHeadless(temp.width, temp.height, converted); 336 | } 337 | 338 | void contrastImage() async { 339 | final temp = value!; 340 | value = null; 341 | 342 | final Uint8List converted = await compute( 343 | contrastImageIsolate, 344 | [temp.content, temp.width, temp.height], 345 | ); 346 | 347 | value = Bitmap.fromHeadless(temp.width, temp.height, converted); 348 | } 349 | 350 | void brightnessImage() async { 351 | final temp = value!; 352 | value = null; 353 | 354 | final Uint8List converted = await compute( 355 | brightnessImageIsolate, 356 | [temp.content, temp.width, temp.height], 357 | ); 358 | 359 | value = Bitmap.fromHeadless(temp.width, temp.height, converted); 360 | } 361 | 362 | void adjustColorImage() async { 363 | final temp = value!; 364 | value = null; 365 | 366 | final Uint8List converted = await compute( 367 | adjustColorsImageIsolate, 368 | [temp.content, temp.width, temp.height], 369 | ); 370 | 371 | value = Bitmap.fromHeadless(temp.width, temp.height, converted); 372 | } 373 | 374 | void batchOperations() async { 375 | final temp = value!; 376 | value = null; 377 | 378 | final Uint8List converted = await compute( 379 | batchOperationsImageIsolate, 380 | [temp.content, temp.width, temp.height], 381 | ); 382 | 383 | value = Bitmap.fromHeadless(temp.width - 20, temp.height - 20, converted); 384 | } 385 | } 386 | 387 | Future flipHImageIsolate(List imageData) async { 388 | final Uint8List byteData = imageData[0]; 389 | final int width = imageData[1]; 390 | final int height = imageData[2]; 391 | 392 | final bigBitmap = Bitmap.fromHeadless(width, height, byteData); 393 | final returnBitmap = bigBitmap.apply(BitmapFlip.horizontal()); 394 | 395 | return returnBitmap.content; 396 | } 397 | 398 | Future flipVImageIsolate(List imageData) async { 399 | final Uint8List byteData = imageData[0]; 400 | final int width = imageData[1]; 401 | final int height = imageData[2]; 402 | 403 | final Bitmap bigBitmap = Bitmap.fromHeadless(width, height, byteData); 404 | 405 | final Bitmap returnBitmap = bigBitmap.apply(BitmapFlip.vertical()); 406 | 407 | return returnBitmap.content; 408 | } 409 | 410 | Future rotateClockwiseImageIsolate(List imageData) async { 411 | final Uint8List byteData = imageData[0]; 412 | final int width = imageData[1]; 413 | final int height = imageData[2]; 414 | 415 | final Bitmap bigBitmap = Bitmap.fromHeadless(width, height, byteData); 416 | 417 | final Bitmap returnBitmap = bigBitmap.apply(BitmapRotate.rotateClockwise()); 418 | 419 | return returnBitmap.content; 420 | } 421 | 422 | Future rotateCounterClockwiseImageIsolate(List imageData) async { 423 | final Uint8List byteData = imageData[0]; 424 | final int width = imageData[1]; 425 | final int height = imageData[2]; 426 | 427 | final Bitmap bigBitmap = Bitmap.fromHeadless(width, height, byteData); 428 | 429 | final Bitmap returnBitmap = 430 | bigBitmap.apply(BitmapRotate.rotateCounterClockwise()); 431 | 432 | return returnBitmap.content; 433 | } 434 | 435 | Future rotate180ImageIsolate(List imageData) async { 436 | final Uint8List byteData = imageData[0]; 437 | final int width = imageData[1]; 438 | final int height = imageData[2]; 439 | 440 | final Bitmap bigBitmap = Bitmap.fromHeadless(width, height, byteData); 441 | 442 | final Bitmap returnBitmap = bigBitmap.apply(BitmapRotate.rotate180()); 443 | 444 | return returnBitmap.content; 445 | } 446 | 447 | Future contrastImageIsolate(List imageData) async { 448 | final Uint8List byteData = imageData[0]; 449 | final int width = imageData[1]; 450 | final int height = imageData[2]; 451 | 452 | final Bitmap bigBitmap = Bitmap.fromHeadless(width, height, byteData); 453 | 454 | final returnBitmap = bigBitmap.apply(BitmapContrast(1.2)); 455 | 456 | return returnBitmap.content; 457 | } 458 | 459 | Future brightnessImageIsolate(List imageData) async { 460 | final Uint8List byteData = imageData[0]; 461 | final int width = imageData[1]; 462 | final int height = imageData[2]; 463 | 464 | final Bitmap bigBitmap = Bitmap.fromHeadless(width, height, byteData); 465 | 466 | final Bitmap returnBitmap = bigBitmap.apply(BitmapBrightness(0.1)); 467 | 468 | return returnBitmap.content; 469 | } 470 | 471 | Future adjustColorsImageIsolate(List imageData) async { 472 | final Uint8List byteData = imageData[0]; 473 | final int width = imageData[1]; 474 | final int height = imageData[2]; 475 | 476 | final Bitmap bigBitmap = Bitmap.fromHeadless(width, height, byteData); 477 | 478 | final Bitmap returnBitmap = bigBitmap.apply( 479 | BitmapAdjustColor( 480 | blacks: 0x00000000, 481 | saturation: 1.9, // 0 and 5 mid 1.0 482 | ), 483 | ); 484 | 485 | return returnBitmap.content; 486 | } 487 | 488 | Future batchOperationsImageIsolate(List imageData) async { 489 | final Uint8List byteData = imageData[0]; 490 | final int width = imageData[1]; 491 | final int height = imageData[2]; 492 | 493 | final Bitmap bigBitmap = Bitmap.fromHeadless(width, height, byteData); 494 | 495 | final Bitmap returnBitmap = bigBitmap.applyBatch([ 496 | BitmapAdjustColor( 497 | saturation: 1.9, 498 | ), 499 | BitmapCrop.fromLTWH( 500 | left: 10, 501 | top: 10, 502 | width: width - 20, 503 | height: height - 20, 504 | ), 505 | ]); 506 | 507 | return returnBitmap.content; 508 | } 509 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | bitmap: 13 | dependency: "direct dev" 14 | description: 15 | path: ".." 16 | relative: true 17 | source: path 18 | version: "0.2.0" 19 | boolean_selector: 20 | dependency: transitive 21 | description: 22 | name: boolean_selector 23 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 24 | url: "https://pub.dev" 25 | source: hosted 26 | version: "2.1.1" 27 | characters: 28 | dependency: transitive 29 | description: 30 | name: characters 31 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 32 | url: "https://pub.dev" 33 | source: hosted 34 | version: "1.3.0" 35 | clock: 36 | dependency: transitive 37 | description: 38 | name: clock 39 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 40 | url: "https://pub.dev" 41 | source: hosted 42 | version: "1.1.1" 43 | collection: 44 | dependency: transitive 45 | description: 46 | name: collection 47 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 48 | url: "https://pub.dev" 49 | source: hosted 50 | version: "1.18.0" 51 | cupertino_icons: 52 | dependency: "direct main" 53 | description: 54 | name: cupertino_icons 55 | sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d 56 | url: "https://pub.dev" 57 | source: hosted 58 | version: "1.0.6" 59 | fake_async: 60 | dependency: transitive 61 | description: 62 | name: fake_async 63 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 64 | url: "https://pub.dev" 65 | source: hosted 66 | version: "1.3.1" 67 | ffi: 68 | dependency: transitive 69 | description: 70 | name: ffi 71 | sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" 72 | url: "https://pub.dev" 73 | source: hosted 74 | version: "2.1.0" 75 | flutter: 76 | dependency: "direct main" 77 | description: flutter 78 | source: sdk 79 | version: "0.0.0" 80 | flutter_test: 81 | dependency: "direct dev" 82 | description: flutter 83 | source: sdk 84 | version: "0.0.0" 85 | matcher: 86 | dependency: transitive 87 | description: 88 | name: matcher 89 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" 90 | url: "https://pub.dev" 91 | source: hosted 92 | version: "0.12.16" 93 | material_color_utilities: 94 | dependency: transitive 95 | description: 96 | name: material_color_utilities 97 | sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" 98 | url: "https://pub.dev" 99 | source: hosted 100 | version: "0.5.0" 101 | meta: 102 | dependency: transitive 103 | description: 104 | name: meta 105 | sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e 106 | url: "https://pub.dev" 107 | source: hosted 108 | version: "1.10.0" 109 | path: 110 | dependency: transitive 111 | description: 112 | name: path 113 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 114 | url: "https://pub.dev" 115 | source: hosted 116 | version: "1.8.3" 117 | sky_engine: 118 | dependency: transitive 119 | description: flutter 120 | source: sdk 121 | version: "0.0.99" 122 | source_span: 123 | dependency: transitive 124 | description: 125 | name: source_span 126 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 127 | url: "https://pub.dev" 128 | source: hosted 129 | version: "1.10.0" 130 | stack_trace: 131 | dependency: transitive 132 | description: 133 | name: stack_trace 134 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 135 | url: "https://pub.dev" 136 | source: hosted 137 | version: "1.11.1" 138 | stream_channel: 139 | dependency: transitive 140 | description: 141 | name: stream_channel 142 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 143 | url: "https://pub.dev" 144 | source: hosted 145 | version: "2.1.2" 146 | string_scanner: 147 | dependency: transitive 148 | description: 149 | name: string_scanner 150 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 151 | url: "https://pub.dev" 152 | source: hosted 153 | version: "1.2.0" 154 | term_glyph: 155 | dependency: transitive 156 | description: 157 | name: term_glyph 158 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 159 | url: "https://pub.dev" 160 | source: hosted 161 | version: "1.2.1" 162 | test_api: 163 | dependency: transitive 164 | description: 165 | name: test_api 166 | sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" 167 | url: "https://pub.dev" 168 | source: hosted 169 | version: "0.6.1" 170 | vector_math: 171 | dependency: transitive 172 | description: 173 | name: vector_math 174 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 175 | url: "https://pub.dev" 176 | source: hosted 177 | version: "2.1.4" 178 | web: 179 | dependency: transitive 180 | description: 181 | name: web 182 | sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 183 | url: "https://pub.dev" 184 | source: hosted 185 | version: "0.3.0" 186 | sdks: 187 | dart: ">=3.2.0-194.0.dev <4.0.0" 188 | flutter: ">=3.13.9" 189 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: bitmap_example 2 | description: Demonstrates how to use the bitmap plugin. 3 | publish_to: 'none' 4 | 5 | environment: 6 | sdk: ">=3.0.3 <4.0.0" 7 | flutter: ">=3.13.9 <4.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | cupertino_icons: ^1.0.6 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | bitmap: 19 | path: ../ 20 | 21 | flutter: 22 | uses-material-design: true 23 | assets: 24 | - assets/doggo.jpeg 25 | - assets/street.jpg 26 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:bitmap_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => 22 | widget is Text && widget.data!.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/ephemeral/ 38 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/BitmapPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface BitmapPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /ios/Classes/BitmapPlugin.m: -------------------------------------------------------------------------------- 1 | #import "BitmapPlugin.h" 2 | #if __has_include() 3 | #import 4 | #else 5 | // Support project import fallback if the generated compatibility header 6 | // is not copied when this plugin is created as a library. 7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 8 | #import "bitmap-Swift.h" 9 | #endif 10 | 11 | @implementation BitmapPlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftBitmapPlugin registerWithRegistrar:registrar]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ios/Classes/SwiftBitmapPlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | public class SwiftBitmapPlugin: NSObject, FlutterPlugin { 5 | public static func register(with registrar: FlutterPluginRegistrar) { 6 | let channel = FlutterMethodChannel(name: "bitmap", binaryMessenger: registrar.messenger()) 7 | let instance = SwiftBitmapPlugin() 8 | registrar.addMethodCallDelegate(instance, channel: channel) 9 | } 10 | 11 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 12 | result("iOS " + UIDevice.current.systemVersion) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ios/Classes/bitmap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int get_red(uint64_t color) { return (color) & 0xff; } 6 | int get_green(uint64_t color) { return (color >> 8) & 0xff; } 7 | int get_blue(uint64_t color) { return (color >> 16) & 0xff; } 8 | int get_alpha(uint64_t color) { return (color >> 24) & 0xff; } 9 | 10 | int clamp255_0(int before) { 11 | if(before > 255) return 255; 12 | if(before < 0) return 0; 13 | return before; 14 | } 15 | 16 | int clamp255_n255(int before) { 17 | if(before > 255) return 255; 18 | if(before < -255) return -255; 19 | return before; 20 | } 21 | 22 | /** 23 | * Brightness 24 | * Receives a bitmap, its length and a brightness amount valuating between -255 and 255 25 | */ 26 | extern "C" __attribute__((visibility("default"))) __attribute__((used)) 27 | void brightness(uint8_t *starting_pointer, int bitmap_length, int brightness_amount) { 28 | for (int i = 0; i < bitmap_length; i += 4) { 29 | uint8_t *r = starting_pointer + i; 30 | uint8_t *g = starting_pointer + i + 1; 31 | uint8_t *b = starting_pointer + i + 2; 32 | uint8_t *a = starting_pointer + i + 3; 33 | 34 | *r = clamp255_0(*r + brightness_amount); 35 | *g = clamp255_0(*g + brightness_amount); 36 | *b = clamp255_0(*b + brightness_amount); 37 | } 38 | return; 39 | } 40 | 41 | /** 42 | * Contrast 43 | * Receives a bitmap, its length and a contrast rate greater than 0 44 | */ 45 | extern "C" __attribute__((visibility("default"))) __attribute__((used)) 46 | void contrast(uint8_t *starting_pointer, int bitmap_length, double contrast_rate) { 47 | double contrast_sqare = contrast_rate * contrast_rate; 48 | uint8_t contrast_applier[256]; 49 | for (int i = 0; i < 256; ++i) { 50 | contrast_applier[i] = clamp255_0(floor(((((i / 255.0) - 0.5) * contrast_sqare) + 0.5) * 255.0)); 51 | } 52 | 53 | for (int i = 0; i < bitmap_length; i += 4) { 54 | uint8_t *r = starting_pointer + i; 55 | uint8_t *g = starting_pointer + i + 1; 56 | uint8_t *b = starting_pointer + i + 2; 57 | uint8_t *a = starting_pointer + i + 3; 58 | 59 | *r = contrast_applier[*r]; 60 | *g = contrast_applier[*g]; 61 | *b = contrast_applier[*b]; 62 | } 63 | return; 64 | } 65 | 66 | /** 67 | * Adjust color 68 | * Receives a lot of stuff 69 | */ 70 | extern "C" __attribute__((visibility("default"))) __attribute__((used)) 71 | void adjust_color( 72 | uint8_t *starting_pointer, 73 | int bitmap_length, 74 | 75 | uint64_t blacks, 76 | uint64_t whites, 77 | double saturation, 78 | double exposure, 79 | 80 | int compute_blacks, 81 | int compute_whites 82 | ) { 83 | // constants 84 | double DEG_TO_RAD = 0.0174532925; 85 | 86 | double LUM_COEFF_R = 0.2125; 87 | double LUM_COEFF_G = 0.7154; 88 | double LUM_COEFF_B = 0.0721; 89 | 90 | // prepare exposure 91 | if (exposure != 0.0) { 92 | exposure = pow(2, exposure); 93 | } 94 | 95 | // prepare saturation 96 | double inv_saturation = 1 - saturation; 97 | 98 | /// prepare whites and blacks 99 | double br, bg, bb; 100 | double wr, wg, wb; 101 | if (compute_blacks || compute_whites) { 102 | br = compute_blacks ? get_red(blacks) / 255.0 : 0.0; 103 | bg = compute_blacks ? get_green(blacks) / 255.0 : 0.0; 104 | bb = compute_blacks ? get_blue(blacks) / 255.0 : 0.0; 105 | 106 | wr = compute_whites ? get_red(whites) / 255.0 : 1.0; 107 | wg = compute_whites ? get_green(whites) / 255.0 : 1.0; 108 | wb = compute_whites ? get_blue(whites) / 255.0 : 1.0; 109 | } 110 | 111 | for (int i = 0; i < bitmap_length; i += 4) { 112 | uint8_t *r = starting_pointer + i; 113 | uint8_t *g = starting_pointer + i + 1; 114 | uint8_t *b = starting_pointer + i + 2; 115 | 116 | 117 | double r_rep = *r / 255.0; 118 | double g_rep = *g / 255.0; 119 | double b_rep = *b / 255.0; 120 | 121 | if (compute_blacks) { 122 | r_rep = (r_rep + br) * wr; 123 | g_rep = (g_rep + bg) * wg; 124 | b_rep = (b_rep + bb) * wb; 125 | } 126 | 127 | // saturation 128 | double lum = r_rep * LUM_COEFF_R + g_rep * LUM_COEFF_G + b_rep * LUM_COEFF_B; 129 | 130 | r_rep = lum * inv_saturation + r_rep * saturation; 131 | g_rep = lum * inv_saturation + g_rep * saturation; 132 | b_rep = lum * inv_saturation + b_rep * saturation; 133 | 134 | /// exposure 135 | if (exposure != 0.0) { 136 | r_rep = r_rep * exposure; 137 | g_rep = g_rep * exposure; 138 | b_rep = b_rep * exposure; 139 | } 140 | 141 | *r = clamp255_0(floor(r_rep * 255)); 142 | *g = clamp255_0(floor(g_rep * 255)); 143 | *b = clamp255_0(floor(b_rep * 255)); 144 | 145 | } 146 | return; 147 | } 148 | 149 | /** 150 | * RGB overlay 151 | * Receives a RGB color and an overlay intensity (scale parameter) 152 | */ 153 | extern "C" __attribute__((visibility("default"))) __attribute__((used)) 154 | void rgb_overlay( 155 | uint8_t *starting_pointer, 156 | int bitmap_length, 157 | double red, 158 | double green, 159 | double blue, 160 | double scale 161 | ) { 162 | for(int i = 0; i < bitmap_length; i += 4) { 163 | uint8_t *r = starting_pointer + i; 164 | uint8_t *g = starting_pointer + i + 1; 165 | uint8_t *b = starting_pointer + i + 2; 166 | 167 | *r = clamp255_0(round((*r - (*r - red) * scale))); 168 | *g = clamp255_0(round((*g - (*g - green) * scale))); 169 | *b = clamp255_0(round((*b - (*b - blue) * scale))); 170 | } 171 | 172 | return; 173 | } -------------------------------------------------------------------------------- /ios/bitmap.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint bitmap.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'bitmap' 7 | s.version = '0.0.1' 8 | s.summary = 'A new flutter plugin project.' 9 | s.description = <<-DESC 10 | A new flutter plugin project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '8.0' 19 | 20 | # Flutter.framework does not contain a i386 slice. 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 22 | s.swift_version = '5.0' 23 | end 24 | -------------------------------------------------------------------------------- /lib/bitmap_flutter.dart: -------------------------------------------------------------------------------- 1 | library bitmap; 2 | 3 | export 'src/bitmap.dart'; 4 | export 'src/ffi.dart'; 5 | export 'src/operation/operation.dart'; 6 | -------------------------------------------------------------------------------- /lib/src/bitmap.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:typed_data'; 3 | import 'dart:ui' as ui; 4 | 5 | import 'package:flutter/rendering.dart'; 6 | 7 | import 'operation/operation.dart'; 8 | 9 | class Bitmap { 10 | Bitmap.fromHeadless(this.width, this.height, this.content); 11 | 12 | Bitmap.fromHeadful(this.width, this.height, Uint8List headedIntList) 13 | : content = headedIntList.sublist( 14 | RGBA32BitmapHeader.RGBA32HeaderSize, 15 | headedIntList.length, 16 | ); 17 | 18 | Bitmap.blank( 19 | this.width, 20 | this.height, 21 | ) : content = Uint8List.fromList( 22 | List.filled(width * height * RGBA32BitmapHeader.pixelLength, 0), 23 | ); 24 | 25 | /// The width in pixels of the image. 26 | final int width; 27 | 28 | /// The width in pixels of the image. 29 | final int height; 30 | 31 | /// A [Uint8List] of bytes in a RGBA format. 32 | final Uint8List content; 33 | 34 | int get size => (width * height) * RGBA32BitmapHeader.pixelLength; 35 | 36 | // Creates a new instance of bitmap 37 | Bitmap cloneHeadless() { 38 | return Bitmap.fromHeadless( 39 | width, 40 | height, 41 | Uint8List.fromList(content), 42 | ); 43 | } 44 | 45 | static Future fromProvider(ImageProvider provider) async { 46 | final Completer completer = Completer(); 47 | final ImageStream stream = provider.resolve(const ImageConfiguration()); 48 | final listener = ImageStreamListener( 49 | (ImageInfo info, bool synchronousCall) { 50 | if (!completer.isCompleted) { 51 | completer.complete(info); 52 | } 53 | }, 54 | ); 55 | stream.addListener(listener); 56 | final imageInfo = await completer.future; 57 | final ui.Image image = imageInfo.image; 58 | final ByteData? byteData = await image.toByteData(); 59 | if (byteData == null) { 60 | throw StateError("Couldn't serialize image into bytes"); 61 | } 62 | 63 | final Uint8List listInt = byteData.buffer.asUint8List(); 64 | 65 | return Bitmap.fromHeadless(image.width, image.height, listInt); 66 | } 67 | 68 | Future buildImage() async { 69 | final Completer imageCompleter = Completer(); 70 | final headedContent = buildHeaded(); 71 | ui.decodeImageFromList(headedContent, (ui.Image img) { 72 | imageCompleter.complete(img); 73 | }); 74 | return imageCompleter.future; 75 | } 76 | 77 | Uint8List buildHeaded() { 78 | final header = RGBA32BitmapHeader(size, width, height) 79 | ..applyContent(content); 80 | return header.headerIntList; 81 | } 82 | 83 | Bitmap apply(BitmapOperation operation) { 84 | return operation.applyTo(this); 85 | } 86 | 87 | Bitmap applyBatch(List operations) { 88 | Bitmap result = this; 89 | for (final operation in operations) { 90 | result = operation.applyTo(result); 91 | } 92 | return result; 93 | } 94 | 95 | @override 96 | bool operator ==(Object other) => 97 | identical(this, other) || 98 | other is Bitmap && 99 | runtimeType == other.runtimeType && 100 | width == other.width && 101 | height == other.height && 102 | content == other.content; 103 | 104 | @override 105 | int get hashCode => width.hashCode ^ height.hashCode ^ content.hashCode; 106 | } 107 | 108 | class RGBA32BitmapHeader { 109 | static const int pixelLength = 4; 110 | static const int RGBA32HeaderSize = 122; 111 | 112 | RGBA32BitmapHeader(this.contentSize, int width, int height) { 113 | headerIntList = Uint8List(fileLength); 114 | 115 | final ByteData bd = headerIntList.buffer.asByteData(); 116 | bd.setUint8(0x0, 0x42); 117 | bd.setUint8(0x1, 0x4d); 118 | bd.setInt32(0x2, fileLength, Endian.little); 119 | bd.setInt32(0xa, RGBA32HeaderSize, Endian.little); 120 | bd.setUint32(0xe, 108, Endian.little); 121 | bd.setUint32(0x12, width, Endian.little); 122 | bd.setUint32(0x16, -height, Endian.little); 123 | bd.setUint16(0x1a, 1, Endian.little); 124 | bd.setUint32(0x1c, 32, Endian.little); // pixel size 125 | bd.setUint32(0x1e, 3, Endian.little); //BI_BITFIELDS 126 | bd.setUint32(0x22, contentSize, Endian.little); 127 | bd.setUint32(0x36, 0x000000ff, Endian.little); 128 | bd.setUint32(0x3a, 0x0000ff00, Endian.little); 129 | bd.setUint32(0x3e, 0x00ff0000, Endian.little); 130 | bd.setUint32(0x42, 0xff000000, Endian.little); 131 | } 132 | 133 | int contentSize; 134 | 135 | void applyContent(Uint8List contentIntList) { 136 | headerIntList.setRange( 137 | RGBA32HeaderSize, 138 | fileLength, 139 | contentIntList, 140 | ); 141 | } 142 | 143 | late Uint8List headerIntList; 144 | 145 | int get fileLength => contentSize + RGBA32HeaderSize; 146 | } 147 | -------------------------------------------------------------------------------- /lib/src/ffi.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ffi' as ffi; 2 | 3 | import 'dart:io'; 4 | 5 | import 'dart:typed_data' as typed; // For Platform.isX 6 | import 'package:ffi/ffi.dart' as ext_ffi; 7 | 8 | final ffi.DynamicLibrary bitmapFFILib = Platform.isAndroid 9 | ? ffi.DynamicLibrary.open("libbitmap.so") 10 | : ffi.DynamicLibrary.process(); 11 | 12 | typedef BitmapFFIExecution = void Function( 13 | ffi.Pointer startingPointer, 14 | typed.Uint8List pointerList, 15 | ); 16 | 17 | class FFIImpl { 18 | FFIImpl(this.ffiExecution); 19 | 20 | final BitmapFFIExecution ffiExecution; 21 | 22 | void execute(typed.Uint8List sourceBmp) { 23 | final ffi.Pointer startingPointer = ext_ffi.calloc( 24 | sourceBmp.length, 25 | ); 26 | final pointerList = startingPointer.asTypedList(sourceBmp.length); 27 | pointerList.setAll(0, sourceBmp); 28 | ffiExecution(startingPointer, pointerList); 29 | sourceBmp.setAll(0, pointerList); 30 | 31 | ext_ffi.calloc.free(startingPointer); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/operation/adjust_color.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ffi' as ffi; 2 | import 'dart:typed_data'; 3 | 4 | import '../bitmap.dart'; 5 | import '../ffi.dart'; 6 | import 'operation.dart'; 7 | 8 | // *** FFi C++ bindings *** 9 | const _nativeFunctionName = "adjust_color"; 10 | 11 | typedef _NativeSideFunction = ffi.Void Function( 12 | ffi.Pointer, 13 | ffi.Int32, 14 | ffi.Uint64, 15 | ffi.Uint64, 16 | ffi.Double, 17 | ffi.Double, 18 | ffi.Int32, 19 | ffi.Int32, 20 | ); 21 | 22 | typedef _DartSideFunction = void Function( 23 | ffi.Pointer startingPointer, 24 | int bitmapLength, 25 | int blacks, 26 | int whites, 27 | double saturation, 28 | double exposure, 29 | int computeBlacks, 30 | int computeWhites, 31 | ); 32 | 33 | _DartSideFunction _adjustColorFFIImpl = bitmapFFILib 34 | .lookup>(_nativeFunctionName) 35 | .asFunction(); 36 | 37 | /// Adjusts a lot of stuff of color 38 | class BitmapAdjustColor implements BitmapOperation { 39 | BitmapAdjustColor({ 40 | this.blacks, 41 | this.whites, 42 | this.exposure, 43 | this.saturation, 44 | }); 45 | 46 | static const DEG_TO_RAD = 0.0174532925; 47 | static const lumCoeffR = 0.2125; 48 | static const lumCoeffG = 0.7154; 49 | static const lumCoeffB = 0.0721; 50 | 51 | /// Enhancement factor of the dark parts of an image 52 | int? blacks; 53 | 54 | /// Enhancement factor of the light parts of an image 55 | int? whites; 56 | 57 | /// Defines the saturation to be adjusted in an image 58 | double? saturation; 59 | 60 | /// Enhancement factor of the dark parts of an image 61 | double? exposure; 62 | 63 | @override 64 | Bitmap applyTo(Bitmap bitmap) { 65 | final Bitmap copy = bitmap.cloneHeadless(); 66 | _adjustColorCore( 67 | copy.content, 68 | ); 69 | return copy; 70 | } 71 | 72 | void _adjustColorCore(Uint8List sourceBmp) { 73 | if ((exposure == null || exposure == 0.0) && 74 | (blacks == null || blacks == 0) && 75 | (whites == null || whites == 0x00FFFFFF) && 76 | saturation == null) { 77 | return; 78 | } 79 | 80 | final size = sourceBmp.length; 81 | 82 | final exposureNonNull = exposure ?? 0.0; 83 | final saturationNonNull = saturation ?? 1.0; 84 | 85 | final computeBlacks = (blacks != null && blacks != 0) ? 1 : 0; 86 | final computeWhites = (whites != null && whites != 0x00FFFFFF) ? 1 : 0; 87 | 88 | final blacksNonNull = blacks ?? 0; 89 | final whitesNonNull = whites ?? 0; 90 | 91 | // start native execution 92 | FFIImpl((startingPointer, pointerList) { 93 | _adjustColorFFIImpl( 94 | startingPointer, 95 | size, 96 | blacksNonNull, 97 | whitesNonNull, 98 | saturationNonNull, 99 | exposureNonNull, 100 | computeBlacks, 101 | computeWhites, 102 | ); 103 | }).execute(sourceBmp); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/src/operation/brightness.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ffi' as ffi; 2 | import 'dart:typed_data'; 3 | 4 | import '../bitmap.dart'; 5 | import '../ffi.dart'; 6 | import 'operation.dart'; 7 | 8 | // *** FFi C++ bindings *** 9 | const _nativeFunctionName = "brightness"; 10 | 11 | typedef _NativeSideFunction = ffi.Void Function( 12 | ffi.Pointer, 13 | ffi.Int32, 14 | ffi.Int32, 15 | ); 16 | 17 | typedef _DartSideFunction = void Function( 18 | ffi.Pointer startingPointer, 19 | int bitmapLength, 20 | int brightnessAmount, 21 | ); 22 | 23 | _DartSideFunction _brightnessFFIImpl = bitmapFFILib 24 | .lookup>(_nativeFunctionName) 25 | .asFunction(); 26 | 27 | /// Changes brightness of [sourceBmp] accordingly to [brightnessRate] . 28 | /// 29 | /// [brightnessRate] Can be between -1.0 and 1.0. 0.0 does nothing; 30 | class BitmapBrightness implements BitmapOperation { 31 | BitmapBrightness(double brightnessFactor) 32 | : brightnessFactor = brightnessFactor.clamp(-1.0, 1.0); 33 | 34 | final double brightnessFactor; 35 | 36 | @override 37 | Bitmap applyTo(Bitmap bitmap) { 38 | final Bitmap copy = bitmap.cloneHeadless(); 39 | _brightnessCore(copy.content, brightnessFactor); 40 | return copy; 41 | } 42 | 43 | void _brightnessCore(Uint8List sourceBmp, double brightnessRate) { 44 | assert(brightnessRate >= -1.0 && brightnessRate <= 1.0); 45 | 46 | if (brightnessRate == 0.0) { 47 | return; 48 | } 49 | 50 | final brightnessAmount = (brightnessRate * 255).floor(); 51 | final size = sourceBmp.length; 52 | 53 | // start native execution 54 | FFIImpl((startingPointer, pointerList) { 55 | _brightnessFFIImpl(startingPointer, size, brightnessAmount); 56 | }).execute(sourceBmp); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/src/operation/contrast.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ffi' as ffi; 2 | import 'dart:typed_data'; 3 | 4 | import '../bitmap.dart'; 5 | import '../ffi.dart'; 6 | import 'operation.dart'; 7 | 8 | // *** FFi C++ bindings *** 9 | const _nativeFunctionName = "contrast"; 10 | 11 | typedef _NativeSideFunction = ffi.Void Function( 12 | ffi.Pointer, 13 | ffi.Int32, 14 | ffi.Double, 15 | ); 16 | 17 | typedef _DartSideFunction = void Function( 18 | ffi.Pointer startingPointer, 19 | int bitmapLength, 20 | double contrastRate, 21 | ); 22 | 23 | _DartSideFunction _contrastFFIImpl = bitmapFFILib 24 | .lookup>(_nativeFunctionName) 25 | .asFunction(); 26 | 27 | /// Sets a contrast of in image given [contrastFactor]. 28 | class BitmapContrast implements BitmapOperation { 29 | BitmapContrast(this.contrastFactor) : assert(contrastFactor >= 0.0); 30 | 31 | double contrastFactor; 32 | 33 | @override 34 | Bitmap applyTo(Bitmap bitmap) { 35 | final Bitmap copy = bitmap.cloneHeadless(); 36 | _contrastCore(copy.content, contrastFactor); 37 | return copy; 38 | } 39 | 40 | void _contrastCore(Uint8List sourceBmp, double contrastRate) { 41 | assert(contrastRate >= 0.0); 42 | final size = sourceBmp.length; 43 | FFIImpl((startingPointer, pointerList) { 44 | _contrastFFIImpl(startingPointer, size, contrastRate); 45 | }).execute(sourceBmp); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/src/operation/crop.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import '../bitmap.dart'; 4 | import 'operation.dart'; 5 | 6 | /// Crops the source bitmap to rectangle defined by [top], [left], [width] and [height]. 7 | class BitmapCrop extends BitmapOperation { 8 | /// Crops the source bitmap to rectangle defined by top, left, width and height. 9 | BitmapCrop.fromLTWH({ 10 | required this.left, 11 | required this.top, 12 | required this.width, 13 | required this.height, 14 | }) : assert(left >= 0), 15 | assert(top >= 0), 16 | assert(width > 0), 17 | assert(height > 0); 18 | 19 | BitmapCrop.fromLTRB({ 20 | required this.left, 21 | required this.top, 22 | required int right, 23 | required int bottom, 24 | }) : width = right - left, 25 | height = bottom - top; 26 | 27 | int left; 28 | int top; 29 | int width; 30 | int height; 31 | 32 | @override 33 | Bitmap applyTo(Bitmap bitmap) { 34 | assert(left + width <= bitmap.width); 35 | assert(top + height <= bitmap.height); 36 | 37 | final int newBitmapSize = width * height * RGBA32BitmapHeader.pixelLength; 38 | 39 | final Bitmap cropped = Bitmap.fromHeadless( 40 | width, 41 | height, 42 | Uint8List(newBitmapSize), 43 | ); 44 | 45 | _cropCore( 46 | bitmap.content, 47 | cropped.content, 48 | bitmap.width, 49 | // Height is not needed. 50 | left, 51 | top, 52 | width, 53 | height, 54 | ); 55 | 56 | return cropped; 57 | } 58 | 59 | void _cropCore( 60 | Uint8List sourceBmp, 61 | Uint8List destBmp, 62 | int sourceWidth, 63 | int left, 64 | int top, 65 | int width, 66 | int height, 67 | ) { 68 | const pixelLength = RGBA32BitmapHeader.pixelLength; 69 | 70 | for (int x = left * pixelLength; x < (left + width) * pixelLength; x++) { 71 | for (int y = top; y < (top + height); y++) { 72 | destBmp[x - left * pixelLength + (y - top) * width * pixelLength] = 73 | sourceBmp[x + y * sourceWidth * pixelLength]; 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/src/operation/flip.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import '../bitmap.dart'; 3 | import 'operation.dart'; 4 | 5 | class BitmapFlip implements BitmapOperation { 6 | final _Flip _flip; 7 | 8 | BitmapFlip.vertical() : _flip = _VerticalFlip(); 9 | 10 | BitmapFlip.horizontal() : _flip = _HorizontalFlip(); 11 | 12 | @override 13 | Bitmap applyTo(Bitmap bitmap) { 14 | return _flip.flip(bitmap); 15 | } 16 | } 17 | 18 | abstract class _Flip { 19 | Bitmap flip(Bitmap bitmap); 20 | } 21 | 22 | class _VerticalFlip implements _Flip { 23 | @override 24 | Bitmap flip(Bitmap bitmap) { 25 | final Bitmap copy = bitmap.cloneHeadless(); 26 | final width = bitmap.width; 27 | final height = bitmap.height; 28 | final Uint8List copyContent = copy.content; 29 | 30 | _verticalFlipCore(copyContent, width, height); 31 | 32 | return copy; 33 | } 34 | 35 | void _verticalFlipCore(Uint8List bmp, int width, int height) { 36 | const pixelLength = RGBA32BitmapHeader.pixelLength; 37 | 38 | final int lineLength = width * pixelLength; 39 | final int halfHeight = height ~/ 2; 40 | 41 | for (int line = 0; line < halfHeight; line++) { 42 | final int startOfLine = line * lineLength; 43 | final int startOfOppositeLine = (height - 1 - line) * lineLength; 44 | for (int column = 0; column < width; column++) { 45 | final int pixelStart = startOfLine + column * pixelLength; 46 | final int pixelEnd = pixelStart + pixelLength; 47 | 48 | final int oppositePixelStart = 49 | startOfOppositeLine + column * pixelLength; 50 | final int oppositePixelEnd = oppositePixelStart + pixelLength; 51 | 52 | final Uint8List oppositePixel = bmp.sublist( 53 | oppositePixelStart, 54 | oppositePixelEnd, 55 | ); 56 | final Uint8List targetPixel = bmp.sublist(pixelStart, pixelEnd); 57 | 58 | bmp.setRange(oppositePixelStart, oppositePixelEnd, targetPixel); 59 | bmp.setRange(pixelStart, pixelEnd, oppositePixel); 60 | } 61 | } 62 | } 63 | } 64 | 65 | class _HorizontalFlip implements _Flip { 66 | @override 67 | Bitmap flip(Bitmap bitmap) { 68 | final Bitmap copy = bitmap.cloneHeadless(); 69 | final width = bitmap.width; 70 | final height = bitmap.height; 71 | final Uint8List copyContent = copy.content; 72 | 73 | _horizontalFlipCore(copyContent, width, height); 74 | 75 | return copy; 76 | } 77 | 78 | void _horizontalFlipCore(Uint8List bmp, int width, int height) { 79 | const pixelLength = RGBA32BitmapHeader.pixelLength; 80 | 81 | final int lineLength = width * pixelLength; 82 | final int halfLine = lineLength ~/ 2; 83 | 84 | for (int line = 0; line < height; line++) { 85 | final int startOfLine = line * lineLength; 86 | for (int relativeColumnStart = 0; 87 | relativeColumnStart < halfLine; 88 | relativeColumnStart += pixelLength) { 89 | final int pixelStart = startOfLine + relativeColumnStart; 90 | final int pixelEnd = pixelStart + pixelLength; 91 | 92 | final int relativeOppositePixelStart = 93 | lineLength - relativeColumnStart - pixelLength; 94 | final int oppositePixelStart = startOfLine + relativeOppositePixelStart; 95 | final int oppositePixelEnd = oppositePixelStart + pixelLength; 96 | 97 | final Uint8List oppositePixel = bmp.sublist( 98 | oppositePixelStart, 99 | oppositePixelEnd, 100 | ); 101 | final Uint8List targetPixel = bmp.sublist(pixelStart, pixelEnd); 102 | 103 | bmp.setRange(oppositePixelStart, oppositePixelEnd, targetPixel); 104 | bmp.setRange(pixelStart, pixelEnd, oppositePixel); 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /lib/src/operation/operation.dart: -------------------------------------------------------------------------------- 1 | import '../bitmap.dart'; 2 | 3 | export 'adjust_color.dart'; 4 | export 'brightness.dart'; 5 | export 'contrast.dart'; 6 | export 'crop.dart'; 7 | export 'flip.dart'; 8 | export 'resize.dart'; 9 | export 'rgb_overlay.dart'; 10 | export 'rotation.dart'; 11 | 12 | abstract class BitmapOperation { 13 | Bitmap applyTo(Bitmap bitmap); 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/operation/resize.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import '../bitmap.dart'; 3 | import 'operation.dart'; 4 | 5 | class BitmapResize implements BitmapOperation { 6 | BitmapResize.to({int? width, int? height}) 7 | : resizeWidth = width, 8 | resizeHeight = height, 9 | assert( 10 | width != null || height != null, 11 | "You have to provide either width or height to resize an image", 12 | ); 13 | 14 | final int? resizeHeight; 15 | final int? resizeWidth; 16 | 17 | @override 18 | Bitmap applyTo(Bitmap bitmap) { 19 | final width = bitmap.width; 20 | final height = bitmap.height; 21 | 22 | if (resizeWidth == null && resizeHeight == null) { 23 | throw UnsupportedError( 24 | "You have to provide either width or height to resize an image", 25 | ); 26 | } 27 | 28 | // keep aspect ratio 29 | final toWidth = resizeWidth ?? (resizeHeight! * (width / height)).toInt(); 30 | final toHeight = resizeHeight ?? (resizeWidth! * (height / width)).toInt(); 31 | 32 | final int newBitmapBytesExtent = 33 | (toWidth * toHeight) * RGBA32BitmapHeader.pixelLength; 34 | 35 | final Bitmap resized = Bitmap.fromHeadless( 36 | toWidth, 37 | toHeight, 38 | Uint8List(newBitmapBytesExtent), 39 | ); 40 | 41 | _resizeCore( 42 | bitmap.content, 43 | resized.content, 44 | width, 45 | height, 46 | toWidth, 47 | toHeight, 48 | ); 49 | 50 | return resized; 51 | } 52 | 53 | void _resizeCore( 54 | Uint8List sourceBmp, 55 | Uint8List destBmp, 56 | int sourceWidth, 57 | int sourceHeight, 58 | int width, [ 59 | int height = -1, 60 | ]) { 61 | assert(width > 0 && height > 0); 62 | const pixelLength = RGBA32BitmapHeader.pixelLength; 63 | 64 | final double proportionY = sourceHeight / height; 65 | final double proportionX = sourceWidth / width; 66 | 67 | final int lineLength = width * pixelLength; 68 | final int sourceLineLength = sourceWidth * pixelLength; 69 | 70 | // inspired by dart_image, interpolation: nearest 71 | final sourceColumns = Int32List(width); 72 | 73 | for (int column = 0; column < width; column++) { 74 | sourceColumns[column] = (column * proportionX).toInt(); 75 | } 76 | 77 | for (int line = 0; line < height; line++) { 78 | final int startOfLine = line * lineLength; 79 | 80 | final int sourceLine = (line * proportionY).toInt(); 81 | final int sourceStartOfLine = sourceLine * sourceLineLength; 82 | 83 | for (int column = 0; column < width; column++) { 84 | final int columnStart = column * pixelLength; 85 | final int pixelStart = startOfLine + columnStart; 86 | final int pixelEnd = pixelStart + pixelLength; 87 | 88 | final int sourceColumnStart = sourceColumns[column] * pixelLength; 89 | final int sourcePixelStart = sourceStartOfLine + sourceColumnStart; 90 | final int sourcePixelEnd = sourcePixelStart + pixelLength; 91 | 92 | final Uint8List sourcePixel = 93 | sourceBmp.sublist(sourcePixelStart, sourcePixelEnd); 94 | 95 | destBmp.setRange(pixelStart, pixelEnd, sourcePixel); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/src/operation/rgb_overlay.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ffi' as ffi; 2 | import 'dart:typed_data'; 3 | 4 | import '../bitmap.dart'; 5 | import '../ffi.dart'; 6 | import 'operation.dart'; 7 | 8 | // *** FFi C++ bindings *** 9 | const _nativeFunctionName = "rgb_overlay"; 10 | 11 | typedef _NativeSideFunction = ffi.Void Function(ffi.Pointer, 12 | ffi.Int32, ffi.Double, ffi.Double, ffi.Double, ffi.Double); 13 | 14 | typedef _DartSideFunction = void Function( 15 | ffi.Pointer startingPointer, 16 | int bitmapLength, 17 | double red, 18 | double green, 19 | double blue, 20 | double scale); 21 | 22 | _DartSideFunction _rgbOverlayFFIImpl = bitmapFFILib 23 | .lookup>(_nativeFunctionName) 24 | .asFunction(); 25 | 26 | class BitmapRgbOverlay implements BitmapOperation { 27 | BitmapRgbOverlay(this.red, this.green, this.blue, this.scale); 28 | 29 | final double red; 30 | final double green; 31 | final double blue; 32 | final double scale; 33 | 34 | @override 35 | Bitmap applyTo(Bitmap bitmap) { 36 | final Bitmap copy = bitmap.cloneHeadless(); 37 | _rgbOverlayCore(copy.content, red, green, blue, scale); 38 | return copy; 39 | } 40 | 41 | void _rgbOverlayCore(Uint8List sourceBmp, double red, double green, 42 | double blue, double scale) { 43 | final size = sourceBmp.length; 44 | 45 | // start native execution 46 | FFIImpl((startingPointer, pointerList) { 47 | _rgbOverlayFFIImpl(startingPointer, size, red, green, blue, scale); 48 | }).execute(sourceBmp); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/src/operation/rotation.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import '../bitmap.dart'; 4 | import 'operation.dart'; 5 | 6 | class BitmapRotate implements BitmapOperation { 7 | final _Rotate _rotate; 8 | 9 | BitmapRotate.rotateClockwise() : _rotate = _RotateClockwise(); 10 | 11 | BitmapRotate.rotate180() : _rotate = _Rotate180(); 12 | 13 | BitmapRotate.rotateCounterClockwise() : _rotate = _RotateCounterClockwise(); 14 | 15 | @override 16 | Bitmap applyTo(Bitmap bitmap) { 17 | return _rotate.doRotate(bitmap); 18 | } 19 | } 20 | 21 | abstract class _Rotate { 22 | Bitmap doRotate(Bitmap bitmap); 23 | } 24 | 25 | class _RotateClockwise implements _Rotate { 26 | @override 27 | Bitmap doRotate(Bitmap bitmap) { 28 | final Bitmap rotated = Bitmap.fromHeadless( 29 | bitmap.height, 30 | bitmap.width, 31 | Uint8List(bitmap.width * bitmap.height * RGBA32BitmapHeader.pixelLength), 32 | ); 33 | 34 | _rotateClockwiseCore( 35 | bitmap.content, 36 | rotated.content, 37 | bitmap.width, 38 | bitmap.height, 39 | ); 40 | 41 | return rotated; 42 | } 43 | 44 | void _rotateClockwiseCore( 45 | Uint8List sourceBmp, 46 | Uint8List destBmp, 47 | int width, 48 | int height, 49 | ) { 50 | assert(width > 0 && height > 0); 51 | 52 | const pixelLength = RGBA32BitmapHeader.pixelLength; 53 | 54 | final int lineLength = width * pixelLength; 55 | for (int line = 0; line < height; line++) { 56 | final startOfLine = line * lineLength; 57 | for (int column = 0; column < width; column++) { 58 | final int columnStart = column * pixelLength; 59 | final int pixelStart = startOfLine + columnStart; 60 | final int pixelEnd = pixelStart + pixelLength; 61 | 62 | final int rotatedStart = 63 | (height * column) * pixelLength + (height - line - 1) * pixelLength; 64 | final int rotatedEnd = rotatedStart + pixelLength; 65 | 66 | final Uint8List sourcePixel = sourceBmp.sublist(pixelStart, pixelEnd); 67 | 68 | destBmp.setRange(rotatedStart, rotatedEnd, sourcePixel); 69 | } 70 | } 71 | } 72 | } 73 | 74 | class _RotateCounterClockwise implements _Rotate { 75 | @override 76 | Bitmap doRotate(Bitmap bitmap) { 77 | final Bitmap rotated = Bitmap.fromHeadless( 78 | bitmap.height, 79 | bitmap.width, 80 | Uint8List(bitmap.width * bitmap.height * RGBA32BitmapHeader.pixelLength), 81 | ); 82 | 83 | _rotateCounterClockwiseCore( 84 | bitmap.content, 85 | rotated.content, 86 | bitmap.width, 87 | bitmap.height, 88 | ); 89 | 90 | return rotated; 91 | } 92 | 93 | void _rotateCounterClockwiseCore( 94 | Uint8List sourceBmp, 95 | Uint8List destBmp, 96 | int width, 97 | int height, 98 | ) { 99 | assert(width > 0 && height > 0); 100 | const pixelLength = RGBA32BitmapHeader.pixelLength; 101 | 102 | final int lineLength = width * pixelLength; 103 | for (int line = 0; line < height; line++) { 104 | final startOfLine = line * lineLength; 105 | for (int column = 0; column < width; column++) { 106 | final int columnStart = column * pixelLength; 107 | final int pixelStart = startOfLine + columnStart; 108 | final int pixelEnd = pixelStart + pixelLength; 109 | 110 | final int rotatedStart = 111 | (height * (width - column - 1)) * pixelLength + line * pixelLength; 112 | final int rotatedEnd = rotatedStart + pixelLength; 113 | 114 | final Uint8List sourcePixel = sourceBmp.sublist(pixelStart, pixelEnd); 115 | 116 | destBmp.setRange(rotatedStart, rotatedEnd, sourcePixel); 117 | } 118 | } 119 | } 120 | } 121 | 122 | class _Rotate180 implements _Rotate { 123 | @override 124 | Bitmap doRotate(Bitmap bitmap) { 125 | final Bitmap rotated = Bitmap.fromHeadless( 126 | bitmap.height, 127 | bitmap.width, 128 | Uint8List(bitmap.width * bitmap.height * RGBA32BitmapHeader.pixelLength), 129 | ); 130 | 131 | _rotate180Core( 132 | bitmap.content, 133 | rotated.content, 134 | bitmap.width, 135 | bitmap.height, 136 | ); 137 | 138 | return rotated; 139 | } 140 | 141 | void _rotate180Core( 142 | Uint8List sourceBmp, 143 | Uint8List destBmp, 144 | int width, 145 | int height, 146 | ) { 147 | assert(width > 0 && height > 0); 148 | const pixelLength = RGBA32BitmapHeader.pixelLength; 149 | 150 | final int lineLength = width * pixelLength; 151 | for (int line = 0; line < height; line++) { 152 | final startOfLine = line * lineLength; 153 | for (int column = 0; column < width; column++) { 154 | final int columnStart = column * pixelLength; 155 | final int pixelStart = startOfLine + columnStart; 156 | final int pixelEnd = pixelStart + pixelLength; 157 | 158 | final int rotatedStart = width * (height - line - 1) * pixelLength + 159 | (width - column - 1) * pixelLength; 160 | final int rotatedEnd = rotatedStart + pixelLength; 161 | 162 | final Uint8List sourcePixel = sourceBmp.sublist(pixelStart, pixelEnd); 163 | 164 | destBmp.setRange(rotatedStart, rotatedEnd, sourcePixel); 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /macos/Classes/BitmapPlugin.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | public class BitmapPlugin: NSObject, FlutterPlugin { 5 | public static func register(with registrar: FlutterPluginRegistrar) { 6 | let channel = FlutterMethodChannel(name: "bitmap", binaryMessenger: registrar.messenger) 7 | let instance = BitmapPlugin() 8 | registrar.addMethodCallDelegate(instance, channel: channel) 9 | } 10 | 11 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 12 | switch call.method { 13 | case "getPlatformVersion": 14 | result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString) 15 | default: 16 | result(FlutterMethodNotImplemented) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /macos/bitmap.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint bitmap.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'bitmap' 7 | s.version = '0.0.1' 8 | s.summary = 'A new flutter plugin project.' 9 | s.description = <<-DESC 10 | A new flutter plugin project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'FlutterMacOS' 18 | 19 | s.platform = :osx, '10.11' 20 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } 21 | s.swift_version = '5.0' 22 | end 23 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.18.0" 44 | fake_async: 45 | dependency: transitive 46 | description: 47 | name: fake_async 48 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.3.1" 52 | ffi: 53 | dependency: "direct main" 54 | description: 55 | name: ffi 56 | sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "2.1.0" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_test: 66 | dependency: "direct dev" 67 | description: flutter 68 | source: sdk 69 | version: "0.0.0" 70 | matcher: 71 | dependency: transitive 72 | description: 73 | name: matcher 74 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" 75 | url: "https://pub.dev" 76 | source: hosted 77 | version: "0.12.16" 78 | material_color_utilities: 79 | dependency: transitive 80 | description: 81 | name: material_color_utilities 82 | sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "0.5.0" 86 | meta: 87 | dependency: transitive 88 | description: 89 | name: meta 90 | sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "1.10.0" 94 | path: 95 | dependency: transitive 96 | description: 97 | name: path 98 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "1.8.3" 102 | sky_engine: 103 | dependency: transitive 104 | description: flutter 105 | source: sdk 106 | version: "0.0.99" 107 | source_span: 108 | dependency: transitive 109 | description: 110 | name: source_span 111 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 112 | url: "https://pub.dev" 113 | source: hosted 114 | version: "1.10.0" 115 | stack_trace: 116 | dependency: transitive 117 | description: 118 | name: stack_trace 119 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 120 | url: "https://pub.dev" 121 | source: hosted 122 | version: "1.11.1" 123 | stream_channel: 124 | dependency: transitive 125 | description: 126 | name: stream_channel 127 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "2.1.2" 131 | string_scanner: 132 | dependency: transitive 133 | description: 134 | name: string_scanner 135 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "1.2.0" 139 | term_glyph: 140 | dependency: transitive 141 | description: 142 | name: term_glyph 143 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "1.2.1" 147 | test_api: 148 | dependency: transitive 149 | description: 150 | name: test_api 151 | sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "0.6.1" 155 | vector_math: 156 | dependency: transitive 157 | description: 158 | name: vector_math 159 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "2.1.4" 163 | web: 164 | dependency: transitive 165 | description: 166 | name: web 167 | sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "0.3.0" 171 | sdks: 172 | dart: ">=3.2.0-194.0.dev <4.0.0" 173 | flutter: ">=3.13.9" 174 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: bitmap_flutter 2 | description: Bitmap is a fast and minimalistic lib that heelps you to manipulate image on Flutter apps. 3 | version: 1.0.0 4 | homepage: https://github.com/guptan404/bitmap 5 | topics: [image, image-processing, ffi] 6 | 7 | environment: 8 | sdk: ">=3.1.0 <4.0.0" 9 | flutter: ">=3.13.9" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | ffi: ^2.1.0 15 | 16 | dev_dependencies: 17 | flutter_test: 18 | sdk: flutter 19 | 20 | flutter: 21 | plugin: 22 | platforms: 23 | android: 24 | package: com.example.bitmap 25 | pluginClass: BitmapPlugin 26 | ios: 27 | pluginClass: BitmapPlugin 28 | -------------------------------------------------------------------------------- /test/bitmap_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | void main() { 4 | test('Figure out a way to test this with FFI', () {}); 5 | } 6 | -------------------------------------------------------------------------------- /transform.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefireteam/bitmap/6eb13d4980bd53a9b0de4eca178c60809bce3b5d/transform.jpg --------------------------------------------------------------------------------