PhotoEditor

burhanrashid52MIT活跃维护

Android 图片编辑库,基于 Canvas 提供画笔涂鸦、文字、滤镜、表情和贴纸等编辑能力,可快速给应用加上类似 Instagram 故事风格的图片编辑功能。

A Photo Editor library with simple, easy support for image editing using paints,text,filters,emoji and Sticker like stories.

v.3.1.1发布于 2026-09-17 11:33 UTC4,530star1,051fork同步于 2026-11-10 23:38 UTC

怎么上手

由 README 提炼,执行前请确认
implementation 'com.burhanrashid52:photoeditor:3.1.1'
硬件要求按 README 说明

README 未说明;这是 Android 库,要求 API 21 及以上,不涉及 GPU 或显存

支持 Apple Silicon
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

Android 图片编辑库,用画笔、文字、滤镜、表情和贴纸快速给图片加标注

Android 图片编辑库,基于 Canvas 提供画笔涂鸦、文字、滤镜、表情和贴纸等编辑能力,可快速给应用加上类似 Instagram 故事风格的图片编辑功能。

核心能力

  • 用画笔在图片上绘制,可调颜色、大小、透明度和橡皮擦
  • 支持画笔、直线、椭圆、矩形、箭头等基础形状
  • 内置亮度等滤镜,也可通过 Custom.Builder 自定义效果
  • 添加文字、Emoji 和贴纸图片,支持双指缩放旋转
  • 画笔和视图支持撤销重做,编辑后可保存为文件

容易踩的坑

