Convert C-Source image dump into original image - c++

I have created with GIMP a C-Source image dump like the following:
/* GIMP RGBA C-Source image dump (example.c) */
static const struct {
guint width;
guint height;
guint bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
guint8 pixel_data[304 * 98 * 2 + 1];
} example= {
304, 98, 2,
"\206\061\206\061..... }
Is there a way to read this in GIMP again in order to get back the original image? because it doesn't seem possible.
Or does it exist a tool that can do this back-conversion?
EDITED
Following some suggestion I tried to write a simple C programme to make the reverse coversion ending up with something very similar to another code found on internet but both dont work:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "imgs_press.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
using namespace std;
int main(int argc, char** argv) {
int fd;
char *name = "orignal_img.pnm";
fd = open(name, O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("open failed");
exit(1);
}
if (dup2(fd, 1) == -1) {
perror("dup2 failed");
exit(1);
}
// file descriptor 1, i.e. stdout, now points to the file
// "helloworld" which is open for writing
// You can now use printf which writes specifically to stdout
printf("P2\n");
printf("%d %d\n", press_high.width, press_high.height);
for(int x=0; x<press_high.width * press_high.height * 2; x++) {
printf("%d ", press_high.pixel_data[x]);
}
}
As suggested by n-1-8e9-wheres-my-share-m, maybe I need to manipulate the pixels usign the correct decode, but I have no idea how to do that, does anybody have other suggestions?
The image I got is indeed distorted:

Updated Answer
If you want to decode the RGB565 and write a NetPBM format PNM file without using ImageMagick, you can do this:
#include <stdint.h> /* for uint8_t */
#include <stdio.h> /* for printf */
/* tell compiler what those GIMP types are */
typedef int guint;
typedef uint8_t guint8;
#include <YOURGIMPIMAGE>
int main(){
int w = gimp_image.width;
int h = gimp_image.height;
int i;
uint16_t* RGB565p = (uint16_t*)&(gimp_image.pixel_data);
/* Print P3 PNM header on stdout */
printf("P3\n%d %d\n255\n",w, h);
/* Print RGB pixels, ASCII, one RGB pixel per line */
for(i=0;i<w*h;i++){
uint16_t RGB565 = *RGB565p++;
uint8_t r = (RGB565 & 0xf800) >> 8;
uint8_t g = (RGB565 & 0x07e0) >> 3;
uint8_t b = (RGB565 & 0x001f) << 3;
printf("%d %d %d\n", r, g ,b);
}
}
Compile with:
clang example.c
And run with:
./a.out > result.pnm
I have not tested it too extensively beyond your sample image, so you may want to make a test image with some reds, greens, blues and shades of grey to ensure that all my bit-twiddling is correct.
Original Answer
The easiest way to get your image back would be... to let ImageMagick do it.
So, take your C file and add a main() to it that simply writes the 304x98x2 bytes starting at &(example.pixel_data) to stdout:
Compile it with something like:
clang example.c -o program # or with GCC
gcc example.c -o program
Then run it, writing to a file for ImageMagick with:
./program > image.bin
And tell ImageMagick its size, type and where it is and what you want as a result:
magick -size 304x98 RGB565:image.bin result.png
I did a quick, not-too-thorough test of the following code and it worked fine for an image I generated with GIMP. Note it doesn't handle alpha/transparency but that could be added if necessary. Save it as program.c:
#include <unistd.h> /* for write() */
#include <stdint.h> /* for uint8_t */
/* tell compiler what those GIMP types are */
typedef int guint;
typedef uint8_t guint8;
<PASTE YOUR GIMP FILE HERE>
int main(){
/* Work out how many bytes to write */
int nbytes = example.width * example.height * 2;
/* Write on stdout for redirection to a file - may need to reopen in binary mode if on Windows */
write(1, &(example.pixel_data), nbytes);
}
If I run this with the file you provided via Google Drive I get:

Related

Too few arguments to function 'int fclose(FILE*)'

Hello I am a beginner of C language for microprocessors. I want to read a ''.bmp'' file in order to apply line detection on it. I have declared a function to read the image. This error occurs when compile button is pushed:
#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h" // SD Card ESP32
#include "SD_MMC.h" // SD Card ESP32
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h> // read and write from flash memory
#include <SPI.h>
void imageReader(const char *imgName,
int *height,
int *width,
int *bitdepth,
unsigned char *header,
unsigned char *_colortable,
unsigned char *buf
) // READ AN IMAGE
{
int i;
fs::FS &fs = SD_MMC; //
FILE *file;
file = fopen(imgName,"rb"); // read imgName file ( it is a picture in .bmp format )
if(!file){
Serial.printf("Unable to read image");
}
for(i=0 ; i<54 ; i++){
header[i]=getc(file);
}
*width = *(int * )& header[18]; // width information of the image
*height = *(int * )& header[22]; // height information of image
*bitdepth = *(int *)& header[28];
if(*bitdepth<=8){
fread(_colortable,sizeof(unsigned char),1024,file);
}
fread(buf,sizeof(unsigned char),( 1600 * 1200 ) ,file);
fclose();
}
It gives this error. too few arguments to function 'int fclose(FILE*)'
The fclose() function needs to know which file to close. You need to tell it that by supplying "file" as an argument. You want to use fclose(file).

What do I have to do to execute code in data areas, ( segment protection )

I work on a linux platform and I use g++ with the above program that copies a function from the code area to the data area. How do I change protection of data segment in order to allow me to execute the copied function ?
The code is bellow:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define Return asm volatile("pop %rbp; retq; retq; retq; retq; retq;")
int64_t funcEnd=0xc35dc3c3c3c3c35d;
constexpr int maxCode=0x800;
int8_t code[maxCode];
void testCode(void){
int a=8,b=7;
a+=b*a;
Return;
}
typedef void (*action)(void);
int main(int argc, char **argv)
{
action a=&testCode;
testCode();
int8_t *p0=(int8_t*)a,*p=p0,*p1=p0+maxCode;
for(;p!=p1;p++)
if ( (*(int64_t*)p)==funcEnd ) break;
if(p!=p1){
p+=sizeof(int64_t);
printf("found\n");
memcpy(&code,(void*)a,p-(int8_t*)a);
((action)&code)();
}
printf("returning 0\n");
return 0;
}
It depends if you are trying to do this statically (at build-time), or at dynamically (at run-time).
Build-time
You need to tell GCC to put your blob in a section that is executable. We use __attribute__((section)), and this trick to specify the attributes of the section when we create it.
Run-time
TL;DR: Jump to the end of my answer, where I use mmap.
Although others might be questioning why you'd want do allow something like this at run-time, keep in mind that this is exactly what a VM with a JIT compiler (e.g. Java VM, .NET CLR, etc.) do when emitting native code.
You need to change the memory protections of the memory where you're trying to execute. We do that with mprotect(addr, PROT_EXEC). Note that addr must be aligned to the page size of your platform. On x86, the page size is 4K. We use aligned_alloc to guarantee this alignment.
Example (of both):
#define _ISOC11_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h> /* mprotect() */
__attribute__((section(".my_executable_blob,\"awx\",#progbits#")))
static uint8_t code[] = {
0xB8,0x2A,0x00,0x00,0x00, /* mov eax,0x2a */
0xC3, /* ret */
};
int main(void)
{
int (*func)(void);
/* Execute a static blob of data */
func = (void*)code;
printf("(static) code returned %d\n", func());
/* Execute a dynamically-allocated blob of data */
void *p = aligned_alloc(0x1000, sizeof(code));
if (!p) {
fprintf(stderr, "aligned_alloc() failed\n");
return 2;
}
memcpy(p, code, sizeof(code));
if (mprotect(p, sizeof(code), PROT_EXEC) < 0) {
perror("mprotect");
return 2;
}
func = p;
printf("(dynamic) code returned %d\n", func());
return 0;
}
Output:
$ ./a.out
(static) code returned 42
(dynamic) code returned 42
SELinux Impact
Note that this puts your executable code on the heap which might be a bit dangerous. SELinux on my CentOS 7 machine actually denied the mprotect call:
SELinux is preventing /home/jreinhart/so/a.out from using the execheap access on a process.
***** Plugin allow_execheap (53.1 confidence) suggests ********************
If you do not think /home/jreinhart/so/a.out should need to map heap memory that is both writable and executable.
Then you need to report a bug. This is a potentially dangerous access.
So I had to temporarily sudo setenforce 0 to get this to work.
I'm not sure why, however, because looking in /proc/[pid]/maps, the pages are clearly marked only as executable, not as "writable and executable" as SELinux indicated. If I move the memcpy after the mprotect, my process segfaults, because I'm trying to write to non-writable memory. So it seems SELinux is being a bit too over-zealous here.
Use mmap instead
Instead of mprotecting a region of the heap (allocated with aligned_alloc), it is more straightforward to use mmap. This also avoids any issues with SELinux, as we're not trying to execute on the heap.
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h> /* mmap() */
static uint8_t code[] = {
0xB8,0x2A,0x00,0x00,0x00, /* mov eax,0x2a */
0xC3, /* ret */
};
int main(void)
{
void *p = mmap(NULL, sizeof(code), PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (p==MAP_FAILED) {
fprintf(stderr, "mmap() failed\n");
return 2;
}
memcpy(p, code, sizeof(code));
int (*func)(void) = p;
printf("(dynamic) code returned %d\n", func());
pause();
return 0;
}
The final solution
The mmap solution is good, but it doesn't provide us any safety; our mmaped region of code is readable, writable, and executable. It would be better to only allow the memory to be writable while we're putting our code in place, then making it executable only. The following code does just that:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h> /* mmap(), mprotect() */
static uint8_t code[] = {
0xB8,0x2A,0x00,0x00,0x00, /* mov eax,0x2a */
0xC3, /* ret */
};
int main(void)
{
const size_t len = sizeof(code);
/* mmap a region for our code */
void *p = mmap(NULL, len, PROT_READ|PROT_WRITE, /* No PROT_EXEC */
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (p==MAP_FAILED) {
fprintf(stderr, "mmap() failed\n");
return 2;
}
/* Copy it in (still not executable) */
memcpy(p, code, len);
/* Now make it execute-only */
if (mprotect(p, len, PROT_EXEC) < 0) {
fprintf(stderr, "mprotect failed to mark exec-only\n");
return 2;
}
/* Go! */
int (*func)(void) = p;
printf("(dynamic) code returned %d\n", func());
pause();
return 0;
}

undefined reference BUT header is there

I am trying to run the ezsift library example. The example has name "image_match.cpp".
Here is the code
image_match.cpp
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "../ezsift.h"
using namespace std;
#define USE_FIX_FILENAME 0
int main(int argc, char ** argv)
{
#if USE_FIX_FILENAME
char * file1 = "img1.pgm";
char * file2 = "img2.pgm";
#else
if (argc != 3)
{
printf("Please input two image filenames.\n");
printf("usage: image_match img1 img2\n");
return -1;
}
char file1[255];
char file2[255];
memcpy(file1, argv[1], sizeof(char) * strlen(argv[1]));
file1[strlen(argv[1])] = 0;
memcpy(file2, argv[2], sizeof(char) * strlen(argv[2]));
file2[strlen(argv[2])] = 0;
#endif
// Read two input images
ImageObj<uchar> image1, image2;
if(image1.read_pgm(file1) != 0)
{
printf("Failed to open input image1!\n");
return -1;
}
if(image2.read_pgm(file2) != 0)
{
printf("Failed to open input image2!\n");
return -1;
}
printf("Image 1 loaded. Image size: %d x %d\n", image1.w, image1.h);
printf("Image 2 loaded. Image size: %d x %d\n", image2.w, image2.h);
// Double the original image as the first octive.
double_original_image(true);
// Detect keypoints
list<SiftKeypoint> kpt_list1, kpt_list2;
printf("\nSIFT detection on image 1 ...\n");
sift_cpu(image1, kpt_list1, true);
printf("# keypoints in image1: %d\n", kpt_list1.size());
printf("\nSIFT detection on image 2 ...\n");
sift_cpu(image2, kpt_list2, true);
printf("# keypoints in image2: %d\n", kpt_list2.size());
// Save keypoint list, and draw keypoints on images.
char filename[255];
sprintf(filename, "s_A_keypoints.ppm");
draw_keypoints_to_ppm_file(filename, image1, kpt_list1);
export_kpt_list_to_file("s_A_keypoints.key", kpt_list1, true);
sprintf(filename, "s_B_keypoints.ppm");
draw_keypoints_to_ppm_file(filename, image2, kpt_list2);
export_kpt_list_to_file("s_B_keypoints.key", kpt_list2, true);
// Match keypoints.
list<MatchPair> match_list;
match_keypoints(kpt_list1, kpt_list2, match_list);
// Draw result image.
sprintf(filename, "s_A_B_matching.ppm");
draw_match_lines_to_ppm_file(filename, image1, image2, match_list);
printf("# of matched keypoints: %d\n", match_list.size());
return 0;
}
ezsift.h
#ifndef EZSIFT_H
#define EZSIFT_H
#include "util/image.h"
#include "util/img_io.h"
#include <vector>
#include <list>
.
.
.
#endif
#define DEGREE_OF_DESCRIPTORS (128)
// Enable doubling of original image.
void double_original_image(bool doubleFirstOctave);
// Detect keypoints and extract descriptor.
int sift_cpu(
const ImageObj<uchar> &image,
std::list<SiftKeypoint> & kpt_list,
bool bExtractDescriptors);
// Match keypoints from two keypoint lists.
int match_keypoints(
std::list<SiftKeypoint> & kpt_list1,
std::list<SiftKeypoint> & kpt_list2,
std::list<MatchPair> & match_list);
.
.
.
#endif
(I will not include all the code here, I just wanted to give an idea. It is ease to download the source and see the files that I am talking about)
Also there is a "ezsift.cpp" file with more files in the "util" folder
I'm trying to run it from the terminal. I go to the directory and type "gcc image_match.cpp" but is says that double_original_image, sift_cpu (and all other functions in the header file) are not defined.
more specifically is gives this error:
image_match.cpp:(.text+0x1c7): undefined reference to `double_original_image(bool)'
image_match.cpp:(.text+0x20d): undefined reference to `sift_cpu(ImageObj<unsigned char> const&, std::list<_SiftKeypoint, std::allocator<_SiftKeypoint> >&, bool)'
(these are not the only error of course. It gives same error for all the functions)
I then tried "gcc ../ezsift.cpp image_match.cpp" but the same error.
What am I doing wrong?? I am running ubuntu 14.04.
(expending Cameron's comment into a tested answer)
You need to compile both ezsift.cpp and img_io.cpp with your program (image_match.cpp), while providing the location of the header files (-I\path\to\directory). Here is a working snippet, assuming you are in the examples directory:
g++ image_match.cpp ../ezsift.cpp ../util/img_io.cpp -I.. -o image_match

How to decode an animated gif File in MFC2010

Deal all,
I need to decode an animated gif format picture into some bitmap files in MFC2010. Is there any library to decode a gif picture? I cannot use GDIPlus because the program has to run on windows XP. I do appreciate if someone provides me with a library, Activex, dll or anything similar.
Many Thanks,
Shervin Zargham
It's pretty simple using ImageMagick's C++ API (Magick++) :
/* list of Image to store the GIF's frames */
std::vector<Magick::Image> imageList;
/* read all the frames of the animated GIF */
Magick::readImages( &imageList, "animated.gif" );
/* optionnally coalesce the frame sequence depending on the expected result */
Magick::coalesceImages( &imageList, imageList.begin(), imageList.end());
/* store each frame in a separate BMP file */
for(unsigned int i = 0; i < imageList.size(); ++i) {
std::stringstream ss;
ss << "frame" << i << ".bmp";
imageList[i].write(ss.str());
}
WIC (included in Vista, available for XP) offers CLSID_WICGifDecoder, a COM component.
Try this using ImageMagick's C++ API (Magick++) ,tested on VS210:
#include <Magick++.h>
#include <string>
#include <iostream>
#include <list>
using namespace std;
using namespace Magick;
void kk(char * nombre, char *ext)
{
/* list of Image to store the GIF's frames */
std::list<Magick::Image> imageList;
/* read all the frames of the animated GIF */
Magick::readImages( &imageList, nombre );
/* compone las diferencias para obtener los cuadros reales */
Magick::coalesceImages(&imageList,imageList.begin( ),imageList.end( ));
/* store each frame in a separate BMP file */
list <Magick::Image>::iterator it;
int i=1;
for ( it = imageList.begin( ); it != imageList.end( ); it++ , i++)
{
std::string name = "frame" + to_string((_Longlong)(i)) + ext ;
it->write(name);
}
}
int main( int /*argc*/, char ** argv)
{
// Initialize ImageMagick install location for Windows
InitializeMagick(*argv);
try {
kk("luni0.gif", ".png"); // using ".bmp", ".jpg", ".png", OK
return 0;
}
catch( exception &error_ )
{
cout << "Caught exception: " << error_.what() << endl;
return 1;
}
}
It's been a long time, but I recall once using OleLoadPicture to open GIF and PNG files on old versions of Windows, though the documentation seems to suggest that it's only for BMP, ICO, and WMF.

trouble with Open Cv and GPIO on mini6410

I am doing a simple project on arm based mini6410. I have debian package installed on mini. My project is to interface one IR motion sensor and I USB webcam with the mini6410. the working will be simple, whenever there will be any motion detected by IR sensor, the webcam will be on for 30 seconds save the images (over write the previous) and then off.
I have already cross comiled the Open CV code using arm-linux-gcc
For IR I am using GPE register.
Here I am stuck with a issue which I am unable to resolve. and even dont know how to resolve. OpenCv code is a cpp file camera.cpp and the file which deals with I/O ports is a C file named sensor.c. Now in that c file I am polling or whatever mechanism to check if the GPE register is 1 or not. If it is one, I should start the Open CV code which will start to capture images. further more this sensor.c file is not to be compiled rather made a module and then insmod on my mini6410.
However I dont know how to write c++ code in a c file. you can say i dont know how to call the OpenCV thing from the C file. as it is a module and within this i cant write the cpp code as then using namespace std and using namespace cv doesnot work.
i am new to embedded stuff and linux it self. so I wanted to know are there some possible solutions.
i am attaching my codes of both files.
This is sensor.c
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-q.h>
#include <mach/gpio-bank-e.h>
#include <mach/map.h>
#include <plat/regs-timer.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <mach/gpio-bank-k.h>
#define RLV 0x0FFF
unsigned Gpe;
unsigned sensor_value;
typedef struct
{
int delay;
} TIM_DEV;
static TIM_DEV TimDev;
static irqreturn_t INTHandler(int irq,void *TimDev)
{
Gpe = readl(S3C64XX_GPEDAT);
Gpe &= ~(0xF<<1);
readl(sensor_value, S3C64XX_GPEDAT);
while (sensor_value == 1)
{//1 means that IR sensor has detected a motion and given a value of +5 V
for (i = 0; i < 30; i++){
//CV_function();
// delay here such that delay(1 s) * 30 = 30 seconds
}
}
return IRQ_HANDLED;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.write = MyWrite,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{
int ret;
unsigned TimerControl;
unsigned TimerINTControl;
unsigned TimerCNTB;
unsigned TimerCMPB;
unsigned TimerCFG1;
unsigned Ge;
TimerControl = readl(S3C_TCON);
TimerINTControl = readl(S3C_TINT_CSTAT);
TimerCNTB = readl(S3C_TCNTB(0));
TimerCMPB = readl(S3C_TCMPB(0));
TimerCFG1 = readl(S3C_TCFG1);
TimerCFG1 &= ~(S3C_TCFG1_MUX0_MASK);
TimerCNTB = RLV;
TimerCMPB = 0;
writel(TimerCNTB, S3C_TCNTB(0));
writel(TimerCMPB, S3C_TCMPB(0));
writel(TimerCFG1, S3C_TCFG1);
TimerControl |= S3C_TCON_T0MANUALUPD;
TimerINTControl |= S3C_TINT_CSTAT_T0INTEN;
writel(TimerControl, S3C_TCON);
writel(TimerINTControl, S3C_TINT_CSTAT);
TimerControl = readl(S3C_TCON);
TimerControl |= S3C_TCON_T0RELOAD;
TimerControl &= ~S3C_TCON_T0MANUALUPD;
TimerControl |= S3C_TCON_T0START;
writel(TimerControl, S3C_TCON);
//////////////Here I am configuring my GPE as input/////////////
Ge = readl(S3C64XX_GPECON);
Ge &= ~(0xFFFF<<4);
Ge |= (0x0000<<4);
writel(Ge, S3C64XX_GPECON);
/////////////
misc_register(&misc);
ret = request_irq(IRQ_TIMER0, INTHandler, IRQF_SHARED, DEVICE_NAME, &TimDev);
if (ret)
{
return ret;
}
return ret;
}
static void __exit dev_exit(void)
{
free_irq(IRQ_TIMER0, &TimDev);
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("XYZ");
this is camera.cpp
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
int main( int argc, const char** argv )
{CvCapture* capture = 0;
Mat frame, frameCopy, image;
capture = cvCaptureFromCAM( 2 );
if( !capture )
{
cout << "No camera detected" << endl;
}
if( capture )
{
cout << "In capture ..." << endl;
IplImage* iplImg = cvQueryFrame( capture );
frame = iplImg;
if( frame.empty() )
break;
if( iplImg->origin == IPL_ORIGIN_TL )
frame.copyTo( frameCopy );
else
flip( frame, frameCopy, 0 );
cvSaveImage("image.jpg" ,iplImg);
}
cvReleaseCapture( &capture );
return 0;
}
the for loop in the sensor.c file should have my this above code by some means
I hope you get the idea,
Thanks
The missing link in the code shown is a mechanism by which the user-space code shown above can get notification of a change in the GPIO pin detected by the device driver.
There are two obvious ways to achieve this:
Integrate the GPIO pin into the platform's GPIO resources and then use the generic sysfs mechanism from user-space. The Linux kernel GPIO documentation describes both kernel and user-space side of this.
Have your driver expose a sysfs node for the GPIO line. sysfs is fundamental to the Linux Driver Model. I suggest a thorough read of Linux Device Drivers 3rd Edition.
The user-space side of either method is similar: You open the sysfs resource exported by your module and then use either poll() or select() to block until an event occurs.