聊一聊Processing中PImage类和loadImage()、createImage()函数。因为要借P5做多媒体创意展示,图片是一个很重要的媒体。有必要就图片的获取和展放作总结。

首先

有一点需要先提出来,PGraphics是继承自PImage的,看源码:

public class PGraphics extends PImage implements PConstants {
...
}

因此,理论上所有的绘制函数其实它的绘制对象都是PImage,都在这张图纸上呈现内容,即默认的PGraphics g,可参考笔者另一篇:

https://www.cnblogs.com/sharpeye/p/13734132.html

这就给我们一个参考,意思是PGraphicsPImage时常要考虑两者互相转换的问题。实际运行时也是如此。

其次

PImage类中设有混合叠加的方法、图片文件的IO方法,即保存读取方法等,比较常用的是loadPixels()save()filter()等,当然还有许多内部成员变量,比如format width height pixels等等。其中format指的是颜色通道格式,比如有RGB ARGB ALPHA等。save()是可以保存带有alpha通道的图像的。

PImage类要使用必须要new实例对象,一般的,无外乎是使用loadImage()createImage()这两个函数来获得这一对象。如果要读取一张现有的图像信息,那么就load

根据官网说明,loadImage()有两参数可供填写,即:loadImage(filename, extension)

filename指的是本地文件路径或者url文件路径。本地文件路径可以是绝对地址也可以是相对地址。

extension指的是指定文件后缀,即文件类型匹配。如果于真实文件类型不匹配也能读进内存不过通道数据未必能读取,也就是alpha层的问题。文件类型共有几类 ".tga", ".jpg", ".png", ".jpeg", ".gif"等,".tif"无法读取,P5自己的.tiff保存文件是可以的。请见下文例子:

PImage img1;
PImage img2;
PImage webImg;
void setup() {
size(500,500);
img1 = loadImage("mypic.png"); //读取相对路径下的文件,即pde根目录下的文件,如果有data文件夹,则在此文件夹下寻找
img2 = loadImage("d://mypic.png");//读取绝对路径下的文件 String url = "https://processing.org/img/processing-web.png";//读取web互联网上的文件,也可读取局域网下的文件
webImg = loadImage(url, "png");//选定读取的文件类型为png
} void draw() {
background(0); image(img1, 0, 0);
image(img2, 200, 0);
image(webImg, 0, 200);
}

会注意到,读取本地的文件速度非常理想,但是互联网上的文件会根据网络情况产生不少等待时间,给它看成是Processing的假死状态,这是不希望看到的情况,如何来避免呢?有个函数官方给我们了----requstImage()

这个函数就可以避免假死状态,或者称之为非阻塞式读取,而传统读取是阻塞式的。实质上查阅源码会看到它新建了一个thread线程,因此,可以避免占用主线程而耽误往后的语句执行任务。代码如下:


/**
* ( begin auto-generated from requestImage.xml )
*
* This function load images on a separate thread so that your sketch does
* not freeze while images load during <b>setup()</b>. While the image is
* loading, its width and height will be 0. If an error occurs while
* loading the image, its width and height will be set to -1. You'll know
* when the image has loaded properly because its width and height will be
* greater than 0. Asynchronous image loading (particularly when
* downloading from a server) can dramatically improve performance.<br />
* <br/> <b>extension</b> parameter is used to determine the image type in
* cases where the image filename does not end with a proper extension.
* Specify the extension as the second parameter to <b>requestImage()</b>.
*
* ( end auto-generated )
*
* @webref image:loading_displaying
* @param filename name of the file to load, can be .gif, .jpg, .tga, or a handful of other image types depending on your platform
* @param extension the type of image to load, for example "png", "gif", "jpg"
* @see PImage
* @see PApplet#loadImage(String, String)
*/
public PImage requestImage(String filename, String extension) {
// Make sure saving to this file completes before trying to load it
// Has to be called on main thread, because P2D and P3D need GL functions
if (g != null) {
g.awaitAsyncSaveCompletion(filename);
}
PImage vessel = createImage(0, 0, ARGB); // if the image loading thread pool hasn't been created, create it
if (requestImagePool == null) {
ThreadFactory factory = new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r, REQUEST_IMAGE_THREAD_PREFIX);
}
};
requestImagePool = Executors.newFixedThreadPool(4, factory);
}
requestImagePool.execute(() -> {
PImage actual = loadImage(filename, extension); // An error message should have already printed
if (actual == null) {
vessel.width = -1;
vessel.height = -1; } else {
vessel.width = actual.width;
vessel.height = actual.height;
vessel.format = actual.format;
vessel.pixels = actual.pixels; vessel.pixelWidth = actual.width;
vessel.pixelHeight = actual.height;
vessel.pixelDensity = 1;
}
});
return vessel;
}

