简体   繁体   English

C写的应用程序在MacOS上如何打开JPG图片

[英]How to open JPG image in application written in C on MacOS

I want to write a simple image browser in C and then make a bundle for the MacOs.我想在 C 中编写一个简单的图像浏览器,然后为 MacO 打包。

The problem is that I am encountering a warning when I am trying to open a jpg file from a context menu in Finder.问题是当我尝试从 Finder 的上下文菜单中打开 jpg 文件时遇到警告。

在此处输入图像描述

I compiled my code, I prepared a iViewGtk.app bundle with Info.plist file.我编译了我的代码,我准备了一个带有 Info.plist 文件的 iViewGtk.app 包。

The Info.plist is as follows: Info.plist如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>CFBundleExecutable</key>
        <string>iViewGtk</string>
        <key>CFBundleName</key>
        <string>iViewGtk</string>
        <key>CFBundleGetInfoString</key>
        <string>5.0</string>
        <key>CFBundleTypeName</key>
        <string>3r23rfewfwefwef343f</string>
        <key>CFBundleTypeOSTypes</key>
        <array>
            <string>****</string>
        </array>
        <key>CFBundleTypeMIMETypes</key>
        <string>image/jpeg</string>
        <key>CFBundleIconFile</key>
        <string>icon.icns</string>
        <key>CFBundleIdentifier</key>
        <string>net.bean.gtk.iview</string>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>LSMinimumSystemVersion</key>
        <string>10.14</string>
        <key>NSPrincipalClass</key>
        <string>NSApplication</string>
        <key>CFBundleShortVersionString</key>
        <string>5.0</string>
        <key>CFBundleDocumentTypes</key>
        <array>
            <dict>
                <key>CFBundleTypeExtensions</key>
                <array>
                    <string>bmp</string>
                    <string>cur</string>
                    <string>gif</string>
                    <string>icns</string>
                    <string>ico</string>
                    <string>jpeg</string>
                    <string>jpg</string>
                    <string>jpe</string>
                    <string>jfi</string>
                    <string>jfif</string>
                    <string>pbm</string>
                    <string>pgm</string>
                    <string>png</string>
                    <string>ppm</string>
                    <string>svg</string>
                    <string>svgz</string>
                    <string>tif</string>
                    <string>tiff</string>
                    <string>wbmp</string>
                    <string>webp</string>
                    <string>xbm</string>
                    <string>xpm</string>
                    <string>ani</string>
                    <string>apng</string>
                    <string>avif</string>
                    <string>avifs</string>
                    <string>bw</string>
                    <string>exr</string>
                    <string>hdr</string>
                    <string>heic</string>
                    <string>heif</string>
                    <string>jxl</string>
                    <string>kra</string>
                    <string>ora</string>
                    <string>pcx</string>
                    <string>pic</string>
                    <string>psd</string>
                    <string>ras</string>
                    <string>rgb</string>
                    <string>rgba</string>
                    <string>sgi</string>
                    <string>tga</string>
                    <string>xcf</string>
                </array>
                <key>CFBundleTypeRole</key>
                <string>Viewer</string>
            </dict>
        </array>
        <key>NSSupportsAutomaticGraphicsSwitching</key>
        <true />
        <key>NSHighResolutionCapable</key>
        <true />
    </dict>
</plist>

Actually the Info.plist file is a copy of Info.plist file from a working application qView which can be installed using brew install qview .实际上 Info.plist 文件是来自工作应用程序 qView 的 Info.plist 文件的副本,可以使用brew install qview

In addition to that I am able to click on the bundle and open the application by clicking it.除此之外,我还可以单击捆绑包并通过单击打开应用程序。

I copied the app into Application folder and it seems that Finder recognizes it as application which can open image files.我将该应用程序复制到应用程序文件夹中,Finder 似乎将其识别为可以打开图像文件的应用程序。 It is not grayed out:它没有变灰:

在此处输入图像描述

