How to get a file from a link starting with file://

No, it starts with file:// -- that means "use the file protocol" in the same way that http:// means "use the http protocol". Everything after file:// is the absolute path to the image. Even so, it should work in a browser, although some do have security restrictions over what they can and can't access.

What's the browser, how are you copying the link in Obsidian, what does your clipboard show after you copy the link in Obsidian (switch to the Finder and from the "Edit" menu select "Show clipboard")?

The browser is Safari. I tried in other browsers with the same result. I did not copy the link from the obisidian software. I copied the image from another dictionary app called eudic. I had to paste it manually in the obsidian software to get the link. The clipboard is blank in the Finder. This is very strange.

I copied the image directly from here, It is a dictionary software. and then I can see the link When I paste it manually, but I can't see link anywhere else.

Not really -- when you copy something to the clipboard it can be a whole bunch of "stuff" containing different data in different formats. What's there will depend on the app you are copying from, what can be used will depend on the app you are pasting into.

What we can't see from your video is whether you are copying a Markdown link from Eudic which Obsidian can interpret and display the file for, image data and file reference and Obsidian is making use of one or both to create the Markdown you are seeing, or something else. Copy from Eudic and then look at the clipboard as described above, try and paste into TextEdit and see what happens, paste into a graphics program.

That will give you some clue as to what's available on the clipboard and how you might be able to convert it into something Safari can use.

It may give that impression, but to inspect the list of (textually representable) pasteboard items which it actually contains, and the bundle id of each, you could try something like:

1 Like

It still doesn't do anything, but I can paste it in Apple Note and see the image, but no link displayed

谢谢您。我得到了一些信息。
这就是结果。

{
"com.apple.webarchive as propertyList": {
WebSubresources:[
{
WebResourceURL:": "file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_popcorn.jpg",
WebResourceMIMEType:image/jpeg,
"WebResourceResponse":{},
WebResourceData:{}
}
],
WebMainResource:{
"WebResourceURL": "file:///Applications/Eudb_en.app/Contents/Library/LoginItems/LightPeek_en.app/Contents/Resources/Html/",
"WebResourceFrameName": "",
"WebResourceMIMEType": "text/html",
"WebResourceData": {},
WebResourceTextEncodingName:"UTF-8"
}
},
"public.rtf as string": "{\\rtf1\ansi\\ansicpg1252\cocoartf2638\n\\cocoatextscaling0\\cococoaplatform0{\\fonttbl\f0\\fswiss\\\fcharset0 Helvetica;}\n{\\colortbl;\red255\\green255\\blue255;\\red224\\green224\\blue224;}\n{\\*\\expandedcolortbl;\cssrgb\\\c90196\\c90196\c90196;}\n\deftab720\n\\pard\pardeftab720\\partightenfactor0\n\n\f0\fs26\fsmilli13333 \\
"public.rtf as data": "{\\rtf1\ansi\\ansicpg1252\\cocoartf2638\n\\cocoatextscaling0\\cococoaplatform0{\\fonttbl\f0\\fswiss\\\fcharset0 Helvetica;}\n{\\colortbl;\red255\\green255\\blue255;\red224\\green224\\\blue224;}\n{\\*\expandedcolortbl;;\cssrgb\\c90196\\c90196\\c90196;}\n\deftab720\n\pard\pardeftab720\\partightenfactor0\n\n\f0\fs26\\fsmilli13333 \
"public.html作为字符串": "<img src=\"file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_popcorn.jpg\" class=\" class=\"caret-color: rgb(230, 230, 230); font-family: Helvetica, &quot; Lucida Grande&quot; Lucida, Verdana, sans-serif; font-size: 13.333333015441895px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-
"public.html作为数据": "<img src=\"file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_popcorn.jpg\" class=\" style=\"caret-color: rgb(230, 230, 230); color: rgb(230, 230); font-family: Helvetica, &quot;Lucida Grande&quot; Lucida, Verdana, sans-serif; font-size: 13.333333015441895px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto
"public.utf8-plain-text as string": "",
"public.utf8-plain-text as data": "",
"com.apple.WebKit.custom-pasteboard-data as string": "\u0001\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0001file://\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
"com.apple.WebKit.custom-pasteboard-data as data": "\u0001\u0000\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0001file://\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
}

