Text Attachments

The cells of outline items can contain non-textual data such as images, or audio files. The following examples show how to add images to new rows using either image import or image data methods.

File Attachment

The fetch() method of the URL class is used to import an image from a file into a row. In this example, the data from a chosen image file is loaded using the fetch() method and then used to create a new instance of the FileWrapper class. The created filewrapper is then passed into the makeFileAttachement() method of the Text class to create an new text attachment object. Once created the attachment is assigned to a specified column in a newly created outline row.

imageURL = URL.choose(['public.image']) if (imageURL == null){throw new Error('user cancelled')} urlString = imageURL.string var imageFileName = urlString.substr(urlString.lastIndexOf('/') + 1) imageFileName = decodeURIComponent(imageFileName) imageURL.fetch(function(data){ wrapper = FileWrapper.withContents(imageFileName, data) textObj = Text.makeFileAttachment(wrapper, document.outline.baseStyle) rootItem.addChild( null, function(item){ item.topic = "This is an image named: " + imageFileName item.setValueForColumn(textObj,columns.byTitle('Image')) } ) })
text-attachment-star
/*{ "type": "action", "targets": ["omnioutliner"], "author": "Otto Automator", "identifier": "com.omni-automation.oo.pics-to-rows", "version": "1.0", "description": "Create a new row for each chosen image file. Requires column named: “Image”", "label": "Add Rows with Pictures", "shortLabel": "Pics to Rows" }*/ var _ = function(){ var action = new PlugIn.Action(function(selection, sender){ // CHECK FOR IMAGE COLUMN var colTitle = 'Image' columnTitles = columns.map(function(col){ return col.title }) if(columnTitles.indexOf(colTitle) === -1){ alertMsg = 'There is no column titled “' + colTitle + '” in this outline.' var alert = new Alert('Missing Column',alertMsg) alert.addOption('Cancel') alert.show(()=>{}) } else { // FILEPICKER INSTANCE CREATED AND PROPERTIES SET var picker = new FilePicker() picker.folders = false picker.multiple = true picker.types = [FileType.image] // PICKER PROMISE IS CREATED AND STORED WHEN PICKER IS DISPLAYED pickerPromise = picker.show() // PROMISE FUNCTION CALLED UPON PICKER APPROVAL pickerPromise.then(function(urlsArray){ var bStyle = document.outline.baseStyle var imageColumn = columns.byTitle(colTitle) urlsArray.forEach(url => { urlStr = url.string // GET FILE NAME var filename = urlStr.substring(urlStr.lastIndexOf('/')+1) // REMOVE FILE EXTENSION AND ENCODING var baseName = filename.substring(0,filename.lastIndexOf('.')) baseName = decodeURIComponent(baseName) // IMPORT IMAGES url.fetch(function(data){ wrapper = FileWrapper.withContents(filename,data) textObj = Text.makeFileAttachment(wrapper, bStyle) rootItem.addChild( null, function(item){ item.topic = baseName item.setValueForColumn(textObj,imageColumn) } ) }) }) }) // PROMISE FUNCTION CALLED UPON PICKER CANCELLATION pickerPromise.catch(function(error){ console.log("form cancelled", error.message) }) } }); action.validate = function(selection, sender){ return true }; return action; }(); _;

Import Images to New Rows Plug-In

Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec sed odio dui. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.

You can download the example document and a folder of employee headshots for use with this plug-in.

Image from Data

If small images are often used as text attachments, they can be stored in the script code as a base64 string. This base64 data can then be used to generate an image attachement.

Here’s a useful script for extracting the data of a chosen image file as base64. It uses the toBase64() method of the Data class to convert image data into a base64 format. Run it in the console, and the chosen image data will be logged:

imageURL = URL.choose(['public.image']) if (imageURL === null){throw new Error('user cancelled')} imageURL.fetch(function(data){ console.log(data.toBase64()) }

And here’s an example script that has stored a small image of a star in a circle:

red-square
img64 = "iVBORw0KGgoAAAANSUhEUgAAABMAAAASCAYAAAC5DOVpAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAgtpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpSZXNvbHV0aW9uVW5pdD4yPC90aWZmOlJlc29sdXRpb25Vbml0PgogICAgICAgICA8dGlmZjpDb21wcmVzc2lvbj41PC90aWZmOkNvbXByZXNzaW9uPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpQaG90b21ldHJpY0ludGVycHJldGF0aW9uPjI8L3RpZmY6UGhvdG9tZXRyaWNJbnRlcnByZXRhdGlvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CobSriQAAAGeSURBVDgRjZS/K4VhFMfv9TOykM0iPzJgkDIYDCyUxSIpi0kZDAaDSUb8CQYmKWGQRXdQykgMSukOlIVIym8+3+s5b8frva5Tn3vOc873fd7ned7z3HTqb2uh3ABlcAVH8Ab/tmKUE3AOn/AKZyG+wS9BNRS0WhQHoEmMDPGsGyt/DV2Q16qonIJNYn6KXGtC/pFcByTaClmbwPv6oLZt+9oFtYpQj1w70Qd4oeLjSJFKLSTUpZk2TUkIxvGH8GSF4NfdeI24040tHCXQR4lMZ6XP3hRlCgeVSFZBq6vz8oeQvMMP+UKeWP13AnYs3V6nXrKC/CLYEXid4mGwl9szfV6k7raC+V4vCLFuglrCNObbvHYrJtB2S73AxZsx7b1pi4JIAm+7DLR12QDMQFoDbPvbRb87RKbNJbUKNaAte4RYL5oH6z89VAO6crrs0r7Djy0yzlkPv3rDCzTDHtjk5rPkdCf3Q20On9fGqGThEmyCuH+mpp5cBjsmwmTTCpMuvE16S30y6VE71HhN/2n9MAiNUA5abQY2QF/7l30BWpSQgTjp6dQAAAAASUVORK5CYII=" imgData = Data.fromBase64(img64) wrapper = FileWrapper.withContents('star-circle.png',imgData) textObj = Text.makeFileAttachment(wrapper, document.outline.baseStyle) rootItem.addChild( null, function(item){ item.topic = "This is a star in a circle:" item.setValueForColumn(textObj,columns.byTitle('Image')) } )

Exporting Audio Attachments

One of the best features of OmniOutliner is the ability to record audio clips that are automatically embedded into the document.

With Omni Automation, you can use the following plug-in to export all of the audio clips from the selected outline rows to MPEG audio files (m4a):

/*{ "type": "action", "targets": ["omnioutliner"], "author": "Otto Automator", "identifier": "com.omni-automation.oo.export-audio-from-selected-rows", "version": "1.5", "description": "This plug-in will export all of the audio clips attached to the text columns of the selected rows.", "label": "Export Audio Clips from Selected Rows", "shortLabel": "Export Audio" }*/ (() => { var action = new PlugIn.Action(function(selection, sender){ // action code // selection options: columns, document, editor, items, nodes, outline, styles try { // GET ARRAY OF VISIBLE TEXT COLUMNS (OMIT “NOTE BUTTON” COLUMN) var editor = document.editors[0] var textColumns = [noteColumn] columns.forEach(col => { if (editor.visibilityOfColumn(col)){ if (col.type === Column.Type.Text){ if (!textColumns.includes(col)){ textColumns.push(col) } } } }) if(textColumns.length === 0){throw new Error("This document has no text columns.")} // GET ARRAY OF FILEWRAPPERS FOR ATTACHED AUDIO CLIPS var exportWrappers = [] selection.items.forEach((row,index) => { textColumns.forEach(col => { if(row.valueForColumn(col)){ var atts = row.valueForColumn(col).attachments if(atts){ atts.forEach(att => { var wrapper = att.fileWrapper if(wrapper.type === FileWrapper.Type.File && wrapper.preferredFilename.endsWith('.m4a')){ exportWrappers.push(wrapper) } }) } } }) }) // EXPORT THE ATTACHED AUDIO CLIPS if(exportWrappers.length > 0){ // Create and Show File Saver var filesaver = new FileSaver() var folderType = new FileType("public.folder") filesaver.types = [folderType] var fldrwrapper = FileWrapper.withChildren("Audio Clips", exportWrappers) var fileSaverPromise = filesaver.show(fldrwrapper) // Process File Saver Result fileSaverPromise.then(function(urlObj){ console.log(urlObj.string) urlObj.open() }) fileSaverPromise.catch(function(err){ console.log(err.message) }) } } catch(err){ console.error(err) } }); action.validate = function(selection, sender){ // validation code // selection options: columns, document, editor, items, nodes, outline, styles return (selection.items.length > 0) }; return action; })();
UNDER CONSTRUCTION

This webpage is in the process of being developed. Any content may change and may not be accurate or complete at this time.

DISCLAIMER