美文网首页程序员
Android 仿6.5以上版本微信相册

Android 仿6.5以上版本微信相册

作者: 一个不掉头发的开发 | 来源:发表于2017-06-08 14:24 被阅读178次

最近开发项目遇到一个功能,类似微信发朋友圈功能,查找资料并没有类似的效果,于是自己参照微信相册动手撸了一个,三天的开发时间比较仓促,有可能会有BUG,希望各撸友们批评指正(QQ:330093887或者QQ邮箱)。在开发此功能的过程中踩了不少坑,也得到不少的经验,特此在这里写博客记录一下。

先上效果图:


1.特点
· 使用“调整图像”将您的相片调整至尽善尽美
· 使用“选择性调整”对相片的特定对象或区域加以美化
·提供各种有趣且极具新意的滤镜,例如“怀旧”、“戏剧”、“复古”、“杂质”以及“移轴”
· 提供许多优质相框,可为美化相片起到画龙点睛的效果
2.功能
(1) 基本调整功能
·选择性调整-图片编辑库使用c++代码,在数秒钟内对相片中的特定区域做出精准的选择和增强。
·调整图像-使用“环境”来制造特别适合色彩和纹理的深度和自然饱和度。调整“白平衡”、“饱和度”和“对比度”等等。
·拉直旋转-使用简单的手势控制旋转90°及/或拉直相片。
·裁切-使用标准的纵横比或自由裁切,轻松裁切图像以去除相片上分散注意力的部分。
(2) 创造性增强
·黑白-此滤镜的灵感源于暗室,可为相片创造经典的黑白外观。
·复古胶片-使任何相片看起来像50年代、60年代或70年代的古老彩色胶片照。
·戏剧-透过为您的相片量身定制的效果来增添风格,从细微的纹理到异想天开的艺术效果都信手拈来。
·杂质-使您的相片呈现完全独特的时尚昏暗外观。
·移轴镜摄影-建立窄聚焦带,用以模拟微缩场景中常见的景深外观。
·中心焦点-透过模糊和调节周围背景的亮度来突出相片的拍摄主体。
·有机相框-为相片增加风格化边框,以达到画龙点睛的完美效果。
3.图片编辑库
{"滤镜","图像变形","剪切","涂鸦","边框","添加文字","添加水印","马赛克","增强","旋转"}等功能底层使用c++完成,达到快速处理图片不卡顿。
4.注意事项:
1,权限问题2,对图片操作过程中处理Bitmap需要谨慎3,数据保存以及异步操作4,更新UI……
5.代码片段:
(1)启动相册

public void selectPhoto() {
        Intent photoIntent = new Intent(this, ImageGridActivity.class);
        photoIntent.putExtra(ImagePicker.MAX_PHOTO_NUMBER, 4);
        startActivityForResult(photoIntent, CommonUtils.REQUEST_CODE_ALBUN);
    }

(2)得到图片路径

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == CommonUtils.REQUEST_CODE_ALBUN) {
            if (data != null) {
                try {
                    final ArrayList<ImageItem> images = (ArrayList<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS);
                    int size = images.size();
                    for (int i = 0; i < size; i++) {
                        mThumbIds.add(images.get(i).path);
                    }
                    imageAdapter.notifyDataSetChanged();
                } catch (Exception e) {
                    Toast.makeText(this, "请您打开读取存储文件权限", Toast.LENGTH_LONG).show();
                    e.printStackTrace();
                }
            }
        }
    }

(3)调用各个功能CompileBitmapActivity

package injection.sw.com.mycocularlater.imagepicker.ui;

import android.content.Intent;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;

import java.io.File;

import cn.jarlen.photoedit.activity.AddTextActivity;
import cn.jarlen.photoedit.activity.AddWatermarkActivity;
import cn.jarlen.photoedit.activity.DrawBaseActivity;
import cn.jarlen.photoedit.activity.EnhanceActivity;
import cn.jarlen.photoedit.activity.ImageFilterActivity;
import cn.jarlen.photoedit.activity.ImagePasteActivity;
import cn.jarlen.photoedit.activity.MosaicActivity;
import cn.jarlen.photoedit.activity.PhotoFrameActivity;
import cn.jarlen.photoedit.activity.RevolveActivity;
import cn.jarlen.photoedit.activity.WarpActivity;
import injection.sw.com.mycocularlater.CommonUtils;
import injection.sw.com.mycocularlater.R;
import injection.sw.com.mycocularlater.imagepicker.Utils;
import injection.sw.com.mycocularlater.imagepicker.adapter.CompileBitmapAdapter;

import static injection.sw.com.mycocularlater.imagepicker.ui.ImagePreviewActivity.DATA_OF_IMAGE_PATH;


/**
 * Created by zhouqiong on 2017/6/6.
 */

public class CompileBitmapActivity extends TranslucentActivity implements View.OnClickListener {