能发现官方设立了一个线程池接口类ExecutorService,而后新建线程池,每次读取图片都新建一个线程入线程池,统一管理,并用ExecutorService实例的对象来execute执行,从而独立于主线程来执行任务。

再次

光有读取还不完善,来看看自己生成图片对象createImage()。很清楚,三个参数

Parameters
w int: width in pixels 图片对象宽度尺寸
h int: height in pixels 图片对象高度尺寸
format int: Either RGB, ARGB, ALPHA (grayscale alpha channel) 图片类型

官方介绍到,要注意使用规范性,如下:

PImage image = createImage(600,400,RGB);	//正确的实例PImage写法	其中图片通道类型有RGB, ARGB, ALPHA
// *错误* PImage image = new PImage(600,400,RGB); //错误的写法!!

实际上参照源码,就是new PImage的方法实例:

public PImage createImage(int w, int h, int format) {
PImage image = new PImage(w, h, format);
image.parent = this; // make save() work
return image;
}

值得思考的是:

一、 PImage对象改变其像素无外乎要修改其pixels数组值,而不能再图片上直接绘制图形,如果要绘制则必须转换成PGraphics;

二、 如果要复制PImage以实例多个对象,可以使用copy()或者clone(),比如:

PImage op;
PImage op2; try {
op = (PImage)img2.clone(); 使用clone方法 注意转换类型
}
catch(Exception e) {
} op2 = img2.copy(): 使用copy方法

三、 绘制在PGraphics上的方法有三种,一种是image(),一种是set(),还有一种是手动以遍历像素的形式来绘制渲染。如下:

  image(img1, 100, 0);
image(img2, 200, 0);
image(webImg, 0, 200); //使用image方法 set(0,0,img2); //使用set方法 loadPixels();
img1.loadPixels();
for (int x = 0; x < img1.width; x++) {
for (int y = 0; y < img1.height; y++) {
color c = img1.pixels[y*img1.width + x];
if(alpha(c) == 0) continue; //alpha通道检测
pixels[y*width + x] = c ; //相当于 g.pixels[]... 使用了pixels数组直接赋值
}
}
updatePixels(); //************************************// 另一种手动填充像素 set
img1.loadPixels();
for (int x = 0; x < img1.width; x++) {
for (int y = 0; y < img1.height; y++) {
color c = img1.pixels[y*img1.width + x];
//if(alpha(c) == 0) continue; 使用set方法 alpha通道检测可跳过
set(x,y,c); //使用set方法 注意使用set方法跟updatePixels方法有冲突,这里去掉其调用
}
}
//************************************//

最后

当然,在实际使用中,会用到大量技巧,比如image()set()两函数渲染图片效率有出入,一般可以用set()来提高渲染效率,但是无法进行矩阵变换等运算。再如,PImage中的save()可以保存带通道的图片。这次就简单做一总结,我们往后再细聊,感谢阅读!!

