Как на самом деле увидеть растровое изображение, взятое из дампа кучи Android

StackOverflow https://stackoverflow.com//questions/9611592

  •  09-12-2019
  •  | 
  •  

Вопрос

В процессе отслеживания серьезных проблем с памятью в моем приложении я просмотрел несколько дампов кучи моего приложения, и большую часть времени у меня было ОГРОМНОЕ растровое изображение, о котором я не знал.

Это занимает 9,4 МБ, или 9 830 400 байт, или фактически изображение 1280x1920 с плотностью 4 байта на пиксель.

Я проверил в Eclipse MAT, это действительно байт [9830400], который имеет одну входящую ссылку, которая является android.graphics.Bitmap.

Я хотел бы сохранить это в файл и попытаться просмотреть.Я не могу понять, откуда это.Мое самое большое изображение из всех моих рисунков — это PNG 640x960, которое занимает менее 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] зеленый и т. д.?

Это было полезно?

Решение 2

ОК. После нескольких неудачных попыток мне наконец удалось что-то извлечь из этого массива байтов.Я написал эту простую программу на 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) – как просмотреть растровые изображения из дампа памяти

TL;DR — установите GIMP и загрузите изображение в виде необработанного RGB Alpha.

Я обнаружил, что, начиная с последней версии Android Studio (2.2.2 на момент написания), вы можете просматривать растровый файл напрямую:

  1. Откройте вкладку «Android Monitor» (слева внизу), а затем вкладку «Память».
  2. Нажмите кнопку «Дамп кучи Java».

  3. Выберите имя класса «Растровое изображение» для текущего снимка, выберите каждый экземпляр растрового изображения и просмотрите, какое именно изображение потребляет больше памяти, чем ожидалось.(экраны 4 и 5)

  4. Выбрать Bitmap название класса…

enter image description here

  1. Выберите каждый экземпляр растрового изображения

enter image description here

и щелкните по нему правой кнопкой мыши, выберите View Bitmap

enter image description here

Просто возьмите входные данные изображения и преобразуйте их в растровый объект, используя поток ввода/потока данных.Также добавьте журналы для просмотра данных для каждого используемого изображения.

Вы можете включить USB-соединение и скопировать файл на другой компьютер с дополнительными инструментами для исследования.

Некоторые устройства можно настроить на сохранение текущего экрана в файловую систему при нажатии кнопки «Пуск».Возможно, это случается с вами.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top