PHP HTTP类

<?php

class Libs_Http_Client {

    private static $boundary = '';

    public static function get($url, $params = array(), $headers = array(), $misc = array(), $cookie='') {
        if (!empty($params)) {
            $url = $url . '?' . http_build_query($params);
        }
        return self::http($url, 'GET', null, $headers, $misc, $cookie);
    }

    public static function post($url, $params, $files = array(), $headers = array(), $misc = array()) {
        if (!$files) {
            if (is_array($params) || is_object($params)) {
                $body = http_build_query($params);
            } else {
                $body = $params;
            }
        } else {
            $body = self::build_http_query_multi($params, $files);
            $headers[] = "Content-Type: multipart/form-data; boundary=" . self::$boundary;
        }
        return self::http($url, 'POST', $body, $headers, $misc);
    }

    public static function postFiles($url, $files, $params = array(), $headers = array(), $misc = array()) {
        if (!is_array($files)) {
            return false;
        }

        foreach ($files as $key => &$val) {
            $val = '@'.$val;
        }
        $body = array_merge($files, $params);
        $headers[] = "Content-Type: multipart/form-data";

        return self::http($url, 'POST', $body, $headers, $misc);
    }

    public static function getFiles($url, $files, $params = array(), $headers = array(), $misc = array()) {
        if (!is_array($files)) {
            return false;
        }

        foreach ($files as $key => &$val) {
            $val = '@'.$val;
        }
        $body = array_merge($files, $params);
        $headers[] = "Content-Type: multipart/form-data";

        return self::http($url, 'GET', $body, $headers, $misc);
    }


    /**
     * Make an HTTP request
     *
     * @return string API results
     * @ignore
     */
    private static function http($url, $method, $postfields = NULL, $headers = array(), $misc = array(), $cookie='') {
        $ci = curl_init();
        /* Curl settings */
        curl_setopt($ci, CURLOPT_USERAGENT, 'Tdot Plum Client v0.1');       //HTTP头部user agent
        curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 30);                       //连接超时时间,单位秒
        curl_setopt($ci, CURLOPT_TIMEOUT, 30);                              //最大执行时间,单位秒
        curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);                     //避免直接输出返回值
        curl_setopt($ci, CURLOPT_ENCODING, "");                             //可接受编码类型,空串支持所有类型
        curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, 2);
        //curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
        curl_setopt($ci, CURLOPT_HEADER, FALSE);

        switch ($method) {
            case 'POST':
                curl_setopt($ci, CURLOPT_POST, TRUE);
                if (!empty($postfields)) {
                    curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
                }
                break;
        }

        foreach ($misc as $key => $val) {
            $key    = strtoupper($key);
            switch ($key) {
                case 'REFERER' :
                    curl_setopt($ci, CURLOPT_REFERER, $val);
                    break;
            }
        }

        curl_setopt($ci, CURLOPT_URL, $url);
        curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
        if($cookie){
            curl_setopt ($ci, CURLOPT_COOKIE , $cookie );
        }
        curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE);

        $response = curl_exec($ci);
        $httpCode = curl_getinfo($ci, CURLINFO_HTTP_CODE);
        $httpInfo = curl_getinfo($ci);
        curl_close ($ci);
        return $response;
    }

    /**
     * 发送文件时使用
     * @param array $params
     * @param array $files
     * @return string
     */
    private static function build_http_query_multi($params, $files) {
        //if (!$params) return '';

        self::$boundary = $boundary = uniqid('------------------');
        $MPboundary = '--'.$boundary;
        $endMPboundary = $MPboundary. '--';
        $multipartbody = '';

        foreach ($params as $key => $value) {
            $multipartbody .= $MPboundary . "\r\n";
            $multipartbody .= 'content-disposition: form-data; name="' . $key . "\"\r\n\r\n";
            $multipartbody .= $value."\r\n";
        }
        foreach ($files as $key => $value) {
            if (!$value) {continue;}

            if (is_array($value)) {
                $url = $value['url'];
                if (isset($value['name'])) {
                    $filename = $value['name'];
                } else {
                    $parts = explode( '?', basename($value['url']));
                    $filename = $parts[0];
                }
                $field = isset($value['field']) ? $value['field'] : $key;
            } else {
                $url = $value;
                $parts = explode( '?', basename($url));
                $filename = $parts[0];
                $field = $key;
            }
            $content = file_get_contents($url);

            $multipartbody .= $MPboundary . "\r\n";
            $multipartbody .= 'Content-Disposition: form-data; name="' . $field . '"; filename="' . $filename . '"'. "\r\n";
            $multipartbody .= "Content-Type: image/unknown\r\n\r\n";
            $multipartbody .= $content. "\r\n";
        }

        $multipartbody .= $endMPboundary;
        return $multipartbody;
    }
}

