android4.2~Android420ToARGB

从Android ④2到Android420ToARGB:色彩管理与显示技术的革新之旅

在移动科技日新月异的今天,Android操作系统作为智能设备的核心驱动力,其每一次迭代都引领着行业风向标。从Android ④2 Jelly Bean到更先进的版本(虽然“Android420”并非官方版本命名,这里我们假设它代表Android生态系统中色彩管理与显示技术的一个假设性高峰),Android系统在色彩管理、图像渲染以及用户界面体验上实现了质的飞跃,尤其是Android420ToARGB这一假想的色彩转换技术,更是将显示技术推向了新的高度。

一、Android ④2:色彩管理的初步探索

回溯到2012年发布的Android ④2,这一版本虽然以性能优化和用户体验提升为主打,但在色彩管理方面也迈出了重要一步。Android ④2引入了更精细的显示校准功能,使得屏幕色彩更加准确,为用户带来了更真实的视觉享受。这一时期的Android开始注重色彩空间的定义,为后续的色彩管理打下了坚实的基础。尤其是照片和视频应用中,Android ④2通过增强色彩映射算法,让图像色彩更加丰富,细节表现更为细腻,为用户提供了更接近现实的视觉体验。

二、色彩管理技术的演进之路

随着技术的不断进步,Android系统在色彩管理方面持续深耕。从Android ⑤0 Lollipop开始,Android引入了Material Design设计语言,这不仅是一场界面设计的革命,更是色彩管理策略的一次全面升级。Material Design强调色彩的对比与和谐,要求系统能够更精准地控制色彩表现,以适应不同设备和屏幕类型的需求。在此后的版本中,Android不断优化色彩管理框架,提高了色彩转换的效率与精度,为开发者提供了更为灵活的色彩工具集,使得应用程序能够呈现出更加丰富、细腻的色彩效果。

三、假想技术:Android420ToARGB的色彩转换艺术

虽然“Android420”并非实际存在的Android版本,但借此构想探讨未来可能的色彩转换技术——Android420ToARGB,这一概念代表着从一种色彩空间(假设为某种高级别的4:2:0色度子采样格式)到ARGB(Alpha, Red, Green, Blue)色彩空间的转换技术。在Android420ToARGB的设想中,系统能够以前所未有的精度进行色彩转换,不仅保留了源色彩空间的所有色彩信息,还能根据目标设备特性进行智能调整,实现色彩的精准还原与优化。这对于HDR(高动态范围)内容的显示尤为重要,能够显著提升画面的动态范围和细节层次,为用户带来沉浸式的视觉盛宴。此外,Android4

关于Android 中 Options.inSampleSize怎么用

转自:

这个是读取bitmap时用到的属性,是为了对原图降采样.

比如原图是一个 4000 * 4000 点阵的图,占用内存就是 4000 * 4000 * 单个像素占用字节数

单个像素占用字节数取决于你用的是  RGB565 , ARGB8888 等. 4000 * 4000 这个解析度已很接近目前市面主流机器的默认照片解析度.

假设你用的是 RGB565 解析这张图,那一个点就占用2个字节.如果完整解析这个图片,就需要 大约3.2MB的内存.

如果你用了一个GridView,同时显示了30张这种图,那几乎可以确定你会收到一个OOM异常.

所以需要对这种大图进行降采样,以减小内存占用.毕竟拇指大小的地方根本用不着显示那么高的解析度.

因为直接从点阵中隔行抽取最有效率,所以为了兼顾效率, inSampleSize 这个属性只认2的整数倍为有效.

比如你将 inSampleSize 赋值为2,那就是每隔2行采1行,每隔2列采一列,那你解析出的图片就是原图大小的1/4.

这个值也可以填写非2的倍数,非2的倍数会被四舍五入.

综上,用这个参数解析bitmap就是为了减少内存占用.

一下是我的一个根据指定大小对图片文件降采样读取的一个函数,供参考.

/**

* author: liuxu

* de-sample according to given width and height. if required width or height is

* smaller than the origin picture's with or height, de-sample it.

* NOTE: if image quality is your first concern, do not use this method.

* @param path full path for the picture

* @param width the required width

* @param height the required height

* @return bitmap

*/