What should I do next?

That depends on what you are trying to do. Are you trying to get the image? The file reference for the image? What app do you want to use that data in?

It really does help us help you if you tell us what you want to achieve and what is going wrong rather than just showing us the one piece that's not working. See "How Do I Get The Best Answer in the Shortest Time?"

1 Like

I want to get the images and then use the variable system clipboard to put them into the obsidian software for use. I can't just get the link because I need to sync to mobile

The link you need appears to be embedded in HTML in a public.html pasteboard.

To capture that as pasteable plain text, from which you can extract the link, you could use an Execute JavaScript for Automation action like this:

Capture public.html pasteboard item as pasteable plain text.kmmacros (4.8 KB)


Expand disclosure triangle to view JS source
(() => {
    "use strict";

    ObjC.import("AppKit");

    // Move HTML content of clipboard to text representation.
    //

    // ---------------------- MAIN -----------------------
    const main = () =>
        either(
            alert("Moving public.html to plain text")
        )(
            html => html
        )(
            fmapLR(
                setClipOfTextType("public.utf8-plain-text")
            )(
                clipOfTypeLR("public.html")
            )
        );


    // ----------------------- JXA -----------------------

    // alert :: String => String -> IO String
    const alert = title =>
        s => {
            const sa = Object.assign(
                Application("System Events"), {
                    includeStandardAdditions: true
                });

            return (
                sa.activate(),
                sa.displayDialog(s, {
                    withTitle: title,
                    buttons: ["OK"],
                    defaultButton: "OK"
                }),
                s
            );
        };

    // clipOfTypeLR :: String -> Either String String
    const clipOfTypeLR = utiOrBundleID => {
        const
            clip = ObjC.deepUnwrap(
                $.NSString.alloc.initWithDataEncoding(
                    $.NSPasteboard.generalPasteboard
                    .dataForType(utiOrBundleID),
                    $.NSUTF8StringEncoding
                )
            );

        return 0 < clip.length ? (
            Right(clip)
        ) : Left(
            "No clipboard content found " + (
                `for type '${utiOrBundleID}'`
            )
        );
    };


    // setClipOfTextType :: String -> String -> IO String
    const setClipOfTextType = utiOrBundleID =>
        txt => {
            const pb = $.NSPasteboard.generalPasteboard;

            return (
                pb.clearContents,
                pb.setStringForType(
                    $(txt),
                    utiOrBundleID
                ),
                txt
            );
        };

    // --------------------- GENERIC ---------------------

    // Left :: a -> Either a b
    const Left = x => ({
        type: "Either",
        Left: x
    });

    // Right :: b -> Either a b
    const Right = x => ({
        type: "Either",
        Right: x
    });

    // bindLR (>>=) :: Either a ->
    // (a -> Either b) -> Either b
    const bindLR = m =>
        mf => m.Left ? (
            m
        ) : mf(m.Right);

    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = fl =>
        // Application of the function fl to the
        // contents of any Left value in e, or
        // the application of fr to its Right value.
        fr => e => e.Left ? (
            fl(e.Left)
        ) : fr(e.Right);

    // fmapLR (<$>) :: (b -> c) -> Either a b -> Either a c
    const fmapLR = f =>
        // Either f mapped into the contents of any Right
        // value in e, or e unchanged if is a Left value.
        e => "Left" in e ? (
            e
        ) : Right(f(e.Right));

    return main();

})();
2 Likes

Once you have extracted a clean url from the HTML text, you should be able to open the image file (if the link is good and live) by using an Execute Shell Script command, consisting of the word open, followed by the url, after a space.

