Как на самом деле увидеть растровое изображение, взятое из дампа кучи Android
В процессе отслеживания серьезных проблем с памятью в моем приложении я просмотрел несколько дампов кучи из своего приложения, и большую часть времени у меня ОГРОМНОЕ растровое изображение, о котором я не знаю.
Он занимает 9,4 МБ, или 9 830 400 байтов, или фактически изображение 1280x1920 при 4 байтах на пиксель.
Я проверил в Eclipse MAT, это действительно байт [9830400], который имеет одну входящую ссылку, которая является android.graphics.Bitmap
,
Я хотел бы сбросить это в файл и попытаться увидеть это. Я не могу понять, откуда это. Мое самое большое изображение во всех моих рисунках - 640x960 png, что занимает менее 3 МБ.
Я пытался использовать Eclipse для "копирования значения в файл", но я думаю, что он просто печатает буфер в файл, и я не знаю ни одной программы для работы с изображениями, которая может считывать поток байтов и отображать его как 4 байта на пиксель. образ.
Любая идея?
Вот что я попробовал: выгрузить массив байтов в файл, поместить его в /sdcard/img и загрузить действие, подобное этому:
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
final File inputFile = new File("/sdcard/img");
final FileInputStream isr = new FileInputStream(inputFile);
final Bitmap bmp = BitmapFactory.decodeStream(isr);
ImageView iv = new ImageView(this);
iv.setImageBitmap(bmp);
setContentView(iv);
Log.d("ImageTest", "Image was inflated");
} catch (final FileNotFoundException e) {
Log.d("ImageTest", "Image was not inflated");
}
}
Я ничего не видел.
Вы знаете, как закодировано изображение? Скажи, что хранится в byte[] buffer
, buffer[0]
красный, buffer[1]
зеленый и т. д.?
5 ответов
ОК - После нескольких неудачных попыток я наконец-то получил что-то из этого байтового массива. Я написал эту простую программу на C для преобразования массива байтов в файл растрового изображения Windows. Я бросаю код на случай, если кому-то будет интересно.
Я скомпилировал это для VisualC 6.0 и gcc 3.4.4, оно должно работать на любой ОС (протестировано на Windows, Linux и MacOS X).
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
/* Types */
typedef unsigned char byte;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef int int32_t;
/* Constants */
#define RMASK 0x00ff0000
#define GMASK 0x0000ff00
#define BMASK 0x000000ff
#define AMASK 0xff000000
/* Structures */
struct bmpfile_magic {
unsigned char magic[2];
};
struct bmpfile_header {
uint32_t filesz;
uint16_t creator1;
uint16_t creator2;
uint32_t bmp_offset;
};
struct bmpfile_dibheader {
uint32_t header_sz;
uint32_t width;
uint32_t height;
uint16_t nplanes;
uint16_t bitspp;
uint32_t compress_type;
uint32_t bmp_bytesz;
int32_t hres;
int32_t vres;
uint32_t ncolors;
uint32_t nimpcolors;
uint32_t rmask, gmask, bmask, amask;
uint32_t colorspace_type;
byte colorspace[0x24];
uint32_t rgamma, ggamma, bgamma;
};
/* Displays usage info and exits */
void usage(char *cmd) {
printf("Usage:\t%s <img_src> <img_dest.bmp> <width> <height>\n"
"\timg_src:\timage byte buffer obtained from Eclipse MAT, using 'copy > save value to file' while selecting the byte[] buffer corresponding to an android.graphics.Bitmap\n"
"\timg_dest:\tpath to target *.bmp file\n"
"\twidth:\t\tpicture width, obtained in Eclipse MAT, selecting the android.graphics.Bitmap object and seeing the object member values\n"
"\theight:\t\tpicture height\n\n", cmd);
exit(1);
}
/* C entry point */
int main(int argc, char **argv) {
FILE *in, *out;
char *file_in, *file_out;
int w, h, W, H;
byte r, g, b, a, *image;
struct bmpfile_magic magic;
struct bmpfile_header header;
struct bmpfile_dibheader dibheader;
/* Parse command line */
if (argc < 5) {
usage(argv[0]);
}
file_in = argv[1];
file_out = argv[2];
W = atoi(argv[3]);
H = atoi(argv[4]);
in = fopen(file_in, "rb");
out = fopen(file_out, "wb");
/* Check parameters */
if (in == NULL || out == NULL || W == 0 || H == 0) {
usage(argv[0]);
}
/* Init BMP headers */
magic.magic[0] = 'B';
magic.magic[1] = 'M';
header.filesz = W * H * 4 + sizeof(magic) + sizeof(header) + sizeof(dibheader);
header.creator1 = 0;
header.creator2 = 0;
header.bmp_offset = sizeof(magic) + sizeof(header) + sizeof(dibheader);
dibheader.header_sz = sizeof(dibheader);
dibheader.width = W;
dibheader.height = H;
dibheader.nplanes = 1;
dibheader.bitspp = 32;
dibheader.compress_type = 3;
dibheader.bmp_bytesz = W * H * 4;
dibheader.hres = 2835;
dibheader.vres = 2835;
dibheader.ncolors = 0;
dibheader.nimpcolors = 0;
dibheader.rmask = RMASK;
dibheader.gmask = BMASK;
dibheader.bmask = GMASK;
dibheader.amask = AMASK;
dibheader.colorspace_type = 0x57696e20;
memset(&dibheader.colorspace, 0, sizeof(dibheader.colorspace));
dibheader.rgamma = dibheader.bgamma = dibheader.ggamma = 0;
/* Read picture data */
image = (byte*) malloc(4*W*H);
if (image == NULL) {
printf("Could not allocate a %d-byte buffer.\n", 4*W*H);
exit(1);
}
fread(image, 4*W*H, sizeof(byte), in);
fclose(in);
/* Write header */
fwrite(&magic, sizeof(magic), 1, out);
fwrite(&header, sizeof(header), 1, out);
fwrite(&dibheader, sizeof(dibheader), 1, out);
/* Convert the byte array to BMP format */
for (h = H-1; h >= 0; h--) {
for (w = 0; w < W; w++) {
r = *(image + w*4 + 4 * W * h);
b = *(image + w*4 + 4 * W * h + 1);
g = *(image + w*4 + 4 * W * h + 2);
a = *(image + w*4 + 4 * W * h + 3);
fwrite(&b, 1, 1, out);
fwrite(&g, 1, 1, out);
fwrite(&r, 1, 1, out);
fwrite(&a, 1, 1, out);
}
}
free(image);
fclose(out);
}
Таким образом, используя этот инструмент, я смог распознать картинку, использованную для создания этого растрового изображения 1280x1920.
Смотрите здесь для более простого ответа: MAT (Eclipse Memory Analyzer) - как просматривать растровые изображения из дампа памяти
TL;DR - установите GIMP и загрузите образ в формате RGB Alpha
Я обнаружил, что начиная с последней версии Android Studio (2.2.2 на момент написания), вы можете просматривать файл растрового изображения напрямую:
- Откройте вкладку "Android Monitor" (внизу слева), а затем вкладку "Память".
Нажмите кнопку "Dump Java Heap"
Выберите имя класса "Растровое изображение" для текущего снимка, выберите каждый экземпляр растрового изображения и посмотрите, какое изображение в точности потребляет больше памяти, чем ожидалось. (экраны 4 и 5)
Выбрать
Bitmap
имя класса...
- Выберите каждый экземпляр растрового изображения
и щелкните правой кнопкой мыши на нем, выберите View Bitmap
Вы можете включить USB-соединение и скопировать файл на другой компьютер с дополнительными инструментами для расследования.
Некоторые устройства могут быть настроены на сброс текущего экрана в файловую систему при нажатии кнопки запуска. Может быть, это случилось с вами.
Просто возьмите входные данные для изображения и преобразуйте его в растровый объект, используя файл входного потока / потока данных. Также добавьте журналы для просмотра данных для каждого изображения, которое используется.