Differenze tra le versioni di "Mostrare una immagine JPEG in una finestra con le funzioni del API di X11 e di Libjpeg"
Riga 247: | Riga 247: | ||
p = Decodifica_jpeg("<FONT Color=gray>''/percorso/del/file/immagine.jpg''</font>", VarPtr(iW), VarPtr(iH)) | p = Decodifica_jpeg("<FONT Color=gray>''/percorso/del/file/immagine.jpg''</font>", VarPtr(iW), VarPtr(iH)) | ||
− | If | + | If p == 0 Then Error.Raise("Errore !") |
disp = XOpenDisplay(Null) | disp = XOpenDisplay(Null) |
Versione delle 20:06, 1 dic 2021
Per mostrare una immagine JPEG in una finestra creata con le risorse della libreria del server grafico X11, sarà necessario decodificare il file immagine.
Per effettuare tale decodifica ci serviremo delle risorse esterne della libreria: "Libjpeg ".
Per maggiore sicurezza la maggior parte della procedura di decodifica sarà effettuata utilizzando istruzioni di codice in linguaggio C poste all'interno di una libreria condivisa .so, da noi realizzata, che sarà chiamata dal programma principale scritto in Gambas.
Per poter utilizzare le risorse esterne del API di X11 sarà necessario richiamare la libreria (nella sua attuale versione): "libX11.so.6.3.0" .
Pertanto, il codice C contenuto dalla libreria condivisa .so, da noi appositamente realizzata e che porremo nella cartella Dati dell'applicazione principale Gambas, supporta solo una profondità di colori non inferiore a 24 bit e sarà il seguente:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <X11/Xlib.h> #include <X11/keysym.h> #include <jpeglib.h> #include <jerror.h> #ifndef u_char #define u_char unsigned char #endif /*Ritorna un vettore per un'immagine a 24 bit.*/ u_char *Decodifica_jpeg (char *nomefile, int *widthP, int *heightP) { register JSAMPARRAY buffer; //--> occupa 8 byte struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr err_mgr; int bytePerPixel, x, y; FILE *fl; u_char *BufferRitorno; fl = fopen (nomefile, "rb"); if (NULL == fl) { perror (NULL); return NULL; } cinfo.err = jpeg_std_error (&err_mgr); jpeg_create_decompress (&cinfo); jpeg_stdio_src (&cinfo, fl); jpeg_read_header (&cinfo, 1); cinfo.do_fancy_upsampling = 0; cinfo.do_block_smoothing = 0; jpeg_start_decompress (&cinfo); *widthP = cinfo.output_width; *heightP = cinfo.output_height; bytePerPixel = cinfo.output_components; buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, (*widthP * bytePerPixel), 1); BufferRitorno = malloc (3 * (*widthP * *heightP)); if (NULL == BufferRitorno) { perror (NULL); return NULL; } if (3 == bytePerPixel) { int scorrLinea = (*widthP * 3); for (y = 0; y < cinfo.output_height; ++y) { jpeg_read_scanlines (&cinfo, buffer, 1); for (x = 0; x < scorrLinea; ++x) { BufferRitorno[(scorrLinea * y) + x] = buffer[0][x]; ++x; BufferRitorno[(scorrLinea * y) + x] = buffer[0][x]; ++x; BufferRitorno[(scorrLinea * y) + x] = buffer[0][x]; } } } else if (1 == bytePerPixel) { unsigned int col; int scorrLinea = (*widthP * 3); int indiceBuff; for (y = 0; y < cinfo.output_height; ++y) { jpeg_read_scanlines (&cinfo, buffer, 1); indiceBuff = 0; for (x = 0; x < scorrLinea; ++x) { col = buffer[0][indiceBuff]; BufferRitorno[(scorrLinea * y) + x] = col; ++x; BufferRitorno[(scorrLinea * y) + x] = col; ++x; BufferRitorno[(scorrLinea * y) + x] = col; ++indiceBuff; } } } else { fprintf (stderr, "Errore: il numero dei canali del colore è %d. Questa applicazione può gestire soltanto 1 o 3\n", bytePerPixel); return NULL; } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); fclose (fl); return BufferRitorno; }
Il codice Gambas potrà essere il seguente:
Private disp As Pointer Library "libX11:6.3.0" Public Struct XEventStruct type As Integer serial As Long send_event As Boolean display As Pointer windowL As Long root As Long subwindow As Long timeL As Long x As Integer y As Integer x_root As Integer y_root As Integer state As Integer keycode As Integer same_screen As Boolean End Struct Public Struct Visual XExtData As Pointer visualid As Integer classe As Long red_mask As Long green_mask As Long blue_mask As Long map_entries As Integer End Struct Private Const ExposureMask As Integer = 32768 Private Const KeyPressMask As Byte = 1 Private Const ButtonPressMask As Byte = 4 Private Const ZPixmap As Integer = 2 Private Enum KeyPress = 2, KeyRelease, ButtonPress, ButtonRelease, MotionNotify, EnterNotify, LeaveNotify, FocusIn, FocusOut, KeymapNotify, Expose, GraphicsExpose, NoExpose ' Display *XOpenDisplay(char *display_name) ' Opens a connection to the X server that controls a display. Private Extern XOpenDisplay(display$ As String) As Pointer ' XCloseDisplay(Display *display) ' Closes the connection to the X server for the display specified in the Display structure and destroys all windows. Private Extern XCloseDisplay(displayP As Pointer) ' int XDefaultScreen (Display *display) ' returns the default screen number referenced by the XOpenDisplay function. Private Extern XDefaultScreen(displayP As Pointer) As Integer ' unsigned long XWhitePixel (Display *display, int screen_number) ' returns the white pixel value for the specified screen. Private Extern XWhitePixel(displayP As Pointer, screen_number As Integer) As Long ' unsigned long XBlackPixel (Display *display, int screen_number) ' returns the black pixel value for the specified screen. Private Extern XBlackPixel(displayP As Pointer, screen_number As Integer) As Long ' Window XDefaultRootWindow(Display *display) ' Return the root window for the default screen. Private Extern XDefaultRootWindow(displayP As Pointer) As Integer ' Window XCreateSimpleWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, unsigned long border, unsigned long background) ' Creates an unmapped InputOutput subwindow for a specified parent window, returns the window ID of the created window. Private Extern XCreateSimpleWindow(displayP As Pointer, parent As Long, x As Integer, y As Integer, width As Integer, height As Integer, border_width As Integer, border As Integer, background As Long) As Integer ' XSetStandardProperties (Display *display, Window w, char *window_name, char *icon_name, Pixmap icon_pixmap, char **argv, int argc, XSizeHints *hints) ' Specifies a minimum set of properties describing the simplest application. Private Extern XSetStandardProperties(displayP As Pointer, w As Long, window_name As String, icon_name As String, icon_pixmap As Integer, argv As String, argc As Integer, hints As Pointer) ' XSelectInput (Display *display, Window w, long event_mask) ' Requests that the X server report the events associated with the specified Event mask. Private Extern XSelectInput(displayP As Pointer, w As Long, event_mask As Long) ' GC XCreateGC(Display *display, Drawable d, unsigned long valuemask, XGCValues *values) ' Creates a graphics context and returns a GC. Private Extern XCreateGC(displayP As Pointer, w As Long, valuemask As Long, values As Pointer) As Pointer ' XClearWindow(Display *display, Window w) ' Clears the entire area in the specified window. Private Extern XClearWindow(displayP As Pointer, w As Long) ' XMapRaised (Display *display, Window w) ' Raises the specified window to the top of the stack. Private Extern XMapRaised(displayP As Pointer, w As Long) ' XNextEvent (Display *display, XEvent *event_return) ' Gets the next event and remove it from the queue. Private Extern XNextEvent(displayP As Pointer, event_return As XEventStruct) ' XFreeGC(Display *display, GC gc) ' Destroys the specified GC as well as all the associated storage. Private Extern XFreeGC(displayP As Pointer, gcP As Pointer) ' XDestroyWindow(Display *display, Window w) ' Destroys the specified window as well as all of its subwindows. Private Extern XDestroyWindow(displayP As Pointer, w As Long) ' XPutImage(Display *display, Drawable d, GC gc, XImage *image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height) ' Combines an image with a rectangle of the specified drawable. Private Extern XPutImage(displayP As Pointer, w As Long, gcP As Pointer, image As Pointer, src_x As Integer, src_y As Integer, dest_x As Integer, dest_y As Integer, width As Integer, height As Integer) ' int XDefaultDepth(Display *display, int screen_number) ' Returns the depth (number of planes) of the default root window for the specified screen. Private Extern XDefaultDepth(displayP As Pointer, screen_number As Integer) As Integer ' Visual *XDefaultVisual(Display *display, int screen_number) ' Returns the default visual type for the specified screen. Private Extern XDefaultVisual(displayP As Pointer, screen_number As Integer) As Visual ' XImage *XCreateImage(Display *display, Visual *visual, unsigned int depth, int format, int offset, char *data, unsigned int width, unsigned int height, int bitmap_pad, int bytes_per_line) ' Allocates the memory needed for an XImage structure for the specified display but does not allocate space for the image itself. Private Extern XCreateImage(displayP As Pointer, visu As Visual, depth As Integer, formatI As Integer, offset As Integer, data As Integer[], width As Integer, height As Integer, bitmap_pad As Integer, bytes_per_line As Integer) As Pointer ' Status XInitImage(XImage *image) ' Initializes the internal image manipulation routines of an image structure, based on the values of the various structure members. Private Extern XInitImage(image As Pointer) ' void exit(int status) ' Terminates the calling process immediately.Any Open file descriptors belonging To the process are closed And any children Of the process are inherited. Private Extern exitus(status As Integer) In "libc:6" Exec "exit" Private Extern Decodifica_jpeg(FileImmagine As String, wP As Pointer, hP As Pointer) As Pointer In "/tmp/libadhoc_jpeg" Public Sub Main() Dim screen, prof, iW, iH As Integer Dim pxW, pxB, id As Long Dim ev As New XEventStruct Dim p, img, gc As Pointer Dim ImmBuffer As Integer[] ' Crea la nostra libreria condivisa ad hoc: If Exist("/tmp/libadhoc_jpeg.c") = False Then Copy "libadhoc_jpeg.c" To "/tmp/libadhoc_jpeg.c" Shell "gcc -o /tmp/libadhoc_jpeg.so /tmp/libadhoc_jpeg.c -shared -fPIC -lX11 -ljpeg" Wait p = Decodifica_jpeg("/percorso/del/file/immagine.jpg", VarPtr(iW), VarPtr(iH)) If p == 0 Then Error.Raise("Errore !") disp = XOpenDisplay(Null) If disp == 0 Then Error.Raise("Impossibile aprire il display !") screen = XDefaultScreen(disp) prof = XDefaultDepth(disp, screen) ImmBuffer = Crea_Dati_immagine(screen, prof, p, iW, iH) img = XCreateImage(disp, Null, prof, ZPixmap, 0, ImmBuffer, iW, iH, 32, 0) If img == 0 Then Error.Raise("Errore !") pxW = XWhitePixel(disp, screen) pxB = XBlackPixel(disp, screen) id = XCreateSimpleWindow(disp, XDefaultRootWindow(disp), 0, 0, iW, iH, 5, pxW, &FF0000) Print "ID della finestra creata: "; Hex(id, 6) XSetStandardProperties(disp, id, "Prova creazione finestra", "Nome icona finestra", 0, Null, 0, Null) XSelectInput(disp, id, ExposureMask Or KeyPressMask Or ButtonPressMask) gc = XCreateGC(disp, id, 0, Null) If gc == 0 Then Error.Raise("Impossibile creare un nuovo contesto grafico !") XMapRaised(disp, id) While True XNextEvent(disp, ev) Select Case ev.type Case Expose redraw(id) XInitImage(img) XPutImage(disp, id, gc, img, 0, 0, 0, 0, iW, IH) Case Else Exit End Select Wend chiude_X(id, gc) End Private Procedure redraw(idR As Integer) ' Pulisce la superficie della finestra da ogni elemento presente: XClearWindow(disp, idR) End Private Procedure chiude_X(idCh As Integer, gcont As Pointer) XFreeGC(disp, gcont) ' Chiude la finestra: XDestroyWindow(disp, idCh) XCloseDisplay(disp) exitus(0) End Private Function Crea_Dati_immagine(screen As Integer, profond As Integer, buf As Pointer, width As Integer, height As Integer) As Integer[] Dim r, g, b, scorr As Integer Dim vis As New Visual Dim rRatio, gRatio, bRatio As Float Dim vettI As Integer[] Dim st As Stream Dim buffer As Byte vis = XDefaultVisual(disp, screen) rRatio = CFloat(vis.red_mask) / 255.0 gRatio = CFloat(vis.green_mask) / 255.0 bRatio = CFloat(vis.blue_mask) / 255.0 st = Memory buf For Read If profond >= 24 Then vettI = New Integer[](width * height) Repeat Read #st, buffer r = CInt(buffer * rRatio) Read #st, buffer g = CInt(buffer * gRatio) Read #st, buffer b = CInt(buffer * bRatio) r = r And vis.red_mask g = g And vis.green_mask b = b And vis.blue_mask vettI[scorr] = r Or g Or b Inc scorr Until scorr >= vettI.Max Else Error.Raise("Questa applicazione non supporta una profondità inferiore a 24 !") Endif st.Close Return vettI End