当前位置: 首页 > news >正文

在MIDP2.0中操作图片像素

作者:chenyi 文章来源:chenyis blog

正文


我们知道,在MIDP1.0中,除非我们利用特定厂商的API(比如Nokia),我们是没法对图片的像素进行操作的,但是在MIDP2.0中,Image和Graphics的功能都大大增强了。比如,我们可以获取Image的所有像素值,然后利用程序来修改这些像素(比如说ARGB各自的值),最后再把修改后的像素图绘制出来。通过直接操作图片像素,我们就获得了一种很强大的能力,用编程的方式实现出很多有趣的效果来,而不用额外制作新图片。比如说透明度渐变,颜色反转等。下面就是2个例子,分别实现透明度渐变和颜色反转的功能。

例题一:透明度渐变效果的实现


给定一张图片,假如我们想实现这么一种效果:图片由全透明状态逐渐清晰,最后达到正常状态。要实现这一个过程,我们首先要获取该图片的所有像素值,逐步让这些像素的alpha值从0转变到正常,每改变图片的所有像素值一次,我们就请求刷屏一次,把最新的像素图画出来,这样我们就能实现透明度渐变的效果了。代码实现如下:

  1. importjava.io.IOException;
  2. importjavax.microedition.lcdui.Canvas;
  3. importjavax.microedition.lcdui.Display;
  4. importjavax.microedition.lcdui.Graphics;
  5. importjavax.microedition.lcdui.Image;
  6. importjavax.microedition.midlet.MIDlet;
  7. importjavax.microedition.midlet.MIDletStateChangeException;
  8. /**
  9. *
  10. *@authorJagie
  11. *
  12. */
  13. publicclassShadowMIDletextendsMIDlet{
  14. Canvasc=newShadowCanvas();
  15. publicShadowMIDlet(){
  16. }
  17. protectedvoidstartApp()throwsMIDletStateChangeException{
  18. Display.getDisplay(this).setCurrent(c);
  19. }
  20. protectedvoidpauseApp(){
  21. //TODOAuto-generatedmethodstub
  22. }
  23. protectedvoiddestroyApp(booleanarg0)throwsMIDletStateChangeException{
  24. //TODOAuto-generatedmethodstub
  25. }
  26. }
  27. /**
  28. *
  29. *@authorJagie
  30. *
  31. */
  32. classShadowCanvasextendsCanvasimplementsRunnable{
  33. intw,h;
  34. //原始图片
  35. ImagesrcImage;
  36. //原始图片的像素数组
  37. int[]srcRgbImage;
  38. //渐变图片的像素数组
  39. int[]shadowRgbImage;
  40. intimgWidth,imgHeight;
  41. intcount;
  42. publicShadowCanvas(){
  43. w=this.getWidth();
  44. h=this.getHeight();
  45. try{
  46. srcImage=Image.createImage("/av.png");
  47. }catch(IOExceptione){
  48. //TODOAuto-generatedcatchblock
  49. e.printStackTrace();
  50. }
  51. imgWidth=srcImage.getWidth();
  52. imgHeight=srcImage.getHeight();
  53. //制造原始图片的像素数组,用一个int来代表每一个像素,按位表示方式是:0xAARRGGBB
  54. srcRgbImage=newint[imgWidth*imgHeight];
  55. //获取原始图片的所有像素,参见MIDPAPPI文档
  56. srcImage.getRGB(srcRgbImage,0,imgWidth,0,0,imgWidth,imgHeight);
  57. shadowRgbImage=newint[srcRgbImage.length];
  58. System.arraycopy(srcRgbImage,0,shadowRgbImage,0,
  59. shadowRgbImage.length);
  60. //渐变图片的所有像素已开始都是全透明的
  61. for(inti=0;i<shadowRgbImage.length;i++){
  62. shadowRgbImage[i]&=0x00ffffff;
  63. }
  64. newThread(this).start();
  65. }
  66. publicvoidpaint(Graphicsg){
  67. g.setColor(0,0,0);
  68. g.fillRect(0,0,w,h);
  69. //绘制渐变图片
  70. g.drawRGB(shadowRgbImage,0,imgWidth,(w-imgWidth)/2,
  71. (h-imgHeight)/2,imgWidth,imgHeight,true);
  72. g.setColor(0,255,0);
  73. g.drawString("count="+count,w/2,30,Graphics.HCENTER
  74. |Graphics.TOP);
  75. }
  76. publicvoidrun(){
  77. while(true){
  78. booleanchanged=false;
  79. //改变渐变图片的每一个像素
  80. for(inti=0;i<shadowRgbImage.length;i++){
  81. //获取渐变图片的某一像素的alpha值
  82. intalpha=(shadowRgbImage[i]&0xff000000)>>>24;
  83. //原始图片的对应像素的alpha值
  84. intoldAlpha=(srcRgbImage[i]&0xff000000)>>>24;
  85. if(alpha<oldAlpha){
  86. //alpha值++
  87. shadowRgbImage[i]=((alpha+1)<<24)
  88. |(shadowRgbImage[i]&0x00ffffff);
  89. changed=true;
  90. }
  91. }
  92. try{
  93. Thread.sleep(10);
  94. }catch(InterruptedExceptione){
  95. //TODOAuto-generatedcatchblock
  96. e.printStackTrace();
  97. }
  98. count++;
  99. repaint();
  100. //当所有像素的alpha值都达到原始值后,线程运行结束
  101. if(!changed){
  102. System.out.println("over");
  103. break;
  104. }
  105. }
  106. }
  107. }