PHP HTTP类

BASH 打包文件夹及文件夹内全部文件,上传至FTP服务器

BASH脚本打包文件夹及文件夹内全部文件并上传FTP服务器,用于快速下载服务器大文件的场景,如:服务器上有大小为2G,包含5万个文件的程序包,服务器带宽仅有2M,要快速下载这么大的文件夹,可先打包成ZIP压缩包,再上传至高带宽的文件服务器(如阿里云OSS),即可低成本高速完成下载过程。

下面以上传到阿里云OSS为例,在服务器上提前启动OSSFTP,然后运行下方代码的脚本

#!/bin/bash

ftpIP="127.0.0.1 2048"
uuid=$(cat /proc/sys/kernel/random/uuid)
filename="$(date +%s).${uuid^^}.zip"

function uploadFile {
	ftp -v -n $ftpIP<<EOF
	user OSS用户名 OSS密码
	binary
	passive
	put $filename
	bye
EOF
rm -rfv $filename
echo "此处是OSS链接$filename"
}

########################################################################
zip -r $filename 此处是被打包的文件夹名称
uploadFile


BASH 打包文件夹及文件夹内全部文件,上传至FTP服务器

JAVA 图片拼接

import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class MergeImageUtil {
	/**
	 * 拼接图片(注:图片需长宽一致)
	 * @param files  img1 ,img2
	 * @param type  1:横向拼接 2:纵向拼接
	 * @param targetFile 合成新的图片地址
	 */
	public static void mergeImage(String[] files, int type, String targetFile) {
		int len = files.length;
		if (len < 1) {
			throw new RuntimeException("图片数量小于1");
		}
		File[] src = new File[len];
		BufferedImage[] images = new BufferedImage[len];
		int[][] ImageArrays = new int[len][];
		for (int i = 0; i < len; i++) {
			try {
				src[i] = new File(files[i]);
				images[i] = ImageIO.read(src[i]);
			}
			catch (Exception e) {
				throw new RuntimeException(e);
			}
			int width = images[i].getWidth();
			int height = images[i].getHeight();
			ImageArrays[i] = new int[width * height];
			ImageArrays[i] = images[i].getRGB(0, 0, width, height, ImageArrays[i], 0, width);
		}
		int newHeight = 0;
		int newWidth = 0;
		for (int i = 0; i < images.length; i++) {
			// 横向
			if (type == 1) {
				newHeight = newHeight > images[i].getHeight() ? newHeight : images[i].getHeight();
				newWidth += images[i].getWidth();
			} else if (type == 2) {
				// 纵向
				newWidth = newWidth > images[i].getWidth() ? newWidth : images[i].getWidth();
				newHeight += images[i].getHeight();
			}
		}
		if (type == 1 && newWidth < 1) {
			return;
		}
		if (type == 2 && newHeight < 1) {
			return;
		}
		// 生成新图片
		try {
			BufferedImage ImageNew = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
			int height_i = 0;
			int width_i = 0;
			for (int i = 0; i < images.length; i++) {
				if (type == 1) {
					ImageNew.setRGB(width_i, 0, images[i].getWidth(), newHeight, ImageArrays[i], 0,
						      images[i].getWidth());
					width_i += images[i].getWidth();
				} else if (type == 2) {
					ImageNew.setRGB(0, height_i, newWidth, images[i].getHeight(), ImageArrays[i], 0, newWidth);
					height_i += images[i].getHeight();
				}
			}
			//输出想要的图片
			ImageIO.write(ImageNew, targetFile.split("\\.")[1], new File(targetFile));
		}
		catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}

JAVA 图片拼接

Java 身份证信息处理类

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;


/**
 * @author QiFeng·Luo
 */
public class IDCardUtil {

    /**
     * 数字
     */
    public final static Pattern NUMBERS = Pattern.compile("\\d+");

    /**
     * 中国公民身份证号码最小长度。
     */
    private static final int CHINA_ID_MIN_LENGTH = 15;

    /**
     * 中国公民身份证号码最大长度。
     */
    private static final int CHINA_ID_MAX_LENGTH = 18;

    public static Exception isValidatedAllIdcard(String idcard) throws Exception {
        boolean ret = isIdcard(idcard);
        if (!ret) {
            throw new Exception("身份证格式有误");
        }
        return null;
    }

    final static Map<Integer, String> zoneNum = new HashMap<>();
    /**
     * 身份证省份编码
     * */
    static {
        zoneNum.put(11, "北京");
        zoneNum.put(12, "天津");
        zoneNum.put(13, "河北");
        zoneNum.put(14, "山西");
        zoneNum.put(15, "内蒙古");
        zoneNum.put(21, "辽宁");
        zoneNum.put(22, "吉林");
        zoneNum.put(23, "黑龙江");
        zoneNum.put(31, "上海");
        zoneNum.put(32, "江苏");
        zoneNum.put(33, "浙江");
        zoneNum.put(34, "安徽");
        zoneNum.put(35, "福建");
        zoneNum.put(36, "江西");
        zoneNum.put(37, "山东");
        zoneNum.put(41, "河南");
        zoneNum.put(42, "湖北");
        zoneNum.put(43, "湖南");
        zoneNum.put(44, "广东");
        zoneNum.put(45, "广西");
        zoneNum.put(46, "海南");
        zoneNum.put(50, "重庆");
        zoneNum.put(51, "四川");
        zoneNum.put(52, "贵州");
        zoneNum.put(53, "云南");
        zoneNum.put(54, "西藏");
        zoneNum.put(61, "陕西");
        zoneNum.put(62, "甘肃");
        zoneNum.put(63, "青海");
        zoneNum.put(64, "宁夏");
        zoneNum.put(65, "新疆");
        zoneNum.put(71, "台湾");
        zoneNum.put(81, "香港");
        zoneNum.put(82, "澳门");
        zoneNum.put(91, "国外");
    }

    /**
     * 校验码
     */
    final static int[] PARITYBIT = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };

    /**
     * 加权因子wi
     */
    final static int[] POWER_LIST = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };

    /**
     * 验证身份证号有效性
     *
     * @param idCard:身份证号
     * @return true/false
     */
    public static boolean isIdcard(String idCard) {
        // 号码长度应为15位或18位
        if (idCard == null || (idCard.length() != 15 && idCard.length() != 18)) {
            return false;
        }
        // 校验区位码
        if (!zoneNum.containsKey(Integer.valueOf(idCard.substring(0, 2)))) {
            return false;
        }
        // 校验年份
        String year = idCard.length() == 15 ? "19" + idCard.substring(6, 8) : idCard.substring(6, 10);
        final int iyear = Integer.parseInt(year);
        if (iyear < 1900 || iyear > Calendar.getInstance().get(Calendar.YEAR)) {
            // 1900年的PASS,超过今年的PASS
            return false;
        }
        // 校验月份
        String month = idCard.length() == 15 ? idCard.substring(8, 10) : idCard.substring(10, 12);
        final int imonth = Integer.parseInt(month);
        if (imonth < 1 || imonth > 12) {
            return false;
        }
        // 校验天数
        String day = idCard.length() == 15 ? idCard.substring(10, 12) : idCard.substring(12, 14);
        final int iday = Integer.parseInt(day);
        if (iday < 1 || iday > 31) {
            return false;
        }
        // 校验一个合法的年月日
        if (!isValidDate(year + month + day)) {
            return false;
        }
        // 校验位数
        int power = 0;
        final char[] cs = idCard.toUpperCase().toCharArray();
        for (int i = 0; i < cs.length; i++) {// 循环比正则表达式更快
            if (i == cs.length - 1 && cs[i] == 'X') {
                break;// 最后一位可以是X或者x
            }
            if (cs[i] < '0' || cs[i] > '9') {
                return false;
            }
            if (i < cs.length - 1) {
                power += (cs[i] - '0') * POWER_LIST[i];
            }
        }
        // 校验“校验码”
        if (idCard.length() == 15) {
            return true;
        }
        return cs[cs.length - 1] == PARITYBIT[power % 11];
    }

    /**
     * 判断字符串是否为日期格式(合法)
     *
     * @param inDate:字符串时间
     * @return true/false
     */
    public static boolean isValidDate(String inDate) {
        if (inDate == null) {
            return false;
        }
        // 或yyyy-MM-dd
        SimpleDateFormat dataFormat = new SimpleDateFormat("yyyyMMdd");
        if (inDate.trim().length() != dataFormat.toPattern().length()) {
            return false;
        }
        // 该方法用于设置Calendar严格解析字符串;默认为true,宽松解析
        dataFormat.setLenient(false);
        try {
            dataFormat.parse(inDate.trim());
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    /**
     * 转换成日期
     * @param birthday
     * @return
     */
    private static Date toBirthDay(String birthday){
        try{
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, Integer.parseInt(birthday.substring(0, 4)));
            // 月份从0开始,所以减1
            calendar.set(Calendar.MONTH, Integer.parseInt(birthday.substring(4, 6)) - 1);
            calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(birthday.substring(6, 8)));
            // 以下设置时分秒,但是对生日的意义不大
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);

            return calendar.getTime();
        }catch (Exception e){
            return null;
        }
    }

    /**
     * 给定内容是否匹配正则
     *
     * @param pattern 模式
     * @param content 内容
     * @return 正则为null或者""则不检查,返回true,内容为null返回false
     */
    private static boolean isMatch(Pattern pattern, CharSequence content) {
        if (content == null || pattern == null) {
            // 提供null的字符串为不匹配
            return false;
        }
        return pattern.matcher(content).matches();
    }

    /**
     * 将字符串转换成指定格式的日期
     *
     * @param str        日期字符串.
     * @param dateFormat 日期格式. 如果为空,默认为:yyyy-MM-dd HH:mm:ss.
     * @return
     */
    private static Date strToDate(final String str, String dateFormat) {
        if (str == null || str.trim().length() == 0) {
            return null;
        }
        try {
            if (dateFormat == null || dateFormat.length() == 0) {
                dateFormat = "yyyy-MM-dd HH:mm:ss";
            }
            DateFormat fmt = new SimpleDateFormat(dateFormat);
            return fmt.parse(str.trim());
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 根据日期获取年
     *
     * @param date 日期
     * @return 年的部分
     */
    public static int year(Date date) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        return ca.get(Calendar.YEAR);
    }

    /**
     * 将power和值与11取模获得余数进行校验码判断
     *
     * @param iSum 加权和
     * @return 校验位
     */
    private static char getCheckCode18(int iSum) {
        switch (iSum % 11) {
            case 10:
                return '2';
            case 9:
                return '3';
            case 8:
                return '4';
            case 7:
                return '5';
            case 6:
                return '6';
            case 5:
                return '7';
            case 4:
                return '8';
            case 3:
                return '9';
            case 2:
                return 'x';
            case 1:
                return '0';
            case 0:
                return '1';
            default:
                return ' ';
        }
    }

    /**
     * 获得18位身份证校验码
     * 计算方式:
     * 将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
     * 将这17位数字和系数相乘的结果相加
     * 用加出来和除以11,看余数是多少
     * 余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3 2
     * 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2
     * @param code17 18位身份证号中的前17位
     * @return 第18位
     */
    private static char getCheckCode18(String code17) {
        int sum = getPowerSum(code17.toCharArray());
        return getCheckCode18(sum);
    }

    /**
     * 将身份证的每位和对应位的加权因子相乘之后,再得到和值
     *
     * @param iArr 身份证号码的数组
     * @return 身份证编码
     */
    private static int getPowerSum(char[] iArr) {
        int iSum = 0;
        if (POWER_LIST.length == iArr.length) {
            for (int i = 0; i < iArr.length; i++) {
                iSum += Integer.valueOf(String.valueOf(iArr[i])) * POWER_LIST[i];
            }
        }
        return iSum;
    }

    /**
     * 将15位身份证号码转换为18位
     *
     * @param idCard 15位身份编码
     * @return 18位身份编码
     */
    public static String convertIdCard(String idCard) {
        StringBuilder idCard18;
        if (idCard.length() != CHINA_ID_MIN_LENGTH) {
            return null;
        }
        if (isMatch(NUMBERS, idCard)) {
            // 获取出生年月日
            String birthday = idCard.substring(6, 12);
            Date birthDate = strToDate(birthday, "yyMMdd");
            // 获取出生年
            int sYear = year(birthDate);
            // 理论上2000年之后不存在15位身份证,可以不要此判断
            if (sYear > 2000) {
                sYear -= 100;
            }
            idCard18 = new StringBuilder().append(idCard, 0, 6).append(sYear).append(idCard.substring(8));
            // 获取校验位
            char sVal = getCheckCode18(idCard18.toString());
            idCard18.append(sVal);
        } else {
            return null;
        }
        return idCard18.toString();
    }

    /**
     * 从身份证号码中获取生日
     * @param idno
     * @return null表示idno错误,未获取到生日
     */
    public static Date getBirthDay(String idno){
        if(!isIdcard(idno)){
            return null;
        }
        if (idno.length() == 15) {
            // 如果是15位转为18位
            idno = convertIdCard(idno);
        }
        return toBirthDay(idno.substring(6, 14));
    }

    /**
     * 从身份证号码中获取生日
     * @param idno
     * @return null表示idno错误,未获取到生日 日期格式为:yyyy-MM-dd
     */
    public static String getBirthDayStr(String idno){
        if(!isIdcard(idno)){
            return null;
        }
        if (idno.length() == 15) {
            // 如果是15位转为18位
            idno = convertIdCard(idno);
        }
        Date birthday = toBirthDay(idno.substring(6, 14));
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        return simpleDateFormat.format(birthday);
    }
    /**
     * 从身份证号中获取性别
     * @param idno
     * @return 0:男,1:女,-1:证件号码错误
     */
    public static String getGender(String idno){
        if(!isIdcard(idno)){
            return "-1";
        }
        if (idno.length() == 15) {
            // 如果是15位转为18位
            idno = convertIdCard(idno);
        }
        // 奇男,偶女
        return (Integer.parseInt(idno.substring(16, 17)) % 2) == 0 ? "1" : "0";
    }

    /**
     * 方法调用测试
     * */
    public static void main(String[] args) {
        String idc= "130503670401001";
        //检查身份证是否合规
        boolean idcard = isIdcard(idc);
        if (idcard) {
            System.out.println("身份证号码合规");
            // 获取身份证号码中的生日
            Date birthDay = getBirthDay(idc);
            System.out.println("当前身份证的生日为:"+ getBirthDayStr(idc));
            // 获取性别
            String gender = getGender(idc);
            if ("0".equals(gender)) {
                System.out.println("当前身份证的性别为:男性");
            } else if ("1".equals(gender)) {
                System.out.println("当前身份证的性别为:女性");
            } else {
                System.out.println("当前身份证格式不正确");
            }
        }else {
            System.out.println("身份证格式有误");
        }
    }

}