Since I don't know how the parameter from Finder is provided to my app, I didn't implement the part which opens and displays the image.因为我不知道 Finder 的参数是如何提供给我的应用程序的,所以我没有实现打开和显示图像的部分。 I think, that it shouldn't be a problem for MacOS, should be?我认为,这对 MacOS 来说应该不是问题,应该是吗? The main.c looks as follows: main.c 如下所示:

int main(int argc, char **argv)
{
    struct ApplicationContext *appContext = malloc(sizeof(appContext));
    GtkApplication *app;
    int status;

    app = gtk_application_new("net.bean.app", G_APPLICATION_HANDLES_OPEN);
    g_signal_connect(app, "activate", G_CALLBACK(activate), appContext);
    g_signal_connect(app, "open", G_CALLBACK(app_open), appContext);
    status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

Could someone tell me why MacOS displays the warning?有人能告诉我为什么 MacOS 会显示警告吗?

Is this somehow related to some MacOs security policies which are forbidding to open a file to an unknown app?这是否与某些禁止将文件打开到未知应用程序的 MacOs 安全策略有关?

Thank you.谢谢你。

It's not sufficient to have a .plist file, there is also handling code necessary.拥有.plist文件是不够的,还需要处理代码。

By the way, this is also the case for a regular Cocoa Objective-C applications.顺便说一句,对于常规的 Cocoa Objective-C 应用程序也是如此。 If none of the corresponding optional NSApplicationDelegate methods (such as application:openURLs: and friends) is implemented there, the dialog shown in the question appears.如果那里没有实现相应的可选NSApplicationDelegate方法(例如application:openURLs:和 friends),则会出现问题中显示的对话框。

Neither from the sample code provided nor from the tags used can one conclude whether the question refers to GTK3 or GTK4 - therefore this answer covers both cases.无论是从提供的示例代码还是从使用的标签中都不能得出问题是指 GTK3 还是 GTK4 - 因此这个答案涵盖了这两种情况。

GTK4 GTK4

GTK4 already supports macOS as a backend. GTK4 已经支持 macOS 作为后端。 Looking for a corresponding NSApplicationDelegate delegate method in gtkapplication-quartz.c one can see application:openFiles: , so the support is there.gtkapplication-quartz.c中寻找相应的NSApplicationDelegate委托方法可以看到application:openFiles: ,所以支持就在那里。

However in line 164 one can see that the delegate is only set if the boolean register_session is true, see the check in line 161 .然而,在第 164 行中,可以看到仅当 boolean register_session为真时才设置委托,请参见第161 行中的检查。

Following that trace backwards via gtk_application_impl_startup , gtk_application_startup in gtkapplication.c etc. one can see that register_session is a property of the application.通过gtk_application_impl_startupgtk_application_startup中的gtkapplication.c等向后追踪,可以看到register_session是应用程序的一个属性。

Basically, we need to set this to true to make sure the delegate is set and we are notified of open file attempts.基本上,我们需要将其设置为 true 以确保委托已设置,并且我们会收到打开文件尝试的通知。

The property can then be set something like this:然后可以像这样设置该属性:

GValue val = G_VALUE_INIT;
g_value_init (&val, G_TYPE_BOOLEAN);
g_value_set_boolean(&val, true);
g_object_set_property(G_OBJECT(app), "register-session", &val);
g_value_unset (&val);

Self-contained GTK4 example自包含的 GTK4 示例

Following on from the above, it could be written something like this:根据上面的内容,它可以这样写:

#include <gtk/gtk.h>

static void
activate (GtkApplication *app) {
    GtkWidget *window = gtk_application_window_new (app);
    GtkWidget *button = gtk_button_new_with_label ("Close App");
    g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_close), window);
    gtk_window_set_child (GTK_WINDOW (window), button);
    gtk_window_present (GTK_WINDOW (window));
}

static void
app_open (GApplication  *application, GFile **files, gint n_files, const gchar *hint) {
    for (gint i = 0; i < n_files; i++) {
        gchar *uri = g_file_get_uri (files[i]);
        g_print ("open %s\n", uri);
        g_free (uri);
    }
}