透明度渐变效果如下:


例题二:颜色反转


在手机游戏中,我们经常会碰上这样一种情况,比如我方飞机和敌方飞机外观是完全一样的,唯一的区别就是颜色不同,比如说敌方飞机是红色的,而我方飞机是绿色的。在MIDP1.0中,我们就只好制作2张图片来表示2种飞机,自然,这样会造成jar空间的极大浪费。但是在MIDP2.0中,通过对图片直接进行像素操作,反转RGB中的一个值,我们只需要一张图片就够了,样例代码如下:

ColorMIDlet.java


  1. importjava.io.IOException;
  2. importjavax.microedition.lcdui.Canvas;
  3. importjavax.microedition.lcdui.Display;
  4. importjavax.microedition.lcdui.Graphics;
  5. importjavax.microedition.lcdui.Image;
  6. importjavax.microedition.midlet.MIDlet;
  7. importjavax.microedition.midlet.MIDletStateChangeException;
  8. /**
  9. *
  10. *@authorJagie
  11. *
  12. */
  13. publicclassColorMIDletextendsMIDlet{
  14. Canvasc=newColorCanvas();
  15. publicColorMIDlet(){
  16. super();
  17. //TODOAuto-generatedconstructorstub
  18. }
  19. protectedvoidstartApp()throwsMIDletStateChangeException{
  20. Display.getDisplay(this).setCurrent(c);
  21. }
  22. protectedvoidpauseApp(){
  23. //TODOAuto-generatedmethodstub
  24. }
  25. protectedvoiddestroyApp(booleanarg0)throwsMIDletStateChangeException{
  26. //TODOAuto-generatedmethodstub
  27. }
  28. }
  29. /**
  30. *
  31. *@authorJagie
  32. *
  33. */
  34. classColorCanvasextendsCanvas{
  35. ImagesrcImage;
  36. int[]targetImage1;
  37. int[]targetImage2;
  38. publicColorCanvas(){
  39. try{
  40. srcImage=Image.createImage("/av.png");
  41. }catch(IOExceptione){
  42. //TODOAuto-generatedcatchblock
  43. e.printStackTrace();
  44. }
  45. targetImage1=GraphicsUtil.flipImageColor(srcImage,
  46. GraphicsUtil.SHIFT_RED_TO_BLUE);
  47. targetImage2=GraphicsUtil.flipImageColor(srcImage,
  48. GraphicsUtil.SHIFT_RED_TO_GREEN);
  49. }
  50. publicvoidpaint(Graphicsg){
  51. g.setColor(0,0,0);
  52. g.fillRect(0,0,this.getWidth(),this.getHeight());
  53. g.setColor(0x00ff00);
  54. g.drawString("origin:",getWidth()/2,0,Graphics.TOP
  55. |Graphics.HCENTER);
  56. g.drawImage(srcImage,30,20,Graphics.LEFT|Graphics.TOP);
  57. g.drawString("SHIFT_RED_TO_BLUE:",getWidth()/2,
  58. srcImage.getHeight()+20,Graphics.TOP|Graphics.HCENTER);
  59. g.drawRGB(targetImage1,0,srcImage.getWidth(),30,srcImage
  60. .getHeight()+40,srcImage.getWidth(),srcImage.getHeight(),
  61. true);
  62. g.drawString("SHIFT_RED_TO_GREEN:",getWidth()/2,srcImage
  63. .getHeight()*2+40,Graphics.TOP|Graphics.HCENTER);
  64. g.drawRGB(targetImage2,0,srcImage.getWidth(),30,srcImage
  65. .getHeight()*2+60,srcImage.getWidth(),srcImage
  66. .getHeight(),true);
  67. }
  68. }


