• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Dropbox to Google drive migration - broken Adobe Illustrator image links - bulk fix?

New Here ,
Aug 29, 2024 Aug 29, 2024

Copy link to clipboard

Copied

We’re  facing a bit of a challenge after trying to move our illustrator files from Dropbox to Google Drive.

 We have 1000s  of Adobe Illustrator documents containing lots of linked images, the beginning of the path always looks similar to this currently :

 C:\Users\username\Dropbox\Media\Files

 But after the move, the paths will change  to:

 C:\Users\username\GoogleDrive\MediaDrive\Files

fixing these links one by one isn't really an option given the sheer number. anyone faced this before and scripted their way out or something like that?

Bulk change links seems to be quite a highly reqeusted feature

TOPICS
How-to , Scripting

Views

120

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe
Community Expert ,
Aug 29, 2024 Aug 29, 2024

Copy link to clipboard

Copied

Hi @paul33910816rb6v, I wrote a script a while back that solved this type of problem on a smaller scale. Use it like this:

 

1. configure the script (I've configured it for your case above—but will need checking). Configure by editing these lines:

findWhat: 'Users/username/Dropbox/Media/Files',
changeTo: 'Users/username/GoogleDrive/MediaDrive/Files',

(you might need to change my forward slashes to backslashes for Windows, if you do, you'll need to escape them with another backslash; eg. 'Users\\username ...'. I can't test this because I don't have Windows here).

 

2. open a bunch of illustrator documents.

 

3. run script—will attempt to relink any placed items to the revised path.

 

By default, it doesn't save the documents, just attempts the relinking, but when you are confident it is working, you can do:

// warning: back up files before using
var SAVE_AND_CLOSE = true;

Let me know if it helps—try it on just a few documents to start with!

- Mark

 

/**
 * Relinker.js
 * for Adobe Illustrator
 *
 * @author m1b
 * @version 2024-04-07
 * @discussion https://community.adobe.com/t5/illustrator-discussions/quot-re-link-to-new-path-quot-script/m-p/12776878
 *
 * with help from advice found here:
 *   https://community.adobe.com/t5/illustrator/get-broken-file-path-of-rasteritem/td-p/9794237
 *
 * Limitations:
 *   • only relinks if the new path points to a valid file
 *   • document must be saved before relinking to ensure
 *     xmp manifest is up-to-date (script handles this)
 *
 * Notes:
 *   • the find/change is performed on the complete path,
 *     including filename and file extension
 *   • findWhat can be String or RegExp
 *   • onlyChangeBrokenLinks means don't do the relinking
 *     if the link isn't broken
 *   • showResults means show an alert with result stats
 *
 */

(function () {

    var findChanges = [
        {
            findWhat: 'Users/username/Dropbox/Media/Files',
            changeTo: 'Users/username/GoogleDrive/MediaDrive/Files',
        },
    ];

    // warning: back up files before using
    var SAVE_AND_CLOSE = false;

    var docs;

    // all open documents
    docs = addCollectionToArray(app.documents);

    for (var i = docs.length - 1; i >= 0; i--) {

        // relink
        findChangeInLinkedFilePaths(findChanges, docs[i]);

        if (SAVE_AND_CLOSE) {
            docs[i].save();
            docs[i].close();
        }

    }



    /**
     * Perform find/changes on link paths.
     * New link paths must resolve to real files.
     * @author m1b
     * @version 2023-02-01
     * @param {Array<Object>} findChanges - the find/change details, eg. [ {findWhat: 'this', changeTo: 'that' } ].
     * @param {Document} [doc] - an Illustrator Document (default: active document).
     * @param {Boolean} [onlyChangeBrokenLinks] - whether to only process broken links (default: false).
     * @param {Boolean} [automaticallySaveDocumentBeforeRelinking] - whether to automatically save document *without asking* before processing (default: false).
     * @param {Boolean} [showResults] - whether to show results (default: true).
     */
    function findChangeInLinkedFilePaths(findChanges, doc, onlyChangeBrokenLinks, automaticallySaveDocumentBeforeRelinking, showResults) {

        doc = doc || app.activeDocument;
        showResults = showResults !== false;

        // must save document before relinking to ensure the xmp manifest is up-to-date
        if (!doc.saved)
            if (automaticallySaveDocumentBeforeRelinking || confirm('Document "' + doc.name + '" must be saved before relinking. Continue?', false, 'Save Document'))
                doc.save();
            else
                return;

        // get all the placedItems
        var items = doc.placedItems,
            manifestPaths = getLinkedFilePaths(doc),
            relinked = [],
            notFound = [],
            notChanged = [];

        for (var i = 0; i < manifestPaths.length; i++) {

            var newPath = manifestPaths[i];

            // do the find/changes
            for (var j = 0; j < findChanges.length; j++)
                var newPath = newPath.replace(findChanges[j].findWhat, findChanges[j].changeTo);

            var filename = newPath.split('/').pop(),
                item = items[i],
                success = false;

            if (newPath === manifestPaths[i]) {
                notChanged.push(filename);
                continue;
            }

            var linkIsValid;

            try {

                linkIsValid = item.file != undefined;
                // current link is okay

            } catch (error) { }

            if (
                !(linkIsValid && onlyChangeBrokenLinks)
                || linkIsValid
            )

                // attempt to relink
                success = relinkPlacedItem(item, newPath);

            if (success)
                relinked.push(filename);
            else
                notFound.push(filename);

        }

        // report
        app.redraw();

        if (showResults) {

            var report = ['Relinker results'];

            if (relinked.length > 0)
                report.push('Relinked:\n' + relinked.join('\n'));
            else
                report.push('No files relinked.');

            if (notFound.length > 0)
                report.push('Link didn\'t exist:\n' + notFound.join('\n'));

            if (notChanged.length > 0)
                report.push('Ignored:\n' + notChanged.join('\n'));

            alert(report.join('\n\n'));

        }

        /**
         * Relinks a placed item.
         * @param {PlacedItem} item - an Illustrator PlacedItem.
         * @param {String} path - the path to a placeable file.
         * @returns {Boolean} - success?
         */
        function relinkPlacedItem(item, path) {

            if (File(path).exists) {
                item.file = new File(path);
                return true;
            }

        };

    };

    /**
     * Returns all the paths from the
     * document's linked file XMP manifest.
     * @param {Document} doc - an Illustrator Document.
     * @returns {Array<String>} - array of the paths.
     */
    function getLinkedFilePaths(doc) {

        var manifestPaths = [],
            items = doc.placedItems;

        // collect the paths of all the placedItems
        if (ExternalObject.AdobeXMPScript == undefined)
            ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');

        var xmp = new XMPMeta(doc.XMPString),
            manifestItemCount = xmp.countArrayItems(XMPConst.NS_XMP_MM, 'Manifest');

        // // sanity check
        // if (manifestItemCount != items.length)
        //     throw ('Aborting: Manifest item count does not match placed item count.');

        // collect the paths
        for (var i = 0; i < manifestItemCount; i++) {

            // get the path from the document's manifest
            var xpath = 'xmpMM:Manifest[' + (i + 1) + ']/stMfs:reference/stRef:filePath',
                path = xmp.getProperty(XMPConst.NS_XMP_MM, xpath).value;
            manifestPaths.push(path);

        }

        return manifestPaths;

    };

    /**
     * Adds items of an Illustrator collection
     * to a given Array.
     * @param {collection} collection - eg. PlacedItems, or Documents.
     * @param {Array} [array] - the array to add to (default: empty array).
     * @returns {Array}
     */
    function addCollectionToArray(collection, array) {

        array = array || [];

        for (var i = 0; i < collection.length; i++)
            array.push(collection[i]);

        return array;

    };

})();

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 29, 2024 Aug 29, 2024

Copy link to clipboard

Copied

LATEST

Another thought: opening a bunch of old files will very likely end up with many [Converted] documents. The script probably won't handle these until they are saved first—and the save and close *definitely* won't work on these ones. It is possible for the script to handle these but it is more work.

- Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines