追求截图的极致-牛牛截图再添新成员-截长图功能
Posted 大蓝头
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了追求截图的极致-牛牛截图再添新成员-截长图功能相关的知识,希望对你有一定的参考价值。
很久没有写关于截图控件的文章了,借着这次截图控件新功能升级,向大家介绍一下牛牛截图!
大家知道,我们对于截图控件的功能性、易用性以及体验都有着非常高的要求,总结如下:
- 能力方面 我们支持多显示器、高清屏DPI放大支持、窗口区域的自动识别、多语言支持等等众多截图控件所不具备的能力
- 涂鸦功能方面 我们支持矩形、圆形、画刷、荧光笔、马赛克、文字等等功能,同时具备涂鸦二次编辑、文字及图片水印、工具栏自定义扩展功能等等非常实用的高价值能力
- 集成能力方面 我们支持集成进任意一款浏览器,支持集成进任何一个桌面软件中
- 平台兼容性方面 我们支持Windows、macOS以及Linux等所有主流操作系统,同时兼容不同架构下国产操作系统,真正做到全面兼容
今天,我们截图控件更进一步,新增加了一项大家都喜欢的功能-截长图,希望大家能够喜欢!
原理
截长图,顾名思义,就是能够选中有限的区域,然后利用鼠标滚动后,将原本未显示的区域也一并截取下来,并最终合并成一张完整的长图;它的应用范围也非常的广泛,比如信息分享、证据固定、数据存档等等。
从前期的技术调研、测试,到后来的功能开发与集成,最后进行细节完善、兼容性优化等处理,我们一共花了半个多月的时间;回过头来看,原理和流程大致如下:
-
利用现有截图中的截图区域选择功能,框选要截长图的区域
-
点击工具栏上指定按钮,触发截长图功能,定时的截取选中区域的图片,同时触发滚动条向下滚动 (实际应用中也可以不触发,而是人为的进行滚动)
-
每次截取下来的图片,在内存中利用opencv进行灰度化,然后对相邻的两张图片进行模式匹配,标记出来重叠的区域,在去掉重叠区域的前提下将两张图片进行合并
因为图片的宽度都是一样的,所以只需要考虑高度上的重叠因素
-
停止截长图,将最终合成的图片复制到剪贴板,与原有截图流程进行对接
原理上来讲,不是太难,主要在于性能、内存、兼容性以及使用体验上的种种优化。
使用方法
目前我们已经上线了Windows的桌面版控件以及浏览器版本控件,大家如果喜欢,可以到我们的网站上进行体验,大致流程如下:
- 打开https://leeqia.com/screencapture/onlinedemo/
- 点击更多个性化选项,选中显示预截图窗口(因为是浏览器页面上测试体验,要截取的窗口可能被浏览器遮挡,所以应用此功能),点击屏幕截图按钮,根据提示安装新版本控件
- 截图功能呼出后,选择指定的窗口区域,注意不要选中不会滚动的区域(此处我们以我们的网站页面为例)
- 点击工具栏上的截长图按钮,此时目标窗口区域开始滚动,截长图功能正在进行中
- 点击完成,停止截长图,截好的图将会回送到浏览器页面中进行显示
完整的操作流程如下:
整个截长图流程保存下来的图片如下:
桌面版控件测试可以下载如下程序包:
http://leeqia.com/download/NiuniuCapture.zip
后记
目前我们只是在Windows平台上实现了截长图的功能,Linux以及macOS平台的截长图功能正在开发中,敬请期待!
牛牛截图从2014年上线第一版以来,已经过去了9年了,未来的路还很长,我们将继续砥砺前行!新功能上线不是结束,我们会持续进行迭代优化,努力打造全网最优秀的截图体验!
Android实现截屏和截长图功能的各种方法
微信好友或者朋友圈的分享,可以是普通的截图分享,也可以是截取长图的分享,甚至还会有需求让你拼上生成的二维码和logo图片,下面我们直接来看看这些方法的使用:
先说一下拼接三张不同的图片后有黑色背景的解决方案(在下面的6拼接合成图片的方法里加上就可以了):
//设置画布背景色为白色,即自定义控件显示的背景色为白色:
canvas.drawRGB(255,255,255);
1.普通的截屏方法
/**
* 截屏
*
* @param activity
* @return
*/
public static Bitmap activityShot(Activity activity)
/*获取windows中最顶层的view*/
View view = activity.getWindow().getDecorView();
//允许当前窗口保存缓存信息
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
//获取状态栏高度
Rect rect = new Rect();
view.getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
WindowManager windowManager = activity.getWindowManager();
//获取屏幕宽和高
DisplayMetrics outMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(outMetrics);
int width = outMetrics.widthPixels;
int height = outMetrics.heightPixels;
//去掉状态栏
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, statusBarHeight, width, height - statusBarHeight);
//销毁缓存信息
view.destroyDrawingCache();
view.setDrawingCacheEnabled(false);
return bitmap;
2.截取scrollView的屏幕方法
/**
* 截取scrollview的屏幕
* @param scrollView
* @return
*/
public static Bitmap getBitmapByView(ScrollView scrollView)
int h = 0;
Bitmap bitmap = null;
// 获取listView实际高度
for (int i = 0; i < scrollView.getChildCount(); i++)
h += scrollView.getChildAt(i).getHeight();
scrollView.getChildAt(i).setBackgroundResource(R.drawable.white_drawable);
// 创建对应大小的bitmap
bitmap = Bitmap.createBitmap(scrollView.getWidth(), h,
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
scrollView.draw(canvas);
// 测试输出
FileOutputStream out = null;
try
out = new FileOutputStream("/sdcard/screen_test.png");
catch (FileNotFoundException e)
e.printStackTrace();
try
if (null != out)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
catch (IOException e)
// TODO: handle exception
return bitmap;
3.截取ListvListView的屏幕方法
/**
* 截图listview
* **/
public static Bitmap getbBitmap(ListView listView)
int h = 0;
Bitmap bitmap = null;
// 获取listView实际高度
for (int i = 0; i < listView.getChildCount(); i++)
h += listView.getChildAt(i).getHeight();
// 创建对应大小的bitmap
bitmap = Bitmap.createBitmap(listView.getWidth(), h,
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
listView.draw(canvas);
// 测试输出
FileOutputStream out = null;
try
out = new FileOutputStream("/sdcard/screen_test.png");
catch (FileNotFoundException e)
e.printStackTrace();
try
if (null != out)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
catch (IOException e)
// TODO: handle exception
return bitmap;
4.截取线性布局或相对布局屏幕的方法
/**
* 截取RelativeLayout
**/
public static Bitmap getRelativeLayoutBitmap(RelativeLayout relativeLayout)
int h = 0;
Bitmap bitmap;
for (int i = 0; i < relativeLayout.getChildCount(); i++)
h += relativeLayout.getChildAt(i).getHeight();
// 创建对应大小的bitmap
bitmap = Bitmap.createBitmap(relativeLayout.getWidth(), h,
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
relativeLayout.draw(canvas);
return bitmap;
/**
* 截取LinearLayout
**/
public static Bitmap getLinearLayoutBitmap(LinearLayout linearLayout)
int h = 0;
Bitmap bitmap;
for (int i = 0; i < linearLayout.getChildCount(); i++)
h += linearLayout.getChildAt(i).getHeight();
// 创建对应大小的bitmap
bitmap = Bitmap.createBitmap(linearLayout.getWidth(), h,
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
linearLayout.draw(canvas);
return bitmap;
5.截取除了导航栏之外的整个屏幕
/**
* 截取除了导航栏之外的整个屏幕
*/
public static Bitmap screenShotWholeScreen(Activity activity)
View dView = activity.getWindow().getDecorView();
dView.setDrawingCacheEnabled(true);
dView.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(dView.getDrawingCache());
return bitmap;
6.拼接合成图片的方法
//合成三张图片
private static Bitmap mergeBitmap(Bitmap firstBitmap, Bitmap secondBitmap, Bitmap threeBitmap)
Bitmap bitmap = Bitmap.createBitmap(firstBitmap.getWidth(), firstBitmap.getHeight() + secondBitmap.getHeight() + threeBitmap.getHeight(), firstBitmap.getConfig());
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(firstBitmap, new Matrix(), null);
canvas.drawBitmap(secondBitmap, 0, firstBitmap.getHeight(), null);
canvas.drawBitmap(threeBitmap, secondBitmap.getWidth(), firstBitmap.getHeight(), null);
return bitmap;
//合成两张图片
public static Bitmap mergeBitmap(Bitmap firstBitmap, Bitmap secondBitmap)
Bitmap bitmap = Bitmap.createBitmap(firstBitmap.getWidth(), firstBitmap.getHeight(),firstBitmap.getConfig());
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(firstBitmap, new Matrix(), null);
canvas.drawBitmap(secondBitmap, 0, 0, null);
return bitmap;
7.具体的调用和拼接合成图片:
Bitmap bitmap = StringUtil.activityShot(JCZQTDetailActivity.this);
Bitmap bitmap = StringUtil.getBitmapByView(scrollView_jc_type);//截取长图
// Bitmap bitmap = StringUtil.getRelativeLayoutBitmap(rl_jc_all);
// Bitmap bitmap1 = StringUtil.screenShotWholeScreen(JCZQTDetailActivity.this);
// Bitmap bitmap2 = ShareUtil.mergeBitmap(bitmap, bitmap1);ShareUtil.weiChatPic(Constants.wx_api, 7, MakeReceiptDetailsActivity.this, bitmap2);
8.微信分享图片方法和链接生成二维码图片方法:
/**
* 分享 图片
*/
public static void weiChatPic(IWXAPI api, int flag, Context context, Bitmap bitmap)
if (api.isWXAppInstalled()) //判断微信是否安装
//Bitmap mWXShareBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.logo_icon);//将截屏得到的bitmap赋值
GlobalLog.e("sgf", "-------GlobalEntity.USER.getUrl()-------" + GlobalConfig.getURL(context));
if ("".equals(GlobalConfig.getURL(context)) || "null".equals(GlobalConfig.getURL(context)))
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
return;
loadRQInfo(GlobalConfig.getURL(context));
Bitmap b = BitmapFactory.decodeResource(context.getResources(), R.drawable.sharewinlogo);
GlobalLog.e("sgf", "-------bitmap-------" + bitmap);
GlobalLog.e("sgf", "-------bitmaps-------" + bitmaps);
GlobalLog.e("sgf", "-------b-------" + b);
Bitmap bitmap1 = mergeBitmap(bitmap, bitmaps, b);
WXImageObject imgObject = new WXImageObject(bitmap1);
//imgObject.imagePath
WXMediaMessage mediaMessage = new WXMediaMessage();
mediaMessage.mediaObject = imgObject;
//设置缩略图
Bitmap thumbBmp = Bitmap.createScaledBitmap(bitmap1, bitmap1.getWidth() / 10, bitmap1.getHeight() / 10, true);
mediaMessage.thumbData = bmpToByteArray(thumbBmp, true);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("img");//分享类型是图片
req.message = mediaMessage;
//表示发送给朋友圈 WXSceneTimeline 表示发送给朋友 WXSceneSession
req.scene = flag == 7 ? SendMessageToWX.Req.WXSceneSession : SendMessageToWX.Req.WXSceneTimeline;
api.sendReq(req);
GlobalLog.e("sgf", "-------end-------");
else
Toast.makeText(context, "您没有安装微信客户端", Toast.LENGTH_SHORT).show();
/**
* 生成万二维码
*
* @param soldUrl
*/
private static void loadRQInfo(String soldUrl)
//回收bitmaps
if (null != bitmaps && !bitmaps.isRecycled())
bitmaps.recycle();
bitmaps = null;
try
bitmaps = StringUtil.makeQRImage(soldUrl, 480, 350);
catch (WriterException e)
e.printStackTrace();
9.项目中的StringUtil类,在此分享出来:
package com.yasenagat.yy.rf.util;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Environment;
import android.text.Html;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.yasenagat.yy.rf.R;
import com.yasenagat.yy.rf.common.GlobalException;
import com.yasenagat.yy.rf.common.GlobalLog;
import static com.yasenagat.yy.rf.R.id.iv_codes_qr;
import static com.yasenagat.yy.rf.R.id.linearLayout;
public class StringUtil
private static int counter = 0;
private static final String TAG = "StringUtil";
public static boolean isEmpty(String str)
if (null == str || str.trim().equals(""))
return true;
return false;
public static boolean isEmptyMoney(String str)
try
if (null == str || str.equals("") || str.equals("0")
|| str.equals("0.00") || 0 == Double.parseDouble(str))
return true;
if (Double.parseDouble(str) == 0)
return true;
catch (NumberFormatException e)
e.printStackTrace();
return false;
return false;
// String five_before = hitlistsBean.getHit_five().substring(0, hitlistsBean.getHit_five().indexOf(":"));
//String five_after = hitlistsBean.getHit_five().substring(hitlistsBean.getHit_five().indexOf(":") + 1, hitlistsBean.getHit_five().length());
/**
* 截取字符串的前半截
*
* @param str
* @return
*/
public static String subStringBefore(String str)
String beforeStr = str.substring(0, str.indexOf(":"));
return beforeStr;
/**
* 截取字符串的后半截
*
* @param str
* @return
*/
public static String subStringAfter(String str)
String afterStr = str.substring(str.indexOf(":") + 1, str.length());
return afterStr;
/**
* 截取":" 字符的字符串数组
*
* @param str
* @return 返回一个数组
*/
public static String[] subStringArray_one(String str)
String StrArray[] = str.split(":");
return StrArray;
/**
* 截取":" 字符的字符串数组
*
* @param str
* @return 返回一个数组
*/
public static String[] subStringArray_two(String str)
String[] StrArray = str.split(",");
return StrArray;
/**
* 截取":" 字符的字符串数组
*
* @param str
* @return 返回一个数组
*/
public static String[] subStringArray_three(String str)
String[] StrArray = subStringArray_two(str);
//for()
return StrArray;
/**
* 判断str1中包含str2的个数
*
* @param str1
* @param str2
* @return counter
*/
public static int countStr(char str1, String str2)
int countss = 0;
for (int i = 0; i < str2.length(); i++)
if (str2.charAt(i) == str1)
countss++;
return countss;
/**
* 截取()中的字符串
*
* @param str2
* @return counter
*/
public static String countStrParentheses(String str2)
// TODO SGF ADD
String str1 = "";
Pattern pattern = Pattern.compile("(?<=\\\\()[^\\\\)]+");
Matcher matcher = pattern.matcher(str2);
while (matcher.find())
str1 = matcher.group();
return str1;
/**
* 1:0:1:0:1
*
* @param
* @return
*/
public static String[] getCount(String a, String b)
String[] arrayStr = ;
arrayStr = a.split(b);
return arrayStr;
public static boolean isZero(String m1)
if (isEmpty(m1))
m1 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal("0");
return b1.compareTo(b2) == 0;
// public static boolean checkPhone(String phone)
// if (null == phone || !phone.matches("^1[3-8]+\\\\d9"))
// return false;
//
// return true;
//
//
// public static boolean checkPassword(String password)
// if (null == password || !password.matches("[a-f A-F 0-9]6-15"))
// return false;
//
// return true;
//
/**
* 将分转化为元
*
* @param str
* @return fen->yuan 112000(分)-> 1120.00(元)
*/
public static String formatMoney_FenToYuan(String str)
try
GlobalLog.d(TAG, "formatMoney_FenToYuan : " + str);
if (!isEmpty(str))
if (str.equals("0"))
return "0";
else if (str.endsWith("00"))
GlobalLog.d(TAG, str.substring(0, str.length() - 2));
return new BigDecimal(str.substring(0, str.length() - 2))
.toString();
else
return BigDecimal.valueOf(new BigDecimal(str).longValue(),
2).toString();
catch (Exception e)
GlobalException.proxy.handle(e, null);
return "0.00";
/**
* @param str
* @return 5->5.00
*/
public static String formatMoney_Yuan(String str)
if (!isEmpty(str))
return str + ".00";
return "0.00";
/**
* @param str
* @return 5->500
*/
public static String formatMoney_Fen(String str)
if (!isEmpty(str))
double ret = Double.valueOf(str) * 100;
return String.valueOf((int) ret);
// return str + "00";
return "0";
/**
* @param str
* @return 5->500
*/
public static String format_FenToYuan(String str)
//TODO SGF ADD
if (!isEmpty(str))
double ret = Double.valueOf(str) / 100;
return String.valueOf((int) ret);
// return str + "00";
return "0";
/**
* @param m1
* @param m2
* @return true m1 > m2
*/
public static boolean greaterThanMoney(String m1, String m2)
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.compareTo(b2) == 1;
/**
* @param m1
* @param m2
* @return
*/
public static boolean greaterEqualMoney(String m1, String m2)
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.compareTo(b2) == 1 || b1.compareTo(b2) == 0;
public static boolean greaterThanZero(String m1)
return greaterThan(m1, "0");
public static boolean greaterEqualZero(String m1)
return greaterEqual(m1, "0");
public static boolean greaterEqual(String m1, String m2)
if (isEmpty(m1))
m1 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.compareTo(b2) == 1 || b1.compareTo(b2) == 0;
public static boolean greaterThan(String m1, String m2)
if (isEmpty(m1))
m1 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.compareTo(b2) == 1 || b1.compareTo(b2) == 0;
public static boolean lessEqualZero(String m1)
return lessEqual(m1, "0");
public static boolean lessThanZero(String m1)
return lessThan(m1, "0");
public static boolean lessEqual(String m1, String m2)
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.compareTo(b2) == -1 || b1.compareTo(b2) == 0;
/**
* 比较大小
*
* @param m1
* @param m2
* @return
*/
public static boolean lessThan(String m1, String m2)
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.compareTo(b2) == -1;
/**
* @param m1
* @param m2
* @return true m1 >= m2
*/
public static boolean compareMoneyEqual(String m1, String m2)
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.compareTo(b2) == 1 || b1.compareTo(b2) == 0;
public static boolean isMoneyZero(String m1)
if (isEmpty(m1))
m1 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal("0");
return b1.compareTo(b2) == 0;
/**
* 加法运算
*
* @param m1 "1.7"
* @param m2 "7.85"
* @return "1.7" + "7.85" => 9.55
*/
public static String add(String m1, String m2)
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.add(b2).toString();
public static String add(String m1, String m2, String m3)
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "0";
if (isEmpty(m3))
m3 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
BigDecimal b3 = new BigDecimal(m3);
return b1.add(b2).add(b3).toString();
/**
* 减法运算
*
* @param m1 2.3
* @param m2 1.1
* @return 1.2
*/
public static String subtract(String m1, String m2)
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.subtract(b2).toString();
/**
* @param m1
* @param m2
* @return
*/
public static String divide(String m1, String m2)
GlobalLog.d(TAG, "m1 : " + m1 + " m2 : " + m2);
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "1";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.divide(b2, 2, RoundingMode.HALF_UP).toString();
/**
* 乘法运算
*
* @param m1 参数1
* @param m2 参数2
* @return 两个数相乘
*/
public static String multiply(String m1, String m2)
GlobalLog.d(TAG, "m1 : " + m1 + " ; m2 : " + m2);
if (isEmpty(m1))
m1 = "0";
if (isEmpty(m2))
m2 = "0";
BigDecimal b1 = new BigDecimal(m1);
BigDecimal b2 = new BigDecimal(m2);
return b1.multiply(b2).toString();
public static String getProgress(int progress)
return (progress / 20) + "";
public static String getLimit(String total_unit)
double l = Double.valueOf(total_unit);
return (int) Math.max(Math.round(l * 0.05), 1) + "";
private static BigDecimal one_hundred_million = new BigDecimal("100000000");
private static BigDecimal ten_thousand = new BigDecimal("10000");
private static BigDecimal hundred_thousand = new BigDecimal("100000");
private static BigDecimal one_million = new BigDecimal("1000000");
private static BigDecimal ten_million = new BigDecimal("10000000");
public static String formatMoney_Chinese(String m)
BigDecimal b1 = new BigDecimal(m);
BigDecimal b2 = b1.divide(one_hundred_million);
if (b2.doubleValue() >= 10)
return b2.toString() + "亿";
else if (b2.doubleValue() >= 1)
return b1.divide(one_hundred_million).setScale(2,
RoundingMode.HALF_DOWN)
+ "亿";
else
b2 = b1.divide(ten_million);
if (b2.intValue() > 0)
System.out.println(b2);
return b2.multiply(new BigDecimal(1000))
.setScale(1, RoundingMode.HALF_DOWN).toString()
+ "万";
else
b2 = b1.divide(one_million);
if (b2.intValue() > 0)
return b2.multiply(new BigDecimal(100))
.setScale(0, RoundingMode.HALF_DOWN).toString()
+ "万";
else
b2 = b1.divide(hundred_thousand);
if (b2.intValue() > 0)
return b2.multiply(new BigDecimal(10))
.setScale(0, RoundingMode.HALF_DOWN).toString()
+ "万";
else
b2 = b1.divide(ten_thousand);
if (b2.intValue() > 0)
return b2.setScale(2, RoundingMode.HALF_DOWN) + "万";
return m + "元";
/**
* 是否显示出票明细
*
* @param issueState
* @return
*/
public static boolean isCanShowTicket(String issueState)
try
if (issueState.startsWith("QC@"))
String str = issueState.substring(3);
if (Integer.parseInt(str) > 1)
return true;
GlobalLog.d(TAG, str);
else
return false;
catch (Exception e)
e.printStackTrace();
return false;
public static boolean verifyPassword(String password)
if (isEmpty(password))
return false;
else if (password.matches("^[0-9a-zA-Z]6,15$"))
return true;
return false;
/**
* 手机号码验证
*/
public static boolean verifyPhoneNumber(String phone)
if (isEmpty(phone))
return false;
else if (!phone.startsWith("1"))
return false;
else if (phone.length() == 11)
return true;
// if (phone
// .matches("^((13[0-9])|(15[^4,\\\\D])|(18[0,5-9])|(170))\\\\d8$"))
// return true;
//
return false;
// /** 数字验证 */
// public static boolean verifyNumeric(String paramString)
// return Pattern.compile("[0-9]*").matcher(paramString).matches();
//
/**
* 用户名验证 "^[^0-9]\\\\w3,16$"
*/
public static boolean verifyUsername(String username)
if (isEmpty(username))
return false;
else if (username.matches("[\\u4E00-\\u9FA5a-zA-Z]1[\\u4E00-\\u9FA5a-zA-Z0-9]2,15"))
return true;
return false;
// /** 密码验证 */
// public static boolean verifyPassword(String paramString)
// return Pattern.compile("^[A-Za-z0-9]6,16$")
// .matcher(paramString)
// .matches();
//
public static boolean verifyEmail(String paramString)
return Pattern
.compile("^\\\\s*([A-Za-z0-9_-]+(\\\\.\\\\w+)*@(\\\\w+\\\\.)+\\\\w+)\\\\s*$")
.matcher(paramString).matches();
public static boolean verifyIDCard(String validateStr)
String regex = "(^\\\\d15$)|(^\\\\d18$)|(^\\\\d17(\\\\d|X|x)$)";
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
if (!pattern.matcher(validateStr).matches())
return false;
return true;
/**
* 校验密码有 6到18位 字母和数字 组成 的正则
*
* @param passStr
* @return
*/
public static boolean verifyPasswordLen(String passStr)
String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]6,18$";
return passStr.matches(regex);
/**
* 校验输入框小数点后面只能有2位数字 的正则
*
* @param passStr
* @return
*/
public static boolean verifTwo(String passStr)
String regex = "^\\\\d1,8(\\\\.\\\\d1,2)?$";
return passStr.matches(regex);
/**
* 校验输入框只能输入数字 的正则
*
* @param passStr
* @return
*/
public static boolean verifNum(String passStr)
String regex = "^[0-9]*[1-9][0-9]*$";
return passStr.matches(regex);
public static String getLast_2(String issue)
if (StringUtil.isEmpty(issue))
return "";
else
return issue.substring(issue.length() - 2);
public static String getLast_3(String issue)
if (StringUtil.isEmpty(issue))
return "";
else
return issue.substring(issue.length() - 3);
public static Map<String, String> parseData(String data)
Map<String, String> retMap = new HashMap<String, String>();
String[] items = data.split("#");
String[] item = null;
for (String i : items)
item = i.split("=");
if (item.length >= 2)
retMap.put(item[0], item[1]);
// for (String key : retMap.keySet())
// System.out.println(key + " : " + retMap.get(key));
//
return retMap;
public static String setStrRed(String str)
return "<font color='red'>" + str + "</font>";
//白色
public static String setStrWhite(String str)
return "<font color='#ffffff'>" + str + "</font>";
public static String setStrMainRed(String str)
return "<font color='#f33b3b'>" + str + "</font>";
//灰色
public static String setStrGray(String str)
return "<font color='#888888'>" + str + "</font>";
public static String setStrOrenge(String str)
return "<font color='#ff9e14'>" + str + "</font>";
//竞彩篮球-绿色
public static String setStrGreen(String str)
return "<font color='#4bc160'>" + str + "</font>";
public static String setStrBlack(String str)
return "<font color='#313131'>" + str + "</font>";
public static String setStrOrange(String str)
return "<font color='#FF3D3D'>" + str + "</font>";
public static String setStrRedBold(String str)
return "<b><font color='red'>" + str + "</font></>";
public static String setStrBold(String str)
return "<b>" + str + "</b>";
public static List<String> getNumList(int start, int end)
List<String> list = new ArrayList<String>();
for (int i = start; i <= end; i++)
list.add(i + "");
return list;
public static String setWinCodeRed(String drawCode, String code)
StringBuffer retBuf = new StringBuffer("");
String[] drawCodes = drawCode.split(",");
List<String> codes = new ArrayList<String>();
for (String c : code.split(","))
codes.add(c);
for (String d : drawCodes)
if (codes.contains(d))
retBuf.append(setStrRed(d));
retBuf.append(" ");
else
retBuf.append(d);
retBuf.append(" ");
return retBuf.toString();
public static boolean isNumeric(String str)
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNum = pattern.matcher(str);
if (!isNum.matches())
return false;
return true;
public static String getString(String str)
if (isEmpty(str))
return "";
return str.trim();
/**
* 生成创建二维码
*/
public static Bitmap createQRImage(String url, int QR_WIDTH, int QR_HEIGHT) throws WriterException
// 判断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, QR_WIDTH, QR_HEIGHT, hints);
int[] pixels = new int[QR_WIDTH * QR_HEIGHT];
// 下面这里按照二维码的算法,逐个生成二维码的图片,
// 两个for循环是图片横列扫描的结果
for (int y = 0; y < QR_HEIGHT; y++)
for (int x = 0; x < QR_WIDTH; x++)
if (bitMatrix.get(x, y))
pixels[y * QR_WIDTH + x] = 0xff000000;
else
// pixels[y * QR_WIDTH + x] = 0xffffffff;
// 生成二维码图片的格式,使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);
//TODO WH 显示到一个ImageView上面
//iv_codes_qr.setImageBitmap(bitmap);
return bitmap;
/**
* 根据指定内容生成自定义宽高的二维码图片
*
* @param content 需要生成二维码的内容
* @param width 二维码宽度
* @param height 二维码高度
* @throws WriterException 生成二维码异常
*/
public static Bitmap makeQRImage(String content, int width, int height)
throws WriterException
// 判断URL合法性
if (!isNoBlankAndNoNull(content))
return null;
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 图像数据转换,使用了矩阵转换
BitMatrix bitMatrix = new QRCodeWriter().encode(content,
BarcodeFormat.QR_CODE, width, height, hints);
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_8888
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
/**
* 判断字符串是否非空非null
*
* @param strParm 需要判断的字符串
* @return 真假
*/
public static boolean isNoBlankAndNoNull(String strParm)
return !((strParm == null) || (strParm.equals("")));
/**
* 指定目录写入文件内容
*
* @param filePath 文件路径+文件名
* @param
* @throws IOException
*/
public static void saveAsJPEG(Bitmap bitmap, String filePath)
throws IOException
FileOutputStream fos = null;
try
File file = new File(filePath);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
finally
if (fos != null)
fos.close();
/**
* 是否有内存
*
* @return
*/
public static boolean isMountedSDCard()
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState()))
return true;
else
return false;
/**
* 截屏
*
* @param activity
* @return
*/
public static Bitmap activityShot(Activity activity)
/*获取windows中最顶层的view*/
View view = activity.getWindow().getDecorView();
//允许当前窗口保存缓存信息
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
//获取状态栏高度
Rect rect = new Rect();
view.getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
WindowManager windowManager = activity.getWindowManager();
//获取屏幕宽和高
DisplayMetrics outMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(outMetrics);
int width = outMetrics.widthPixels;
int height = outMetrics.heightPixels;
//去掉状态栏
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, statusBarHeight, width, height - statusBarHeight);
//销毁缓存信息
view.destroyDrawingCache();
view.setDrawingCacheEnabled(false);
return bitmap;
/**
* 截取scrollview的屏幕
* @param scrollView
* @return
*/
public static Bitmap getBitmapByView(ScrollView scrollView)
int h = 0;
Bitmap bitmap = null;
// 获取listView实际高度
for (int i = 0; i < scrollView.getChildCount(); i++)
h += scrollView.getChildAt(i).getHeight();
scrollView.getChildAt(i).setBackgroundResource(R.drawable.white_drawable);
// 创建对应大小的bitmap
bitmap = Bitmap.createBitmap(scrollView.getWidth(), h,
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
scrollView.draw(canvas);
// 测试输出
FileOutputStream out = null;
try
out = new FileOutputStream("/sdcard/screen_test.png");
catch (FileNotFoundException e)
e.printStackTrace();
try
if (null != out)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
catch (IOException e)
// TODO: handle exception
return bitmap;
/**
* 截图listview
* **/
public static Bitmap getbBitmap(ListView listView)
int h = 0;
Bitmap bitmap = null;
// 获取listView实际高度
for (int i = 0; i < listView.getChildCount(); i++)
h += listView.getChildAt(i).getHeight();
// 创建对应大小的bitmap
bitmap = Bitmap.createBitmap(listView.getWidth(), h,
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
listView.draw(canvas);
// 测试输出
FileOutputStream out = null;
try
out = new FileOutputStream("/sdcard/screen_test.png");
catch (FileNotFoundException e)
e.printStackTrace();
try
if (null != out)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
catch (IOException e)
// TODO: handle exception
return bitmap;
/**
* 截取RelativeLayout
**/
public static Bitmap getRelativeLayoutBitmap(RelativeLayout relativeLayout)
int h = 0;
Bitmap bitmap;
for (int i = 0; i < relativeLayout.getChildCount(); i++)
h += relativeLayout.getChildAt(i).getHeight();
// 创建对应大小的bitmap
bitmap = Bitmap.createBitmap(relativeLayout.getWidth(), h,
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
relativeLayout.draw(canvas);
return bitmap;
/**
* 截取LinearLayout
**/
public static Bitmap getLinearLayoutBitmap(LinearLayout linearLayout)
int h = 0;
Bitmap bitmap;
for (int i = 0; i < linearLayout.getChildCount(); i++)
h += linearLayout.getChildAt(i).getHeight();
// 创建对应大小的bitmap
bitmap = Bitmap.createBitmap(linearLayout.getWidth(), h,
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
linearLayout.draw(canvas);
return bitmap;
/**
* 截取除了导航栏之外的整个屏幕
*/
public static Bitmap screenShotWholeScreen(Activity activity)
View dView = activity.getWindow().getDecorView();
dView.setDrawingCacheEnabled(true);
dView.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(dView.getDrawingCache());
return bitmap;
以上是关于追求截图的极致-牛牛截图再添新成员-截长图功能的主要内容,如果未能解决你的问题,请参考以下文章