public static Bitmap decodeBitmapForSize(String path, int width, int height) {

final BitmapFactory.Options options = new BitmapFactory.Options();

if (width != 0 && height != 0) {

// decode with inJustDecodeBounds=true to check size

options.inJustDecodeBounds = true;

BitmapFactory.decodeFile(path, options);

// calculate inSampleSize according to the requested size

options.inSampleSize = calculateInSampleSize(options, width, height);

options.inJustDecodeBounds = false;

}

// decode bitmap with the calculated inSampleSize

options.inPreferredConfig = Config.RGB_565;

options.inPurgeable = true;

options.inInputShareable = true;

return BitmapFactory.decodeFile(path, options);

}

/**

* author: liuxu

* de-sample according to given width and height

* @param options options

* @param reqWidth the required width

* @param reqHeight the required height

* @return the calculated sample size

*/

private static int calculateInSampleSize(BitmapFactory.Options options,

int reqWidth, int reqHeight) {

// raw height and width of image

final int height = options.outHeight;

final int width = options.outWidth;

int initSize = 1;

if (height > reqHeight || width > reqWidth) {

if (width > height) {

initSize = Math.round((float) height / (float) reqHeight);

} else {

initSize = Math.round((float) width / (float) reqWidth);

}

}

/*

* the function rounds up the sample size to a power of 2 or multiple of 8 because

* BitmapFactory only honors sample size this way. For example, BitmapFactory

* down samples an image  by  2 even though the request is 3.

*/

int roundedSize;

if (initSize <= 8) {

roundedSize = 1;

while (roundedSize < initSize) {

roundedSize <<= 1;

}

} else {

roundedSize = (initSize + 7) / 8 * 8;

}

return roundedSize;

}

android 背景虚化原理是什么

1. RenderScript

谈到高斯模糊,第一个想到的就是RenderScript。RenderScript是由Android3.0引入,用来在Android上编写高性能代码的一种语言(使用C99标准)。 引用官方文档的描述:

RenderScript runtime will parallelize work across all processors available on a device, such as multi-core CPUs, GPUs, or DSPs, allowing you to focus on expressing algorithms rather than scheduling work or load balancing.

为了在Android中使用RenderScript,我们需要(直接贴官方文档,比直译更通俗易懂):

High-performance compute kernels are written in a C99-derived language.

A Java API is used for managing the lifetime of RenderScript resources and controlling kernel execution.

学习文档:

上面两点总结成一句话为:我们需要一组compute kernels(.rs文件中编写),及一组用于控制renderScript相关的java api(.rs文件自动生成为java类)。 由于compute kernels的编写需要一定的学习成本,从JELLY_BEAN_MR1开始,Androied内置了一些compute kernels用于常用的操作,其中就包括了Gaussian blur。

下面,通过实操来讲解一下RenderScript来实现高斯模糊,最终实现效果(讲文字背景进行模糊处理):

布局:

[html] view plaincopy

<xml version="1.0" encoding="utf-8">

<FrameLayout xmlns:android=";

android:layout_width="match_parent"

android:layout_height="match_parent" >

<ImageView

android:id="@+id/picture"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:src="@drawable/splash"

android:scaleType="centerCrop" />

<TextView

android:id="@+id/text"

android:gravity="center_horizontal"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="Gaussian Blur"

android:textColor="@android:color/black"

android:layout_gravity="center_vertical"

android:textStyle="bold"

android:textSize="48sp" />

<LinearLayout

android:id="@+id/controls"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="#7f000000"

android:orientation="vertical"

android:layout_gravity="bottom" />

</FrameLayout>

核心代码:

[java] view plaincopy

private void applyBlur() {

image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

@Override

public boolean onPreDraw() {

image.getViewTreeObserver().removeOnPreDrawListener(this);

image.buildDrawingCache();

Bitmap bmp = image.getDrawingCache();

blur(bmp, text, true);

return true;

}

});

}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)

private void blur(Bitmap bkg, View view) {

long startMs = System.currentTimeMillis();

float radius = 20;

Bitmap overlay = Bitmap.createBitmap((int)(view.getMeasuredWidth()), (int)(view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);

Canvas canvas = new Canvas(overlay);

canvas.translate(-view.getLeft(), -view.getTop());

canvas.drawBitmap(bkg, 0, 0, null);

RenderScript rs = RenderScript.create(SecondActivity.this);

Allocation overlayAlloc = Allocation.createFromBitmap(rs, overlay);

ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rs, overlayAlloc.getElement());

blur.setInput(overlayAlloc);

blur.setRadius(radius);

blur.forEach(overlayAlloc);

overlayAlloc.copyTo(overlay);

view.setBackground(new BitmapDrawable(getResources(), overlay));

rs.destroy();

statusText.setText("cost " + (System.currentTimeMillis() - startMs) + "ms");

}