I think your best bet, at least until @ComplexPoint (or someone? Please?) can come up with a way to extract the file path from the clipboard data above, is to let Obsidian to do the "translation" then use a macro to convert the Obsidian link to image data and paste that back into Obsidian.

So do the paste into Obsidian as in your first post. Then select the entire Markdown link from the ! to the ) (which will also select the image), ⌘C, and run the following macro:

Obsidian Clipboard Test.kmmacros (2.6 KB)

Summary

...which will extract the URL from the Markdown, convert it to a file path, read that file into the clipboard as an image, then paste into Obsidian replacing the selected line (and therefore replacing the link/image from Eudic).

Once you are happy it is working and you know your own workflow you can add more automation -- for example, manually selecting the whole link but moving the ⌘C into the macro.

1 Like

Thank you.
But I now get not a pure link.
How do I get this link file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_popcorn.jpg

<img src="file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_popcorn.jpg" class="" style="caret-color: rgb(230, 230, 230); color: rgb(230, 230, 230); font-family: Helvetica, &quot;Lucida Grande&quot;, Lucida, Verdana, sans-serif; font-size: 13.333333015441895px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacin

Put @ComplexPoint's marvellous extraction action as the first action in the macro I posted and set it to save to the variable Local_filepath. Change my "Search System Clipboard" action to one that searches Local_filepath and returns the text between (and not including) the first pair of double-quotes:
pathSearch

Leave the "Filter", "Set System Clipboard", and "Paste" as-is and you should be able to Copy in Eudic, switch to Obsidian, put the insertion point where you want and run the macro to have the image pasted in.

1 Like

Yes, it works well.
but there is a problem.
If I accidentally select the image and the text, there is no way to extract the link.
So I changed the regular expression "(file[^"]+)
It looks clumsy. But can barely work.

If I copy the image and text together you will get this text

<br class="" style="caret-color: rgb(230, 230, 230); color: rgb(230, 230, 230); font-family: Helvetica, &quot;Lucida Grande&quot;, Lucida, Verdana, sans-serif; font-size: 13.333333015441895px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;"><img src="file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_fire.jpg" class="" style="caret-color: rgb(230, 230, 230); color: rgb(230, 230, 230); font-family: Helvetica, &quot;Lucida Grande&quot;, Lucida, Verdana, sans-serif; font-size: 13.333333015441895px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;">

More generally, if the clipboard contains any HTML material, then you can extract the links (if any) from it with something like this:

URLs in public.html pasteboard item .kmmacros (8.4 KB)