v1.0.0 起迁移到 AndroidX,不再支持旧 support library;v2.0.0 起完全用 Kotlin 重写,需要 Java 版本请用 v1.5.1;使用自定义 Emoji 字体需自行把字体文件放入 assets 并创建 Typeface

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v.3.1.1
  1. v.3.1.1v.3.1.1 - Text Selection Position最新正式版2026-09-17 · 2026-09-17 11:33 UTC

    What's Changed

    New Contributors

    Full Changelog: https://github.com/burhanrashid52/PhotoEditor/compare/v.3.0.2...v.3.1.1

  2. v.3.1.02026-03-14 · 2026-03-14 02:28 UTC
    查看更新说明

    What's Changed

    New Contributors

    Full Changelog: https://github.com/burhanrashid52/PhotoEditor/compare/v.3.0.2...v.3.1.0

  3. v.3.0.22024-03-04 · 2024-03-04 07:39 UTC
    查看更新说明

    What's Changed

    New Contributors

    Full Changelog: https://github.com/burhanrashid52/PhotoEditor/compare/v.3.0.1...v.3.0.2

  4. v.3.0.0Coroutine support2023-02-17 · 2023-02-17 15:01 UTC
    查看更新说明

    New : Arrow shape Change : (Breaking Change) minSdkVersion changed to 21 Change : (Breaking Change) Shape names are no longer UPPERCASE New : Suspending functions for saving images: saveAsFile(String[, SaveSettings]) and saveAsBitmap([SaveSettings])

    // Please note that if you call this from a fragment, you should call
    // 'viewLifecycleOwner.lifecycleScope.launch' instead.
    lifecycleScope.launch {
        val result = photoEditor.saveAsFile(filePath)
        if (result is SaveFileResult.Success) {
            showSnackbar("Image saved!")
        } else {
            showSnackbar("Couldn't save image")
        }
    }
    

    Fixed : #374 IndexOutOfBoundsException when saving bitmap

  5. v.2.0.0Kotlin Migration2022-01-22 · 2022-01-22 04:42 UTC
    查看更新说明

    PhotoEditor v.2.0.0 is fully migrated to Kotlin. You can use v.1.5.1 for the Java version. There are no breaking API changes in these two versions.

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    PhotoEditor

    Github Action Downloads API JavaDoc Uplabs AndroidArsenal AndroidDevDigest AwesomeAndroid AndroidWeekly Mindorks

    A Photo Editor library with simple, easy support for image editing using Paints, Text, Filters, Emoji and Sticker like stories.

    Download link

    Features

    Benefits

    • Hassle free coding
    • Increase efficiency
    • Easy image editing

    Getting Started

    To start with this, we need to simply add the dependencies from mavenCentral() in the gradle file of our app module like this

    implementation 'com.burhanrashid52:photoeditor:3.1.1'
    

    or we can also import the :photoeditor module from sample for further customization

    Migrations

    AndroidX

    PhotoEditor v.1.0.0 is a migration to androidX and dropping the support of older support library. There are no API changes. If you find any issue migrating to v.1.0.0 , please follow this Guide. If you still facing the issue than you can always rollback to v.0.4.0. Any fix in PR are Welcome :)

    Kotlin

    PhotoEditor v.2.0.0 is fully migrated to Kotlin. You can use v.1.5.1 for the Java version. There are no breaking API changes in these two versions.

    Setting up the View

    First we need to add PhotoEditorView in our xml layout

     <ja.burhanrashid52.photoeditor.PhotoEditorView
            android:id="@+id/photoEditorView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:photo_src="@drawable/got_s" />
      
    

    We can define our drawable or color resource directly using app:photo_src

    We can set the image programmatically by getting source from PhotoEditorView which will return a ImageView so that we can load image from resources,file or (Picasso/Glide)

    mPhotoEditorView = findViewById(R.id.photoEditorView)
    
    mPhotoEditorView.source.setImageResource(R.drawable.paris_tower)
    

    Building a PhotoEditor

    To use the image editing feature we need to build a PhotoEditor which requires a Context and PhotoEditorView which we have to setup in our xml layout

    //Use custom font using latest support library
    val mTextRobotoTf = ResourcesCompat.getFont(this, R.font.roboto_medium)
    //loading font from asset
    val mEmojiTypeFace = Typeface.createFromAsset(getAssets(), "emojione-android.ttf")
    
    mPhotoEditor = PhotoEditor.Builder(this, mPhotoEditorView)
                .setPinchTextScalable(pinchTextScalable) // set flag to make text scalable when pinch
                .setDefaultTextTypeface(mTextRobotoTf)
                .setDefaultEmojiTypeface(mEmojiTypeFace)
                .build() // build photo editor sdk
    

    We can customize the properties in the PhotoEditor as per our requirement

    PropertyUsage
    setPinchTextScalable()set false to disable pinch to zoom on text insertion. Default: true.
    setClipSourceImage()set true to clip the drawing brush to the source image. Default: false.
    setDefaultTextTypeface()set default text font to be added on image
    setDefaultEmojiTypeface()set default font specifc to add emojis

    That's it we are done with setting up our library

    Drawing

    We can customize our brush and paint with different set of property. To start drawing on image we need to enable the drawing mode

    TypeMethod
    Enable/DisablemPhotoEditor.setBrushDrawingMode(true);
    Shape (brush, line, oval, rectangle, arrow)mPhotoEditor.addShape(shape)
    Shape size (px)mPhotoEditor.setBrushSize(brushSize) or through the a ShapeBuilder
    Shape opacity (In %)mPhotoEditor.setOpacity(opacity) or through the a ShapeBuilder
    Shape colormPhotoEditor.setBrushColor(colorCode) or through the a ShapeBuilder
    Brush ErasermPhotoEditor.brushEraser()

    Note: Whenever we set any property of a brush for drawing it will automatically enable the drawing mode

    Shapes

    We can draw shapes from v.1.5.0. We use ShapeBuilder to define shape and other properties.

    val shapeBuilder = ShapeBuilder()
        .withShapeOpacity(100)
        .withShapeType(ShapeType.Oval)
        .withShapeSize(50f)
    
    photoEditor.setShape(mShapeBuilder)
    

    For more details check ShapeBuilder.

    Filter Effect

    We can apply inbuild filter to the source images using

    mPhotoEditor.setFilterEffect(PhotoFilter.BRIGHTNESS)

    We can also apply custom effect using Custom.Builder

    For more details check Custom Filters

    Text

    Use addText with named optional parameters:

    photoEditor.addText(
        text = inputText,
        colorCodeTextView = colorCode
    )
    

    It uses the default font from the builder unless you provide a typeface:

    photoEditor.addText(
        text = inputText,
        textTypeface = mTypeface,
        colorCodeTextView = colorCode
    )
    

    To place text away from the default centre position, provide a Position:

    photoEditor.addText(
        text = inputText,
        position = Position(80, 160),
        colorCodeTextView = colorCode
    )
    

    Java callers must provide all parameters explicitly:

    mPhotoEditor.addText(inputText, null, new Position(80, 160), null, colorCode);
    

    After insertion, text can still be dragged, rotated, and scaled on the canvas.

    In the sample app, the end-user flow is now:

    1. Tap Text.
    2. Tap the image where the label should appear.
    3. Enter the text in the dialog.

    Repeat the same flow to add multiple text labels in different positions on the image.

    In order to edit the text we need the view, which we will receive in our PhotoEditor callback. This callback will trigger when we Long Press the added text

    mPhotoEditor.setOnPhotoEditorListener(new OnPhotoEditorListener() {
               @Override
               public void onEditTextChangeListener(View rootView, String text, int colorCode) {
                   
               }
           });
    

    Now we can edit the text with a view like this

    mPhotoEditor.editText(rootView, inputText, colorCode);

    If you want more customization on text. Please refer the wiki page for more details.

    Emoji

    We can add the Emoji by PhotoEditor.getEmojis(getActivity()); which will return a list of emojis unicode.

    mPhotoEditor.addEmoji(emojiUnicode);

    It will take default fonts provided in the builder. If we want different Emoji fonts for different emoji we can set typeface with each Emoji like this

    mPhotoEditor.addEmoji(mEmojiTypeface,emojiUnicode);

    Adding Images/Stickers

    We need to provide a Bitmap to add our Images mPhotoEditor.addImage(bitmap);

    Undo and Redo

      mPhotoEditor.undo();
      mPhotoEditor.redo();
    

    Deleting

    For deleting a Text/Emoji/Image we can click on the view to toggle the view highlighter box which will have a close icon. So, by clicking on the icon we can delete the view.

    Saving

    In v.3.0.0 onward, we can save an image to a file using coroutines:

    // Please note that if you call this from a fragment, you should call
    // 'viewLifecycleOwner.lifecycleScope.launch' instead.
    lifecycleScope.launch {
        val result = photoEditor.saveAsFile(filePath)
        if (result is SaveFileResult.Success) {
            showSnackbar("Image saved!")
        } else {
            showSnackbar("Couldn't save image")
        }
    }
    

    You can also save an image to a file from Java. We need to provide a file with callback method when edited image is saved.

     mPhotoEditor.saveAsFile(filePath, new PhotoEditor.OnSaveListener() {
                     @Override
                     public void onSuccess(@NonNull String imagePath) {
                        Log.e("PhotoEditor","Image Saved Successfully");
                     }
    
                     @Override
                     public void onFailure(@NonNull Exception exception) {
                         Log.e("PhotoEditor","Failed to save Image");
                     }
                 });
    

    For more details see Saving

    How to contribute?

    Questions?🤔

    Hit me on twitter Twitter Medium Facebook

    FAQ

    Yes. It's an open-source library and free to use. If this library has saved your time then showing a little credit will increase my motivation towards making the library better :)

    Currently, No. I started to build in branch PE-79. But due to time constraint, I drop the idea. Any PR related to CROP is welcomed :)

    The filter effect is applied using GlSurfaceView and the implementation of this feature causing a lot of issues. Need to think of some other alternative solution. Here is the issue list.

    No. Currently, the focus is on making the android library better. We don't have any plans for other Platform.

    Image Scaling. Memory Issue in Filter.

    Who is using PhotoEditor?

    1. Pixxo
    2. Couple Blog: Long distance
    3. Screenshot Tile (NoRoot)

    Note: I will be happy to add your app to the list. Please reach out to me with details. You know how to reach me :)

    Credits

    This project is inspired from PhotoEditorSDK

    Buy a cup of coffee

    If you found this project helpful or you learned something from the source code and want to thank me, consider buying me a cup of ☕️ BuyMeACoffee

    Lesson Learned from building successful android library PhotoEditor: Droidcon Berlin 2021

    Lesson Learned from building successful android library PhotoEditor

    Open source Support by JetBrains

    MIT License

    Copyright (c) 2022 Burhanuddin Rashid

    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:

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    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.