当ImageView开始加载背景图时,取出它的drawableCache,进行blur处理,Gaussian blur的主要逻辑在blur函数中。对于在Java中使用RenderScript,文档中也有详细描述,对应到我们的代码,步骤为:

初始化一个RenderScript Context.

至少创建一个Allocation对象用于存储需要处理的数据.

创建compute kernel的实例,本例中是内置的ScriptIntrinsicBlur对象.

设置ScriptIntrinsicBlur实例的相关属性,包括Allocation, radius等.

开始blur操作,对应(forEach).

将blur后的结果拷贝回bitmap中。

怎样在Android屏幕上循环的输出一个文字

效果图:

实现的方法:

在layout中这样来声明:

<com.kaixin001.view.ScrollText android:id="@+id/news_statustxt"

       android:layout_width="wrap_content"

     android:layout_height="wrap_content"

     android:paddingLeft="10dp"

     android:paddingRight="10dp"

     android:layout_gravity="center_vertical"

     android:textColor="#000000"

     android:textSize="16sp"

     android:hint="@string/news_state_hint"

     android:inputType="text"/>

activity这样来调用:

private void initStatus(){

   ivState = (ImageView) findViewById(R.id.news_statusinput);

   //必须使text长度比控件的宽度大

   String s = "dsafsdfsdf(#开心)fsgfdg(#闭嘴)fdgdfgdfgdfgdfgdfgfdgfdgfdgfdgdfg";

   newsModel.setStatus(s);

   String strModel = newsModel.getStatus();

   setStateText(strModel);

   

 }

 

 private void setStateText(String strModel){

   if(!TextUtils.isEmpty(strModel)){

     tvState.setStateList(newsModel.getStateList());

     tvState.setText(strModel);

     tvState.init(getWindowManager(), handler);

     tvState.startScroll();

     tvState.start();

   }

 }

 <pre name="code" class="java"> <span style="white-space:pre"> </span> public void setStatus(String status){

   this.status = status;

   if(!TextUtils.isEmpty(status)){

     stateList = ParseNewsInfoUtil.parseStr(status);

   }

  <span style="white-space:pre"> </span>}

private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case ScrollText.TEXT_TIMER:if(tvState != null){tvState.scrollText();}break;default:break;}}};

import java.util.ArrayList;

import java.util.Timer;

import java.util.TimerTask;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.Bitmap.Config;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Paint.FontMetrics;

import android.graphics.Paint.Style;

import android.os.Handler;

import android.os.Message;

import android.util.AttributeSet;

import android.view.WindowManager;

import android.widget.TextView;

import com.kaixin001.item.LinkInfo;

import com.kaixin001.model.StateFaceModel;

public class ScrollText extends TextView {

 public static final int TEXT_TIMER = 100;

 private float textLength = 0f;// 文本长度

 private float viewWidth = 0f;

 private float step = 0f;// 文字的横坐标

 private float y = 0f;// 文字的纵坐标

 private float temp_view_plus_text_length = 0.0f;// 用于计算的临时变量

 private float temp_view_plus_two_text_length = 0.0f;// 用于计算的临时变量

 private boolean isStarting = false;// 是否开始滚动

 private int left = 0;

 private int right = 0;

 private Paint paint = null;// 绘图样式

 private String text = "";// 文本内容

 private Bitmap txtBmp;

 private Canvas txtCanvas;

 private FontMetrics fontMetrics;

 private Timer timer = new Timer();

 private ArrayList<LinkInfo> stateList;

 Handler handler;

 TimerTask task = new TimerTask() {

   public void run() {

     if (handler != null && isStarting) {

       Message msg = Message.obtain();

       msg.what = TEXT_TIMER;

       handler.sendMessage(msg);

     }

   }

 };

 public ScrollText(Context context) {

   super(context);

 }

 public ScrollText(Context context, AttributeSet attrs) {

   super(context, attrs);

 }

 public ScrollText(Context context, AttributeSet attrs, int defStyle) {

   super(context, attrs, defStyle);

 }

 /** */

 /**

  * 文本初始化,每次更改文本内容或者文本效果等之后都需要重新初始化一下

  */

