Merge change I9a181cb7 into eclair
* changes: Use SWT to write PNG screenshot now that we moved to SWT 3.3+
This commit is contained in:
@@ -21,6 +21,7 @@ import com.android.ddmlib.Log;
|
|||||||
import com.android.ddmlib.RawImage;
|
import com.android.ddmlib.RawImage;
|
||||||
|
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.SWTException;
|
||||||
import org.eclipse.swt.dnd.Clipboard;
|
import org.eclipse.swt.dnd.Clipboard;
|
||||||
import org.eclipse.swt.dnd.ImageTransfer;
|
import org.eclipse.swt.dnd.ImageTransfer;
|
||||||
import org.eclipse.swt.dnd.Transfer;
|
import org.eclipse.swt.dnd.Transfer;
|
||||||
@@ -28,6 +29,7 @@ import org.eclipse.swt.events.SelectionAdapter;
|
|||||||
import org.eclipse.swt.events.SelectionEvent;
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
import org.eclipse.swt.graphics.Image;
|
import org.eclipse.swt.graphics.Image;
|
||||||
import org.eclipse.swt.graphics.ImageData;
|
import org.eclipse.swt.graphics.ImageData;
|
||||||
|
import org.eclipse.swt.graphics.ImageLoader;
|
||||||
import org.eclipse.swt.graphics.PaletteData;
|
import org.eclipse.swt.graphics.PaletteData;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
@@ -292,10 +294,12 @@ public class ScreenShotDialog extends Dialog {
|
|||||||
ImageData imageData = mImageLabel.getImage().getImageData();
|
ImageData imageData = mImageLabel.getImage().getImageData();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
WritePng.savePng(fileName, imageData);
|
ImageLoader loader = new ImageLoader();
|
||||||
|
loader.data = new ImageData[] { imageData };
|
||||||
|
loader.save(fileName, SWT.IMAGE_PNG);
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (SWTException e) {
|
||||||
Log.w("ddms", "Unable to save " + fileName + ": " + ioe);
|
Log.w("ddms", "Unable to save " + fileName + ": " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,258 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2007 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.ddmuilib;
|
|
||||||
|
|
||||||
import com.android.ddmlib.Log;
|
|
||||||
|
|
||||||
import org.eclipse.swt.graphics.ImageData;
|
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.util.zip.CRC32;
|
|
||||||
import java.util.zip.Deflater;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compensate for SWT issues by writing our own PNGs from ImageData.
|
|
||||||
*/
|
|
||||||
public class WritePng {
|
|
||||||
private WritePng() {}
|
|
||||||
|
|
||||||
private static final byte[] PNG_MAGIC =
|
|
||||||
new byte[] { -119, 80, 78, 71, 13, 10, 26, 10 };
|
|
||||||
|
|
||||||
public static void savePng(String fileName, ImageData imageData)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
try {
|
|
||||||
FileOutputStream out = new FileOutputStream(fileName);
|
|
||||||
|
|
||||||
Log.d("ddms", "Saving to PNG, width=" + imageData.width
|
|
||||||
+ ", height=" + imageData.height
|
|
||||||
+ ", depth=" + imageData.depth
|
|
||||||
+ ", bpl=" + imageData.bytesPerLine);
|
|
||||||
|
|
||||||
savePng(out, imageData);
|
|
||||||
|
|
||||||
// need to do that on, or the file is empty on windows!
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("writepng", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Supply functionality missing from our version of SWT.
|
|
||||||
*/
|
|
||||||
private static void savePng(OutputStream out, ImageData imageData)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
int width = imageData.width;
|
|
||||||
int height = imageData.height;
|
|
||||||
byte[] out24;
|
|
||||||
|
|
||||||
Log.d("ddms-png", "Convert to 24bit from " + imageData.depth);
|
|
||||||
|
|
||||||
if (imageData.depth == 24 || imageData.depth == 32) {
|
|
||||||
out24 = convertTo24ForPng(imageData.data, width, height,
|
|
||||||
imageData.depth, imageData.bytesPerLine);
|
|
||||||
} else if (imageData.depth == 16) {
|
|
||||||
out24 = convert16to24(imageData);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the compressed form. I'm taking the low road here and
|
|
||||||
// just creating a large buffer, which should always be enough to
|
|
||||||
// hold the compressed output.
|
|
||||||
byte[] compPixels = new byte[out24.length + 16384];
|
|
||||||
Deflater compressor = new Deflater();
|
|
||||||
compressor.setLevel(Deflater.BEST_COMPRESSION);
|
|
||||||
compressor.setInput(out24);
|
|
||||||
compressor.finish();
|
|
||||||
int compLen;
|
|
||||||
do { // must do this in a loop to satisfy java.util.Zip
|
|
||||||
compLen = compressor.deflate(compPixels);
|
|
||||||
assert compLen != 0 || !compressor.needsInput();
|
|
||||||
} while (compLen == 0);
|
|
||||||
Log.d("ddms", "Compressed image data from " + out24.length
|
|
||||||
+ " to " + compLen);
|
|
||||||
|
|
||||||
// Write the PNG magic
|
|
||||||
out.write(PNG_MAGIC);
|
|
||||||
|
|
||||||
ByteBuffer buf;
|
|
||||||
CRC32 crc;
|
|
||||||
|
|
||||||
// Write the IHDR chunk (13 bytes)
|
|
||||||
byte[] header = new byte[8 + 13 + 4];
|
|
||||||
buf = ByteBuffer.wrap(header);
|
|
||||||
buf.order(ByteOrder.BIG_ENDIAN);
|
|
||||||
|
|
||||||
putChunkHeader(buf, 13, "IHDR");
|
|
||||||
buf.putInt(width);
|
|
||||||
buf.putInt(height);
|
|
||||||
buf.put((byte) 8); // 8pp
|
|
||||||
buf.put((byte) 2); // direct color used
|
|
||||||
buf.put((byte) 0); // compression method == deflate
|
|
||||||
buf.put((byte) 0); // filter method (none)
|
|
||||||
buf.put((byte) 0); // interlace method (none)
|
|
||||||
|
|
||||||
crc = new CRC32();
|
|
||||||
crc.update(header, 4, 4+13);
|
|
||||||
buf.putInt((int)crc.getValue());
|
|
||||||
|
|
||||||
out.write(header);
|
|
||||||
|
|
||||||
// Write the IDAT chunk
|
|
||||||
byte[] datHdr = new byte[8 + 0 + 4];
|
|
||||||
buf = ByteBuffer.wrap(datHdr);
|
|
||||||
buf.order(ByteOrder.BIG_ENDIAN);
|
|
||||||
|
|
||||||
putChunkHeader(buf, compLen, "IDAT");
|
|
||||||
crc = new CRC32();
|
|
||||||
crc.update(datHdr, 4, 4+0);
|
|
||||||
crc.update(compPixels, 0, compLen);
|
|
||||||
buf.putInt((int) crc.getValue());
|
|
||||||
|
|
||||||
out.write(datHdr, 0, 8);
|
|
||||||
out.write(compPixels, 0, compLen);
|
|
||||||
out.write(datHdr, 8, 4);
|
|
||||||
|
|
||||||
// Write the IEND chunk (0 bytes)
|
|
||||||
byte[] trailer = new byte[8 + 0 + 4];
|
|
||||||
|
|
||||||
buf = ByteBuffer.wrap(trailer);
|
|
||||||
buf.order(ByteOrder.BIG_ENDIAN);
|
|
||||||
putChunkHeader(buf, 0, "IEND");
|
|
||||||
|
|
||||||
crc = new CRC32();
|
|
||||||
crc.update(trailer, 4, 4+0);
|
|
||||||
buf.putInt((int)crc.getValue());
|
|
||||||
|
|
||||||
out.write(trailer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Output a chunk header.
|
|
||||||
*/
|
|
||||||
private static void putChunkHeader(ByteBuffer buf, int length,
|
|
||||||
String typeStr) {
|
|
||||||
|
|
||||||
int type = 0;
|
|
||||||
|
|
||||||
if (typeStr.length() != 4)
|
|
||||||
throw new RuntimeException();
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
type <<= 8;
|
|
||||||
type |= (byte) typeStr.charAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.putInt(length);
|
|
||||||
buf.putInt(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert raw pixels to 24-bit RGB with a "filter" byte at the start
|
|
||||||
* of each row.
|
|
||||||
*/
|
|
||||||
private static byte[] convertTo24ForPng(byte[] in, int width, int height,
|
|
||||||
int depth, int stride) {
|
|
||||||
|
|
||||||
assert depth == 24 || depth == 32;
|
|
||||||
assert stride == width * (depth/8);
|
|
||||||
|
|
||||||
// 24 bit pixels plus one byte per line for "filter"
|
|
||||||
byte[] out24 = new byte[width * height * 3 + height];
|
|
||||||
int y;
|
|
||||||
|
|
||||||
int inOff = 0;
|
|
||||||
int outOff = 0;
|
|
||||||
for (y = 0; y < height; y++) {
|
|
||||||
out24[outOff++] = 0; // filter flag
|
|
||||||
|
|
||||||
if (depth == 24) {
|
|
||||||
System.arraycopy(in, inOff, out24, outOff, width * 3);
|
|
||||||
outOff += width * 3;
|
|
||||||
} else if (depth == 32) {
|
|
||||||
int tmpOff = inOff;
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
tmpOff++; // ignore alpha
|
|
||||||
out24[outOff++] = in[tmpOff++];
|
|
||||||
out24[outOff++] = in[tmpOff++];
|
|
||||||
out24[outOff++] = in[tmpOff++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inOff += stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert outOff == out24.length;
|
|
||||||
|
|
||||||
return out24;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] convert16to24(ImageData imageData) {
|
|
||||||
int width = imageData.width;
|
|
||||||
int height = imageData.height;
|
|
||||||
|
|
||||||
int redShift = imageData.palette.redShift;
|
|
||||||
int greenShift = imageData.palette.greenShift;
|
|
||||||
int blueShift = imageData.palette.blueShift;
|
|
||||||
|
|
||||||
int redMask = imageData.palette.redMask;
|
|
||||||
int greenMask = imageData.palette.greenMask;
|
|
||||||
int blueMask = imageData.palette.blueMask;
|
|
||||||
|
|
||||||
// 24 bit pixels plus one byte per line for "filter"
|
|
||||||
byte[] out24 = new byte[width * height * 3 + height];
|
|
||||||
int outOff = 0;
|
|
||||||
|
|
||||||
|
|
||||||
int[] line = new int[width];
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
imageData.getPixels(0, y, width, line, 0);
|
|
||||||
|
|
||||||
out24[outOff++] = 0; // filter flag
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
int pixelValue = line[x];
|
|
||||||
out24[outOff++] = byteChannelValue(pixelValue, redMask, redShift);
|
|
||||||
out24[outOff++] = byteChannelValue(pixelValue, greenMask, greenShift);
|
|
||||||
out24[outOff++] = byteChannelValue(pixelValue, blueMask, blueShift);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out24;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte byteChannelValue(int value, int mask, int shift) {
|
|
||||||
int bValue = value & mask;
|
|
||||||
if (shift < 0) {
|
|
||||||
bValue = bValue >>> -shift;
|
|
||||||
} else {
|
|
||||||
bValue = bValue << shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (byte)bValue;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user