Expand disclosure triangle to view JS source
(() => {
    "use strict";

    ObjC.import("AppKit");

    // Link(s) found in any HTML component of the clipboard

    // Rob Trew
    // Ver 0.02

    // ---------------------- MAIN -----------------------
    const main = () =>
        either(
            alert("Collecting links from HTML clipboard")
        )(
            links => links.join("\n")
        )(
            bindLR(
                clipOfTypeLR("public.html")
            )(
                linksInHTML
            )
        );

    // ------------------ LINKS IN HTML ------------------

    // linksInHTML :: HTML String -> Either String [URL]
    const linksInHTML = html =>
    // Either a message or a list of URLs.
        bindLR(
            dictFromHTML(html)
        )(
            compose(
                xs => 0 < xs.length ? (
                    Right(xs)
                ) : Left("No links found in the given HTML"),
                map(x => x.attributes.href),
                filterTree(x => "a" === x.name)
            )
        );

    // dictFromHTML :: String -> Either String Tree Dict
    const dictFromHTML = html => {
        const
            error = $(),
            node = $.NSXMLDocument.alloc
            .initWithXMLStringOptionsError(
                html, $.NSXMLDocumentTidyHTML, error
            );

        return Right(xmlNodeDict(node));

        // ERROR WARNINGS FOR ECCENTRIC HTML ALL SKIPPED

        // return Boolean(error.code) ? (
        //     Left("Not parseable as XML: " + (
        //         `${ObjC.unwrap(error.description)}`
        //     ))
        // ) : Right(xmlNodeDict(node));
    };

    // xmlNodeDict :: NSXMLNode -> Node Dict
    const xmlNodeDict = xmlNode => {
        const
            unWrap = ObjC.unwrap,
            blnChiln = 0 < parseInt(
                xmlNode.childCount, 10
            );

        return Node({
            name: unWrap(xmlNode.name),
            content: blnChiln ? (
                undefined
            ) : (unWrap(xmlNode.stringValue) || " "),
            attributes: (() => {
                const attrs = unWrap(xmlNode.attributes);

                return Array.isArray(attrs) ? (
                    attrs.reduce(
                        (a, x) => Object.assign(a, {
                            [unWrap(x.name)]: unWrap(
                                x.stringValue
                            )
                        }),
                        {}
                    )
                ) : {};
            })()
        })(
            blnChiln ? (
                unWrap(xmlNode.children)
                .reduce(
                    (a, x) => a.concat(xmlNodeDict(x)),
                    []
                )
            ) : []
        );
    };

    // ----------------------- JXA -----------------------

    // alert :: String => String -> IO String
    const alert = title =>
        s => {
            const sa = Object.assign(
                Application("System Events"), {
                    includeStandardAdditions: true
                });

            return (
                sa.activate(),
                sa.displayDialog(s, {
                    withTitle: title,
                    buttons: ["OK"],
                    defaultButton: "OK"
                }),
                s
            );
        };


    // clipOfTypeLR :: String -> Either String String
    const clipOfTypeLR = utiOrBundleID => {
        const
            clip = ObjC.deepUnwrap(
                $.NSString.alloc.initWithDataEncoding(
                    $.NSPasteboard.generalPasteboard
                    .dataForType(utiOrBundleID),
                    $.NSUTF8StringEncoding
                )
            );

        return 0 < clip.length ? (
            Right(clip)
        ) : Left(
            "No clipboard content found " + (
                `for type '${utiOrBundleID}'`
            )
        );
    };


    // setClipOfTextType :: String -> String -> IO String
    const setClipOfTextType = utiOrBundleID =>
        txt => {
            const pb = $.NSPasteboard.generalPasteboard;

            return (
                pb.clearContents,
                pb.setStringForType(
                    $(txt),
                    utiOrBundleID
                ),
                txt
            );
        };

    // --------------------- GENERIC ---------------------

    // Left :: a -> Either a b
    const Left = x => ({
        type: "Either",
        Left: x
    });


    // Node :: a -> [Tree a] -> Tree a
    const Node = v =>
    // Constructor for a Tree node which connects a
    // value of some kind to a list of zero or
    // more child trees.
        xs => ({
            type: "Node",
            root: v,
            nest: xs || []
        });


    // Right :: b -> Either a b
    const Right = x => ({
        type: "Either",
        Right: x
    });


    // bindLR (>>=) :: Either a ->
    // (a -> Either b) -> Either b
    const bindLR = m =>
        mf => m.Left ? (
            m
        ) : mf(m.Right);


    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (...fs) =>
    // A function defined by the right-to-left
    // composition of all the functions in fs.
        fs.reduce(
            (f, g) => x => f(g(x)),
            x => x
        );


    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = fl =>
        // Application of the function fl to the
        // contents of any Left value in e, or
        // the application of fr to its Right value.
        fr => e => e.Left ? (
            fl(e.Left)
        ) : fr(e.Right);


    // filterTree (a -> Bool) -> Tree a -> [a]
    const filterTree = p =>
    // List of all values in the tree
    // which match the predicate p.
        foldTree(x => xs =>
            (
                p(x) ? [
                    [x], ...xs
                ] : xs
            ).flat(1)
        );


    // fmapLR (<$>) :: (b -> c) -> Either a b -> Either a c
    const fmapLR = f =>
        // Either f mapped into the contents of any Right
        // value in e, or e unchanged if is a Left value.
        e => "Left" in e ? (
            e
        ) : Right(f(e.Right));


    // foldTree :: (a -> [b] -> b) -> Tree a -> b
    const foldTree = f => {
    // The catamorphism on trees. A summary
    // value obtained by a depth-first fold.
        const go = tree => f(
            tree.root
        )(
            tree.nest.map(go)
        );

        return go;
    };


    // map :: (a -> b) -> [a] -> [b]
    const map = f =>
    // The list obtained by applying f
    // to each element of xs.
    // (The image of xs under f).
        xs => [...xs].map(f);

    return main();
})();

