$ git clone https://librecgm.ion.nu/librecgm.git
commit 2da2264ab4ad67ebf6fac9f691c218ff5cb92ea2
Author: Alicia <...>
Date: Sat Sep 25 23:47:10 2021 +0200
Made libraries optional.
diff --git a/Makefile b/Makefile
index be66e6f..0d76203 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,23 @@
PREFIX=/usr
GLADEPATH=$(PREFIX)/share/librecgm/gui.glade
-LIBS=$(shell pkg-config --libs gdk-pixbuf-2.0 libv4l2 gtk+-3.0 freetype2 fontconfig)
-CFLAGS=$(shell pkg-config --cflags gdk-pixbuf-2.0 libv4l2 gtk+-3.0 freetype2 fontconfig) -g3 -Wall -Wextra -DGLADEPATH='"$(GLADEPATH)"'
+CFLAGS=-g3 -Wall -Wextra -DGLADEPATH='"$(GLADEPATH)"'
OBJ=findrect.o img.o read.o main.o cam.o gui.o data.o
+optionallibs=$(shell pkg-config --libs $(1) 2> /dev/null)
+optionalcflags=$(shell pkg-config --cflags $(1) 2> /dev/null && echo '-DENABLE_$(2)' || echo 'Warning: building without $(3) due to missing one or more of $(1)' >&2)
+# Labels
+LIBS+=$(call optionallibs,freetype2 fontconfig)
+CFLAGS+=$(call optionalcflags,freetype2 fontconfig,LABELS,labels)
+# Webcam
+LIBS+=$(call optionallibs,libv4l2)
+CFLAGS+=$(call optionalcflags,libv4l2,V4L2,webcam support)
+# GUI
+LIBS+=$(call optionallibs,gtk+-3.0)
+CFLAGS+=$(call optionalcflags,gtk+-3.0,GUI,GUI)
+# Image formats (beyond PNM)
+LIBS+=$(call optionallibs,gdk-pixbuf-2.0)
+CFLAGS+=$(call optionalcflags,gdk-pixbuf-2.0,GDKPIXBUF,support for more image formats)
+
librecgm: $(OBJ)
$(CC) $^ $(LIBS) -o $@
diff --git a/cam.c b/cam.c
index 144a3ff..a161938 100644
--- a/cam.c
+++ b/cam.c
@@ -16,15 +16,19 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
+#include <string.h>
#include <fcntl.h>
+#ifdef ENABLE_V4L2
#include <linux/videodev2.h>
#include <libv4l2.h>
+#endif
#include "img.h"
#include "cam.h"
struct cam* cam_init(const char* dev)
{
struct cam* cam=malloc(sizeof(struct cam));
+#ifdef ENABLE_V4L2
int fd=v4l2_open(dev, O_RDWR);
struct v4l2_format fmt;
fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -39,22 +43,34 @@ struct cam* cam_init(const char* dev)
cam->fd=fd;
cam->w=fmt.fmt.pix.width;
cam->h=fmt.fmt.pix.height;
+#else
+ // Bogus values to prevent division by 0
+ cam->w=16;
+ cam->h=16;
+#endif
return cam;
}
void cam_read(struct cam* cam, void* pixels)
{
+#ifdef ENABLE_V4L2
v4l2_read(cam->fd, pixels, cam->w*cam->h*3);
+#else
+ memset(pixels, 128, 16*16*3);
+#endif
}
void cam_free(struct cam* cam)
{
+#ifdef ENABLE_V4L2
v4l2_close(cam->fd);
free(cam);
+#endif
}
void cam_grab(struct img* img, const char* dev)
{
+#ifdef ENABLE_V4L2
struct cam* cam=cam_init(dev);
img->w=cam->w;
img->h=cam->h;
@@ -69,4 +85,5 @@ void cam_grab(struct img* img, const char* dev)
cam_read(cam, img->pixels);
}
cam_free(cam);
+#endif
}
diff --git a/findrect.c b/findrect.c
index a147ee0..474c899 100644
--- a/findrect.c
+++ b/findrect.c
@@ -129,7 +129,7 @@ static int area(int* rect)
int* findrect(struct img* img)
{
- static int rect[8];
+ static int rect[8]={0};
int x,y;
int min=255*3, max=0;
for(y=0; y<img->h; y++)
@@ -144,7 +144,7 @@ int* findrect(struct img* img)
}
int edge=(min*2+max)/3; // Median color value to determine if a pixel hits the screen (except a little lower which gives more accurate results)
int i;
- int drect[8];
+ int drect[8]={0};
for(i=0; i<4; i++)
{
if(!search(img, &rect[i*2], edge, i)){printf("Failed to find corner %i\n", i);}
diff --git a/gui.c b/gui.c
index 54a8ad0..8e59e17 100644
--- a/gui.c
+++ b/gui.c
@@ -15,6 +15,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifdef ENABLE_GUI
#include <stdio.h>
#include <gtk/gtk.h>
#include "cam.h"
@@ -259,3 +260,4 @@ void gui_run(int** onlygrab, int unitmax)
g_timeout_add_full(G_PRIORITY_LOW, 1000/10, G_SOURCE_FUNC(updatecam), onlygrab, 0);
gtk_main();
}
+#endif
diff --git a/img.c b/img.c
index caac43b..1555851 100644
--- a/img.c
+++ b/img.c
@@ -18,9 +18,11 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include <fontconfig/fontconfig.h>
+#ifdef ENABLE_LABELS
+ #include <ft2build.h>
+ #include FT_FREETYPE_H
+ #include <fontconfig/fontconfig.h>
+#endif
#include "img.h"
void createimg(struct img* img, int w, int h)
@@ -89,8 +91,39 @@ void writepnm(struct img* img, const char* name)
fclose(f);
}
+void readpnm(struct img* img, const char* name)
+{
+ FILE* f=fopen(name, "r");
+ char head[32];
+ fgets(head, 32, f);
+ if(head[0]!='P' || head[1]!='6' || (head[2]!='\r' && head[2]!='\n'))
+ {
+ fprintf(stderr, "Unsupported PNM image format. Only 'P6' binary PNM is supported in LibreCGM built without gdk-pixbuf support.\n");
+ return;
+ }
+ while(fgets(head, 32, f)){if(head[0]!='#'){break;}}
+ char* space;
+ int w=strtol(head, &space, 0);
+ if(!space || space[0]!=' ')
+ {
+ fprintf(stderr, "Invalid PNM, expected width and height separated by space\n");
+ return;
+ }
+ int h=strtol(&space[1], 0, 0);
+ while(fgets(head, 32, f)){if(head[0]!='#'){break;}}
+ if(strncmp(head, "255", 3))
+ {
+ fprintf(stderr, "Only 24-bit colors supported by builtin PNM reader (expected '255', got '%s')\n", head);
+ return;
+ }
+ createimg(img, w, h);
+ fread(img->pixels, img->rowstride, img->h, f);
+ fclose(f);
+}
+
static void text(struct img* img, int x, int y, const char* text)
{
+#ifdef ENABLE_LABELS
static FT_Library ft=0;
if(!ft && FT_Init_FreeType(&ft))
{
@@ -150,6 +183,7 @@ static void text(struct img* img, int x, int y, const char* text)
x+=face->glyph->advance.x/64;
y+=face->glyph->advance.y/64;
}
+#endif
}
void drawgraph(struct img* img, int h, int listlen, int* list)
diff --git a/img.h b/img.h
index 6fdea4f..b275a17 100644
--- a/img.h
+++ b/img.h
@@ -26,5 +26,6 @@ struct img
extern void createimg(struct img* img, int w, int h);
extern void drawline(struct img* img, int* start, int* end, int color);
extern void writepnm(struct img* img, const char* name);
+extern void readpnm(struct img* img, const char* name);
extern void drawgraph(struct img* img, int h, int listlen, int* list);
#define pixel(img,x,y) (&(img)->pixels[(y)*(img)->rowstride+(x)*(img)->pixstride])
diff --git a/main.c b/main.c
index 04eaca9..85a3b90 100644
--- a/main.c
+++ b/main.c
@@ -15,7 +15,12 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef ENABLE_GDKPIXBUF
#include <gdk-pixbuf/gdk-pixbuf.h>
+#endif
#include "img.h"
#include "data.h"
extern int* readgraph(struct img* img, int* rect, int max);
@@ -34,7 +39,9 @@ static void helptext(void)
printf("Usage: librecgm [options]\n\n"
"Valid options:\n"
"Inputs: (specifying one of these implies --nogui)\n"
+#ifdef ENABLE_V4L2
"--cam <device> = Scan values from the given V4L2 device (e.g. /dev/video0)\n"
+#endif
"--img <image file> = Scan values from image file\n"
"--data <file> = Load blood sugar values from file\n\n"
"Outputs:\n"
@@ -43,7 +50,9 @@ static void helptext(void)
" (written to stdout by default)\n\n"
"--mgdl = Use mg/dL units instead of mmol/L\n"
"--nogui = Do not use the GUI\n"
- "-h/--help = Show this help text\n");
+ "-h/--help = Show this help text\n\n"
+ "LibreCGM is free/libre software licensed under the GNU Affero General Public License version 3.\n"
+ "For more information see https://librecgm.ion.nu\n");
}
int main(int argc, char** argv)
@@ -71,22 +80,32 @@ int main(int argc, char** argv)
int listlen=283;
if(gui)
{
+ #ifdef ENABLE_GUI
char onlygrab=out_data||out_graph;
gui_run(onlygrab?&list:0, unitmax);
if(!onlygrab){return 0;}
+ #else
+ fprintf(stderr, "This copy of LibreCGM was built without GUI support. See the help text (run 'librecgm --help') for further information.\nResuming in commandline mode.\n");
+ #endif
}
struct img img={0};
if(!list)switch(inputtype)
{
case in_v4l2:
+ #ifdef ENABLE_V4L2
cam_grab(&img, input);
list=readgraph(&img, 0, unitmax*10);
// if(img.pixels){writepnm(&img, "read.pnm");}
free(img.pixels);
break;
+ #else
+ fprintf(stderr, "This copy of LibreCGM was built without webcam support. Please specify an image file instead.\nSee the help text (run 'librecgm --help') for further information.\n");
+ return 1;
+ #endif
case in_img:
{
+ #ifdef ENABLE_GDKPIXBUF
GdkPixbuf* img_=gdk_pixbuf_new_from_file(input, 0);
if(!img_){printf("Failed to open image '%s'\n", input); return 1;}
img.pixels=gdk_pixbuf_get_pixels(img_);
@@ -97,6 +116,12 @@ int main(int argc, char** argv)
list=readgraph(&img, 0, unitmax*10);
// if(img.pixels){writepnm(&img, "read.pnm");}
g_object_unref(img_);
+ #else
+ fprintf(stderr, "This copy of LibreCGM was built without gdk-pixbuf for support for additional image formats. Attempting to load as PNM.\n");
+ readpnm(&img, input);
+ if(!img.pixels){return 1;}
+ list=readgraph(&img, 0, unitmax*10);
+ #endif
}
break;
case in_data:
@@ -115,26 +140,41 @@ int main(int argc, char** argv)
// Output: graph
if(out_graph)
{
+ #ifdef ENABLE_GDKPIXBUF
GdkPixbuf* img_=gdk_pixbuf_new(GDK_COLORSPACE_RGB, 0, 8, 800, 600);
img.pixels=gdk_pixbuf_get_pixels(img_);
img.w=gdk_pixbuf_get_width(img_);
img.h=gdk_pixbuf_get_height(img_);
img.rowstride=gdk_pixbuf_get_rowstride(img_);
img.pixstride=gdk_pixbuf_get_n_channels(img_);
+ #else
+ fprintf(stderr, "This copy of LibreCGM was built without gdk-pixbuf for support for additional image formats. Writing PNM image.\n");
+ createimg(&img, 800, 600);
+ #endif
memset(img.pixels, 255, img.h*img.rowstride); // Clear to white
-// drawgraph(&img, 210, listlen, list);
drawgraph(&img, unitmax*10, listlen, list);
char* ext=strrchr(out_graph, '.');
if(!ext) // Default to PNG
{
char path2[strlen(out_graph)+strlen(".png0")];
+ #ifdef ENABLE_GDKPIXBUF
sprintf(path2, "%s.png", out_graph);
gdk_pixbuf_save(img_, path2, "png", 0, (void*)0);
+ #else
+ sprintf(path2, "%s.pnm", out_graph);
+ writepnm(&img, path2);
+ #endif
}else{
+ #ifdef ENABLE_GDKPIXBUF
ext=&ext[1];
- gdk_pixbuf_save(img_, out_graph, ext, 0, (void*)0);
+ if(!gdk_pixbuf_save(img_, out_graph, ext, 0, (void*)0) && !strcasecmp(ext, "pnm")){writepnm(&img, out_graph);}
+ #else
+ writepnm(&img, out_graph);
+ #endif
}
+ #ifdef ENABLE_GDKPIXBUF
g_object_unref(img_);
+ #endif
}
// Cleanup
free(list);