GraphicsUtil.java


  1. importjavax.microedition.lcdui.Image;
  2. /**
  3. *
  4. *@authorJagie
  5. *
  6. */
  7. publicclassGraphicsUtil{
  8. publicstaticfinalintSHIFT_RED_TO_GREEN=0;
  9. publicstaticfinalintSHIFT_RED_TO_BLUE=1;
  10. publicstaticfinalintSHIFT_GREEN_TO_BLUE=2;
  11. publicstaticfinalintSHIFT_GREEN_TO_RED=3;
  12. publicstaticfinalintSHIFT_BLUE_TO_RED=4;
  13. publicstaticfinalintSHIFT_BLUE_TO_GREEN=5;
  14. publicstaticint[]flipImageColor(Imagesource,intshiftType){
  15. //westartbygettingtheimagedataintoanintarray-thenumber
  16. //of32-bitintsisequaltothewidthmultipliedbytheheight
  17. int[]rgbData=newint[(source.getWidth()*source.getHeight())];
  18. source.getRGB(rgbData,0,source.getWidth(),0,0,source.getWidth(),
  19. source.getHeight());
  20. //nowgothrougheverypixelandadjustit'scolor
  21. for(inti=0;i<rgbData.length;i++){
  22. intp=rgbData[i];
  23. //splitoutthedifferentbytecomponentsofthepixelby
  24. //applying
  25. //amasksoweonlygetwhatweneed,thenshiftittomakeit
  26. //anormalnumberwecanplayaroundwith
  27. inta=((p&0xff000000)>>24);
  28. intr=((p&0x00ff0000)>>16);
  29. intg=((p&0x0000ff00)>>8);
  30. intb=((p&0x000000ff)>>0);
  31. intba=a,br=r,bb=b,bg=g;//backupcopies
  32. //flipthecolorsaroundaccordingtotheoperationrequired
  33. switch(shiftType){
  34. caseSHIFT_RED_TO_GREEN:
  35. g=r;
  36. r=bg;
  37. break;
  38. caseSHIFT_RED_TO_BLUE:
  39. b=r;
  40. r=bb;
  41. break;
  42. caseSHIFT_GREEN_TO_BLUE:
  43. g=b;
  44. b=bg;
  45. break;
  46. caseSHIFT_GREEN_TO_RED:
  47. g=r;
  48. r=bg;
  49. break;
  50. caseSHIFT_BLUE_TO_RED:
  51. b=r;
  52. r=bb;
  53. break;
  54. caseSHIFT_BLUE_TO_GREEN:
  55. b=g;
  56. g=bb;
  57. break;
  58. }
  59. //shiftallourvaluesbackin
  60. rgbData[i]=(a<<24)|(r<<16)|(g<<8)|b;
  61. }
  62. returnrgbData;
  63. }
  64. }

相关文章:

  • 配置 vue 环境
  • 介绍J2ME的几个重要概念
  • 谷歌浏览器插件
  • 基于MIDP实现ResourceBundle类
  • Node.js 基础-01
  • vscode保存代码,自动按照eslint规范格式化代码设置(vscode最新版配置)
  • 关注J2ME WTK2.2新特性
  • 高级前端面试题
  • 介绍MIDP的属性问题
  • 破解 vue3.x 新特性
  • UniJa2.1声音播放问题(MIDI格式)
  • 在MIDP2.0中调用平台服务
  • 前端模块化
  • 搭建OTA下载服务器
  • Promise的理解
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • 08.Android之View事件问题
  • Brief introduction of how to 'Call, Apply and Bind'
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • flask接收请求并推入栈
  • Hexo+码云+git快速搭建免费的静态Blog
  • Java IO学习笔记一
  • javascript 总结(常用工具类的封装)
  • Java多态
  • maya建模与骨骼动画快速实现人工鱼
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • OSS Web直传 (文件图片)
  • PhantomJS 安装
  • Spring声明式事务管理之一:五大属性分析
  • SpriteKit 技巧之添加背景图片
  • windows下使用nginx调试简介
  • 动态魔术使用DBMS_SQL
  • 基于Android乐音识别(2)
  • 如何使用 JavaScript 解析 URL
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • 如何用纯 CSS 创作一个货车 loader
  • ​iOS实时查看App运行日志
  • #Linux(权限管理)
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (第一天)包装对象、作用域、创建对象
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (离散数学)逻辑连接词
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (十八)三元表达式和列表解析
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • (转)Linq学习笔记
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • .net core Swagger 过滤部分Api
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • .NetCore 如何动态路由
  • /dev/VolGroup00/LogVol00:unexpected inconsistency;run fsck manually
  • @Query中countQuery的介绍