Java 身份证信息处理类

Java Canny边缘检测

import java.awt.image.BufferedImage;

public class CannyUtil {
	int Y;
	int X;
	int src[][];
	int dest[][];
	double tan[][];
	BufferedImage bufferedImage;
	BufferedImage bufferedImage_old;
	public CannyUtil(BufferedImage bi) {
		bufferedImage_old = bi;
		bufferedImage = bi;
		Y = bi.getWidth();
		X = bi.getHeight();
		src = new int[Y][X];
		dest = new int[Y][X];
		tan = new double[Y][X];
	}
	
	//灰度
	public BufferedImage Gray() {
		for(int y=0;y<Y;y++) {
			for(int x=0;x<X;x++) {
				int r=(bufferedImage.getRGB(y,x)>>16)&0x000000ff;
		    	int g=(bufferedImage.getRGB(y,x)>>8)&0x000000ff;
		    	int b=bufferedImage.getRGB(y,x)&0x000000ff;
		    	src[y][x]=(int)(0.2989*r+0.587*g+0.114*b);
				//bufferedImage.setRGB(y,x,0xff000000|src[y][x]|(src[y][x]<<8)|(src[y][x]<<16));
			}
		}
		return bufferedImage;
	}
	
	//高斯平滑
	public BufferedImage Gauss()
	{
		int M[][]={{1,2,1},{2,4,2},{1,2,1}};
    	bufferedImage=new BufferedImage(Y,X,BufferedImage.TYPE_INT_RGB);
		for(int y=1;y<Y-1;y++)
			for(int x=1;x<X-1;x++)
			{
				dest[y][x]= src[y-1][x-1]*M[0][0]+src[y][x-1]*M[1][0]+src[y+1][x-1]*M[2][0]
						+src[y-1][x]  *M[0][1]+src[y][x]  *M[1][1]+src[y+1][x]  *M[2][1]
						+src[y-1][x+1]*M[0][2]+src[y][x+1]*M[1][2]+src[y+1][x+1]*M[2][2];
				dest[y][x]/=16;
				bufferedImage.setRGB(y,x,0xff000000|dest[y][x]|(dest[y][x]<<8)|(dest[y][x]<<16));
			}
		for(int y=1;y<Y-1;y++)
			for(int x=1;x<X-1;x++)
				src[y][x]=dest[y][x];
		return bufferedImage;
	}
	//索贝尔边缘提取
	public BufferedImage Sobel()
    {
    	int Mx[][]={{-1,0,1},{-2,0,2},{-1,0,1}};
    	int My[][]={{-1,-2,-1},{0,0,0},{1,2,1}};
    	bufferedImage=new BufferedImage(Y,X,BufferedImage.TYPE_INT_RGB);
		for(int y=1;y<Y-1;y++)
			for(int x=1;x<X-1;x++)
			{
				int dx=	 src[y-1][x-1]*Mx[0][0]+src[y][x-1]*Mx[1][0]+src[y+1][x-1]*Mx[2][0]
						+src[y-1][x]  *Mx[0][1]+src[y][x]  *Mx[1][1]+src[y+1][x]  *Mx[2][1]
						+src[y-1][x+1]*Mx[0][2]+src[y][x+1]*Mx[1][2]+src[y+1][x+1]*Mx[2][2];
				int dy=	 src[y-1][x-1]*My[0][0]+src[y][x-1]*My[1][0]+src[y+1][x-1]*My[2][0]
						+src[y-1][x]  *My[0][1]+src[y][x]  *My[1][1]+src[y+1][x]  *My[2][1]
						+src[y-1][x+1]*My[0][2]+src[y][x+1]*My[1][2]+src[y+1][x+1]*My[2][2];
				dest[y][x]=(int)(Math.sqrt(dx*dx+dy*dy)+0.5);
				if(dest[y][x]>255) dest[y][x]=255;
				if(dest[y][x]<0) dest[y][x]=0;
				bufferedImage.setRGB(y,x,0xff000000|dest[y][x]|(dest[y][x]<<8)|(dest[y][x]<<16));
				tan[y][x]=1.0*dy/dx;
			}
		for(int y=1;y<Y-1;y++)
			for(int x=1;x<X-1;x++)
				src[y][x]=dest[y][x];
		return bufferedImage;
    }
    //非极大值抑制
	public BufferedImage NMS()
	{
		for(int y=1;y<Y-1;y++)
			for(int x=1;x<X-1;x++)
			{
				if(Math.abs(tan[y][x])<=0.5)
				{
					if(src[y][x]>=src[y][x-1]&&src[y][x]>=src[y][x+1])
						dest[y][x]=src[y][x];
					else
						dest[y][x]=0;
				}
				else if(-2<=tan[y][x]&&tan[y][x]<=-0.5)
				{
					if(src[y][x]>=src[y+1][x-1]&&src[y][x]>=src[y-1][x+1])
						dest[y][x]=src[y][x];
					else
						dest[y][x]=0;
				}
				else if(0.5<=tan[y][x]&&tan[y][x]<=2)
				{
					if(src[y][x]>=src[y-1][x-1]&&src[y][x]>=src[y+1][x+1])
						dest[y][x]=src[y][x];
					else
						dest[y][x]=0;
				}
				else if(2<=Math.abs(tan[y][x]))
				{
					if(src[y][x]>=src[y-1][x]&&src[y][x]>=src[y+1][x])
						dest[y][x]=src[y][x];
					else
						dest[y][x]=0;
				}
				bufferedImage.setRGB(y,x,0xff000000|dest[y][x]|(dest[y][x]<<8)|(dest[y][x]<<16));
			}
		for(int y=1;y<Y-1;y++)
			for(int x=1;x<X-1;x++)
				src[y][x]=dest[y][x];
		return bufferedImage;
	}
	//双阈值连接
	public BufferedImage DT()
	{
		int th1=127;
		int th2=63;
		for(int y=1;y<Y-1;y++)
			for(int x=1;x<X-1;x++)
			{
				if(src[y][x]>=th1)
					dest[y][x]=255;
				else if(src[y][x]<=th2)
					dest[y][x]=0;
				else
				{
					if(src[y-1][x-1]>=th1||src[y-1][x]>=th1||src[y-1][x+1]>=th1||src[y][x-1]>=th1||src[y][x+1]>=th1||src[y+1][x-1]>=th1||src[y+1][x]>=th1||src[y+1][x+1]>=th1)
						dest[y][x]=255;
					else
						dest[y][x]=0;
				}	
				bufferedImage.setRGB(y,x,0xff000000|dest[y][x]|(dest[y][x]<<8)|(dest[y][x]<<16));
			}
		for(int y=1;y<Y-1;y++)
			for(int x=1;x<X-1;x++)
				src[y][x]=dest[y][x];
		return bufferedImage;
	}
	
