相机的连拍和水印的功能
2017-05-03 17:24
274 查看
相机的连拍和水印的功能
首先介绍相机的连拍功能
说到连拍的功能,大家很容易想到就是拍照获取照片,其实这样的连拍是最常见的,不过会出现卡一下的现象,需要做类似录像截屏的操作。
下面我就简单的说明一下这种连拍的实现,都要实现无卡顿的连拍我们就不能再通过camera.takePicture(null, null, pictureCallback);
而要换成另外的方法,
/** * <p>Installs a callback to be invoked for the next preview frame in * addition to displaying it on the screen. After one invocation, the * callback is cleared. This method can be called any time, even when * preview is live. Any other preview callbacks are overridden.</p> * * <p>If you are using the preview data to create video or still images, * strongly consider using {@link android.media.MediaActionSound} to * properly indicate image capture or recording start/stop to the user.</p> * * @param cb a callback object that receives a copy of the next preview frame, * or null to stop receiving callbacks. * @see android.media.MediaActionSound */ camera.setOneShotPreviewCallback(new Camera.PreviewCallback() { /** * Called as preview frames are displayed. This callback is invoked * on the event thread {@link #open(int)} was called from. * * <p>If using the {@link android.graphics.ImageFormat#YV12} format, * refer to the equations in {@link Camera.Parameters#setPreviewFormat} * for the arrangement of the pixel data in the preview callback * buffers. * * @param data the contents of the preview frame in the format defined * by {@link android.graphics.ImageFormat}, which can be queried * with {@link android.hardware.Camera.Parameters#getPreviewFormat()}. * If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)} * is never called, the default will be the YCbCr_420_SP * (NV21) format. * @param camera the Camera service object. */ @Override public void onPreviewFrame(byte[] data, Camera camera) { });
下面的方法主要不直接获取jpeg的图片流,是获取视频流格式的数据,这里只要将格式做转换即可得到数据图片,下面是转换的代码:
Size size = camera.getParameters().getPreviewSize(); Bitmap bitmap = null; try { YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null); if (image != null) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream); bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size()); stream.close(); } } catch (Exception ex) { Log.e("Sys", "Error:" + ex.getMessage()); }
这样即实现了简单的连拍功能。
相机的水印功能添加
水印添加主要是两部分,一部分是预览界面的水印,一部分是实际打到照片上的水印。下面分开介绍:
水印旋转的秘密
上图是完成后的图片,主要的要求是水印信息要根据屏幕旋转而旋转。
这里主要是在预览的suferview上方覆盖一层水印层,然后在通过设置水印层view的参数实现,因为我这个水印会根据横屏或竖屏来变化水印的显示效果,所以会有对坐标的转换。
下面是水印文字旋转的核心代码:
private void rotateText(int orientation) { switch (orientation) { case ORIGIN: LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) linearLayout.getLayoutParams(); lp.setMargins(0, 0, 0, 0); linearLayout.setLayoutParams(lp); linearLayout.setRotation(0); break; case LEFT: int marginRight = ll_preview_watermark.getWidth() - ll_preview_watermark.getHeight(); lp = (LinearLayout.LayoutParams) linearLayout.getLayoutParams(); lp.setMargins(0, 0, marginRight, 0); linearLayout.setLayoutParams(lp); linearLayout.measure( View.MeasureSpec.makeMeasureSpec(linearLayout.getWidth() - marginRight, View.MeasureSpec .EXACTLY), 0); int hRoot = ll_preview_watermark.getHeight(); int hBottom = linearLayout.getMeasuredHeight(); int x1 = hBottom; int y1 = 0; int x2 = 0; int y2 = hRoot - hBottom; float[] pivot = calcPivot(x1, y1, x2, y2, false, hRoot / 2); linearLayout.setPivotX(pivot[0]); linearLayout.setPivotY(pivot[1] - y2); linearLayout.setRotation(90); break; case RIGHT: marginRight = ll_preview_watermark.getWidth() - ll_preview_watermark.getHeight(); lp = (LinearLayout.LayoutParams) linearLayout.getLayoutParams(); lp.setMargins(0, 0, marginRight, 0); linearLayout.setLayoutParams(lp); linearLayout.measure( View.MeasureSpec.makeMeasureSpec(linearLayout.getWidth() - marginRight, View.MeasureSpec .EXACTLY), 0); int wRoot = ll_preview_watermark.getWidth(); hRoot = ll_preview_watermark.getHeight(); hBottom = linearLayout.getMeasuredHeight(); x1 = 0; y1 = hRoot - hBottom; x2 = wRoot - hBottom; y2 = hRoot; pivot = calcPivot(x1, y1, x2, y2, true, wRoot / 2); linearLayout.setPivotX(pivot[0]); linearLayout.setPivotY(pivot[1] - y1); linearLayout.setRotation(-90); break; case TOP: lp = (LinearLayout.LayoutParams) linearLayout.getLayoutParams(); lp.setMargins(0, 0, 0, 0); linearLayout.setLayoutParams(lp); wRoot = ll_preview_watermark.getWidth(); hRoot = ll_preview_watermark.getHeight(); hBottom = linearLayout.getHeight(); linearLayout.setPivotX(wRoot / 2); linearLayout.setPivotY(hBottom - hRoot / 2); linearLayout.setRotation(180); break; } } private float[] calcPivot(int x1, int y1, int x2, int y2, boolean isConstantX, int constant) { double k1 = ((double) y2 - y1) / (x2 - x1); double k2 = -1d / k1; int x3 = (x1 + x2) / 2; int y3 = (y1 + y2) / 2; double b = y3 - k2 * x3; if (isConstantX) { return new float[] {constant, (float) (k2 * constant + b)}; } else { return new float[] {(float) ((constant - b) / k2), constant}; } }
通过传入屏幕的四个方向的标记来做相应的旋转。
水印是如何打到照片上
方式有很多,我是用两种方式来实现的:1.因为我这的水印信息分为两部分,一个是icon一个是文字,我之前是通过在拍照获取到的照片上,通过canvas来进行绘制的,不过如果说你的水印信息很简单,这个方法是很好的选择,以为写上去的水印清晰度很高。
2.另一种就是通过照片合成来做,不过这里遇到了比较多的问题,主要的原因是因为对图片的压缩到导致的,我简单介绍一下我这的图片合成操作,我的水印信息是一个view上承载的内容,图片是通过相机获取的,我吧水印view上的内容转换为图片在做合成即可。
下面介绍一下view获取图片的代码,
public static Bitmap convertViewToBitmap(View view) { // view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), // View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); // view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); view.destroyDrawingCache(); view.setDrawingCacheEnabled(true); view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache(); // Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), // Bitmap.Config.ARGB_8888); // Canvas canvas = new Canvas(bitmap); // view.draw(canvas); return bitmap; }
获取到view转换过来的图片后就可以和照片进行合成了,照片和成主要是看水印在照片上的位置,
下面就是简单的工具类:
public static Bitmap newBitmapToWatermark(Bitmap src, Bitmap watermark) { if (src == null) { return null; } int screenWidth = FSScreen.getScreenWidth(); int screenHeight = FSScreen.getScreenHeight(); int w = src.getWidth(); int h = src.getHeight(); Log.i("图片尺寸,宽", w + "--高" + h); //横着 宽: 1920--高1080 //竖着 宽: 1080--高1920 // create the new blank bitmap Bitmap newb = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);// 创建一个新的和SRC长度宽度一样的位图,Bitmap.Config.ARGB_8888 Canvas cv = new Canvas(newb); // draw src into cv.drawBitmap(src, 0, 0, null);// 在 0,0坐标开始画入src if (null != watermark) { int ww = watermark.getWidth(); int wh = watermark.getHeight(); watermark = watermark.copy(Bitmap.Config.ARGB_8888, true); Canvas c = new Canvas(watermark); Paint p1 = new Paint(); int removeColor = 0;//要去除的背景色; // store this color's int for later use p1.setAlpha(0); p1.setXfermode(new AvoidXfermode(removeColor, 0, AvoidXfermode.Mode.TARGET)); c.drawPaint(p1); /**下面是绘制黑色背景,判断照片横竖**/ Paint p = new Paint(); //CLAMP夹紧 REPEAT重复 MIRROR镜像 LinearGradient lg = new LinearGradient(0, h - wh, 0, h, Color.parseColor("#00000000"), Color.parseColor("#99000000"), Shader.TileMode.CLAMP); p.setShader(lg); if (ww > w) { float i = w / (float) ww; int result = (int) (wh * i); watermark = cropPhotoImage(src, watermark, result); cv.drawRect(0, h, screenWidth, wh, p); cv.drawBitmap(watermark, 5, h - result + 5, null);// 在src的左下角画入水印 } else { cv.drawRect(0, h, screenWidth, wh, p); cv.drawBitmap(watermark, 5, h - wh + 5, null);// 在src的左下角画入水印 } } // save all clip cv.save(Canvas.ALL_SAVE_FLAG);// 保存 // store cv.restore();// 存储 return newb; }
里面涉及到一个LinearGradient线性渐变的类,这个类可以去看官方的文档,里面介绍的比较清除,主要是通过几种模式来绘制不同样式,我这里主要是在水印的背景上绘制一个渐变的黑色背景条,防止水印打在白色区域无法看到的问题。
上面基本上就这主要和两个知识点了,如果有什么问题,欢迎反馈。
相关文章推荐
- Unity利用双相机巧做水印功能
- Android相机连续拍照实现连拍功能
- iOS学习:调用相机,选择图片上传,带预览功能
- unity3d实现LOL中的相机控制功能
- asp.net 生成缩略图、为图片添加文字水印、图片水印等功能
- 调用系统相机拍照功能
- 相机拍照功能之权限和Android6.0版本问题
- 高仿美图相机 滤镜,贴纸,标签等功能俱全
- 基于Unity3D的相机功能的实现(一)——VR相机
- 调用相机图片拍照生成图片并加水印(非获得缩略图)
- Android中级第六讲--相机对焦功能实现
- ffmpeg 最简单的水印功能
- PHP上传图片进行等比缩放可增加水印功能
- 自定义相机3连拍
- 给上传图片加个图片水印,文字水印的功能
- iOS 用Quartz2D实现图片水印,裁剪,连线等功能
- 基于opencv的相机之马赛克功能实现(九)
- Unity3D 使用备忘(二) 实现相机自动漫游功能。
- Kindeditor编辑器添加图片上传水印功能(php代码)
- 【单目全景相机】友盟分享功能的集成