分享一下 java 处理图像的工具类

本贴最后更新于 2721 天前,其中的信息可能已经水流花落

package com.mss.utils;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

/**

  • 图片处理类

*/
@SuppressWarnings("unused")
public class ImgUtils {

private String IMAGE_TYPE_GIF = "gif";// 图形交换格式
private String IMAGE_TYPE_JPG = "jpg";// 联合照片专家组
private String IMAGE_TYPE_JPEG = "jpeg";// 联合照片专家组
private String IMAGE_TYPE_BMP = "bmp";// 英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式
private String IMAGE_TYPE_PNG = "png";// 可移植网络图形
private String IMAGE_TYPE_PSD = "psd";// Photoshop的专用格式Photoshop

/**
 * 按比例缩放图片
 * 
 * 
 * @date 2016年11月21日
 * @param srcImageFile 文件路径
 * @param result 文件存放路径
 * @param scale 放大或缩小倍数
 * @param flag true:放大,false:缩小
 * void
 */
public void scale(String srcImageFile, String result,
        int scale, boolean flag) {
    try {
        BufferedImage src = ImageIO.read(new File(srcImageFile)); // 读入文件
        int width = src.getWidth(); // 得到源图宽
        int height = src.getHeight(); // 得到源图长
        if (flag) {// 放大
            width = width * scale;
            height = height * scale;
        } else {// 缩小
            width = width / scale;
            height = height / scale;
        }
        Image image = src.getScaledInstance(width, height,Image.SCALE_DEFAULT);
        BufferedImage tag = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
        Graphics g = tag.getGraphics();
        g.drawImage(image, 0, 0, null); // 绘制缩小后的图
        g.dispose();
        ImageIO.write(tag, "JPEG", new File(result));// 输出到文件流
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 * 
 * 根据宽高缩放
 * 
 * @date 2016年11月21日
 * @param srcImageFile  文件路径
 * @param result 存放文件路径
 * @param height 缩放高度
 * @param width 缩放宽度
 * @param bb 是否缩放
 * void
 */
@SuppressWarnings("static-access")
public  void scale2(String srcImageFile, String result, int height, int width, boolean bb) {
    try {
        double ratio = 0.0; // 缩放比例
        File f = new File(srcImageFile);
        BufferedImage bi = ImageIO.read(f);
		Image itemp = bi.getScaledInstance(width, height, bi.SCALE_SMOOTH);
        // 计算比例
        if ((bi.getHeight() > height) || (bi.getWidth() > width)) {
            if (bi.getHeight() > bi.getWidth()) {
                ratio = (new Integer(height)).doubleValue() / bi.getHeight();
            } else {
                ratio = (new Integer(width)).doubleValue() / bi.getWidth();
            }
            AffineTransformOp op = new AffineTransformOp(AffineTransform
                    .getScaleInstance(ratio, ratio), null);
            itemp = op.filter(bi, null);
        }
        if (bb) {//补白
            BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
            Graphics2D g = image.createGraphics();
            g.setColor(Color.white);
            g.fillRect(0, 0, width, height);
            if (width == itemp.getWidth(null))
                g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2,itemp.getWidth(null), itemp.getHeight(null),
                        Color.white, null);
            else
                g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0,itemp.getWidth(null), itemp.getHeight(null),
                        Color.white, null);
            g.dispose();
            itemp = image;
        }
        ImageIO.write((BufferedImage) itemp, "JPEG", new File(result));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 * 
 * 按指定起点坐标和宽高 进行切割
 * 注意 y+height!= 图片本身的高度,否则会以补白填充。
 * 坐标0,0  是以坐上角开始
 * @date 2016年11月21日
 * @param srcImageFile
 * @param result
 * @param x 
 * @param y
 * @param width
 * @param height
 * void
 */
public void cut(String srcImageFile, String result,
        int x, int y, int width, int height) {
    try {
        // 读取源图像
        BufferedImage bi = ImageIO.read(new File(srcImageFile));
        int srcWidth = bi.getHeight(); // 源图宽度
        int srcHeight = bi.getWidth(); // 源图高度
        if (srcWidth > 0 && srcHeight > 0) {
            Image image = bi.getScaledInstance(srcWidth, srcHeight,Image.SCALE_DEFAULT);
            // 四个参数分别为图像起点坐标和宽高
            // 即: CropImageFilter(int x,int y,int width,int height)
            ImageFilter cropFilter = new CropImageFilter(x, y, width, height);
            Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cropFilter));
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(img, 0, 0, width, height, null); // 绘制切割后的图
            g.dispose();
            // 输出为文件
            ImageIO.write(tag, "JPEG", new File(result));
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/**
 * 
 * 指定切片的行数和列数
 * 
 * @date 2016年11月21日
 * @param srcImageFile
 * @param descDir
 * @param rows
 * @param cols
 * void
 */
public  void cut2(String srcImageFile, String descDir,
        int rows, int cols) {
    try {
        if(rows<=0||rows>20) rows = 2; // 切片行数
        if(cols<=0||cols>20) cols = 2; // 切片列数
        // 读取源图像
        BufferedImage bi = ImageIO.read(new File(srcImageFile));
        int srcWidth = bi.getHeight(); // 源图宽度
        int srcHeight = bi.getWidth(); // 源图高度
        if (srcWidth > 0 && srcHeight > 0) {
            Image img;
            ImageFilter cropFilter;
            Image image = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);
            int destWidth = srcWidth; // 每张切片的宽度
            int destHeight = srcHeight; // 每张切片的高度
            // 计算切片的宽度和高度
            if (srcWidth % cols == 0) {
                destWidth = srcWidth / cols;
            } else {
                destWidth = (int) Math.floor(srcWidth / cols) + 1;
            }
            if (srcHeight % rows == 0) {
                destHeight = srcHeight / rows;
            } else {
                destHeight = (int) Math.floor(srcWidth / rows) + 1;
            }
            // 循环建立切片
            // 改进的想法:是否可用多线程加快切割速度
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    // 四个参数分别为图像起点坐标和宽高
                    // 即: CropImageFilter(int x,int y,int width,int height)
                    cropFilter = new CropImageFilter(j * destWidth, i * destHeight,destWidth, destHeight);
                    img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cropFilter));
                    BufferedImage tag = new BufferedImage(destWidth,destHeight, BufferedImage.TYPE_INT_RGB);
                    Graphics g = tag.getGraphics();
                    g.drawImage(img, 0, 0, null); // 绘制缩小后的图
                    g.dispose();
                    // 输出为文件
                    ImageIO.write(tag, "JPEG", new File(descDir
                            + "_r" + i + "_c" + j + ".jpg"));
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/**
 * 
 * 指定切片的宽度和高度
 * 
 * @date 2016年11月21日
 * @param srcImageFile
 * @param descDir
 * @param destWidth
 * @param destHeight
 * void
 */
public void cut3(String srcImageFile, String descDir,
        int destWidth, int destHeight) {
    try {
        if(destWidth<=0) destWidth = 200; // 切片宽度
        if(destHeight<=0) destHeight = 150; // 切片高度
        // 读取源图像
        BufferedImage bi = ImageIO.read(new File(srcImageFile));
        int srcWidth = bi.getHeight(); // 源图宽度
        int srcHeight = bi.getWidth(); // 源图高度
        if (srcWidth > destWidth && srcHeight > destHeight) {
            Image img;
            ImageFilter cropFilter;
            Image image = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);
            int cols = 0; // 切片横向数量
            int rows = 0; // 切片纵向数量
            // 计算切片的横向和纵向数量
            if (srcWidth % destWidth == 0) {
                cols = srcWidth / destWidth;
            } else {
                cols = (int) Math.floor(srcWidth / destWidth) + 1;
            }
            if (srcHeight % destHeight == 0) {
                rows = srcHeight / destHeight;
            } else {
                rows = (int) Math.floor(srcHeight / destHeight) + 1;
            }
            // 循环建立切片
            // 改进的想法:是否可用多线程加快切割速度
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    // 四个参数分别为图像起点坐标和宽高
                    // 即: CropImageFilter(int x,int y,int width,int height)
                    cropFilter = new CropImageFilter(j * destWidth, i * destHeight,destWidth, destHeight);
                    img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cropFilter));
                    BufferedImage tag = new BufferedImage(destWidth,destHeight, BufferedImage.TYPE_INT_RGB);
                    Graphics g = tag.getGraphics();
                    g.drawImage(img, 0, 0, null); // 绘制缩小后的图
                    g.dispose();
                    // 输出为文件
                    ImageIO.write(tag, "JPEG", new File(descDir
                            + "_r" + i + "_c" + j + ".jpg"));
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
/**
 * 
 * 图像类型转换 
 * 
 * @date 2016年11月21日
 * @param srcImageFile 文件路径
 * @param formatName  转换格式
 * @param destImageFile  文件存储路径
 * void
 */
public void convert(String srcImageFile, String formatName, String destImageFile) {
    try {
        File f = new File(srcImageFile);
        f.canRead();
        f.canWrite();
        BufferedImage src = ImageIO.read(f);
        ImageIO.write(src, formatName, new File(destImageFile));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/**
 * 
 * 彩色图片转黑白
 * 
 * @date 2016年11月21日
 * @param srcImageFile
 * @param destImageFile
 * void
 */
public void gray(String srcImageFile, String destImageFile) {
        try {
            BufferedImage src = ImageIO.read(new File(srcImageFile));
            ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
            ColorConvertOp op = new ColorConvertOp(cs, null);
            src = op.filter(src, null);
            ImageIO.write(src, "JPEG", new File(destImageFile));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 * 
 * 给图片添加文字水印
 * 
 * @date 2016年11月21日
 * @param pressText 水印文字
 * @param srcImageFile 文件路径
 * @param destImageFile 文件保存路径
 * @param fontName 字体名称 例如:宋体
 * @param fontStyle 字体风格
 * @param color 字体颜色
 * @param fontSize 字体大小 
 * @param x 文字的起始坐标
 * @param y
 * @param alpha  文字透明度
 * void
 */
public void pressText(String pressText,
        String srcImageFile, String destImageFile, String fontName,
        int fontStyle, Color color, int fontSize,int x,
        int y, float alpha) {
    try {
        File img = new File(srcImageFile);
        Image src = ImageIO.read(img);
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        g.drawImage(src, 0, 0, width, height, null);
        g.setColor(color);
        g.setFont(new Font(fontName, fontStyle, fontSize));
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,alpha));
        // 在指定坐标绘制水印文字
        g.drawString(pressText, (width - (getLength(pressText) * fontSize))/ 2 + x, (height - fontSize) / 2 + y);
        g.dispose();
        ImageIO.write((BufferedImage) image, "JPEG", new File(destImageFile));// 输出到文件流
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/**
 * 
 * 
 * 
 * @date 2016年11月21日
 * @param pressText 		水印文字
 * @param srcImageFile 		文件路径
 * @param destImageFile 	文件保存路径
 * @param fontName 			字体名称 例如:宋体
 * @param fontStyle 		字体风格
 * @param color 			字体颜色
 * @param fontSize 			字体大小 
 * @param x 				文字的起始坐标
 * @param y
 * @param alpha  			文字透明度
 * void
 */
public void pressText2(String pressText, String srcImageFile,String destImageFile,
        String fontName, int fontStyle, Color color, int fontSize, int x,
        int y, float alpha) {
    try {
        File img = new File(srcImageFile);
        Image src = ImageIO.read(img);
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        g.drawImage(src, 0, 0, width, height, null);
        g.setColor(color);
        g.setFont(new Font(fontName, fontStyle, fontSize));
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,alpha));
        // 在指定坐标绘制水印文字
        g.drawString(pressText, (width - (getLength(pressText) * fontSize))/ 2 + x, (height - fontSize) / 2 + y);
        g.dispose();
        ImageIO.write((BufferedImage) image, "JPEG", new File(destImageFile));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/**
 * 
 * 给图片添加水印图片
 * 
 * @date 2016年11月21日
 * @param pressImg 			水印文件路径
 * @param srcImageFile		原文件路径
 * @param destImageFile		存储文件路径
 * @param x
 * @param y
 * @param alpha				透明度
 * void
 */
public void pressImage(String pressImg, String srcImageFile,String destImageFile,
        int x, int y, float alpha) {
    try {
        File img = new File(srcImageFile);
        Image src = ImageIO.read(img);
        int wideth = src.getWidth(null);
        int height = src.getHeight(null);
        BufferedImage image = new BufferedImage(wideth, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        g.drawImage(src, 0, 0, wideth, height, null);
        // 水印文件
        Image src_biao = ImageIO.read(new File(pressImg));
        int wideth_biao = src_biao.getWidth(null);
        int height_biao = src_biao.getHeight(null);
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
                alpha));
        g.drawImage(src_biao, (wideth - wideth_biao) / 2,
                (height - height_biao) / 2, wideth_biao, height_biao, null);
        // 水印文件结束
        g.dispose();
        ImageIO.write((BufferedImage) image,  "JPEG", new File(destImageFile));
    } catch (Exception e) {
        e.printStackTrace();
    }
}


public static int getLength(String text) {
    int length = 0;
    for (int i = 0; i < text.length(); i++) {
        if (new String(text.charAt(i) + "").getBytes().length > 1) {
            length += 2;
        } else {
            length += 1;
        }
    }
    return length / 2;
}

}

打赏 1 积分后可见
1 积分 • 3 打赏
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3169 引用 • 8207 回帖
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    75 引用 • 258 回帖 • 626 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    89 引用 • 113 回帖
  • abitmean

    有点意思就行了

    24 关注
  • jsDelivr

    jsDelivr 是一个开源的 CDN 服务,可为 npm 包、GitHub 仓库提供免费、快速并且可靠的全球 CDN 加速服务。

    5 引用 • 31 回帖 • 47 关注
  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 549 关注
  • 笔记

    好记性不如烂笔头。

    305 引用 • 780 回帖
  • 大疆创新

    深圳市大疆创新科技有限公司(DJI-Innovations,简称 DJI),成立于 2006 年,是全球领先的无人飞行器控制系统及无人机解决方案的研发和生产商,客户遍布全球 100 多个国家。通过持续的创新,大疆致力于为无人机工业、行业用户以及专业航拍应用提供性能最强、体验最佳的革命性智能飞控产品和解决方案。

    2 引用 • 14 回帖 • 2 关注
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 43 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    941 引用 • 1458 回帖 • 151 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1083 引用 • 3461 回帖 • 286 关注
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    28 引用 • 108 回帖
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖 • 3 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    45 引用 • 113 回帖 • 308 关注
  • CAP

    CAP 指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

    11 引用 • 5 回帖 • 567 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 31 关注
  • AngularJS

    AngularJS 诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。AngularJS 有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等。2.0 版本后已经改名为 Angular。

    12 引用 • 50 回帖 • 427 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    333 引用 • 323 回帖 • 65 关注
  • 反馈

    Communication channel for makers and users.

    123 引用 • 906 回帖 • 193 关注
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 244 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 341 关注
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖
  • 安全

    安全永远都不是一个小问题。

    189 引用 • 813 回帖 • 1 关注
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 55 关注
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 13 关注
  • flomo

    flomo 是新一代 「卡片笔记」 ,专注在碎片化时代,促进你的记录,帮你积累更多知识资产。

    3 引用 • 82 回帖
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖 • 1 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    14 引用 • 7 回帖 • 3 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 521 关注