int main(int argc, char **argv) {
    GtkApplication *app = gtk_application_new("net.bean.app", G_APPLICATION_HANDLES_OPEN);

    GValue val = G_VALUE_INIT;
    g_value_init (&val, G_TYPE_BOOLEAN);
    g_value_set_boolean(&val, true);
    g_object_set_property(G_OBJECT(app), "register-session", &val);
    g_value_unset (&val);

    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    g_signal_connect(app, "open", G_CALLBACK(app_open), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

CFBundleTypeExtensions is deprecated CFBundleTypeExtensions 已弃用

This should work with your .plist file, however CFBundleTypeExtensions is deprecated since OS X v10.5., see https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html这应该适用于您的.plist文件,但是自 OS X v10.5 以来不推荐使用CFBundleTypeExtensions ,请参阅https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html

For viewing .jpeg files, you should rather use something like the following:要查看.jpeg文件,您应该使用如下内容:

    <key>CFBundleDocumentTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeName</key>
            <string>JPEG File</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSHandlerRank</key>
            <string>Alternate</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.jpeg</string>
            </array>
        </dict>
    </array>

GTK4 Test GTK4 测试

After creating the iViewGTK app bundle, you can run a quick test with the above test program - if you run it from the command line, you can even see the output of prinft on the console:创建 iViewGTK 应用程序包后,您可以使用上面的测试程序运行快速测试——如果您从命令行运行它,您甚至可以在控制台上看到 prinft 的prinft

iViewGTK.app/Contents/MacOS/iViewGTK

When you open a file by right-clicking a.jpeg file in the Finder and choosing Open With / iViewGTK from the context menu, the following appears:当您通过在 Finder 中右键单击 a.jpeg 文件并从上下文菜单中选择“ Open With方式”/ iViewGTK ”来打开文件时,将出现以下内容:

open file:///Users/stephan/tmp/gtk/testsuite/gdk/image-data/iamge-cmyk.jpeg

So there is no error dialog and the file path is successfully passed to the GTK application.所以没有错误对话框,文件路径成功传递给 GTK 应用程序。

GTK3 GTK3

In the case of a GTK3 application, there are important notes at https://www.gtk.org/docs/installations/macos :对于 GTK3 应用程序,在https://www.gtk.org/docs/installations/macos中有重要说明:

Linking with GTK's Quartz backend connects your application to the Mac's native display manager, keyboard, and pointing device.与 GTK 的 Quartz 后端链接将您的应用程序连接到 Mac 的本机显示管理器、键盘和指点设备。 With a little extra code and gtk-mac-integration you can:通过一些额外的代码和 gtk-mac-integration,您可以:

... ...

  • Receive open events from Finder.从 Finder 接收打开的事件。
  • ... ...

Completely self-contained GTK3 example完全独立的 GTK3 示例

#include <gtk/gtk.h>
#include <assert.h>
#include <gtkosxapplication.h>

static  GtkWidget *
new_window(void) {
    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    assert (window != NULL);
    gtk_widget_show_all(window);
    return window;
}

static gboolean
app_open_file_cb (GtkosxApplication *app, gchar *path, gpointer user_data) {
    printf("open file '%s'\n", path);
    //do sth with file
    return TRUE;
}

int main(int argc, char **argv) {
    gtk_init (&argc, &argv);
    GtkApplication *app  = g_object_new (GTKOSX_TYPE_APPLICATION, NULL);
    GtkWidget *window = new_window();
    g_signal_connect (app, "NSApplicationOpenFile",
                      G_CALLBACK (app_open_file_cb), NULL);
    gtkosx_application_ready (app);
    gtk_main ();
    g_object_unref(app);
    return 0;
}

GTK3 Test GTK3 测试

The same test as above, if you select Open with / iViewGTK in the Finder, the following appears:同上测试,如果你在Finder中用/ iViewGTK Open with select,出现如下:

gtk 打开文件测试

So again no error dialog is shown and the file path is successfully passed to the GTK application.因此再次没有显示错误对话框,文件路径已成功传递给 GTK 应用程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM