购物商城里面的商品分享给朋友的时候会生成一张海报图片,图片上附带这二维码图片,朋友拿到这张图片扫描上面的二维码就可以进入商品详情页查看此商品了。今天来做一下这种功能,先生成商品海报图片,然后长按这张图片识别图中二维码。先附上两张效果图:

      

这里面会用到二维码的生成与识别,使用的是google ZXing,要在app的build.gradle里面引入

dependencies {compile 'com.google.zxing:core:3.3.0'//zxing二维码
}

图中还有一处现售价文字中间有一横线,此处是这样实现的

        //中间加横线tv_nowPrice.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);//底部加横线:tv_nowPrice .getPaint().setFlags(Paint. UNDERLINE_TEXT_FLAG );

首先来说下海报图片的生成,海报样式根据UI新建个布局文件,这里以我做的例子为例来说:

新建一个generateposter.xml布局文件,效果图和布局代码如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/img_good"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="3"android:src="@mipmap/pic_share"android:scaleType="fitXY"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="2"android:orientation="horizontal"><LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="2"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginRight="10dp"android:layout_marginTop="15dp"android:text="包邮  卤料包卤料卤菜四川味100g×4卤味调料秘制包配方五香鸭脖自家卤水"android:textSize="16dp"android:textColor="@color/edittext_color"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginTop="10dp"android:text="券:15"android:textSize="16dp"android:textColor="@color/colorAccent"/><TextViewandroid:id="@+id/tv_nowPrice"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginTop="10dp"android:text="现售价  ¥29.8"android:textSize="16dp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginTop="10dp"android:text="券后价  ¥14.8"android:textSize="16dp"android:textColor="@color/colorAccent"/></LinearLayout><LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:orientation="vertical"><ImageViewandroid:id="@+id/img_erweima"android:layout_width="90dp"android:layout_height="90dp"android:layout_marginTop="15dp"android:scaleType="fitXY"android:layout_gravity="center_horizontal"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:layout_marginTop="10dp"android:text="长按扫码购买商品"android:textSize="16dp"android:textColor="@color/edittext_color"/></LinearLayout></LinearLayout>
</LinearLayout>

把布局文件view转换成图片

    //然后View和其内部的子View都具有了实际大小,也就是完成了布局,相当与添加到了界面上。接着就可以创建位图并在上面绘制了:public static void layoutView(View v, int width, int height) {// 整个View的大小 参数是左上角 和右下角的坐标v.layout(0, 0, width, height);int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);int measuredHeight = View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.AT_MOST);/** 当然,measure完后,并不会实际改变View的尺寸,需要调用View.layout方法去进行布局。* 按示例调用layout函数后,View的大小将会变成你想要设置成的大小。*/v.measure(measuredWidth, measuredHeight);v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());}/*** 把一个View转换成图片* @param v* @return*/public static Bitmap loadBitmapFromView(View v) {int w = v.getWidth();int h = v.getHeight();Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);Canvas c = new Canvas(bmp);/** 如果不设置canvas画布为白色,则生成透明 */c.drawColor(Color.WHITE);v.layout(0, 0, w, h);v.draw(c);return bmp;}

二维码生成

/*** 生成二维码 要转换的地址或字符串,可以是中文** @param url* @param width* @param height* @return*/public static Bitmap createQRImage(String url, int width, int height, boolean needDeleteWhiteBorder) {try {// 判断URL合法性if (url == null || "".equals(url) || url.length() < 1) {return null;}Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();hints.put(EncodeHintType.CHARACTER_SET, "utf-8");// 图像数据转换,使用了矩阵转换BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints);if (needDeleteWhiteBorder) {bitMatrix = deleteWhite(bitMatrix);//删除白边}width = bitMatrix.getWidth();height = bitMatrix.getHeight();int[] pixels = new int[width * height];// 下面这里按照二维码的算法,逐个生成二维码的图片,// 两个for循环是图片横列扫描的结果for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {if (bitMatrix.get(x, y)) {pixels[y * width + x] = 0xff000000;} else {pixels[y * width + x] = 0xffffffff;}}}// 生成二维码图片的格式,使用ARGB_8888Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, width, 0, 0, width, height);return bitmap;} catch (WriterException e) {e.printStackTrace();}return null;}

二维码的识别

   /*** 识别图中是否有二维码* @param bitmap* @return*/public static Result handleQRCodeFormBitmap(Bitmap bitmap) {Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);hints.put(DecodeHintType.CHARACTER_SET, "utf-8");hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);hints.put(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);int width = bitmap.getWidth();int height = bitmap.getHeight();int[] data = new int[width * height];bitmap.getPixels(data, 0, width, 0, 0, width, height);RGBLuminanceSource source = new RGBLuminanceSource(width, height, data);BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));QRCodeReader reader2 = new QRCodeReader();Result result = null;try {result = reader2.decode(bitmap1, hints);Log.e("tag","result="+result.getText());} catch (Exception e) {e.printStackTrace();if (source != null) {BinaryBitmap bitmap2 = new BinaryBitmap(new GlobalHistogramBinarizer(source));try {result = reader2.decode(bitmap2, hints);} catch (Exception e1) {e1.printStackTrace();}}}return result;}

如果图片上有二维码,长按图片弹窗显示识别图中二维码,如果图片上没有二维码,长按图片弹窗中则不显示识别图中二维码,这里的处理逻辑为,先识别二维码,通过对识别的结果判断图中是否有二维码,如果有识别结果则证明图片上有二维码,如果没有识别结果或者识别结果为空,这表明图片上没有二维码;下面是两种情况的图片进行对比:

    

代码如下:

img_show.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {Bitmap obmp = ((BitmapDrawable) (img_show.getDrawable())).getBitmap();Result result = handleQRCodeFormBitmap(obmp);if (result == null) {Log.e("tag", "图上无二维码");showAlert(obmp);} else {Log.e("tag", "图中二维码识别结果=" + result.getText());showSelectAlert(obmp,result.toString());}return false;}});/*** 图中无二维码显示此弹窗* @param bitmap*/private void showAlert(final Bitmap bitmap) {AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setMessage("保存图片").setCancelable(false).setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterfacem, int i) {SaveImgToSD.saveMyBitmap("img_goods",bitmap);}}).setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterfacem, int i) {}});builder.show();}/*** 图中有二维码显示此弹窗* @param bitmap* @param url*/private void showSelectAlert(final Bitmap bitmap, final String url) {AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("请选择");String str[] = {"保存图片", "识别图中二维码"};builder.setItems(str, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterfacem, int i) {switch (i) {case 0:SaveImgToSD.saveMyBitmap("img_goods",bitmap);break;case 1://用默认浏览器打开扫描得到的地址Intent intent = new Intent();intent.setAction("android.intent.action.VIEW");Uri content_url = Uri.parse(url);intent.setData(content_url);startActivity(intent);break;}}});builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterfacem, int i) {}});builder.show();}

以上就实现的全部功能,下面附上整个工程的完整代码:

有两个布局文件,一个是activity类的布局,另一个是生成海报图片的布局。

activity类的布局文件activity_generateposter_null.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewstyle="@style/textview_title"android:text="生成海报" /><Buttonandroid:id="@+id/btn_generate"android:layout_width="match_parent"android:layout_height="40dp"android:layout_margin="20dp"android:text="生成海报"/><ImageViewandroid:id="@+id/img_show"android:layout_width="match_parent"android:layout_height="match_parent"/>
</LinearLayout>

生成海报图片的布局文件activity_generateposter.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/img_good"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="3"android:src="@mipmap/pic_share"android:scaleType="fitXY"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="2"android:orientation="horizontal"><LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="2"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginRight="10dp"android:layout_marginTop="15dp"android:text="包邮  卤料包卤料卤菜四川味100g×4卤味调料秘制包配方五香鸭脖自家卤水"android:textSize="16dp"android:textColor="@color/edittext_color"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginTop="10dp"android:text="券:15"android:textSize="16dp"android:textColor="@color/colorAccent"/><TextViewandroid:id="@+id/tv_nowPrice"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginTop="10dp"android:text="现售价  ¥29.8"android:textSize="16dp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginTop="10dp"android:text="券后价  ¥14.8"android:textSize="16dp"android:textColor="@color/colorAccent"/></LinearLayout><LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:orientation="vertical"><ImageViewandroid:id="@+id/img_erweima"android:layout_width="90dp"android:layout_height="90dp"android:layout_marginTop="15dp"android:scaleType="fitXY"android:layout_gravity="center_horizontal"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:layout_marginTop="10dp"android:text="长按扫码购买商品"android:textSize="16dp"android:textColor="@color/edittext_color"/></LinearLayout></LinearLayout>
</LinearLayout>

activity类文件GeneratePosterActivity.class

package com.junto.text.Posters;import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;import com.google.zxing.Result;
import com.junto.text.R;
import com.junto.text.tools.SaveImgToSD;
import com.junto.text.tools.ZXingUtils;import static com.junto.text.Posters.ImageUtils.loadBitmapFromView;
import static com.junto.text.tools.ZXingUtils.handleQRCodeFormBitmap;/*** Created by WangJinyong on 2019/10/23.* 生成海报*/
public class GeneratePosterActivity extends Activity {View view;ImageView img_show, img_erweima;Button btn_generate;TextView tv_nowPrice;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_generateposter_null);initView();}private void initView() {view = View.inflate(this, R.layout.activity_generateposter, null);img_show = findViewById(R.id.img_show);tv_nowPrice = view.findViewById(R.id.tv_nowPrice);//现售价//中间加横线tv_nowPrice.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);//底部加横线:
//        tv_nowPrice .getPaint().setFlags(Paint. UNDERLINE_TEXT_FLAG );img_erweima = view.findViewById(R.id.img_erweima);btn_generate = findViewById(R.id.btn_generate);btn_generate.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {img_erweima.setImageBitmap(ZXingUtils.createQRImage("http://www.taobao.com", 90, 90, true));ImageUtils.layoutView(view, 840, 1200);// 把一个View转换成图片Bitmap cachebmp = loadBitmapFromView(view);img_show.setImageBitmap(cachebmp);//直接展示转化的bitmap
//                ImageUtils.viewSaveToImage(view,"GeneratePoster",img_show);}});img_show.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {Bitmap obmp = ((BitmapDrawable) (img_show.getDrawable())).getBitmap();Result result = handleQRCodeFormBitmap(obmp);if (result == null) {Log.e("tag", "图上无二维码");showAlert(obmp);} else {Log.e("tag", "图中二维码识别结果=" + result.getText());showSelectAlert(obmp,result.toString());}return false;}});}/*** 图中无二维码显示此弹窗* @param bitmap*/private void showAlert(final Bitmap bitmap) {AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setMessage("保存图片").setCancelable(false).setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterfacem, int i) {SaveImgToSD.saveMyBitmap("img_goods",bitmap);}}).setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterfacem, int i) {}});builder.show();}/*** 图中有二维码显示此弹窗* @param bitmap* @param url*/private void showSelectAlert(final Bitmap bitmap, final String url) {AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("请选择");String str[] = {"保存图片", "识别图中二维码"};builder.setItems(str, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterfacem, int i) {switch (i) {case 0:SaveImgToSD.saveMyBitmap("img_goods",bitmap);break;case 1://用默认浏览器打开扫描得到的地址Intent intent = new Intent();intent.setAction("android.intent.action.VIEW");Uri content_url = Uri.parse(url);intent.setData(content_url);startActivity(intent);break;}}});builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterfacem, int i) {}});builder.show();}
}

用到的工具类:

1.二维码的生成与识别工具ZXingUtils
package com.junto.text.tools;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.GlobalHistogramBinarizer;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.QRCodeWriter;import java.util.EnumMap;
import java.util.Hashtable;
import java.util.Map;/*** 生成条形码和二维码的工具*/
public class ZXingUtils {/*** 生成二维码 要转换的地址或字符串,可以是中文** @param url* @param width* @param height* @return*/public static Bitmap createQRImage(String url, int width, int height, boolean needDeleteWhiteBorder) {try {// 判断URL合法性if (url == null || "".equals(url) || url.length() < 1) {return null;}Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();hints.put(EncodeHintType.CHARACTER_SET, "utf-8");// 图像数据转换,使用了矩阵转换BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints);if (needDeleteWhiteBorder) {bitMatrix = deleteWhite(bitMatrix);//删除白边}width = bitMatrix.getWidth();height = bitMatrix.getHeight();int[] pixels = new int[width * height];// 下面这里按照二维码的算法,逐个生成二维码的图片,// 两个for循环是图片横列扫描的结果for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {if (bitMatrix.get(x, y)) {pixels[y * width + x] = 0xff000000;} else {pixels[y * width + x] = 0xffffffff;}}}// 生成二维码图片的格式,使用ARGB_8888Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, width, 0, 0, width, height);return bitmap;} catch (WriterException e) {e.printStackTrace();}return null;}/*** 生成的二维码  删除白边* @param matrix* @return*/private static BitMatrix deleteWhite(BitMatrix matrix) {int[] rec = matrix.getEnclosingRectangle();int resWidth = rec[2] + 1;int resHeight = rec[3] + 1;BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);resMatrix.clear();for (int i = 0; i < resWidth; i++) {for (int j = 0; j < resHeight; j++) {if (matrix.get(i + rec[0], j + rec[1]))resMatrix.set(i, j);}}return resMatrix;}/*** 生成条形码** @param context* @param contents      需要生成的内容* @param desiredWidth  生成条形码的宽带* @param desiredHeight 生成条形码的高度* @param displayCode   是否在条形码下方显示内容* @return*/public static Bitmap creatBarcode(Context context, String contents,int desiredWidth, int desiredHeight, boolean displayCode) {Bitmap ruseltBitmap = null;/*** 图片两端所保留的空白的宽度*/int marginW = 20;/*** 条形码的编码类型*/BarcodeFormat barcodeFormat = BarcodeFormat.CODE_128;if (displayCode) {Bitmap barcodeBitmap = encodeAsBitmap(contents, barcodeFormat, desiredWidth, desiredHeight);Bitmap codeBitmap = creatCodeBitmap(contents, desiredWidth + 2 * marginW, desiredHeight, context);ruseltBitmap = mixtureBitmap(barcodeBitmap, codeBitmap, new PointF(0, desiredHeight));} else {ruseltBitmap = encodeAsBitmap(contents, barcodeFormat, desiredWidth, desiredHeight);}return ruseltBitmap;}/*** 生成条形码的Bitmap** @param contents 需要生成的内容* @param format 编码格式* @param desiredWidth* @param desiredHeight* @return* @throws WriterException*/protected static Bitmap encodeAsBitmap(String contents, BarcodeFormat format, int desiredWidth, int desiredHeight) {final int WHITE = 0xFFFFFFFF;final int BLACK = 0xFF000000;MultiFormatWriter writer = new MultiFormatWriter();BitMatrix result = null;try {result = writer.encode(contents, format, desiredWidth,desiredHeight, null);} catch (WriterException e) {e.printStackTrace();}int width = result.getWidth();int height = result.getHeight();int[] pixels = new int[width * height];// All are 0, or black, by defaultfor (int y = 0; y < height; y++) {int offset = y * width;for (int x = 0; x < width; x++) {pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;}}Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, width, 0, 0, width, height);return bitmap;}/*** 生成显示编码的Bitmap** @param contents* @param width* @param height* @param context* @return*/protected static Bitmap creatCodeBitmap(String contents, int width, int height, Context context) {TextView tv = new TextView(context);LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);tv.setLayoutParams(layoutParams);tv.setText(contents);tv.setHeight(height);tv.setGravity(Gravity.CENTER_HORIZONTAL);tv.setWidth(width);tv.setDrawingCacheEnabled(true);tv.setTextColor(Color.BLACK);tv.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());tv.buildDrawingCache();Bitmap bitmapCode = tv.getDrawingCache();return bitmapCode;}/*** 将两个Bitmap合并成一个** @param first* @param second* @param fromPoint 第二个Bitmap开始绘制的起始位置(相对于第一个Bitmap)* @return*/protected static Bitmap mixtureBitmap(Bitmap first, Bitmap second, PointF fromPoint) {if (first == null || second == null || fromPoint == null) {return null;}int marginW = 20;Bitmap newBitmap = Bitmap.createBitmap(first.getWidth() + second.getWidth() + marginW,first.getHeight() + second.getHeight(), Bitmap.Config.ARGB_4444);Canvas cv = new Canvas(newBitmap);cv.drawBitmap(first, marginW, 0, null);cv.drawBitmap(second, fromPoint.x, fromPoint.y, null);cv.save();cv.restore();return newBitmap;}/*** 识别图中是否有二维码* @param bitmap* @return*/public static Result handleQRCodeFormBitmap(Bitmap bitmap) {Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);hints.put(DecodeHintType.CHARACTER_SET, "utf-8");hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);hints.put(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);int width = bitmap.getWidth();int height = bitmap.getHeight();int[] data = new int[width * height];bitmap.getPixels(data, 0, width, 0, 0, width, height);RGBLuminanceSource source = new RGBLuminanceSource(width, height, data);BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));QRCodeReader reader2 = new QRCodeReader();Result result = null;try {result = reader2.decode(bitmap1, hints);Log.e("tag","result="+result.getText());} catch (Exception e) {e.printStackTrace();if (source != null) {BinaryBitmap bitmap2 = new BinaryBitmap(new GlobalHistogramBinarizer(source));try {result = reader2.decode(bitmap2, hints);} catch (Exception e1) {e1.printStackTrace();}}}return result;}
}

2.布局文件生成海报图片的工具类ImageUtils

package com.junto.text.Posters;import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;/*** Created by WangJinyong on 2019/10/23.* 布局生成分享图片 工具类*/
public class ImageUtils {//然后View和其内部的子View都具有了实际大小,也就是完成了布局,相当与添加到了界面上。接着就可以创建位图并在上面绘制了:public static void layoutView(View v, int width, int height) {// 整个View的大小 参数是左上角 和右下角的坐标v.layout(0, 0, width, height);int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);int measuredHeight = View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.AT_MOST);/** 当然,measure完后,并不会实际改变View的尺寸,需要调用View.layout方法去进行布局。* 按示例调用layout函数后,View的大小将会变成你想要设置成的大小。*/v.measure(measuredWidth, measuredHeight);v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());}public static String viewSaveToImage(View view, String child, ImageView img_show) {Log.e("tag","viewSaveToImage");/*** View组件显示的内容可以通过cache机制保存为bitmap* 我们要获取它的cache先要通过setDrawingCacheEnable方法把cache开启,* 然后再调用getDrawingCache方法就可 以获得view的cache图片了* 。buildDrawingCache方法可以不用调用,因为调用getDrawingCache方法时,* 若果 cache没有建立,系统会自动调用buildDrawingCache方法生成cache。* 若果要更新cache, 必须要调用destoryDrawingCache方法把旧的cache销毁,才能建立新的。*///        view.setDrawingCacheEnabled(true);//        view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);//设置绘制缓存背景颜色//        view.setDrawingCacheBackgroundColor(Color.WHITE);// 把一个View转换成图片Bitmap cachebmp = loadBitmapFromView(view);img_show.setImageBitmap(cachebmp);//直接展示转化的bitmap//保存在本地 产品还没决定要不要保存在本地FileOutputStream fos;try {// 判断手机设备是否有SD卡boolean isHasSDCard = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);if (isHasSDCard) {// SD卡根目录File sdRoot = Environment.getExternalStorageDirectory();Log.e("tag","SD卡根目录="+sdRoot.toString());File file = new File(sdRoot, child+".png");fos = new FileOutputStream(file);} elsethrow new Exception("创建文件失败!");//压缩图片 30 是压缩率,表示压缩70%; 如果不压缩是100,表示压缩率为0cachebmp.compress(Bitmap.CompressFormat.PNG, 90, fos);fos.flush();fos.close();} catch (Exception e) {e.printStackTrace();}view.destroyDrawingCache();return sharePic(cachebmp,child);}/*** 把一个View转换成图片* @param v* @return*/public static Bitmap loadBitmapFromView(View v) {int w = v.getWidth();int h = v.getHeight();Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);Canvas c = new Canvas(bmp);/** 如果不设置canvas画布为白色,则生成透明 */c.drawColor(Color.WHITE);v.layout(0, 0, w, h);v.draw(c);return bmp;}//保存在本地并一键分享private static String sharePic(Bitmap cachebmp,String child) {final File qrImage = new File(Environment.getExternalStorageDirectory(), child+".jpg");if(qrImage.exists()){qrImage.delete();}try {qrImage.createNewFile();} catch (IOException e) {e.printStackTrace();}FileOutputStream fOut = null;try {fOut = new FileOutputStream(qrImage);} catch (FileNotFoundException e) {e.printStackTrace();}if(cachebmp == null){return "";}cachebmp.compress(Bitmap.CompressFormat.JPEG, 100, fOut);try {fOut.flush();fOut.close();} catch (IOException e) {e.printStackTrace();}
//        Toast.makeText(this, "保存成功 " + qrImage.getPath().toString(), Toast.LENGTH_SHORT).show();return qrImage.getPath();}
}

3.保存图片到本地的工具类SaveImgToSD,这个类可以和上面第二个工具类整理合并成一个,里面有好几个方法在此例子里面的用不到的。

package com.junto.text.tools;import android.graphics.Bitmap;
import android.os.Environment;
import android.util.Log;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;import static java.lang.System.out;/*** Created by WangJinyong on 2018/9/18.*/public class SaveImgToSD {public static String filePath = "/sdcard/UVCCamera/";//将Bitmap图片保存到sd卡public static void saveBitmapToSD(Bitmap bt) {File path = Environment.getExternalStorageDirectory();File file = new File(path, System.currentTimeMillis() + ".jpg");out.println(Environment.getExternalStorageState() + "/Cool/" +"000000000000000000000000000");try {FileOutputStream out = new FileOutputStream(file);bt.compress(Bitmap.CompressFormat.JPEG, 90, out);} catch (FileNotFoundException e) {e.printStackTrace();}out.flush();out.close();}/*** 保存bitmap到SD卡* @param bitName 保存的名字* @param mBitmap 图片对像* return 生成压缩图片后的图片路径*/public static String saveMyBitmap(String bitName, Bitmap mBitmap) {makeRootDirectory();File f = new File(filePath + bitName + ".png");try {f.createNewFile();} catch (IOException e) {out.println("在保存图片时出错:" + e.toString());}FileOutputStream fOut = null;try {fOut = new FileOutputStream(f);} catch (FileNotFoundException e) {e.printStackTrace();}try {mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);} catch (Exception e) {return "create_bitmap_error";}try {fOut.flush();} catch (IOException e) {e.printStackTrace();}try {fOut.close();} catch (IOException e) {e.printStackTrace();}return filePath + bitName + ".png";}/*** 保存bitmap到SD卡* @param bitmap* @param imagename*/public static String saveBitmapToSDCard(Bitmap bitmap, String imagename) {makeRootDirectory();String path = filePath + "img-" + imagename + ".jpg";FileOutputStream fos = null;try {fos = new FileOutputStream(path);if (fos != null) {bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);fos.close();}return path;} catch (Exception e) {e.printStackTrace();}return null;}//生成文件夹public static void makeRootDirectory(){File file = null;try {file = new File(filePath);if (!file.exists()){//判断指定的路径或者指定的目录文件是否已经存在。file.mkdir();//建立文件夹Log.e("cacacaca","新建文件夹成功,路径为:" + filePath);}}catch (Exception e){Log.e("error:", e+"");}}
}

到此,这篇文章就结束啦,有不足之处还请大家多多指正。

仿商城商品生成分享海报图片和识别图中二维码并跳转商品详情页相关推荐

  1. cocoscreator实现微信内置浏览器点击图片识别图中二维码

    最近在做一个微信内置浏览器的小游戏,小游戏中有一个二维码,需要用户点击长按二维码弹出系统识别二维码按钮. 下面是解决步骤: 1.cocoscreator是如何实现在浏览器中渲染游戏画面的 看图中箭头处 ...

  2. Vue实现长按图片识别图中二维码

    Vue实现长按图片识别图中二维码 思路:要想实现可以识别图片中的二维码,那必定是要将这张图进行上传操作,上传则需要file对象格式.不管是在H5还是APP中,展示的图片都是通过url的方式展示在img ...

  3. Vue页面生成分享海报最详说明(含二维码+多种水印方式+常见的坑处理)

    功能需求: 海报有1张背景图, 海报上的文案内容动态变化 在背景图的某个位置上添加二维码图片 水印功能 大致思路 html页面部分, 包括背景图,接口得来的数据,以及二维码图片的位置 使用 qrcod ...

  4. 微信小程序长按图片,实现保存、转发、识别图中二维码

    在小程序image组件中二维码/小程序码图片不支持长按识别,仅在 wx.previewImage 中支持长按识别 但是通过wx.previewImage只能实现保存,转发,小程序 只能识别 小程序二维 ...

  5. 小程序中图片点击预览、长按识别图中二维码的问题

    通过自己的测试以及各类博客资料的查询,总结如下: 1.小程序中的图片不能识别除小程序码以外的二维码 2.并且仅在 wx.previewImage 中支持长按识别 官方文档(wx.previewImag ...

  6. android仿微信识别相册中二维码图片信息

    仿照微信识别相册中二维码,写了一个Demo,供参考使用 1.添加依赖,基于zxing,使用了Glide选择的图片进行了显示 compile 'com.google.zxing:core:3.2.1'c ...

  7. python生成马保国敲架子鼓动图二维码(彩色)

    小实验--使用Python合成马保国敲架子鼓的动图二维码 # 实验环境 MacOS Catalina v10.15.7 Python3 # 马保国敲架子鼓动图测试图 # 代码 # coding: ut ...

  8. 微信小程序生成海报中二维码-----长按识别不了问题及处理方案

    > 问题描述: 小程序某个页面中点击按钮,想要生成带有二维码的图片,后续保存本地.生成图片后转发微信中,后长按图片不会出现识别图中二维码的选项问题. 一年前写过一个分享页,当时大部分可以识别,只 ...

  9. iOS和Android使用同一个二维码自动跳转不同下载页面链接(附生成二维码地址方法)

    一.使用场景 开发了一款App,包括iOS及Android版,到了推广阶段,准备生成二维码让用户扫码下载,那这个二维码该怎么生成?iOS及Andorid各自生成一个二维码让用户区分下载?当然这种方式是 ...

最新文章

  1. 程序员深夜啪啪啪真相,看完笑翻!
  2. VK维客众筹网整站源码 手机端众筹网站系统源码
  3. WPF仿网易云音乐系列(一、左侧菜单栏:Expander+RadioButton)
  4. 苹果第二代自研M系列芯片MacBook Pro有望在未来几周上市
  5. python求一个数的因子_求一个整数的所有素数因子的思路是什么?
  6. 计算机 管理策略,有关管理组策略管理模板的建议 (.adm) 文件
  7. Xilinx Artix-7 Aurora调试过程中遇到的问题
  8. 新中国成立60周年重要科技成果知识竞赛试题
  9. python问号堂--第二篇
  10. windows server上通过关闭端口有效防治勒索病毒
  11. 日志文件的格式和内容,日志文件的作用,登记日志文件的规则
  12. C# 后台js重定向Response.Write
  13. CorelDRAW X8官方正版序列号如何安装使用?
  14. kafka connector使用(单机手动启动版)
  15. PCB治具设计、制造和管理
  16. 学习使用微信小程序动态获取当前时间并实时跳动
  17. 杰理之使用 mic_rec_play_start()测试 mic 无声的解决方法【篇】
  18. java 适配器_java里面的适配器是什么东西
  19. 香港电影男演员十大代表
  20. 如何实现服务注册与发现?

热门文章

  1. ES7和 ES8 一览
  2. RecyclerView --- 分割线
  3. 华为服务器磁盘没显示不出来,服务器磁盘读取不了
  4. 世界正游弋于开源之海,但只有 Red Hat 从中盈利
  5. JavaScript:实现按字典顺序查找给定字符串的所有不同的非空子序列算法(附完整源码)
  6. 使用面向对象思想,输出员工信息并计算员工的工资。定义一个部门(Department)类,该类有部门编号(Id)、部门名称(Name)属性;再定义一个员工(Employee)类,该类的属性有员工编号
  7. VS Code配置C/C++环境
  8. Android 开发小技巧(2)
  9. 蒙特卡洛方法 (Monte Carlo Method)(5)
  10. 嵌入式Linux使用TFT屏幕:使用树莓派4B的MIPI-DSI接口点亮ST7701S屏幕