How can I print 16-bit grayscale image in SDL? - c

I have a structure which contains 16-bit grayscale image from scientific camera, structure is like this:
struct qscam_image {
int row;
int col;
int max_gray; // this should be 65535
unsigned short *data;
};
Then I have program which should display updated grayscale image each second or so (depending on time which takes to transfer data from camera).
#include <GL/gl.h>
#include <GL/glu.h>
#include "qscapi.h"
#include <SDL/SDL.h>
static void render(SDL_Surface * sf)
{
SDL_Surface * screen = SDL_GetVideoSurface();
if(SDL_BlitSurface(sf, NULL, screen, NULL) == 0)
SDL_UpdateRect(screen, 0, 0, 0, 0);
}
int main(int argc, char **argv)
{
//initialize camera
struct qscam_image *image = NULL;
qscam_create_image(&image);
qscam_init();
//initialize SDL
SDL_Event ev;
int active;
/* Initialize SDL */
if(SDL_Init(SDL_INIT_VIDEO) != 0)
fprintf(stderr,"Could not initialize SDL: %s\n",SDL_GetError());
SDL_SetVideoMode(1900, 1080, 24, SDL_HWSURFACE);
/* Main loop */
active = 1;
while(active)
{
/* Handle events */
while(SDL_PollEvent(&ev))
{
if(ev.type == SDL_QUIT)
active = 0; /* End */
}
qscam_get_image(0.030, &image); //get image from camera
/* create the image variable */
Uint32 mask = 0xff00; // gray
SDL_Surface* print_image = SDL_CreateRGBSurfaceFrom
(image->data, image->col, image->row,
16, image->col*2, mask, mask, mask, 0);
render(print_image);
}
/* Exit */
qscam_disconnect();
qscam_destroy_image(&image);
SDL_Quit();
return 0;
}
It works to some extent, with mask=0x00ff it displays random noise but that is only 8-bit image. With mask=0xffff nothing is displayed and with mask=0xff00 again image is displayed, but in a way that leads me to think that the image matrix should be transposed.
First question: What is the proper way to display 16-bit grayscale image (which is in memory saved as unsigned short[]) using SDL and c?
And second question: Is there any easy way to transpose image matrix with SDL or do I have to write separate function?

Related

How to blit a transparent surface onto screen ie. for it to not be displayed

