#android #android-image
#Android #android-изображение
Вопрос:
Я считываю необработанное изображение из сети. Это изображение было считано датчиком изображения, а не из файла.
Вот что я знаю об изображении:
~ Высота и ширина
~ Общий размер (в байтах)
~ 8-битные оттенки серого
~ 1 байт / пиксель
Я пытаюсь преобразовать это изображение в растровое изображение для отображения в imageview.
Вот что я попробовал:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.outHeight = shortHeight; //360
opt.outWidth = shortWidth;//248
imageBitmap = BitmapFactory.decodeByteArray(imageArray, 0, imageSize, opt);
decodeByteArray возвращает null, поскольку он не может декодировать мое изображение.
Я также попытался прочитать его непосредственно из входного потока, без предварительного преобразования в массив байтов:
imageBitmap = BitmapFactory.decodeStream(imageInputStream, null, opt);
Это также возвращает null.
Я искал на этом и других форумах, но не могу найти способ добиться этого.
Есть идеи?
РЕДАКТИРОВАТЬ: я должен добавить, что первое, что я сделал, это проверить, действительно ли поток содержит необработанное изображение. Я сделал это с помощью других приложений (iPhone / Windows MFC), и они могут прочитать его и правильно отобразить изображение. Мне просто нужно найти способ сделать это на Java / Android.
Ответ №1:
Android не поддерживает растровые изображения в оттенках серого. Итак, первым делом, вы должны расширить каждый байт до 32-разрядного ARGB int. Альфа равна 0xff, а байты R, G и B являются копиями значения исходного изображения в байтах-пикселях. Затем создайте растровое изображение поверх этого массива.
Кроме того (см. Комментарии), кажется, что устройство считает, что 0 — белый, 1 — черный — мы должны инвертировать исходные биты.
Итак, давайте предположим, что исходное изображение находится в массиве байтов, называемом Src. Вот код:
byte [] src; //Comes from somewhere...
byte [] bits = new byte[src.length*4]; //That's where the RGBA array goes.
int i;
for(i=0;i<src.length;i )
{
bits[i*4] =
bits[i*4 1] =
bits[i*4 2] = ~src[i]; //Invert the source bits
bits[i*4 3] = 0xff; // the alpha.
}
//Now put these nice RGBA pixels into a Bitmap object
Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bm.copyPixelsFromBuffer(ByteBuffer.wrap(bits));
Комментарии:
1. @Сева Алексеев: Спасибо за ответ. Я попробовал ваше предложение. Я получаю исключение Runtimeexception. Согласно logcat «Буфер недостаточно велик для пикселей». Я создаю растровое изображение, используя ширину и высоту изображения.
2. @OceanBlue: В сообщении предполагается, что размер буфера Bits составляет менее 4 байт ширины * высоты. Проверьте, так ли это. ARGB_888 — это формат размером 4 байта на пиксель.
3. @Seva Alekseyev: Я точно знаю, что размер буфера Bits равен ширине * высоте байт. Изображение имеет формат 1 байт на пиксель. Таким образом, даже если я создам массив байтов в 4 раза большего размера, изображение будет сохранено в первой 1/4-й его части. Вы случайно не знаете какой-нибудь формат «1 байт на пиксель» в Android?
4. @Сева Алексеев: Спасибо за вашу постоянную поддержку. Я действительно вижу изображение (ого!!!) . По какой-то странной причине оно нарисовано белыми линиями на голубом фоне вместо черных линий на белом фоне . Если вы случайно знаете причину, я был бы очень признателен.
5. Вы, вероятно, взяли первую версию моего фрагмента кода с опечаткой в нем. В последней строке цикла было 1 вместо 3, поэтому красные биты не были инициализированы.
Ответ №2:
Однажды я сделал что-то подобное, чтобы декодировать поток байтов, полученный из обратного вызова предварительного просмотра камеры:
Bitmap.createBitmap(imageBytes, previewWidth, previewHeight,
Bitmap.Config.ARGB_8888);
Попробуйте.
Комментарии:
1. Спасибо за ответ. Что содержит первый параметр «imageBytes»? Из всех перегруженных версий Bitmap.CreateBitmap (…), которые я вижу в онлайн-Javadocs, ни одна не принимает массив байтов в качестве параметра.
Ответ №3:
for(i=0;i<src.length;i )
{
bits[i*4] = bits[i*4 1] = bits[i*4 2] = ~src[i]; //Invert the source bits
bits[i*4 3] = 0xff; // the alpha.
}
Преобразование 8-разрядного изображения в RGBA может занять много времени, изображение размером 640×800 может занять более 500 мс… Более быстрое решение — использовать формат ALPHA8 для растрового изображения и цветовой фильтр:
//setup color filter to inverse alpha, in my case it was needed
float[] mx = new float[]{
1.0f, 0, 0, 0, 0, //red
0, 1.0f, 0, 0, 0, //green
0, 0, 1.0f, 0, 0, //blue
0, 0, 0, -1.0f, 255 //alpha
};
ColorMatrixColorFilter cf = new ColorMatrixColorFilter(mx);
imageView.setColorFilter(cf);
// after set only the alpha channel of the image, it should be a lot faster without the conversion step
Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
bm.copyPixelsFromBuffer(ByteBuffer.wrap(src)); //src is not modified, it's just an 8bit grayscale array
imageview.setImageBitmap(bm);
Ответ №4:
Используйте Drawable create из stream. Вот как это сделать с помощью HttpResponse, но вы можете получить inputstream в любом случае, когда захотите.
InputStream stream = response.getEntity().getContent();
Drawable drawable = Drawable.createFromStream(stream, "Get Full Image Task");
Комментарии:
1. Спасибо за ваш ответ. К сожалению, это также возвращает значение null 🙁 . Я проверил онлайн-JavaDocs о том, почему Drawable.createFromStream вернет значение null developer.android.com/reference/android/graphics/drawable / … но это не подробно. Я должен добавить, что я знаю, что сам поток действителен, поскольку другое приложение, отличное от Android, может прочитать его и отобразить изображение. (У меня нет исходного кода для этого приложения).
2. Конечно, это кажется наиболее вероятной возможностью, но я протестировал, и сервис возвращает изображение правильно (пожалуйста, смотрите мою ПРАВКУ в вопросе). Итак, я сейчас в замешательстве 🙁