    private RecyclerView recyclerView;
    private CompileBitmapAdapter adapter;
    private Class<?> intentClass;
    private int intentType = 0;
    private String cameraPath = null;
    private ImageView pictureShow, backImageView;
    private TextView saveTextView;
    private String[] str;
    private FrameLayout bannerFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_compile_bitmap);
        initView();
        initData();
        setOnClickListener();
    }

    private void initView() {
        setArgument();
        recyclerView = (RecyclerView) findViewById(R.id.bottom_gallery);
        pictureShow = (ImageView) findViewById(R.id.pictureShow);
        backImageView = (ImageView) findViewById(R.id.back_btn);
        saveTextView = (TextView) findViewById(R.id.save_btn);
        bannerFragment = (FrameLayout) findViewById(R.id.banner);
        Glide.with(this).load(cameraPath).into(pictureShow);
    }

    private void initData() {
        //设置布局管理器
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        str = new String[]{"滤镜", "图像变形", "剪切", "涂鸦", "边框", "添加文字", "添加水印", "马赛克", "增强", "旋转"};
        recyclerView.setLayoutManager(linearLayoutManager);
        //设置适配器
        adapter = new CompileBitmapAdapter(this, str);
        recyclerView.setAdapter(adapter);
    }

    private void setOnClickListener() {
        backImageView.setOnClickListener(this);
        saveTextView.setOnClickListener(this);
        pictureShow.setOnClickListener(this);
        adapter.setOnItemClickListener(new CompileBitmapAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                switch (position) {
                    case 0:
                        intentClass = ImageFilterActivity.class;
                        intentType = CommonUtils.PHOTO_FILTER_WITH_DATA;
                        break;
                    case 1:
                        intentClass = WarpActivity.class;
                        intentType = CommonUtils.PHOTO_WARP_WITH_DATA;
                        break;
                    case 2:
                        intentClass = ImagePasteActivity.class;
                        intentType = CommonUtils.PHOTO_CROP_WITH_DATA;
                        break;
                    case 3:
                        intentClass = DrawBaseActivity.class;
                        intentType = CommonUtils.PHOTO_DRAW_WITH_DATA;
                        break;
                    case 4:
                        intentClass = PhotoFrameActivity.class;
                        intentType = CommonUtils.PHOTO_FRAME_WITH_DATA;
                        break;
                    case 5:
                        intentClass = AddTextActivity.class;
                        intentType = CommonUtils.PHOTO_ADD_TEXT_DATA;
                        break;
                    case 6:
                        intentClass = AddWatermarkActivity.class;
                        intentType = CommonUtils.PHOTO_ADD_WATERMARK_DATA;
                        break;
                    case 7:
                        intentClass = MosaicActivity.class;
                        intentType = CommonUtils.PHOTO_MOSAIC_WITH_DATA;
                        break;
                    case 8:
                        intentClass = EnhanceActivity.class;
                        intentType = CommonUtils.PHOTO_ENHANCE_WITH_DATA;
                        break;
                    case 9:
                        intentClass = RevolveActivity.class;
                        intentType = CommonUtils.PHOTO_REVOLVE_WITH_DATA;
                        break;
                    default:
                        intentClass = null;
                        intentType = 0;
                        break;
                }

                if (cameraPath == null) {
                    Toast.makeText(CompileBitmapActivity.this, "请选择图片",
                            Toast.LENGTH_SHORT).show();
                    return;
                }
                if (intentClass == null) {
                    Toast.makeText(CompileBitmapActivity.this, "请图片操作类型",
                            Toast.LENGTH_SHORT).show();
                    return;
                }

                // 将图片路径photoPath传到所要调试的模块
                Intent photoFrameIntent = new Intent(CompileBitmapActivity.this, intentClass);
                photoFrameIntent.putExtra("camera_path", cameraPath);
                CompileBitmapActivity.this.startActivityForResult(photoFrameIntent, intentType);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != RESULT_OK) {
            return;
        }
        switch (requestCode) {
            case CommonUtils.PHOTO_FRAME_WITH_DATA:
            case CommonUtils.PHOTO_MOSAIC_WITH_DATA:
            case CommonUtils.PHOTO_DRAW_WITH_DATA:
            case CommonUtils.PHOTO_CROP_WITH_DATA:
            case CommonUtils.PHOTO_FILTER_WITH_DATA:
            case CommonUtils.PHOTO_ENHANCE_WITH_DATA:
            case CommonUtils.PHOTO_REVOLVE_WITH_DATA:
            case CommonUtils.PHOTO_WARP_WITH_DATA:
            case CommonUtils.PHOTO_ADD_WATERMARK_DATA:
            case CommonUtils.PHOTO_ADD_TEXT_DATA:
                cameraPath = data.getStringExtra("camera_path");
                Glide.with(this)
                        .load(Uri.fromFile(new File(cameraPath)))
                        .centerCrop()
                        .placeholder(R.mipmap.default_image)
                        .into(pictureShow);
                break;
        }
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.back_btn) {
            finish();
        } else if (id == R.id.save_btn) {
            File file = Utils.saveBitmap(this, BitmapFactory.decodeFile(cameraPath), "" + SystemClock.currentThreadTimeMillis() + ".jpg");
            Intent mIntent = new Intent();
            mIntent.putExtra(DATA_OF_IMAGE_PATH, file.getAbsolutePath());
            this.setResult(RESULT_OK, mIntent);
            finish();
        } else if (id == R.id.pictureShow) {
            //点击图片,其他view隐藏
            onImageSingleTap();
        }
    }

    public void onImageSingleTap() {
        if (bannerFragment.getVisibility() == View.VISIBLE) {
            showToolBar(AnimationUtils.loadAnimation(this, R.anim.top_out), AnimationUtils.loadAnimation(this, R.anim.fade_out), View.GONE);
        } else {
            showToolBar(AnimationUtils.loadAnimation(this, R.anim.top_in), AnimationUtils.loadAnimation(this, R.anim.fade_in), View.VISIBLE);
        }
    }

    private void showToolBar(Animation animation, Animation animation2, int visible) {
        bannerFragment.setAnimation(animation);
        bannerFragment.setVisibility(visible);
        bannerFragment.setAnimation(animation);
        recyclerView.setAnimation(animation2);
        bannerFragment.setVisibility(visible);
        recyclerView.setVisibility(visible);
    }

    private void setArgument() {
        Bundle bundle = getIntent().getExtras();
        cameraPath = bundle.getString("bitmap");
    }
}