Hey I'm trying to find out which channel is alpha.
But everytime I blit what I think should be a completely transparent surface it turns out to modify the RGB channels as well.
SDL 1.2-master
Here's my code and what I've problem with:
#include <SDL/SDL.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
int main(int argc, char** argv) {
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) == -1) {
fprintf(stderr, "Couldn't initialize SDL: %s.\n", SDL_GetError());
exit(-1);
}
SDL_Rect** modes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
if(!modes) {
printf(":(\n");
return 1;
}
SDL_Surface* screen = SDL_SetVideoMode(modes[0]->w, modes[0]->h, 0, SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF);
if(!screen) {
printf(":(\n");
return 1;
}
SDL_Surface* surface = SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA, 32, 32, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
if(!surface) {
printf(":((\n");
return 1;
}
for(int i=0; i!=32; i++) {
for(int j=0; j!=32; j++) {
// 0 blue
// 1 green
// 2 red
// 3 alpha?
((char*)(surface->pixels))[0+i*4*32+j*4] = 0xff;
((char*)(surface->pixels))[1+i*4*32+j*4] = 0xff;
((char*)(surface->pixels))[2+i*4*32+j*4] = 0xff;
((char*)(surface->pixels))[3+i*4*32+j*4] = 0xff; // SDL_OPAQUE_ALPHA is 0xFF
// not an alpha channel
}
}
int ret = SDL_BlitSurface(surface, NULL, screen, NULL);
SDL_Flip(screen);
sleep(2);
for(int i=0; i!=32; i++) {
for(int j=0; j!=32; j++) {
// 0 blue
// 1 green
// 2 red
// 3 alpha?
((char*)(surface->pixels))[0+i*4*32+j*4] = 0x30;
((char*)(surface->pixels))[1+i*4*32+j*4] = 0x40;
((char*)(surface->pixels))[2+i*4*32+j*4] = 0x50;
((char*)(surface->pixels))[3+i*4*32+j*4] = 0x00;// This surface should be transparent, SDL_TRANSPARENT_ALPHA is 0
// not an alpha channel
}
}
int ret = SDL_BlitSurface(surface, NULL, screen, NULL);
while(1) {
SDL_Flip(screen);
//if the color is anything but pure white, alpha channel modification failed.
}
}
I basically need this code working for font handling.
For now I do one surface per glyph(Yeah I should do something else).
I need to be able to set the alpha channel to a value of the surface and have a guarantee that if the alpha is set to partial/full transparency that the RGB values of the texture don't get blitted.
Consider this example:
void main(void) {
unsigned int t = 0x000000ff;
unsigned char *ct = (unsigned char*)&t;
printf("0x%x 0x%x 0x%x 0x%x\n", ct[0], ct[1], ct[2], ct[3]);
}
On little-endian machine (i.e. most machines nowadays) it will output 0xff 0x0 0x0 0x0. You set alpha mask to 0x000000ff, meaning when you access pixels your byte offset for alpha channel is 0 (i.e. in memory it is placed as A,B,G,R).
On a big-endian machine the output would be 0x0 0x0 0x0 0xff, as byte order in integer is opposite (R,G,B,A in memory).
If you look at SDL 1.2 documentation for SDL_CreateRGBSurface you may notice that example code checks for SDL_BYTEORDER and reverses masks upon surface creation to keep consistent byte order.
You already set SDL_SRCALPHA flag upon surface creation, so no SDL_SetAlpha is required; but when you set surface values you set alpha value to incorrect offset, as alpha is at offset 0 (if you're on little-endian machine).

why is incorrect audio format?

when i start the code i get warning: incorrect audio format
i figured out its related to the mp3 file.
whats the problem and how can i fix it?
i already tried to convert the mp3 to a wav file but that also didnt work.
is it possible that 3mb of mp3 is to big? shouldnt be?
Edit: when i let it run without of mp3 the wav files will run just fine
with mp3 the programm will start but no sound at all
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
static const int width = 800;
static const int height = 600;
int main(int argc, char **argv)
{
// Initialize SDL video and audio systems
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
// Initialize SDL mixer
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 3, 2048);
// Load audio files
Mix_Music *backgroundSound = Mix_LoadMUS("portfolio.mp3");
Mix_Chunk *jumpEffect = Mix_LoadWAV("JumpEffect.wav");
Mix_Chunk *laserEffect = Mix_LoadWAV("LaserEffect.wav");
//Mix_Chunk *musicEffect = Mix_LoadWAV("portfolio2.wav");
// Create a SDL window
SDL_Window *window = SDL_CreateWindow("Hello, SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_OPENGL);
// Create a renderer (accelerated and in sync with the display refresh rate)
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
// Start the background music
Mix_PlayMusic(backgroundSound, -1);
bool running = true;
SDL_Event event;
while(running)
{
// Process events
while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
running = false;
}
else if(event.type == SDL_KEYDOWN)
{
// Press "1" and play jump effect
if(event.key.keysym.sym == SDLK_1)
{
Mix_PlayChannel(-1, jumpEffect, 0);
}
// Press "2" and play laser effect
else if(event.key.keysym.sym == SDLK_2)
{
Mix_PlayChannel(-1, laserEffect, 0);
}
}
}
// Clear screen
SDL_RenderClear(renderer);
// Draw
// Show what was drawn
SDL_RenderPresent(renderer);
}
// Release resources
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
Mix_FreeMusic(backgroundSound);
Mix_FreeChunk(jumpEffect);
Mix_FreeChunk(laserEffect);
//Mix_FreeChunk(music);
Mix_CloseAudio();
SDL_Quit();
return 0;
}

Create a System Tray Icon in Linux without GTK/QT

