探索Apache Commons Imaging处理图像

第1章:引言

大家好,我是小黑,咱们今天来聊聊图像处理。在这个数字化日益增长的时代,图像处理已经成为了一个不可或缺的技能。不论是社交媒体上的照片编辑,还是专业领域的图像分析,图像处理无处不在。而作为一名Java开发者,小黑自然也对这一领域充满了兴趣。

为什么要选择Apache Commons Imaging(原名Sanselan)来进行图像处理呢?原因很简单:它是一个纯Java的库,不仅功能强大,而且使用起来非常方便。这个库支持广泛的图像格式,从常见的JPEG、PNG到专业的TIFF、PSD等,都能轻松处理。最重要的是,它的开源特性让咱们可以深入了解其内部工作机制,更好地掌握图像处理的精髓。

第2章:Apache Commons Imaging简介

Apache Commons Imaging,之前被称为Sanselan,是一个开源的Java图像库,主要用于读取、写入和操作图像数据。这个库的强大之处在于它对多种格式的图像文件都有很好的支持,比如JPEG、PNG、GIF、BMP,甚至还包括一些不太常见的格式,比如TIFF、PSD等。

为了让咱们更好地理解这个库的使用,小黑会在本篇博客中通过一系列的实际案例来展示它的功能。这样不仅能让咱们更加直观地了解Apache Commons Imaging,还能帮助咱们在实际项目中快速应用这些技巧。

咱们来看看如何在Java项目中添加Apache Commons Imaging。一般来说,如果咱们使用的是Maven来管理项目,只需在pom.xml文件中添加以下依赖:

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-imaging</artifactId><version>1.0-alpha2</version>
</dependency>

接下来,小黑会展示一个简单的示例,让咱们看看如何使用Apache Commons Imaging来读取一个图像文件。假设咱们有一个名为“测试图片.jpg”的图像文件,想要读取它并获取一些基本信息,可以使用以下代码:

