Why the stride of image returned from Tango Support C-API is strange? - google-project-tango

Anyone find similar issue: Strange image.stride returned by TangoSupport_getLatestImageBufferAndNewDataFlag in Tango Support C-API (Qianru July, 2016) ?
.....
TangoImageBuffer* b = nullptr;
TangoSupport_getLatestImageBufferAndNewDataFlag(image_buffer_manager, &b, &new_image);
if(new_image)
{
LOGE("b: %p: width %zu, stride %zu", b, b->width, b->stride );
}
....
The output is:
b: 0x4cdd3ca8: width 1280, stride 7471215
b: 0x4cdd3c78: width 1280, stride 0
b: 0x4cbbe500: width 1280, stride 6881398
b: 0x4cdd3ca8: width 1280, stride 7471215
.... repeat from the above line ...
Pointer, and width look fine. But the stride looks strange.

This is a problem on the Tango side, and it's fixed in the currently release (T release).

Related

How to use glReadPixels to read pixels to bitmap in Android NDK?

I use glReadPixels to read pixels data to bitmap, and get a wrong bitmap.
Main code is blow:
jni code
jint size = width * height * 4;
GLubyte *pixels = static_cast<GLubyte *>(malloc(size));
glReadPixels(
0,
0,
width,
height,
GL_RGBA,
GL_UNSIGNED_BYTE,
pixels
)
kotlin code
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
var dataBuf = ByteBuffer.wrap(pixels)
dataBuf.rewind()
bitmap.copyPixelsFromBuffer(dataBuf)
And get the wrong bitmap like blow
The correct one should like this
Anyone can tell me where is wrong?
The reason is that the texture has been rotated and the sort to read pixels has been changed.

Very unexpected behavior of C++ win32 BitBlt

I noticed when I try to run BitBlt, the resulting data buffer is unexpected in two ways:
It is flipped along the y axis (the origin seems to be bottom left instead of top left)
In each RGBA grouping, the R and B values seem to be switched.
For the first issue, I noticed it when testing with my command prompt; if my command prompt was in the upper left portion of the screen, it would only say it was black when my cursor was in the lower left portion. I had to fix the inversion of the y axis by changing int offset = (y * monitor_width + x) * 4; to int offset = ((monitor_height - 1 - y) * monitor_width + x) * 4; this fixed the pixel location issue because it was showing black where I expected black.
However, the colors were still strong. I tested by trying to get the color of known pixels. I noticed every blue pixel had a very high R value and every red pixel had a very high blue value. That's when I compared with an existing tool I had and found out that the red and blue values seem to be switched in every pixel. At first I thought it was backwards or a byte alignment issue, but I also verified in a clustering of pixels that aren't uniform to make sure it's picking the right position of pixel, and it did perfectly well, just with the colors switched.
Full simplified code below (originally my tool was getting my cursor position and printing the pixel color via hotkey press; this is a simplified version that gets one specific point).
BYTE* my_pixel_data;
HDC hScreenDC = GetDC(GetDesktopWindow());
int BitsPerPixel = GetDeviceCaps(hScreenDC, BITSPIXEL);
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
int monitor_width = GetSystemMetrics(SM_CXSCREEN);
int monitor_height = GetSystemMetrics(SM_CYSCREEN);
std::cout << std::format("monitor width height: {}, {}\n", monitor_width, monitor_height);
BITMAPINFO info;
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biWidth = monitor_width; // client_width;
info.bmiHeader.biHeight = monitor_height; // client_height;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = BitsPerPixel;
info.bmiHeader.biCompression = BI_RGB;
HBITMAP hbitmap = CreateDIBSection(hMemoryDC, &info, DIB_RGB_COLORS, (void**)&my_pixel_data, 0, 0);
SelectObject(hMemoryDC, hbitmap);
BitBlt(hMemoryDC, 0, 0, monitor_width, monitor_height, hScreenDC, 0, 0, SRCCOPY);
int x = 12, y = 12;
int offset = ((monitor_height - 1 - y) * monitor_width + x) * 4;
std::cout << std::format("debug: ({}, {}): ({}, {}, {})\n", x, y, (int)my_pixel_data[offset], (int)my_pixel_data[offset + 1], (int)my_pixel_data[offset + 2], (int)my_pixel_data[offset + 3]);
system("pause");
The output of this will be debug: (12, 12): (199, 76, 133) even though another program has verified the colors are actually (133, 76, 199).
I can easily fix this in my code by flipping the y axis and switching each R and B value and the program will work perfectly well. However, I am just baffled by how this happened and whether there's a more elegant fix.
I can answer the RGB (and it looks like Hans answered the inverted Y axis in a comment). Remember that RGB is stored 0xAARRGGBB, so in that 32 bit value BB is byte 0, GG is byte 1, and RR is byte 2 (alpha is byte 3 if you use it), so when you index in at +0, +1 and +2 you're actually getting the values correctly. When we say RGB we're saying the colors in opposite order of how they're stored in memory.