(4)判断某个点是否在多边形区域内

package cn.jarlen.photoedit.operate;

import android.graphics.PointF;
import android.util.Log;

import java.util.List;


/**
 * 判断某个点是否在多边形区域内
 * Created by zhouqiong on 2017/6/5.
 */
public class Lasso {
    private float[] mPolyX, mPolyY;
    private int mPolySize;

    /**
     * 构造方法
     *
     * @param
     */
    public Lasso(List<PointF> pointFs) {
        this.mPolySize = pointFs.size();

        this.mPolyX = new float[this.mPolySize];
        this.mPolyY = new float[this.mPolySize];

        for (int i = 0; i < this.mPolySize; i++) {
            this.mPolyX[i] = pointFs.get(i).x;
            this.mPolyY[i] = pointFs.get(i).y;
        }

        Log.d("lasso", "lasso size:" + mPolySize);
    }

    /**
     * 判断多边形是否包含点
     *
     * @param x X坐标
     * @param y Y坐标
     * @return true
     */
    public boolean contains(float x, float y) {
        boolean result = false;

        for (int i = 0, j = mPolySize - 1; i < mPolySize; j = i++) {
            if ((mPolyY[i] < y && mPolyY[j] >= y)
                    || (mPolyY[j] < y && mPolyY[i] >= y)) {
                if (mPolyX[i] + (y - mPolyY[i]) / (mPolyY[j] - mPolyY[i])
                        * (mPolyX[j] - mPolyX[i]) < x) {
                    result = !result;
                }
            }
        }
        return result;
    }
}

(5)马赛克效果代码片段

 public static Bitmap getMosaic(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int radius = 10;


        Bitmap mosaicBitmap = Bitmap.createBitmap(width, height,
                Config.ARGB_8888);
        Canvas canvas = new Canvas(mosaicBitmap);

        int horCount = (int) Math.ceil(width / (float) radius);
        int verCount = (int) Math.ceil(height / (float) radius);

        Paint paint = new Paint();
        paint.setAntiAlias(true);

        for (int horIndex = 0; horIndex < horCount; ++horIndex) {
            for (int verIndex = 0; verIndex < verCount; ++verIndex) {
                int l = radius * horIndex;
                int t = radius * verIndex;
                int r = l + radius;
                if (r > width) {
                    r = width;
                }
                int b = t + radius;
                if (b > height) {
                    b = height;
                }
                int color = bitmap.getPixel(l, t);
                Rect rect = new Rect(l, t, r, b);
                paint.setColor(color);
                canvas.drawRect(rect, paint);
            }
        }
        canvas.save();

        return mosaicBitmap;
    }
Paste_Image.png
特别感谢
特别感谢大神@jarlen,使用了@jarlen底层C++对图片处理,大大减少了代码量,类似与美图秀秀。但是具体得不到大神的项目地址和联系方式@jarlen的名字也只是在朋友给我的demo中看到的,这里表达我对大神的崇高敬意。
源码
源码下载地址github

相关文章

网友评论

    本文标题:Android 仿6.5以上版本微信相册

    本文链接:https://www.haomeiwen.com/subject/ecxtqxtx.html