No, that looks fine. It's a good idea to make your search as tight as possible -- you could even go with <img src="(file:///[^"]+) to make sure you only get image links.

1 Like

It does not seem to work.
Is it needed to run with the macros above?

Thank you very much.
You've done me a big favor.

If you copy some well formed HTML material (so that the public.html pasteboard is not empty) you should see a list of links if you run that macro.

It may be worth checking, with the clipboard viewer macro, to see what (if anything) is actually in the public.html component of the clipboard.

( but the simplest attack may be string munching, as suggested by @Nige_S )

{
  "com.apple.webarchive as propertyList": {
    "WebSubresources": [
      {
        "WebResourceURL": "file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_popcorn.jpg",
        "WebResourceMIMEType": "image/jpeg",
        "WebResourceResponse": {},
        "WebResourceData": {}
      }
    ],
    "WebMainResource": {
      "WebResourceURL": "file:///Applications/Eudb_en.app/Contents/Library/LoginItems/LightPeek_en.app/Contents/Resources/Html/",
      "WebResourceFrameName": "",
      "WebResourceMIMEType": "text/html",
      "WebResourceData": {},
      "WebResourceTextEncodingName": "UTF-8"
    }
  },
  "public.rtf as string": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2638\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;\\red224\\green224\\blue224;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c90196\\c90196\\c90196;}\n\\deftab720\n\\pard\\pardeftab720\\partightenfactor0\n\n\\f0\\fs26\\fsmilli13333 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\outl0\\strokewidth0 \\strokec2 }",
  "public.rtf as data": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2638\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;\\red224\\green224\\blue224;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c90196\\c90196\\c90196;}\n\\deftab720\n\\pard\\pardeftab720\\partightenfactor0\n\n\\f0\\fs26\\fsmilli13333 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\outl0\\strokewidth0 \\strokec2 }",
  "public.html as string": "<img src=\"file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_popcorn.jpg\" class=\"\" style=\"caret-color: rgb(230, 230, 230); color: rgb(230, 230, 230); font-family: Helvetica, &quot;Lucida Grande&quot;, Lucida, Verdana, sans-serif; font-size: 13.333333015441895px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;\">",
  "public.html as data": "<img src=\"file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_popcorn.jpg\" class=\"\" style=\"caret-color: rgb(230, 230, 230); color: rgb(230, 230, 230); font-family: Helvetica, &quot;Lucida Grande&quot;, Lucida, Verdana, sans-serif; font-size: 13.333333015441895px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;\">",
  "public.utf8-plain-text as string": "",
  "public.utf8-plain-text as data": "",
  "com.apple.WebKit.custom-pasteboard-data as string": "\u0001\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0001file://\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
  "com.apple.WebKit.custom-pasteboard-data as data": "\u0001\u0000\u0000\u0000\u0007\u0000\u0000\u0000\u0001file://\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
}
<img src="file:///var/folders/f_/v7vs50394951q1rw3s7mt_ww0000gn/T/com.eusoft.eudic.QuickLook/_mdx_1_1310462979/img/zzz_popcorn.jpg" class="" style="caret-color: rgb(230, 230, 230); color: rgb(230, 230, 230); font-family: Helvetica, &quot;Lucida Grande&quot;, Lucida, Verdana, sans-serif; font-size: 13.333333015441895px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;">

I'm trying to extract links from both texts and neither seems to work

These two texts are obtained from the two macros above
I'll start with @Nige_S's method, which I can set up myself.
Thank you.

1 Like