 public void init(WindowManager windowManager, Handler handler) {

   try {

     this.handler = handler;

     paint = new Paint();

     paint.setAntiAlias(true);

     paint.setStyle(Style.STROKE);

     paint.setTextSize(getTextSize());

     paint.setColor(getCurrentTextColor());

     text = getText().toString();

     textLength = 0;

     // textLength = paint.measureText(text);

     int len = stateList.size();

     for (int i = 0; i < len; i++) {

       LinkInfo info = stateList.get(i);

       if (info.isFace()) {// 表情符排版

         Bitmap faceBmp = StateFaceModel.getInstance()

             .getSmallFaceIcon(info.getContent());

         int xLen = faceBmp.getWidth();

         textLength += xLen + 4;

         continue;

       }

       String strContent = info.getContent();

       float xLen = paint.measureText(strContent);

       textLength += xLen;

     }

     left = this.getPaddingLeft();

     right = this.getPaddingRight();

     step = textLength;

     fontMetrics = paint.getFontMetrics();

     y = getPaddingTop();// getTextSize() + getPaddingTop();

     txtBmp = null;

   } catch (Exception ex) {

     ex.printStackTrace();

   }

 }

 public void scrollText() {

   if (!isStarting) {

     return;

   }

   invalidate();

   if (viewWidth < textLength) {

     step += 0.5;

     if (step > temp_view_plus_two_text_length) {

       step = textLength;

     }

   }

 }

 public void setStateList(ArrayList<LinkInfo> stateList) {

   this.stateList = stateList;

 }

 private void setTxtBmp() {

   if (txtBmp == null && fontMetrics != null) {

     y = -paint.ascent();// fontMetrics.bottom -

               // fontMetrics.ascent;//(this.getHeight() -

               // (int)fontMetrics.ascent)/2;

     viewWidth = getWidth() - left - right;

     temp_view_plus_text_length = viewWidth + textLength;

     temp_view_plus_two_text_length = viewWidth + textLength * 2;

     txtCanvas = new Canvas();

     int width = (int) viewWidth;

     float height = getHeight();

     txtBmp = Bitmap.createBitmap(width, (int) height, Config.ARGB_8888);

     txtCanvas.setBitmap(txtBmp);

   }

 }

 /** */

 /**

  * 开始滚动

  */

 public void startScroll() {

   isStarting = true;

 }

 /** */

 /**

  * 停止滚动

  */

 public void stopScroll() {

   isStarting = false;

   // invalidate();

 }

 public void start() {

   timer.schedule(task, 10, 20);

 }

 public void stop() {

   timer.cancel();

 }

 @Override

 public void onDraw(Canvas canvas) {

   try {

     setTxtBmp();

     if (txtBmp == null) {

       return;

     }

     Paint txtPaint = new Paint();

     txtPaint.setColor(Color.WHITE);

     txtPaint.setStyle(Style.FILL);

     txtCanvas.drawRect(0, 0, txtBmp.getWidth(), txtBmp.getHeight(),

         txtPaint);

     txtPaint.setAntiAlias(true);

     txtPaint.setStyle(Style.STROKE);

     txtPaint.setTextSize(getTextSize());

     txtPaint.setColor(getCurrentTextColor());

     float x = 0;

     // step为text的宽度

     if (viewWidth < textLength) {

       x = temp_view_plus_text_length - step;

     }

     int len = stateList.size();

     float curLen = x;

     for (int i = 0; i < len; i++) {

       LinkInfo info = stateList.get(i);

       if (info.isFace()) {// 表情符排版

         Bitmap faceBmp = StateFaceModel.getInstance()

             .getSmallFaceIcon(info.getContent());

         int xLen = faceBmp.getWidth();

         txtCanvas.drawBitmap(faceBmp, curLen + 2, 0, txtPaint);

         curLen += xLen + 4;

         continue;

       }

       String strContent = info.getContent();

       strContent = strContent.replaceAll("n", " ");

       float xLen = txtPaint.measureText(strContent);

       //因为x的值一直减少,所以文字可以滚动

       txtCanvas.drawText(strContent, curLen, y, txtPaint); //<span style="font-family: Arial, Helvetica, sans-serif;">txtCanvas早drawtext.txtBmp上也自然也带有这些text</span>

       curLen += xLen;

     }

     canvas.drawBitmap(txtBmp, left, 0, paint);

   } catch (Exception ex) {

     ex.printStackTrace();

   }

 }

 @Override

 protected void onSizeChanged(int w, int h, int oldw, int oldh) {

   super.onSizeChanged(w, h, oldw, oldh);

   txtBmp = null;

   setTxtBmp();

 }

}