import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.ImagingException;import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;public class ImageReaderExample {public static void main(String[] args) {try {File imageFile = new File("测试图片.jpg");BufferedImage image = Imaging.getBufferedImage(imageFile);// 输出基本信息System.out.println("图像格式: " + Imaging.guessFormat(imageFile));System.out.println("宽度: " + image.getWidth());System.out.println("高度: " + image.getHeight());} catch (ImagingException | IOException e) {e.printStackTrace();}}
}

在这段代码中,咱们首先读取了一个名为“测试图片.jpg”的文件,然后使用Imaging.getBufferedImage方法将其转换为BufferedImage对象。之后,咱们打印出了这个图像的格式、宽度和高度等信息。

第3章:依赖配置

对于使用Maven作为项目管理工具的情况,只需要在项目的pom.xml文件中添加相应的依赖。这里的依赖版本可能会随着时间更新,所以建议到Apache Commons Imaging的官方网站查看最新版本。下面是一个示例的依赖配置:

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-imaging</artifactId><version>1.0-alpha2</version> <!-- 这里的版本号需要根据最新版本进行调整 -->
</dependency>

加入这段依赖后,Maven会自动处理所需库的下载和管理。接下来,咱们来看看如何使用这个库来进行一些基本的图像操作。比如说,读取一张图像并显示其基本信息,这是图像处理中最基础的一步。

import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.common.ImageMetadata;
import org.apache.commons.imaging.common.ImageMetadata.ImageMetadataItem;
import java.io.File;
import java.util.List;public class BasicImageInfo {public static void main(String[] args) {try {File imageFile = new File("测试图片.jpg"); // 图像文件路径List<ImageMetadataItem> metadata = Imaging.getMetadata(imageFile).getItems();for (ImageMetadataItem item : metadata) {System.out.println(item.toString()); // 打印图像的元数据}} catch (Exception e) {e.printStackTrace();}}
}

在这个例子中,小黑使用了Imaging.getMetadata方法来获取图像文件的元数据,并逐个打印出来。这种操作对于理解图像的属性,比如相机设置、拍摄时间等信息非常有用。

图像处理不仅仅是关于读取信息,还包括修改、转换等多种操作。为了进行这些操作,咱们需要确保环境搭建正确无误。在实际开发中,可能会遇到各种问题,比如依赖冲突、版本不兼容等。这时候,查看官方文档、搜索相关问题解决方案或者在社区寻求帮助是非常必要的。

通过以上步骤,咱们就能够在Java项目中成功集成Apache Commons Imaging,并进行基础的图像处理操作了。

第4章:读取和写入图像

读取图像

读取图像是开始任何图像处理任务的第一步。在Apache Commons Imaging中,这个过程非常直观。咱们可以使用Imaging.getBufferedImage方法来读取图像文件。让小黑来展示一下这个过程:

import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.ImagingException;import java.io.File;
import java.awt.image.BufferedImage;public class ReadImageExample {public static void main(String[] args) {try {File imageFile = new File("测试图片.jpg"); // 图像文件路径BufferedImage image = Imaging.getBufferedImage(imageFile);System.out.println("图像宽度: " + image.getWidth());System.out.println("图像高度: " + image.getHeight());// 这里可以添加更多的操作,比如分析图像内容等} catch (ImagingException | IOException e) {e.printStackTrace();}}
}

在这个例子中,小黑首先创建了一个指向图像文件的File对象。然后,使用Imaging.getBufferedImage方法读取这个文件,并将其转换为一个BufferedImage对象。这样就可以获取到图像的宽度、高度等基本信息了。

写入图像

读取图像之后,通常咱们可能会对图像进行一系列处理,如调整大小、应用滤镜等。处理完成后,接下来的任务就是将修改后的图像保存回文件。下面是一个简单的示例,展示如何将处理后的图像写入文件:

import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.ImagingException;import java.io.File;
import java.awt.image.BufferedImage;public class WriteImageExample {public static void main(String[] args) {try {File inputFile = new File("原始图片.jpg");BufferedImage image = Imaging.getBufferedImage(inputFile);// 在这里可以对image进行各种处理...File outputFile = new File("处理后的图片.jpg");Imaging.writeImage(image, outputFile, ImageFormats.JPEG, null);System.out.println("图像保存成功!");} catch (ImagingException | IOException e) {e.printStackTrace();}}
}

在这个例子中,小黑先读取了一个名为“原始图片.jpg”的文件,进行了一些假设的处理(比如调整大小、应用滤镜等),然后将处理后的图像保存为“处理后的图片.jpg”。这里使用了Imaging.writeImage方法,它允许咱们指定图像格式和一些写入参数。

第5章:图像转换和处理

图像格式转换

在日常工作中,咱们经常需要将图像从一种格式转换成另一种格式。比如,可能需要把PNG格式的图片转换成JPEG格式,以便于网络传输或者兼容性更好。小黑这就来展示一个简单的格式转换过程:

import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.ImagingException;import java.io.File;
import java.awt.image.BufferedImage;public class ImageFormatConversion {public static void main(String[] args) {try {File inputFile = new File("原始图片.png");BufferedImage image = Imaging.getBufferedImage(inputFile);File outputFile = new File("转换后的图片.jpg");Imaging.writeImage(image, outputFile, ImageFormats.JPEG, null);System.out.println("格式转换完成!");} catch (ImagingException | IOException e) {e.printStackTrace();}}
}

在这个例子中,小黑首先读取了一个PNG格式的图像文件“原始图片.png”,然后使用Imaging.writeImage方法将其保存为JPEG格式的文件“转换后的图片.jpg”。这个过程非常简单,但在实际应用中却非常有用。

基本图像处理

除了格式转换,咱们还可以进行一些基本的图像处理操作,比如调整图像大小、裁剪、旋转等。下面是一个调整图像大小的示例:

import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.ImagingException;import java.io.File;
import java.awt.image.BufferedImage;public class ResizeImage {public static void main(String[] args) {try {File inputFile = new File("原始图片.jpg");BufferedImage image = Imaging.getBufferedImage(inputFile);BufferedImage resizedImage = resizeImage(image, 200, 200); // 调整为200x200像素File outputFile = new File("调整大小后的图片.jpg");Imaging.writeImage(resizedImage, outputFile, ImageFormats.JPEG, null);System.out.println("图像大小调整完成!");} catch (ImagingException | IOException e) {e.printStackTrace();}}private static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws IOException {BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);Graphics2D graphics2D = resizedImage.createGraphics();graphics2D.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);graphics2D.dispose();return resizedImage;}
}

在这个例子中,小黑创建了一个名为resizeImage的方法,它接受一个BufferedImage对象和目标宽高,返回一个调整大小后的新图像。这种操作在处理用户上传的图片或者为网页准备缩略图时非常有用。

第6章:元数据处理

读取元数据

在Apache Commons Imaging中,读取图像元数据是一个简单而强大的过程。咱们可以获取到很多有关图像的详细信息。下面是一个读取JPEG图像元数据的示例:

import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.common.ImageMetadata;
import org.apache.commons.imaging.common.ImageMetadata.ImageMetadataItem;
import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;import java.io.File;
import java.util.List;public class ReadMetadataExample {public static void main(String[] args) {try {File jpegImageFile = new File("测试图片.jpg");final ImageMetadata metadata = Imaging.getMetadata(jpegImageFile);final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;if (jpegMetadata != null) {// 打印所有元数据项List<ImageMetadataItem> items = jpegMetadata.getItems();for (ImageMetadataItem item : items) {System.out.println(item);}// 获取特定的元数据项,例如拍摄时间String shootingTime = jpegMetadata.findEXIFValueWithExactMatch(TiffTagConstants.TIFF_TAG_DATE_TIME).toString();System.out.println("拍摄时间: " + shootingTime);}} catch (Exception e) {e.printStackTrace();}}
}

在这个示例中,小黑读取了一个JPEG图像文件的元数据,并打印出了所有的元数据项。此外,还特别获取了拍摄时间这一具体的元数据信息。这对于管理大量图像,尤其是对于摄影师来说,是非常有用的。

修改和添加元数据

除了读取元数据,Apache Commons Imaging还允许咱们修改或添加新的元数据信息。这对于个性化图像处理、版权信息添加等场景非常有用。不过,需要注意的是,修改元数据是一个相对复杂的过程,涉及到图像格式和元数据标准的深入理解。

由于修改元数据是一个相对复杂的过程,涉及到直接操作图像的底层数据,所以这个例子将会相对复杂一些。不过别担心,小黑会尽量用清晰的注释来说明每一步的作用。

import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.ImageWriteException;
import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.common.ImageMetadata;
import org.apache.commons.imaging.common.RationalNumber;
import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter;
import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;
import org.apache.commons.imaging.formats.tiff.TiffOutputDirectory;
import org.apache.commons.imaging.formats.tiff.TiffOutputField;
import org.apache.commons.imaging.formats.tiff.TiffOutputSet;
import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;public class ModifyMetadataExample {public static void main(String[] args) {try {File jpegImageFile = new File("测试图片.jpg");File outputFile = new File("修改元数据后的图片.jpg");OutputStream os = null;try {TiffOutputSet outputSet = null;// 尝试读取图像的元数据final ImageMetadata metadata = Imaging.getMetadata(jpegImageFile);final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;if (jpegMetadata != null) {final TiffImageMetadata exif = jpegMetadata.getExif();if (exif != null) {outputSet = exif.getOutputSet();}}// 如果JPEG图像没有Exif元数据,则创建一个新的输出集if (outputSet == null) {outputSet = new TiffOutputSet();}// 添加自定义注释final TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory();exifDirectory.add(TiffOutputField.create(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION, outputSet.byteOrder, "自定义注释"));// 修改现有元数据,例如修改拍摄时间exifDirectory.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);exifDirectory.add(TiffOutputField.create(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, outputSet.byteOrder, "2023:01:01 00:00:00"));os = new FileOutputStream(outputFile);new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os, outputSet);} finally {if (os != null) {try {os.close();} catch (IOException e) {// 忽略关闭异常}}}System.out.println("元数据修改完成!");} catch (ImageReadException | ImageWriteException | IOException e) {e.printStackTrace();}}
}

在这个代码中,小黑首先尝试从原始JPEG图像中读取元数据。如果图像包含Exif元数据,小黑将使用这些元数据来创建一个TiffOutputSet对象。接着,小黑在Exif目录中添加了一个自定义的注释字段,并修改了拍摄时间字段。最后,使用ExifRewriter类的updateExifMetadataLossless方法将修改后的元数据写回到一个新的JPEG文件中。

这个过程显示了如何在不损失图像质量的情况下,修改JPEG图像的Exif元数据。这对于添加版权信息、个性化标签或其他重要信息到图像中非常有用。不过,需要注意的是,操作元数据时要格外小心,因为错误的操作可能会损坏图像文件。

第7章:错误处理和性能优化

错误处理

在进行图像处理时,常常会遇到各种错误,比如文件格式不支持、文件损坏、内存不足等。正确地处理这些错误可以提高程序的健壮性和用户体验。小黑来展示一个基本的错误处理示例:

import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.ImagingException;import java.io.File;
import java.awt.image.BufferedImage;public class ErrorHandlingExample {public static void main(String[] args) {try {File imageFile = new File("可能不存在的图片.jpg");BufferedImage image = Imaging.getBufferedImage(imageFile);// 进行一些图像处理操作...} catch (ImagingException e) {System.err.println("图像处理错误: " + e.getMessage());// 这里可以记录日志或者通知用户错误信息} catch (IOException e) {System.err.println("文件读写错误: " + e.getMessage());// 处理文件读写异常} catch (Exception e) {System.err.println("未知错误: " + e.getMessage());// 处理其他未预见的异常}}
}

在这个例子中,小黑尝试读取一个图像文件,并在此过程中捕获可能出现的异常。根据不同类型的异常,程序会输出相应的错误信息。这种做法可以帮助调试程序,并在出现问题时提供更清晰的指示。

性能优化

在图像处理中,性能优化同样至关重要。尤其是处理大量或高分辨率的图像时,效率成为一个不容忽视的问题。下面小黑会介绍一些基本的性能优化技巧。

  1. 合理管理内存: 图像处理通常是内存密集型的操作。对于大图像,尽量使用缩放或分块处理的方式来减少内存占用。

  2. 避免不必要的重复读写: 读取和写入图像是耗时操作。如果需要对同一图像执行多个操作,考虑先将图像读入内存,完成所有处理后再统一写回。

  3. 利用多线程: 当处理多个图像时,可以考虑使用多线程来并行处理,以提高效率。

  4. 调整缓存和IO策略: 根据实际需要调整缓存策略和IO操作,避免频繁的磁盘访问。

这些只是一些基础的性能优化建议。在实际应用中,根据具体的需求和环境,还可以采取更多的优化措施。

第8章:总结

实际应用案例
  1. 社交媒体自动化工具: 假设你在开发一个社交媒体管理工具,需要自动调整上传图片的大小和格式。使用Apache Commons Imaging,你可以轻松实现这一功能,确保每张图片都符合社交媒体平台的要求。

  2. 数字图像存档系统: 在数字图像存档系统中,保留图像的元数据信息非常重要。Apache Commons Imaging可以帮助你读取和编辑这些信息,确保每张图像都有正确的描述、版权信息和拍摄日期。

  3. 个性化图像生成器: 想象一下,你在为一个广告公司工作,需要生成大量包含特定文本和图案的图像。利用Apache Commons Imaging,你可以自动化这一过程,为每个客户快速定制个性化图像。

通过这些实际应用案例,我们可以看到Apache Commons Imaging在不同场景下的灵活性和实用性。无论你是在处理个人项目,还是开发复杂的商业应用,这个库都能提供强大的支持。

小黑希望你已经对Apache Commons Imaging有了全面的了解。通过这系列文章,我们一起深入探索了它的主要功能和应用场景。图像处理是一个既有趣又充满挑战的领域,而Apache Commons Imaging则是一把强大的工具,帮助你在这个领域里游刃有余。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/226485.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

再谈动态SQL

专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 文章目录 专栏精选摘要引言正文动态sql标签ifchoose...when...otherwisewhere、…

【XR806开发板试用】XR806串口驱动CM32M对小厨宝的控制实验

一.说明 非常感谢基于安谋科技STAR-MC1的全志XR806 Wi-FiBLE开源鸿蒙开发板试用活动,并获得开发板试用。 XR806是全志科技旗下子公司广州芯之联研发设计的一款支持WiFi和BLE的高集成度无线MCU芯片&#xff0c;支持OpenHarmony minisystem和FreeRTOS&#xff0c;具有集成度高、…

什么是骨传导耳机?骨传导能保护听力吗?

骨传导耳机是一种非常特殊的蓝牙耳机&#xff0c;它通过骨传导技术将声音直接传送到内耳。这种技术不同于传统耳机&#xff0c;它不通过空气传送声音&#xff0c;而是通过头骨的振动来传送声音。 并且骨传导耳机能够在一定程度上起到保护听力的作用&#xff0c;主要是因为它们不…

python统计分析——单变量描述统计

资料来源于&#xff1a;用Python动手学统计学 1、求和 numpy.sum()&#xff1a;要求求和的对象为数组格式。 也可以使用python的标准函数sum()。 2、平均数 numpy.mean() 3、计数 len() 4、方差 np.var()&#xff1b; 注意ddof的参数设置。ddof即Delta Degrees of Fr…

uniapp:全局消息是推送,实现app在线更新,WebSocket,apk上传

全局消息是推送&#xff0c;实现app在线更新&#xff0c;WebSocket 1.在main.js中定义全局的WebSocket2.java后端建立和发送WebSocket3.通知所有用户更新 背景&#xff1a; 开发人员开发后app后打包成.apk文件&#xff0c;上传后通知厂区在线用户更新app。 那么没在线的怎么办&…

Linux中的gcc\g++使用

文章目录 gcc\g的使用预处理编译汇编链接函数库gcc选项 gcc\g的使用 这里我们需要知道gcc和g实际上是对应的c语言和c编译器&#xff0c;而其他的Java&#xff08;半解释型&#xff09;&#xff0c;PHP&#xff0c;Python等语言实际上是解释型语言&#xff0c;因此我们经常能听…

DML语言(重点)———update

格式&#xff1a;update 要修改的对象 set 原来的值新值 -- 修改学员名字,带了简介 代码案例&#xff1a; -- 修改学员名字,带了简介 UPDATE student SET name清宸 WHERE id 1; -- 不指定条件情况下&#xff0c;会改动所有表&#xff01; 代码案例…

边缘计算网关:在智慧储能系统中做好储能通信管家

背景 目前储能系统主要由储能单元和监控与调度管理单元组成&#xff0c;储能单元包含储能电池组(BA)、电池管理系统(BMS)、储能变流器(PCS)等&#xff1b;监控与调度管理单元包括中央控制系统(MGCC)、能量管理系统(EMS)等。 2021年8月&#xff0c;国家发改委发布《电化学储能…

Vscode新手安装与使用

安装与版本选择 VS Code 有两个不同的发布渠道&#xff1a;一个是我们经常使用的稳定版&#xff08;Stable&#xff09;&#xff0c;每个月发布一个主版本&#xff1b;另外一个发布渠道叫做 Insiders&#xff0c;每周一到周五 UTC 时间早上6点从最新的代码发布一个版本&#x…

基于Java车间工时管理系统(源码+部署文档)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

【银行测试】金融银行-理财项目面试/分析总结(二)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 银行理财相关的项…

Redis 分布式锁总结

在一个分布式系统中&#xff0c;由于涉及到多个实例同时对同一个资源加锁的问题&#xff0c;像传统的synchronized、ReentrantLock等单进程情况加锁的api就不再适用&#xff0c;需要使用分布式锁来保证多服务实例之间加锁的安全性。常见的分布式锁的实现方式有zookeeper和redis…

044、门控

之——GRU 目录 之——GRU 杂谈 正文 1.重置门和更新门 2.候选隐藏状态 3.新的隐状态 长短期记忆网络LSTM 1.候选记忆单元 2.记忆单元 3.隐状态 杂谈 关注一个序列&#xff0c;不是每个观察都同等重要&#xff0c;传统RNN会一直在Whh中隐含所有以前的信息&#xff0…

【LeetCode:LCR 143. 子结构判断 | 二叉树 + 递归】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

【12.28】转行小白历险记-刷算法04

01两两交换链表中的节点 整体思路 1.要修改后一个节点的指向一定要知道前一个节点的指向才可以改变后面一个节点的 2.分情况奇数和偶数节点&#xff0c;终止条件很重要 3.虚拟头节点&#xff0c;是对我们操作的指针是不是头节点进行判断 02删除链表的倒数第N个节点 思路 …

第十一章 Stream消息驱动

Stream消息驱动 gitee:springcloud_study: springcloud&#xff1a;服务集群、注册中心、配置中心&#xff08;热更新&#xff09;、服务网关&#xff08;校验、路由、负载均衡&#xff09;、分布式缓存、分布式搜索、消息队列&#xff08;异步通信&#xff09;、数据库集群、…

fastadmin想自定义表格的样式,可以使用模板渲染并在模板中调用自定义的方法

fastadmin 如何在模板中使用自定义的方法 比如页面上要对返回的时间&#xff0c;电话&#xff0c;身份证做处理 html页面 <script type"text/html" id"itemtpl"><span id"<%item.id%>" class"margins mobile"><…

企业品牌推广在国外媒体投放的意义和作用何在?

海外广告投放是企业在国际市场推广的重要战略&#xff0c;具有多种形式&#xff0c;包括社交媒体广告、短视频广告、电视广告等。这些广告形式在传播信息、推动销售、塑造品牌形象等方面发挥着独特的作用。 其中软文发稿是一种注重叙事和信息传递的广告形式&#xff0c;对于企…

【pynput】鼠标行为追踪并模拟

文章目录 前言基本思路安装依赖包实时鼠标捕获捕获鼠标位置捕获鼠标事件记录点击内容效果图 实时按键捕获控制按键操作捕获按键事件组合键记录区间设置 用户操作记录与回溯基本思路完整代码效果图 利用本文内容从事的任何犯法行为和开发与本人无关&#xff0c;请理性利用技术服…

【强化学习】基于蒙特卡洛MC与时序差分TD的简易21点游戏应用

1. 本文将强化学习方法&#xff08;MC、Sarsa、Q learning&#xff09;应用于“S21点的简单纸牌游戏”。 类似于Sutton和Barto的21点游戏示例&#xff0c;但请注意&#xff0c;纸牌游戏的规则是不同且非标准的。 2. 为方便描述&#xff0c;过程使用代码截图&#xff0c;文末附链…