Is this correct to use image fill

async function imageFill() {
    const fs = storage.localFileSystem;
    const pluginFolders = await fs.getPluginFolder();
    const entries = await pluginFolders.getEntries();
    var imagefolder;
    entries.forEach(e => {
        if (e.name == "images") {
            imagefolder = e.nativePath;
        }
    });
    let imageFile = "\\baselinetheme.png"

    return new ImageFill(imagefolder + imageFile);
}

now How to use this fill to use in rectangle element explain… anyone

1 Like

Hi @PramUkesh,

The API reference has a good example documented: https://adobexdplatform.com/plugin-docs/reference/ImageFill.html?h=imagefill.

If you are looking for a solution for using images received from network requests, we have a guide for it:
Have you seen this guide? https://adobexdplatform.com/plugin-docs/tutorials/how-to-make-network-requests/?h=imagefill

Hope this helps!

Using the code you’ve supplied, there’s an easier way – you can use getEntry:

async function imageFill() {
    const fs = storage.localFileSystem;
    const pluginFolders = await fs.getPluginFolder();
    const imageFile = await pluginFolders.getEntry("images/baselinetheme.png");
    return new ImageFill(imageFile);
}

The above should do the trick for you.

function createThemePreview(selection) {
    const rect = new Rectangle();
    rect.name = "themePreview";
    rect.width = 866;
    rect.height = 537;
    rect.cornerRadii = {
        topLeft: 0,
        topRight: 0,
        bottomLeft: 0,
        bottomRight: 0,
    };
    rect.fill = new Color("#000000");
    rect.stroke = new Color("#707070");
    rect.strokeWidth = 1;
    rect.moveInParentCoordinates(0, 156);
    var imagefill;
    imageFill().then(
        (success => {
            console.log("image fill success");
            console.log(success);
            imagefill = success;
        }),
        (failure => {
            console.log("image fill failed");
        })
    );
    rect.fill = imagefill;
    selection.insertionParent.addChild(rect);
    return rect;
}

Throws Error

Plugin Error: Plugin 07b2dfeb is not permitted to make changes from the background. Return a Promise to continue execution asynchronously.
        at convertPluginErrorToString (plugins/PluginErrorUtil.js:1:198)
        at internalFormatPluginError (plugins/PluginErrorUtil.js:1:503)
        at internalReportPluginError (plugins/PluginErrorUtil.js:1:610)
        at Object.reportPluginError (plugins/PluginErrorUtil.js:1:1015)
        at Object.checkAllowedToEdit (plugins/ScenegraphGuard.js:1:1094)
        at Rectangle.<anonymous> (plugins/ScenegraphWrappers.js:1:2286)
        at createThemePreview (C:\Users\PramUkesh\AppData\Local\Packages\Adobe.CC.XD_adky2gkssdxte\LocalState\develop\07b2dfeb\main.js:334:15)

You’re adding something to the scenegraph in an async operation – you must make sure that there’s a complete promise chain returned to the menu handler in order to make changes to the scenegraph. If not, XD locks it down immediately after invoking your plugin.

module.exports = {
    commands: {
        someCommand: function(selection) {
            return new Promise((resolve, reject) => {
                // you can make changes as long as this promises is neither resolved nor rejected
                // once resolved, the scenegraph becomes locked to changes from code
                // if rejected, changes to the scenegraph will be undone completely
            });
        }
    }
};
1 Like

do you suggest me a better way to fill rect obj with an asset file without a promise chain
@kerrishotts

due to lack of timeout api some js operations are hard implement due to js is single threaded

There’s no other way – once you start doing anything that involves an asynchronous operation (file IO, network IO, renditions), you’ll need to be in the land of promises, and one unbroken chain all the way back to the menu handler.

If async/await is easier for you to use, that works too:

module.exports = {
    commands: {
        someCommand: async function(selection) {
            const doSomethingAsync = await someOtherAsyncFunction();
            // can still do things to the scenegraph
            // throw if you want them to be undone
        }
    }
}

(Async/await is built on top of promises, so XD can work with async functions too.)

1 Like

I tried promise function, still not able to fix “xxxx is not permitted to make changes from the background. Return a Promise to continue execution asynchronously.”

Can you please give an example to handle this problem

@realvjy make sure to return inside your Promise block

Hey steve,
Thank you for quick response. Still not luck to solve this problem. I’m not too aware of promise/await/async fx.
Can you please check this code?

// Get Rectangle and oval Shapes
async function fillImages(selection, allImages) {
  var imageCount = allImages.length;
  if (imageCount != 0 && imageCount >= selection.items.length) {
    for (var i = 0; i < selection.items.length; i++) {
      if (selection.items[i] instanceof scenegraph.Rectangle || selection.items[i] instanceof scenegraph.Ellipse) {
        try {
          var imgObj = await getImage(allImages[i]);
          fillSelectionWithImage(selection.items[i], imgObj);
        } catch (e) {
          console.log(e);
        }
      } else {
        console.log('please select elipse or rectangle');
      }
    }
  } else {
    console.log('too many selection');
  }
}

// Check image
function getImage(selectedImage) {
  return new Promise((resolve, reject) => {
    if (selectedImage) {
      try {
        const image = selectedImage;
        resolve(image);
      } catch (e) {
        reject('could not load image')
      }
    } else {
      reject('had an error')
    }
  });
}

// Fill selected shape with image
function fillSelectionWithImage(selectedPath, image) {
  const imageFill = new ImageFill(image);
  selectedPath.fill = imageFill;
}

Higher func i.e func provided in exports to a menu item of your plugin to be a promise to make changes for a scenegraph

See this reply

1 Like

Hey @realvjy Looks like you are working on the XD port of your sketch plugin uiLogos.

@bantya yeah, I’m working on it and struggling with new syntax await/promise/async. :grinning:

@PramUkesh thanks! It works like charm :grinning:

Looking forward to it. Then complete it and release it fast. Best wishes for that. :smile:

Here it is - https://github.com/realvjy/uilogos-XD/releases (Download .xdx file and double click to install)
Can you please test it and share your feedback?

2 Likes

For perfect squares, Logomarks, work flawlessly:

But for Logotypes it just stumbles:

According to me, the logo should just fit in the container, independent of the size and shape of the container (be it square or vertical/horizontal rectangles)

@bantya This was intended to change the width of container to respect ratio of original logo.

Idea behind logotype here -
Logotype have different dimension (height and width can’t fixed for all logo).
Possible solution:

  1. Center fill or fit logo inside the original container/rectangle (Problem: Logo should be visible completely, it’s not general image)
  2. Just picked height of rectangle/container and change the width of container respect to the ratio of original logotype. (Problem: If have group of container/rectangle, will stumbles :grinning:)

Solution 2 is best for logo related stuff. So, I used this approach. We can re-arrange logos with the help of align distribute.

PS: Added border for comparison

1 Like

Completely agree with you bhai. Lage raho…

1 Like