我不太确定为什么我的 C 程序会泄漏,它与set_image_scaled()
我很确定的功能有关,并且与我调整图像大小有关。基本上,一旦我用 gphoto2 拍照,我将该文件保存为 jpg,然后我在 GTK 中打开该图片并使用 pixbuf 调整它的大小,然后相应地在显示器上设置图像小部件。我怎样才能解决这个问题?我搞不清楚了。已经玩了几个小时了。我在 raspbian 上使用树莓派。模型 3b+。
这是它给我的错误:
(guiphoto:2344): GdkPixbuf-CRITICAL **: 13:57:26.656: gdk_pixbuf_scale_simple: assertion 'GDK_IS_PIXBUF (src)' failed
**
ERROR:guiphoto.c:94:set_image_scaled: assertion failed (err == NULL): Failed to load image “/media/pi/SD CARD/cam-1_1_b_back.jpg”: Insufficient memory to open TIFF file (gdk-pixbuf-error-quark, 1)
Aborted
不断遇到内存泄漏的有问题的代码在 cam_main 函数中,特别是:
if (front == 1)
set_image_scaled(front_cams[i], buf);
else
set_image_scaled(back_cams[i], buf);
所以我相信这与这里的代码和我程序顶部的静态变量有关:
void set_image_scaled(GtkWidget* img, const char* path) {
pixbuf = gdk_pixbuf_new_from_file(path, &err);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
g_assert_no_error(err);
}
这是我的完整代码:
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <gphoto2/gphoto2-camera.h>
#include <gphoto2/gphoto2-context.h>
#include <wiringPi.h>
#include <gtk/gtk.h>
#include <pthread.h>
//program
static int running = 1;
//libgphoto2
static CameraList* list;
static Camera** cams;
static GPContext* context;
static const char *name, *value;
static int ret, count;
static int pic = 0;
static int front = 1;
//GTK
static GtkWidget *window, *hbox, *hbox2, *vbox, *button1;
static GtkWidget *front_cams[3];
static GtkWidget *back_cams[3];
static GdkPixbuf *pxbscaled;
static GdkPixbuf *pixbuf;
static GError* err = NULL;
static void button_clicked(GtkWidget *widget, gpointer data) {
gtk_button_set_label(GTK_BUTTON(button1), "click me 2"); //change button text
}
void *main_gtk() {
//INIT GTK
gtk_init(NULL, NULL);
//SETUP WINDOW
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//button1=gtk_button_new_with_label("Click me");
//gtk_button_set_label(GTK_BUTTON(button1), "click me 1");
g_signal_connect(window,"delete-event", G_CALLBACK(gtk_main_quit), NULL);
//g_signal_connect(button1, "clicked", G_CALLBACK(button_clicked), NULL);
//SET WINDOW SIZE AND TITLE
//gtk_widget_set_size_request(window, 600, 400);
gtk_window_set_title(GTK_WINDOW(window), "CaptureGui");
//RESIZE IMAGES
//image
front_cams[0] = gtk_image_new();
front_cams[1] = gtk_image_new();
front_cams[2] = gtk_image_new();
back_cams[0] = gtk_image_new();
back_cams[1] = gtk_image_new();
back_cams[2] = gtk_image_new();
//g_print("1");
//set_image_scaled(front_cams[0], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
//set_image_scaled(front_cams[1], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
//set_image_scaled(front_cams[2], "/media/pi/SD CARD/cam-1_1_b_back.jpg");
//PACK
hbox = gtk_hbox_new(0, 0);
gtk_box_pack_start(GTK_BOX(hbox), front_cams[0], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), front_cams[1], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), front_cams[2], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), back_cams[0], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), back_cams[1], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), back_cams[2], 0, 0, 0);
gtk_container_add(GTK_CONTAINER(window), hbox);
//ADD ELEMENTS TO GUI
//gtk_container_add(GTK_CONTAINER(window), image1);
//gtk_container_add(GTK_CONTAINER(window), image2);
//image2 = gtk_image_new_from_file("/media/pi/SD CARD/cam-1_0_b_back.jpg");
//gtk_container_add(GTK_CONTAINER(window), image2);
//SHOW GUI
gtk_widget_show_all(window);
gtk_main();
}
void set_image_scaled(GtkWidget *img, const char *path) {
pixbuf = gdk_pixbuf_new_from_file(path, &err);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
g_assert_no_error(err);
}
void *cam_main() {
while (running == 1) {
if (digitalRead(4) == 0) {
printf("taking pics of %s item %i\n", (front == 1) ? "front" : "back", pic);
for (int i = 0; i < count; i++) {
int fd, retval;
CameraFile *file;
CameraFilePath cfPath;
strcpy(cfPath.folder, "/");
strcpy(cfPath.name, "foo1.jpg");
printf("Capturing cam%i...\n", i + 1);
int res = gp_camera_capture(cams[i], GP_CAPTURE_IMAGE, &cfPath, context);
//printf(gp_port_result_as_string(res));
printf("capture result: %i\n", res);
//Camera won't take pic if busy and will continue to program end
char buf[256];
snprintf(buf, sizeof(buf), "/media/pi/SD CARD/cam-%i_%i_%s.jpg", i + 1, pic, (front == 1) ? "a_front" : "b_back"); //a_ to make front come before back otherwise systems will order incorrectly
fd = open(buf, O_CREAT | O_WRONLY, 0644);
retval = gp_file_new_from_fd(&file, fd);
retval = gp_camera_file_get(cams[i], cfPath.folder, cfPath.name, GP_FILE_TYPE_NORMAL, file, context);
retval = gp_camera_file_delete(cams[i], cfPath.folder, cfPath.name, context);
gp_file_free(file);
if (front == 1)
set_image_scaled(front_cams[i], buf);
else
set_image_scaled(back_cams[i], buf);
}
if (front == 1)
front = 0;
else {
front = 1;
pic += 1;
}
printf("pics taken...\n");
}
}
}
int main(int argc, char **argv) {
//Kill any processes using cams
system("pkill -f gphoto2");
//main_gtk();
//Wiring pi init
wiringPiSetupGpio();
//Init
context = gp_context_new();
detect_cams();
pthread_t logic_thread_handle, gui_thread_handle;
pthread_create(&logic_thread_handle, NULL, cam_main, NULL);
pthread_create(&gui_thread_handle, NULL, main_gtk, NULL);
pthread_join(gui_thread_handle, 0);
pthread_join(logic_thread_handle, 0);
//Deinit
for (int i = 0; i < count; i++) {
gp_camera_exit(cams[i], context);
gp_camera_free(cams[i]);
}
return 0;
}
void detect_cams() {
//Detecting all cameras and loading them into mem
//Detecting all cameras
ret = gp_list_new(&list);
if (ret < GP_OK) return 1;
gp_list_reset(list);
count = gp_camera_autodetect(list, context);
if (count < 1) {
printf("No cameras detected.\n");
return 1;
}
//Open all cameras
printf("Number of cameras: %d\n", count);
cams = calloc(sizeof (Camera*), count);
for (int i = 0; i < count; i++) {
gp_list_get_name(list, i, &name);
gp_list_get_value(list, i, &value);
ret = open_cam(&cams[i], name, value, context);
if (ret < GP_OK)
fprintf(stderr, "Camera %s on port %s failed to open\n", name, value);
}
}
int open_cam(Camera ** camera, const char *model, const char *port, GPContext *context) {
GPPortInfoList *portinfolist = NULL;
CameraAbilitiesList *abilities = NULL;
int ret, m, p;
CameraAbilities a;
GPPortInfo pi;
ret = gp_camera_new (camera);
if (ret < GP_OK) return ret;
if (!abilities) {
/* Load all the camera drivers we have... */
ret = gp_abilities_list_new (&abilities);
if (ret < GP_OK) return ret;
ret = gp_abilities_list_load (abilities, context);
if (ret < GP_OK) return ret;
}
/* First lookup the model / driver */
m = gp_abilities_list_lookup_model (abilities, model);
if (m < GP_OK) return ret;
ret = gp_abilities_list_get_abilities (abilities, m, &a);
if (ret < GP_OK) return ret;
ret = gp_camera_set_abilities (*camera, a);
if (ret < GP_OK) return ret;
if (!portinfolist) {
/* Load all the port drivers we have... */
ret = gp_port_info_list_new (&portinfolist);
if (ret < GP_OK) return ret;
ret = gp_port_info_list_load (portinfolist);
if (ret < 0) return ret;
ret = gp_port_info_list_count (portinfolist);
if (ret < 0) return ret;
}
/* Then associate the camera with the specified port */
p = gp_port_info_list_lookup_path (portinfolist, port);
switch (p) {
case GP_ERROR_UNKNOWN_PORT:
fprintf(stderr, "The port you specified "
"('%s') can not be found. Please "
"specify one of the ports found by "
"'gphoto2 --list-ports' and make "
"sure the spelling is correct "
"(i.e. with prefix 'serial:' or 'usb:').",
port);
break;
default:
break;
}
if (p < GP_OK) return p;
ret = gp_port_info_list_get_info (portinfolist, p, &pi);
if (ret < GP_OK) return ret;
ret = gp_camera_set_port_info (*camera, pi);
if (ret < GP_OK) return ret;
return GP_OK;
}