Display data from pnglib as an ximage

I need to import a PNG and display it on screen in a Motif application. For reasons best known to myself, I don't want to use any more libraries than I need to, and I'd like to stick with just Motif and pnglib.
I've been battling with this for a couple of days now, and I'd like to put aside my pride and ask for some help. This screenshot shows the problem:
https://s3.amazonaws.com/gtrebol264929/pnglib_fail.png
The window on the right shows what the image should look like, the window on the left is my Motif application showing what it looks like in my app. Clearly I've got the image data OK, as the basic concept of the picture can be seen. But also clearly I've messed up how I get the pixel data from pnglib into an XImage. Below is my code:
char * xdata = malloc(width * height * (channels + 1));
memset(xdata,100,width * height * channels);
int colc = 0;
int bytec = 0;
while (colc < width) {
int rowc = 0;
while(rowc < height) {
png_byte * row = png.row_pointers[rowc];
memcpy(&xdata[bytec],&row[colc],1);
bytec += 4;
rowc += 1;
}
colc += 1;
}
XImage * img = XCreateImage(display, CopyFromParent, depth * channels, ZPixmap, 0, xdata, width, height, 32, bytes_per_line);
printf("PNG %ix%i (depth: %i x %i) img: %p\n",width,height,depth,channels,img);
XPutImage (display, win, gc, img, 0, 0, 0, 0, width, height); // 0, 0, 0, 0 are src x,y and dst x,y
png.row_pointers is the pixel data from pnglib.
I'm pretty sure I've just misunderstood how the pixel data is stored, but I can't quite work out what I've done wrong. Any help is very much appreciated.
All the best
Garry

how to draw text on a memory buffer

I want to draw some text on a memory buffer, but don't know how to. please help, many thanks!
Code:
widht = 640;
height = 480;
pBuf = malloc( width * 3 * height );
memset( pBuf, 0, width * 3 * height );
//DrawText is the function that needs to be implemented, and I don't know how to do it.
DrawText( "this is the text that i want to draw on the buffer", pBuf, width, height, 3 );
//now there is text on the memory buffer pointed to by pBuf.

How do I find a dimension of aspect ratio 4:3 which fits within a predetermined size?

The problem here is I have a display window of size x by y, and I need to display an image inside the window without any scrolling, and to maintain the aspect ratio of 4:3. I have the following snippet of code:
// Lock the current height, calculate new width of the canvas and scale the viewport.
// get width of the movie canvas
qreal width = canvas_->width();
// Find the height of the video
qreal height = (width/4.0) * 3;
// find original width and height for video to calculate scaling factor
qreal videoWidth = movieData_->GetWidth();
qreal videoHeight = movieData_->GetHeight();
// calculate scaling factor
qreal scaleFactorWidth = width/videoWidth;
qreal scaleFactorHeight = height/videoHeight;
Of course, by using either the height, or the width as the 'anchor', one way or other the new image will cause scrolling (assuming the original image is larger than the window in the first place). How do I find a dimension of aspect ratio 4:3 which fits within a predetermined size?
Edit
I would need to pass in a scale factor for both x and y to do the scaling
canvas_->scale(scaleFactorWidth, scaleFactorHeight);
Just take the minimum of the both calculated values:
scale = min(scaleFactorWidth, scaleFactorHeight)
or (if you want outer-fit)
scale = max(scaleFactorWidth, scaleFactorHeight)
struct dimensions resize_to_fit_in(struct dimensions a, struct dimensions b) {
double wf, hf, f;
struct dimensions out;
wf = (double) b.w / a.w;
hf = (double) b.h / a.h;
if (wf > hf)
f = hf;
else
f = wf;
out.w = a.w * f;
out.h = a.h * f;
return out;
}
An here is a C version where the returned dimension will be a dimension 'a' fitted in dimension 'b' without loosing aspect ratio.
Find the largest of the two values width, w and height h. Say your maximum width x height is 100 x 80. Note that 100/80 = 1.25.
Case 1: If w/h > 1.25, then divide w by 100 to get the ratio of your original size to the new size. Then multiply h by that ratio.
Case 2: Otherwise, then divide h by 80 to get the ratio of your original size to the new size. Then multiply w by that ratio.
Here's an ActionScript version of what you ask (resize while maintaining aspect ratio)... shouldn't be too hard to port to whatever:
private static function resizeTo(dispObj:DisplayObject, width:Number, height:Number) : void
{
var ar:Number = width / height;
var dispObjAr:Number = dispObj.width/dispObj.height;
if (ar < dispObjAr)
{
dispObj.width = width;
dispObj.height = width / dispObjAr;
}
else
{
dispObj.height = height;
dispObj.width = height * dispObjAr;
}
return;
}
EDIT: In order to maintain 4:3 the source images would need to be 4:3

Resources