我试图将纯原始数据转换为 png 图像。我无法获得正确颜色的正确输出图像。
作为参考,我附上了原始文件和图像。请建议我获得正确颜色的图像。我已经添加了图像和原始文件。
代码
File screensPath = new File(SCREENSHOT_FOLDER);
screensPath.mkdirs();
// construct screenshot file name
StringBuilder sb = new StringBuilder();
sb.append(SCREENSHOT_FOLDER);
sb.append(Math.abs(UUID.randomUUID().hashCode())); // hash code of UUID should be quite random yet short
sb.append(".png");
String file = sb.toString();
// fetch the screen and save it
Screenshot ss = null;
try {
ss = retreiveRawScreenshot();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(ss!=null)
{
writeImageFile(ss, file);
}
incre++;
private Screenshot retreiveRawScreenshot() throws Exception {
try {
InputStream is = new FileInputStream("/mnt/sdcard/screenshots/ss"+incre+".raw");
// retrieve response -- first the size and BPP of the screenshot
StringBuilder sb = new StringBuilder();
int c;
while ((c = is.read()) != -1) {
if (c == 0) break;
sb.append((char)c);
}
//========================================= not used =====================================
// parse it
String[] screenData = sb.toString().split(" ");
if (screenData.length >= 3) {
System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$$$ ");
Screenshot ss = new Screenshot();
ss.width = Integer.parseInt(screenData[0]);
ss.height = Integer.parseInt(screenData[1]);
ss.bpp = Integer.parseInt(screenData[2]);
System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$$$ ");
// retreive the screenshot
// (this method - via ByteBuffer - seems to be the fastest)
ByteBuffer bytes = ByteBuffer.allocate (ss.width * ss.height * ss.bpp / 8);
is = new BufferedInputStream(is); // buffering is very important apparently
byte[] rgbsnew = null;
toRGB565(bytes.array(), ss.width, ss.height, rgbsnew);
// is.read(bytes.array()); // reading all at once for speed
is.read(rgbsnew); // reading all at once for speed
bytes.position(0); // reset position to the beginning of ByteBuffer
ss.pixels =ByteBuffer.wrap(rgbsnew);
// convert byte-buffer to integer
return ss;
}
//========================================= not used ==========================================
Screenshot ss = new Screenshot();
ss.width = 320;
ss.height = 480;
ss.bpp = 16;
ByteBuffer bytes = ByteBuffer.allocate (ss.width * ss.height * ss.bpp / 8);
is = new BufferedInputStream(is); // buffering is very important apparently
is.read(bytes.array()); // reading all at once for speed
bytes.position(0); // reset position to the beginning of ByteBuffer
ss.pixels = bytes;
//============================= newly tried to set raw to image view ==============================
/*mRawImage = new RawImage();
mRawImage.readHeader(1, bytes);
// Receive framebuffer data.
byte[] data = new byte[mRawImage.size];
bytes = ByteBuffer.wrap(data);
mRawImage.data = data;
Bitmap bmp=BitmapFactory.decodeByteArray(mRawImage.data,0,mRawImage.data.length);
imageView1.setImageBitmap(bmp);*/
//============================newly tried to set raw to image view ===============================
return ss;
}
catch (Exception e) {
// throw new Exception(e);
return null;
}
finally {}
//return null;
}
class Screenshot {
public Buffer pixels;
public int width;
public int height;
public int bpp;
public boolean isValid() {
if (pixels == null || pixels.capacity() == 0 || pixels.limit() == 0) return false;
if (width <= 0 || height <= 0) return false;
return true;
}
}
private void writeImageFile(Screenshot ss, String file) {
//if (ss == null || !ss.isValid()) throw new IllegalArgumentException();
//if (file == null || file.length() == 0) throw new IllegalArgumentException();
// resolve screenshot's BPP to actual bitmap pixel format
Bitmap.Config pf;
switch (ss.bpp) {
//case 16: pf = Config.RGB_565; break;
case 16: pf = Config.RGB_565; break;
case 32: pf = Config.ARGB_8888; break;
default: pf = Config.ARGB_8888; break;
}
//=====================================================================
/*int[] rgb24 = new int[ss.pixels.capacity()];
int i = 0;
for (;i<320*480;i++)
{
//uint16_t pixel16 = ((uint16_t *)gr_framebuffer[0].data)[i];
//int pixel16=(IntBuffer)
int pixel16=Integer.parseInt(ss.pixels.position(i).toString());
// RRRRRGGGGGGBBBBBB -> RRRRRRRRGGGGGGGGBBBBBBBB
// in rgb24 color max is 2^8 per channel (*255/32 *255/64 *255/32)
rgb24[3*i+2] = (255*(pixel16 & 0x001F))/ 32; //Blue
rgb24[3*i+1] = (255*((pixel16 & 0x07E0) >> 5))/64; //Green
rgb24[3*i] = (255*((pixel16 & 0xF800) >> 11))/32; //Red
}
//ss.pixels=rgb24;
*///=====================================================================
// create appropriate bitmap and fill it wit data
Bitmap bmp = Bitmap.createBitmap(ss.width, ss.height, pf);
bmp.copyPixelsFromBuffer(ss.pixels);
// handle the screen rotation
int rot = getScreenRotation();
if (rot != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(-rot);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
}
// save it in PNG format
FileOutputStream fos;
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e) {
throw new InvalidParameterException();
}
bmp.compress(CompressFormat.PNG, 100, fos);
}
private int getScreenRotation() {
WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
Display disp = wm.getDefaultDisplay();
// check whether we operate under Android 2.2 or later
try {
Class<?> displayClass = disp.getClass();
Method getRotation = displayClass.getMethod("getRotation");
int rot = ((Integer)getRotation.invoke(disp)).intValue();
switch (rot) {
case Surface.ROTATION_0: return 0;
case Surface.ROTATION_90: return 90;
case Surface.ROTATION_180: return 180;
case Surface.ROTATION_270: return 270;
default: return 0;
}
} catch (NoSuchMethodException e) {
// no getRotation() method -- fall back to dispation()
int orientation = disp.getOrientation();
// Sometimes you may get undefined orientation Value is 0
// simple logic solves the problem compare the screen
// X,Y Co-ordinates and determine the Orientation in such cases
if(orientation==Configuration.ORIENTATION_UNDEFINED){
Configuration config = getResources().getConfiguration();
orientation = config.orientation;
if(orientation==Configuration.ORIENTATION_UNDEFINED){
//if height and widht of screen are equal then
// it is square orientation
if(disp.getWidth()==disp.getHeight()){
orientation = Configuration.ORIENTATION_SQUARE;
}else{ //if widht is less than height than it is portrait
if(disp.getWidth() < disp.getHeight()){
orientation = Configuration.ORIENTATION_PORTRAIT;
}else{ // if it is not any of the above it will defineitly be landscape
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
}
}
return orientation == 1 ? 0 : 90; // 1 for portrait, 2 for landscape
} catch (Exception e) {
return 0; // bad, I know ;P
}
}
//===========================================================================
/**
* Converts semi-planar YUV420 as generated for camera preview into RGB565
* format for use as an OpenGL ES texture. It assumes that both the input
* and output data are contiguous and start at zero.
*
* @param yuvs the array of YUV420 semi-planar data
* @param rgbs an array into which the RGB565 data will be written
* @param width the number of pixels horizontally
* @param height the number of pixels vertically
*/
//we tackle the conversion two pixels at a time for greater speed
private void toRGB565(byte[] yuvs, int width, int height, byte[] rgbs) {
//the end of the luminance data
final int lumEnd = width * height;
//points to the next luminance value pair
int lumPtr = 0;
//points to the next chromiance value pair
int chrPtr = lumEnd;
//points to the next byte output pair of RGB565 value
int outPtr = 0;
//the end of the current luminance scanline
int lineEnd = width;
while (true) {
//skip back to the start of the chromiance values when necessary
if (lumPtr == lineEnd) {
if (lumPtr == lumEnd) break; //we've reached the end
//division here is a bit expensive, but's only done once per scanline
chrPtr = lumEnd + ((lumPtr >> 1) / width) * width;
lineEnd += width;
}
//read the luminance and chromiance values
final int Y1 = yuvs[lumPtr++] & 0xff;
final int Y2 = yuvs[lumPtr++] & 0xff;
final int Cr = (yuvs[chrPtr++] & 0xff) - 128;
final int Cb = (yuvs[chrPtr++] & 0xff) - 128;
int R, G, B;
//generate first RGB components
B = Y1 + ((454 * Cb) >> 8);
if(B < 0) B = 0; else if(B > 255) B = 255;
G = Y1 - ((88 * Cb + 183 * Cr) >> 8);
if(G < 0) G = 0; else if(G > 255) G = 255;
R = Y1 + ((359 * Cr) >> 8);
if(R < 0) R = 0; else if(R > 255) R = 255;
//NOTE: this assume little-endian encoding
rgbs[outPtr++] = (byte) (((G & 0x3c) << 3) | (B >> 3));
rgbs[outPtr++] = (byte) ((R & 0xf8) | (G >> 5));
//generate second RGB components
B = Y2 + ((454 * Cb) >> 8);
if(B < 0) B = 0; else if(B > 255) B = 255;
G = Y2 - ((88 * Cb + 183 * Cr) >> 8);
if(G < 0) G = 0; else if(G > 255) G = 255;
R = Y2 + ((359 * Cr) >> 8);
if(R < 0) R = 0; else if(R > 255) R = 255;
//NOTE: this assume little-endian encoding
rgbs[outPtr++] = (byte) (((G & 0x3c) << 3) | (B >> 3));
rgbs[outPtr++] = (byte) ((R & 0xf8) | (G >> 5));
}
}
谢谢 。 原始文件