Export a markdown note with images associated with it

Hello friends

with the recent introduction of a central group of images (which is fantastic for assets management), I am on a hunt for a way to export one single markdown note with all the images associated with it (.e.g to be shared with co-workers etc) as a markdown file + folder with images.

I wonder if there is a better way for that as searching through all the associated image files in a central group manually … :slight_smile: Maybe there is some script which could be provided in the future to make this process simpler?

1 Like

Maybe an option could be added to “convert to” which would basically provide a text bundle format with a markdown file and all associated assets to it.

The existing context menu options of “Convert to PDF…” and Convert to Formatted Note" both work for me—and certainly include any image which is included and which is the subject of an item link.

Stephen

You could probably create an archive containing the relevant files. I posted a script to create an archive from the selected DT documents here a while ago, you could start from there.

Thanks! I will try to find it!

Converting to paginated/single page PDF or rich text documents is already an option. The next release will also improve the conversion to formatted notes & web archives (and embed images using relative links inside the database).

to formatted notes & web archives (and embed images using relative links inside the database).

Thanks - that sounds very interesting.
Ideally I am looking for way to export a markdown document with a separate folder with all images associated with that markdown. By having same name of that folder as the global setting in DT3, relative paths in the md can stay the same … what is needed is the ability to pull in the images associated with that particular file.

This approach would allow to share separate notes between multiple “second brain” setups e.g. private <> corporate or private <> another person.

This script exports Markdown with linked images.

Export includes

  • images stored in “Assets” group
  • other relatively linked images
  • images linked via reference URL
-- Export Markdown with linked images

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

