No, it starts with file:// -- that means "use the file protocol" in the same way that http:// means "use the http protocol". Everything afterfile:// 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:
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?"
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
(() => {
"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();
})();
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:
...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.
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
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:
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.
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
(() => {
"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.