Processing中PImage类和loadImage()、createImage()函数的相关解析的更多相关文章

  1. C++中模板类使用友元模板函数

    在类模板中可以出现三种友元声明:(1)普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数.(2)类模板或函数模板的友元声明,授予对友元所有实例的访问权.(3)只授予对类模板或函数模板的特定 ...

  2. 【转】doxygen+graphviz生成工程中的类继承树及函数调用图

    转自----hequn8128 在阅读代码量比较多的项目时,类的继承树和函数调用图能够直观地向我们显示类之间或者函数之间的各种关系,方便我们了解程序的整体框架,很多时候可以起到事半功倍的作用.这里尝试 ...

  3. Java中Collections类的排序sort函数两种用法

    java中的Colletions类主要实现列表List的排序功能.根据函数参数的传递,具体的排序可以分为 : 1.  自然排序(natural ordering). 函数原型:sort(List< ...

  4. JAVA中String类的方法(函数)总结--JAVA基础

    1.concat()方法,当参数为两字符串时,可实现字符串的连接: package cn.nxl123.www; public class Test { public static void main ...

  5. php中常用的字符串大小写转换函数实例解释

    PHP字符串处理函数中,最为简单的几个函数,相关解释就不上了,直接看例子. PHP字符串处理函数中,最为简单的几个函数,相关解释就不上了,直接看例子. strtolower函数.strtoupper函 ...

  6. Oracle数据库中调用Java类开发存储过程、函数的方法

    Oracle数据库中调用Java类开发存储过程.函数的方法 时间:2014年12月24日  浏览:5538次 oracle数据库的开发非常灵活,不仅支持最基本的SQL,而且还提供了独有的PL/SQL, ...

  7. (转) C++中基类和派生类之间的同名函数的重载问题

    下面有关派生类与基类中存在同名函数 fn: class A { public: void fn() {} void fn(int a) {} }; class B : public A { publi ...

  8. C++类中的静态成员变量与静态成员函数

    最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下. 静态成员的概念: 静态 ...

  9. C++中的类继承(2)派生类的默认成员函数

    在继承关系里面, 在派生类中如果没有显示定义这六个成员 函数, 编译系统则会默认合成这六个默认的成员函数. 构造函数. 调用关系先看一段代码: class Base { public : Base() ...

随机推荐

  1. 面向对象JML系列作业总结

    面向对象JML系列作业总结 一.综述 本单元作业,由简到难地迭代式实现了三种JML需求,主要学习了面向规格的编程方法. 第一次:实现Path类和PathContainer类 第二次:继承PathCon ...

  2. JMM——Java内存模型抽象|八种同步操作|操作规则

    JMM 调用栈&本地变量在线程栈上 对象整体在堆上(包括其本地变量,不论类型),栈有其引用即可访问, 线程调用同一个对象时,是访问该对象的私有拷贝 每个CPU有自己的高速缓存 高速缓存存在意义 ...

  3. Node.js核心模块API之文件操作

    参考:https://www.runoob.com/nodejs/nodejs-fs.html 异步I/O 1,文件操作 2,网络操作 在浏览器中也存在异步操作 1,定时任务 2,事件处理 3,Aja ...

  4. 驰骋CCFlow开源工作流程引擎如何设置PDF打印

    前言 经常有驰骋CCFlow爱好者朋友提问关于打印相关问题.在这篇博文中大家介绍一下工作流引擎CCFlow的HTML打印和PDF打印,针对Java版本和.NET版本有不同的操作步骤,包括开关设置.水印 ...

  5. Linux信号与golang中的捕获处理

    什么是信号 在计算机科学中,信号是Unix.类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式.它是一种异步的通知机制,用来提醒进程一个事件已经发生. 当一个信号发送给一个进程, ...

  6. [Linux] Linux C编程一站式学习 Part.2

    C语言本质 计算机中数的表示 浮点数:符号位+指数部分(2的多少次方)+尾数部分(小数点后的数字) 用偏移的指数(Biased Exponent)表示负指数 正规化(Normalize):尾数部分最高 ...

  7. [转载]centos 7(1611)安装笔记

    centos 7(1611)安装笔记   麻烦 前天我把双系统笔记本里的 deepin 的磁盘分区直接从 Windows 7 磁盘管理里格式化了,结果悲催了,开不了机了,显示: 我以为是 Window ...

  8. 进入除错模式!进入此模式后,将会出现更多的选项,分别是: · 以基本图形介面安装 CentOS 7 (使用标准显卡来设定安装流程图示); · 救援Centos系统; · 执行内存测试(Run a memory test);

    Centos 7.3 安装 0.0392017.07.14 20:12:09字数 1550阅读 985 Centos 7.3 基于 Red Hat 企业版的源代码的最新版本的 CentOS 7 在今年 ...

  9. Linux服务之DHCP服务篇(scp)

    一.概念 名称:DHCP----Dynamic Host Configuration Protocol 动态主机配置协议 功能:DHCP是一个局域网的网络协议,使用UDP协议工作 主要用途:给内部网络 ...

  10. shell进阶之tree、pstree、lsof命令详解

    一.tree命令详解: 主要功能是创建文件列表,将所有文件以树的形式列出来 -a 显示所有文件和目录. -A 使用ASNI绘图字符显示树状图而非以ASCII字符组合. -C 在文件和目录清单加上色彩, ...