tell application id "DNtp"
	try
		set theRecords to selected records
		if theRecords = {} then error "Please select some Markdown records"
		set thePath to POSIX path of (choose folder)
		set theImageDestinationName to my getImageDestinationFromPlist()
		
		show progress indicator "Exporting... " steps ((count theRecords) + 1) with cancel button
		
		repeat with thisRecord in theRecords
			set thisRecord_Type to (type of thisRecord) as string
			if thisRecord_Type is in {"markdown", "«constant ****mkdn»"} then
				set thisRecord_Name to (name without extension of thisRecord) as string
				step progress indicator "... " & thisRecord_Name
				set thisTempGroup to create record with {name:thisRecord_Name, type:group, exclude from search:true} in root of database of thisRecord
				set thisExportFolderPath to export record thisTempGroup to thePath
				set thisExportSubfolderPath to thisExportFolderPath & "/" & theImageDestinationName
				
				set thisRecord_Text to plain text of thisRecord
				set thisRecord_Text_modified to thisRecord_Text
				set thisRecord_Location to location of thisRecord
				set theLinkURLsAndRanges to my regexFindStringAndRange(thisRecord_Text, "\\!\\[.*?\\]\\((.*?)\\)", 1)
				set theLinkURLsAndRanges_reverse to reverse of theLinkURLsAndRanges
				
				repeat with thisItem in theLinkURLsAndRanges_reverse
					set replaceLink to missing value
					set thisLinkURL to MatchString of thisItem
					set thisLinkURL_Range to MatchRange of thisItem
					if thisLinkURL starts with "x-devonthink" then
						set thisImageRecord to get record with uuid thisLinkURL
						if thisImageRecord ≠ missing value then
							set replaceLink to true
						end if
					else
						if thisLinkURL does not contain "%" then
							set thisImageRecord to get record at thisRecord_Location & thisLinkURL
						else
							set thisImageRecord to get record at thisRecord_Location & my percentDecode(thisLinkURL)
						end if
						if thisImageRecord ≠ missing value then
							if thisLinkURL starts with ((theImageDestinationName & "/") as string) then
								if (item 2 of (my tid(thisLinkURL, "/"))) ≠ ((filename of thisImageRecord) as string) then
									set replaceLink to true
								end if
							else
								set replaceLink to true
							end if
						end if
					end if
					if replaceLink = true then
						set thisLinkURL_modified to theImageDestinationName & "/" & my percentEncode((filename of thisImageRecord) as string)
						set thisRecord_Text_modified to my replaceInRange(thisRecord_Text_modified, thisLinkURL, thisLinkURL_modified, thisLinkURL_Range)
					end if
					if thisImageRecord ≠ missing value then export record thisImageRecord to thisExportSubfolderPath
				end repeat
				
				if not indexed of thisRecord then
					set thisDuplicatedRecord to duplicate record thisRecord to thisTempGroup
				else
					consolidate record thisRecord
					set thisDuplicatedRecord to duplicate record thisRecord to thisTempGroup
					deconsolidate record thisRecord
				end if
				set plain text of thisDuplicatedRecord to thisRecord_Text_modified
				export record thisDuplicatedRecord to thisExportFolderPath
				delete record thisTempGroup
			end if
		end repeat
		
		step progress indicator
		hide progress indicator
		
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on getImageDestinationFromPlist()
	try
		if current application's id = "com.devon-technologies.think3" then
			set theDefaults to current application's NSUserDefaults's standardUserDefaults()
		else
			set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.devon-technologies.think3"
		end if
		set theImageDestination to (theDefaults's dictionaryRepresentation())'s stringForKey:"ImageDestination"
		return theImageDestination as string
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"getImageDestinationFromPlist\"" message error_message as warning
		error number -128
	end try
end getImageDestinationFromPlist

on regexFindStringAndRange(theText, thePattern, theCaptureGroup)
	try
		set theString to current application's NSString's stringWithString:theText
		set {theRegex, theError} to current application's NSRegularExpression's regularExpressionWithPattern:(thePattern) options:0 |error|:(reference)
		set theMatches to theRegex's matchesInString:theString options:0 range:{0, theString's |length|()}
		set theResults to {}
		repeat with thisMatch in theMatches
			set thisMatchRange to (thisMatch's rangeAtIndex:theCaptureGroup)
			set thisMatchString to (theString's substringWithRange:thisMatchRange) as string
			set end of theResults to {MatchRange:thisMatchRange, MatchString:thisMatchString}
		end repeat
		return theResults
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"regexFindStringAndRange\"" message error_message as warning
		error number -128
	end try
end regexFindStringAndRange

on replaceInRange(theText, thePattern, theRepacement, theRange)
	try
		set theString to (current application's NSString's stringWithString:theText)
		set newString to (theString's stringByReplacingOccurrencesOfString:(thePattern) withString:(theRepacement) options:0 range:theRange)
		return newString as string
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"replaceInRange\"" message error_message as warning
		error number -128
	end try
end replaceInRange

on percentDecode(theText)
	try
		set theString to (current application's NSString's stringWithString:theText)
		set theString_decoded to theString's stringByRemovingPercentEncoding()
		return theString_decoded as string
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"percentDecode\"" message error_message as warning
		error number -128
	end try
end percentDecode

on percentEncode(theText)
	try
		set theString to (current application's NSString's stringWithString:theText)
		set theCharacterSet to current application's NSCharacterSet's alphanumericCharacterSet()
		set theString_encoded to (theString's stringByAddingPercentEncodingWithAllowedCharacters:theCharacterSet)
		return theString_encoded as string
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"percentEncode\"" message error_message as warning
		error number -128
	end try
end percentEncode

on tid(theInput, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	if class of theInput = text then
		set theOutput to text items of theInput
	else if class of theInput = list then
		set theOutput to theInput as text
	end if
	set AppleScript's text item delimiters to d
	return theOutput
end tid

4 Likes

@pete31 Pete! This is fabulous :slight_smile: Your contribution on the forum is beyond all levels of recognition - thank you so much for this work. Works like magic, indeed and now would allow easy sharing of markdown notes between different setups!!! :slight_smile: THANK YOU.

1 Like

@pete31 One question: export process generates this file: image
which seem to be a byproduct of the export with some binary data in it?

See page 135 of the user guide (also available through the in-app Help):

Internal metadata for the items is preserved in invisible .DEVONtech_storage files, used for reimporting into DEVONthink. If you will not be reimporting the exported files, you can safely delete .DEVONtech_storage files.

Stephen

2 Likes

Cool! thanks!