需要在原生c++中增加红色像素值



在android与jni我有一个CPP代码改变或增加红色像素值与帮助从android传递的位图数据

Java_com_journaldev_androidjnibasics_MainActivity_sendMyBitmap(JNIEnv *env, jobject thiz,
jobject bitmap) {
AndroidBitmapInfo info;
int ret;
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
return NULL;
}
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
return NULL;
}
//
//read pixels of bitmap into native memory :
//
void *bitmapPixels;
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels)) < 0) {
return NULL;
}
uint32_t *src = (uint32_t *) bitmapPixels;
uint32_t *tempPixels = new uint32_t[info.height * info.width];
int stride = info.stride;
int pixelsCount = info.height * info.width;
int x, y, red, green, blue;
for (y=0;y<info.height;y++) {

uint32_t * line = (uint32_t *)bitmapPixels;
for (x=0;x<info.width;x++) {
blue = (int) ((line[x] & 0xFF0000) >> 16);
green = (int)((line[x] & 0x00FF00) >> 8);
red = (int) (line[x] & 0x0000FF);
//just set it to all be red for testing
red = 255;
green = 0;
blue = 0;
//why is the image totally blue??
line[x] =
((blue<< 16) & 0xFF0000) |
((green << 8) & 0x00FF00) |
(red & 0x0000FF);
}
bitmapPixels = (char *)bitmapPixels + info.stride;
}

memcpy(tempPixels, src, sizeof(uint32_t) * pixelsCount);
AndroidBitmap_unlockPixels(env, bitmap);
//
//recycle bitmap - using bitmap.recycle()
//
jclass bitmapCls = env->GetObjectClass(bitmap);
jmethodID recycleFunction = env->GetMethodID(bitmapCls, "recycle", "()V");
if (recycleFunction == 0) {
return NULL;
}
env->CallVoidMethod(bitmap, recycleFunction);
//
//creating a new bitmap to put the pixels into it - using Bitmap Bitmap.createBitmap (int width, int height, Bitmap.Config config) :
//
jmethodID createBitmapFunction = env->GetStaticMethodID(bitmapCls, "createBitmap",
"(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
jstring configName = env->NewStringUTF("ARGB_8888");
jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
jmethodID valueOfBitmapConfigFunction = env->GetStaticMethodID(bitmapConfigClass, "valueOf",
"(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");
jobject bitmapConfig = env->CallStaticObjectMethod(bitmapConfigClass,
valueOfBitmapConfigFunction, configName);
jobject newBitmap = env->CallStaticObjectMethod(bitmapCls, createBitmapFunction, info.height,
info.width, bitmapConfig);
//
// putting the pixels into the new bitmap:
//
if ((ret = AndroidBitmap_lockPixels(env, newBitmap, &bitmapPixels)) < 0) {
return NULL;
}
uint32_t *newBitmapPixels = (uint32_t *) bitmapPixels;
int whereToPut = 0;
for (int x = info.width - 1; x >= 0; --x)
for (int y = 0; y < info.height; ++y) {
uint32_t pixel = tempPixels[info.width * y + x];
newBitmapPixels[whereToPut++] = pixel;
}
AndroidBitmap_unlockPixels(env, newBitmap);
delete[] tempPixels;


return newBitmap;
}

这里经过这个过程,图像得到完全透明或白色。有人能帮我做这个吗?我的目标是改变这个位图数据中R(红色)像素的值。提前感谢

//-------------------------------------------------------------------------------------------------
// header file byte_masks.h
// two constexpr functions that will write out the shift and mask functions at compile time
// from_byte<0> will be the same as (value & 0x000000FF) >> 0;
// from_byte<1> will be the same as (value & 0x0000FF00) >> 8;
// from_byte<2> will be the same as (value & 0x00FF0000) >> 16;
// from_byte<3> will be the same as (value & 0xFF000000) >> 24;
#pragma once
#include <cstdint>
template<size_t N>
constexpr auto from_byte(std::uint32_t value)
{
const std::uint32_t shift = 8 * N;
const std::uint32_t mask = 0xFF << shift;
std::uint32_t retval{ (value & mask) >> shift };
return static_cast<std::uint8_t>(retval);
}
// to_byte<1> will be the same as value << 8 etc...
template<size_t N>
constexpr auto to_byte(std::uint8_t value)
{
const std::uint32_t shift = 8 * N;
return static_cast<std::uint32_t>(value << shift);
}
//-------------------------------------------------------------------------------------------------
// header file color_t.h
#pragma once
#include <cstdint>
struct color_t
{
static color_t from_argb(std::uint32_t pixel);
static color_t from_bgra(std::uint32_t pixel);
std::uint32_t to_argb_value();
std::uint32_t to_bgra_value();
std::uint8_t alpha = 0;
std::uint8_t red = 0;
std::uint8_t green = 0;
std::uint8_t blue = 0;
};
//-------------------------------------------------------------------------------------------------
// source file color_t.cpp
#include<color_t.h>
#include <byte_masks.h>
// this is basically the logic you used reading the data as ARGB
// to create a color from an integer value
color_t color_t::from_argb(std::uint32_t pixel)
{
color_t color{};
color.alpha = from_byte<3>(pixel);
color.red = from_byte<2>(pixel);
color.green = from_byte<1>(pixel);
color.blue = from_byte<0>(pixel);
return color;
}
// But your bitmap data has a different order for alpha, red, green, blue!!!
// ANDROID_BITMAP_FORMAT_RGBA_8888
color_t color_t::from_bgra(std::uint32_t pixel)
{
color_t color{};
color.blue = from_byte<3>(pixel);
color.green = from_byte<2>(pixel);
color.red = from_byte<1>(pixel);
color.alpha = from_byte<0>(pixel);
return color;
}
std::uint32_t color_t::to_argb_value()
{
return (to_byte<3>(alpha) | to_byte<2>(red) | to_byte<1>(green) | to_byte<0>(blue));
}
std::uint32_t color_t::to_bgra_value()
{
return (to_byte<3>(blue) | to_byte<2>(green) | to_byte<1>(red) | to_byte<0>(alpha));
}
//-------------------------------------------------------------------------------------------------
// my main.cpp, but use the color_t functions from below in your code
#include <cassert>
#include <color_t.h>
int main()
{
// two lines just to simulate a bit of your code
std::uint32_t line[]{ 0x00000, 0x11223344 };
const size_t x = 1;
// now it's easy to get the color and change it.
// this will use the blue, green, red alpha order matching your 
// ANDROID_BITMAP_FORMAT_RGBA_8888 format.
auto color = color_t::from_bgra(line[x]);
color.red = 255;
// also note that by splitting out code into smaller functions
// it becomes much easier to read (specially for other people)
line[x] = color.to_bgra_value();
assert(to_byte<1>(line[x]) == 255);
}

我看到你的代码中有几个错误:

  1. 您将位图作为BGRA_8888读入tempPixels,并使用tempPixels作为新ARGB_8888缓冲区的源。您应该确保两个缓冲区具有相同的格式或翻转像素组件顺序。

  2. 传入位图有一个步幅(=行长度,以字节为单位),可能不等于4 *宽度。这意味着您应该将info.heightinfo.stride相乘。可能乘以4,我不知道跨步是否以像素为单位或以字节为单位。

  3. 正如我所说,输入像素格式是BGRA,但您完全忽略了A组件。这使得输出完全透明。我建议使用struct { uint8_t b,g,r,a; } pixel来分解像素并操作单个元素。

  4. 最后,是否有一个很好的理由,你不能操纵传入的位图,而不是创建一个新的并制作两个副本?

最新更新