I need to create a Tray Icon for my application using purely the Xlib. After some searching, reading the XEmbed documentation and some stuff on SO, this is what the code looks like so far (mostly copy & paste). I understand what it does, but not why. It is creating a tray icon appearantly, but only 1px wide in my mate-panels area. What am I doing wrong? Why is it not the size of a normal tray icon?
Here is my code:
#include <X11/Xutil.h>
#include <string.h>
#define MIN(A, B) ((A) < (B) ? (A) : (B))
/* --------- XEMBED and systray stuff */
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
static int trapped_error_code = 0;
static int (*old_error_handler) (Display *, XErrorEvent *);
static int
error_handler(Display *display, XErrorEvent *error) {
trapped_error_code = error->error_code;
return 0;
}
void
trap_errors(void) {
trapped_error_code = 0;
old_error_handler = XSetErrorHandler(error_handler);
}
int
untrap_errors(void) {
XSetErrorHandler(old_error_handler);
return trapped_error_code;
}
void
send_systray_message(Display* dpy, long message, long data1, long data2, long data3) {
XEvent ev;
Atom selection_atom = XInternAtom (dpy,"_NET_SYSTEM_TRAY_S0",False);
Window tray = XGetSelectionOwner (dpy,selection_atom);
if ( tray != None)
XSelectInput (dpy,tray,StructureNotifyMask);
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = tray;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1; // <--- your window is only here
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, tray, False, NoEventMask, &ev);
XSync(dpy, False);
usleep(10000);
if (untrap_errors()) {
/* Handle errors */
}
}
/* ------------ Regular X stuff */
int
main(int argc, char **argv) {
int width, height;
XWindowAttributes wa;
XEvent ev;
Display *dpy;
int screen;
Window root, win;
/* init */
if (!(dpy=XOpenDisplay(NULL)))
return 1;
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
if(!XGetWindowAttributes(dpy, root, &wa))
return 1;
width = height = MIN(wa.width, wa.height);
/* create window */
win = XCreateSimpleWindow(dpy, root, 0, 0, width, height, 0, 0, 0x7F7F997F);
send_systray_message(dpy, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0); // pass win only once
XMapWindow(dpy, win);
XSync(dpy, False);
/* run */
while(1) {
while(XPending(dpy)) {
XNextEvent(dpy, &ev); /* just waiting until we error because window closed */
}
}
}
I am thankful for everything that will point me in the right direction, even if its just some documentation that I have not found so far.

How to draw on a texture using SDL2_gfx in SDL2 and then render?

I want to implement a MS-Paint-like program (although my actual program will do more than this) where one can draw using mouse.
I am using SDL2 and also SDL2_gfx.
I want to maintain an SDL_Texture where the user will do the drawing in a continuously way without clearing (unless requested by the user) at any time.
And then continuously update the SDL_Texture on to the screen.
My question specifically is how to draw SDL2_gfx primitives on the SDL_Texture and copy that to the renderer. Any completely different way than to use texture will also do for me but must be using SDL2.
Below is a minimal runnable extraction from my code:
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <SDL2/SDL.h>
#include <SDL2_gfxPrimitives.h>
#define WIDTH (320)
#define HEIGHT (240)
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_RendererInfo rendererInfo;
SDL_Texture* texture = NULL;
SDL_Event event;
Sint16 cx = WIDTH/2, cy = HEIGHT/2;
uint8_t quit = 0;
void init()
{
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, SDL_WINDOW_OPENGL, &window, &renderer);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, WIDTH, HEIGHT); // create texture to draw on to
// SDL_SetRenderTarget(renderer, texture); // this one I have removed
}
void draw()
{
pixelRGBA(renderer, cx, cy, 0xff, 0xff, 0x00, 0xff); // draw a pixel here, or whatever cx and cy are mouse position
// what I want is to draw on to the texture, and not directly on the screen buffer
}
void render()
{
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // set clear color
SDL_RenderClear(renderer); // clear the buffer
SDL_RenderCopy(renderer, texture, NULL, NULL); // now copy the drawn texture to the buffer
SDL_RenderPresent(renderer); // now update window
}
int main(int argc, char* argv[])
{
int p;
init();
while(!quit)
{
SDL_PumpEvents();
p = SDL_PollEvent(&event);
if(p>0)
{
if(event.type==SDL_QUIT) quit = 1;
else
{
// here other things are there to handle the mouse positions etc for drawing exactly what the user wants
// ...
draw();
render();
}
}
}
SDL_Quit();
return 0;
}
Thanks in advance.

Edit the amount of colors available in a picture plotting program. It's written in C with Xlib