	//自动裁剪
	public BufferedImage autoClip(int GaussCount) {
		bufferedImage = Gray();
		for(int i=0;i<GaussCount;i++) {
			bufferedImage = Gauss();
		}
		bufferedImage = Sobel();		
		bufferedImage = NMS();
		bufferedImage = DT();
		
		boolean minXb = false, minYb = false;
	    int minX = 0, minY = 0, maxX = 0, maxY = 0;
	    
		for (int x = 0; x < bufferedImage.getWidth(); x++) {
	        for (int y = 0; y < bufferedImage.getHeight(); y++) {
	            // 如果是透明像素 跳过
	            if (bufferedImage.getRGB(x,y) == 0) continue;

	            // 获取该点像素,并以object类型表示
	            Object data = bufferedImage.getRaster().getDataElements(x, y, null);
	            int r = bufferedImage.getColorModel().getRed(data);
	            int g = bufferedImage.getColorModel().getGreen(data);
	            int b = bufferedImage.getColorModel().getBlue(data);
	            
	            if (r == 0 && g == 0 && b == 0) continue;

	            if (!minXb) {
	                minX = x;
	                minXb = true;
	            }

	            if (!minYb) {
	                minY = y;
	                minYb = true;
	            }

	            minX = Math.min(minX, x);
	            minY = Math.min(minY, y);

	            maxX = Math.max(maxX, x);
	            maxY = Math.max(maxY, y);
	        }
	    }
		System.out.printf("minX=%d,minY=%d,maxX=%d,maxY=%d\n", minX,minY,maxX,maxY);
		return bufferedImage_old.getSubimage(minX, minY, maxX - minX, maxY - minY);
	}
}

Java Canny边缘检测