I'm a fortran programmer working with a program written in C (which I have Little to no experience with).
I have a program written in fortan that creates an image in the form of a multidimentional array of pixels with their X value, Y value, and RGB values (0-4 for each color). It then passes the array, the size of the array in the x and y dimensions, the color map containing all the colors arranged in a spectrum, and the number of colors in the spectrum to a program written in C that is supposed to plot the image using Xlib.
The program works when I pass a particular one color map with 125 colors (5 values for red/green/blue) but when I try to increase the amount of colors I pass to the C program I exceed some sort of limit and the program shuts down. How do I raise the limit in the C source code?
Here is the program:
#define USEPIXMAP /* sets drawing into background pixmap of window */
#include "putras.h"
#include <stdlib.h>
static unsigned def_map[256];
void putras_(int *pixel_values, int *arrayx, int *arrayy,
int *colormap_entries, int *colormap_size)
{
extern Colormap cmap;
extern Window window;
extern Display *dpy;
extern XColor color;
extern XWindowAttributes window_attr;
extern GC gc;
extern XGCValues gcv;
extern Pixmap pixmap;
static int call_flag = 0;
char *display_name=NULL;
char *dummy;
unsigned pixel;
int i, j;
XPoint *pointarray[256];
unsigned arraylen[256];
unsigned maxlen[256];
int remain_len;
if(call_flag == 0) {
/* THis only gets done on the first call to putras */
call_flag = 1;
if( (dpy = XOpenDisplay(display_name) ) == NULL){
fprintf(stderr,"Error: Couldn't open display\n");
exit(1);
}
XGetWindowAttributes(dpy, RootWindow(dpy,DefaultScreen(dpy)),
&window_attr);
window=XCreateSimpleWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)), 0, 0,
*arrayx, *arrayy,window_attr.border_width,
BlackPixel(dpy, DefaultScreen(dpy)),
WhitePixel(dpy, DefaultScreen(dpy)));
#ifdef USEPIXMAP
pixmap=XCreatePixmap(dpy, window, *arrayx, *arrayy,
DefaultDepth(dpy,DefaultScreen(dpy)) );
XMapWindow(dpy, window);
XClearWindow(dpy, window);
XCopyArea(dpy, window, pixmap, DefaultGC(dpy, DefaultScreen(dpy)),
0,0,*arrayx, *arrayy, 0,0);
XFlush(dpy);
#else
XMapWindow(dpy, window);
#endif
cmap=DefaultColormap(dpy,DefaultScreen(dpy));
color.flags=DoRed|DoBlue|DoGreen;
for (i=0;i<(*colormap_size);i++){
color.pixel= colormap_entries[4*i];
j = color.pixel;
color.red=colormap_entries[4*i+1];
color.green=colormap_entries[4*i+2];
color.blue=colormap_entries[4*i+3];
XAllocColor(dpy, cmap, &color);
def_map[j] = color.pixel;
}
gc = XCreateGC(dpy, window, 0, NULL);
} /* Endif - first time through */
/* The following gets done on each call */
for (i=0; i<256; i++){
pointarray[i]=(XPoint *)malloc((*arrayx)*(*arrayy)/128*sizeof(XPoint));
maxlen[i]=(*arrayx)*(*arrayy)/128 -1;
arraylen[i]=0;
}
for (j=0; j<(*arrayy); j++) {
for (i=0; i<(*arrayx); i++) {
/*pixel = def_map[pixel_values[j * (*arrayx) + i]];*/
pixel=pixel_values[j*(*arrayx)+i];
/*pixel=1;*/
if (arraylen[pixel]==maxlen[pixel]) {
pointarray[pixel]= (XPoint *)realloc(pointarray[pixel],
2*maxlen[pixel]*sizeof(XPoint));
maxlen[pixel]=2*maxlen[pixel];
}
pointarray[pixel][arraylen[pixel]].x=i;
pointarray[pixel][(arraylen[pixel])++].y=j;
} /* end for loop*/
} /* end for loop*/
for (i=0; i<256; i++) {
XSetForeground(dpy, gc, def_map[i]);/*dpy,gc,i);*/
if (arraylen[i]>=MAXPOINT) {
for (j=0; j<=(arraylen[i]/MAXPOINT); j++) {
remain_len=(arraylen[i]-MAXPOINT*j);
#ifdef USEPIXMAP
XDrawPoints(dpy, pixmap, gc,(pointarray[i]+j*MAXPOINT),
((remain_len<MAXPOINT)?remain_len:MAXPOINT),
CoordModeOrigin);
#else
XDrawPoints(dpy, window, gc,(pointarray[i]+j*MAXPOINT),
((remain_len<MAXPOINT)?remain_len:MAXPOINT),
CoordModeOrigin);
#endif
} /* end for loop */
} else {
#ifdef USEPIXMAP
XDrawPoints(dpy, pixmap, gc, pointarray[i], arraylen[i],
CoordModeOrigin);
#else
XDrawPoints(dpy, window, gc, pointarray[i], arraylen[i],
CoordModeOrigin);
#endif
} /* end if */
} /* end for loop 256 */
#ifdef USEPIXMAP
XSetWindowBackgroundPixmap(dpy, window, pixmap);
XClearWindow(dpy, window);
#endif
XFlush(dpy);
for (i=0; i<256;i++)
free(pointarray[i]);
return;
}
void unmap(void)
{
/* extern Pixmap pmap; */
extern Window window;
extern Display *dpy;
/* int width, height; */
XUnmapWindow(dpy, window);
XFlush(dpy);
return;
}
void remap(void)
{
extern Window window;
extern Display *dpy;
XMapRaised(dpy, window);
XFlush(dpy);
return;
}

Resources