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

Simple file browser with import and search (UXP, JS)

Explorer ,
Mar 25, 2025 Mar 25, 2025

I want screate plugin for simple image browser. Now its parially working. I can select folder, show thumbs but double click is not importing/placing image in document. I want use as my quick image library with search function. Any ideas hot to resolve this? My code right now looks like this

const fs = require("uxp").storage.localFileSystem;
const uxp = require("uxp");
const photoshop = require("photoshop").app;

let selectedFolder = null;

// When the "Select Folder" button is clicked
document.getElementById("select-btn").addEventListener("click", async () => {
    try {
        // Let the user select a folder
        selectedFolder = await fs.getFolder();
        if (!selectedFolder) {
            displayMessage("No folder selected.");
            return;
        }
        displayMessage("Folder selected: " + selectedFolder.nativePath);
        console.log("Folder selected:", selectedFolder.nativePath);

        // Clear existing results before loading new images
        clearThumbnails();

        // Load images from the selected folder
        loadImages(selectedFolder);
    } catch (error) {
        displayMessage("Error selecting folder: " + error.message);
        console.error("Error selecting folder:", error);
    }
});

// Function to display messages to the user in the UI
function displayMessage(message) {
    const resultsContainer = document.getElementById("results");
    resultsContainer.innerHTML = `<p>${message}</p>`;
}

// Function to clear thumbnails in the UI
function clearThumbnails() {
    const resultsContainer = document.getElementById("results");
    resultsContainer.innerHTML = "";  // Clear any previous results
}

// Function to load images from the selected folder
async function loadImages(folder) {
    const resultsContainer = document.getElementById("results");

    try {
        console.log("Loading images from folder:", folder.nativePath);
        const images = await getImagesFromFolder(folder);

        if (images.length === 0) {
            displayMessage("No images found in the selected folder.");
            return;
        }

        images.forEach(async (file) => {
            const fileElement = document.createElement("div");
            fileElement.classList.add("thumbnail");

            try {
                // Read file as binary data (ArrayBuffer) for image files
                const fileData = await file.read({ format: uxp.storage.formats.binary });
                console.log("File read successfully:", file.name);

                // Check the type of fileData returned by read()
                if (fileData instanceof ArrayBuffer) {
                    const blob = new Blob([fileData]);
                    const imageUrl = URL.createObjectURL(blob); // Create an object URL for the Blob
                    fileElement.innerHTML = `<img src="${imageUrl}" alt="${file.name}" style="width:50px; height:50px; cursor:pointer;">`;

                    // When double-clicking the thumbnail, open the image in Photoshop
                    fileElement.addEventListener("dblclick", async () => {
                        await importImageToPSD(file);
                    });
                    resultsContainer.appendChild(fileElement);
                } else {
                    console.error("Error: file content is not an ArrayBuffer, it's a", typeof fileData);
                    displayMessage("Error reading file: Not an ArrayBuffer, got: " + typeof fileData);
                }
            } catch (error) {
                console.error("Error reading file:", error);
                displayMessage("Error reading file: " + error.message);
            }
        });
    } catch (error) {
        displayMessage("Error retrieving entries from folder: " + error.message);
        console.error("Error retrieving entries from folder:", error);
    }
}

// Recursive function to get all images (jpg/png) from a folder and its subfolders
async function getImagesFromFolder(folder) {
    let imageFiles = [];
    const entries = await folder.getEntries();

    for (const entry of entries) {
        if (entry.isFile && (entry.name.toLowerCase().endsWith(".jpg") || entry.name.toLowerCase().endsWith(".png"))) {
            imageFiles.push(entry);  // Add image files to the array
        } else if (entry.isFolder) {
            // Recursively check inside subfolders
            const subfolderImages = await getImagesFromFolder(entry);
            imageFiles = imageFiles.concat(subfolderImages);  // Combine results from subfolders
        }
    }

    return imageFiles;
}

// Function to import the selected image to the currently open PSD document
async function importImageToPSD(file) {
    try {
        const fileData = await file.read({ format: uxp.storage.formats.binary });  // Read the file content as binary
        console.log("Importing image to PSD:", file.name);

        // Check the type of fileData returned by read()
        if (fileData instanceof ArrayBuffer) {
            // Create a Blob from the ArrayBuffer
            const blob = new Blob([fileData]);

            // Save the Blob to a temporary file in the system
            const tempFile = await saveTemporaryFile(blob, file.name);

            // Now place the image in Photoshop
            await placeImageInPhotoshop(tempFile);
        } else {
            console.error("Error: file content is not an ArrayBuffer, it's a", typeof fileData);
            displayMessage("Failed to import image: Not an ArrayBuffer");
        }
    } catch (err) {
        displayMessage("Failed to import image: " + err.message);
        console.error("Error importing image:", err);
    }
}

// Function to save the image data to a temporary file
async function saveTemporaryFile(blob, filename) {
    const tempFolder = await fs.getTemporaryFolder(); // Get the system's temporary folder
    const tempFile = await tempFolder.createFile(filename, { overwrite: true }); // Create the temp file with the specified filename

    await tempFile.write(blob); // Write the image data to the temporary file
    return tempFile;  // Return the temporary file object
}

// Function to place the image in Photoshop document using BatchPlay
async function placeImageInPhotoshop(file) {
    try {
        const doc = photoshop.activeDocument;  // Get the currently active document

        // Create the asset object that we will use for placing the image
        const asset = { file: file.nativePath };  // asset file path to the temporary file

        // Ensure we pass the path directly as a string to the placeEvent command
        const cmd = [{
            "_obj": "placeEvent",
            "null": {
                "_path": asset.file,  // The path to the temporary image file
                "_kind": "local"
            },
            "offset": {
                "_obj": "offset",
                "horizontal": {
                    "_unit": "pixelsUnit",
                    "_value": 0
                },
                "vertical": {
                    "_unit": "pixelsUnit",
                    "_value": 0
                }
            },
            "_isCommand": true
        }];

        // Run the BatchPlay command
        await photoshop.batchPlay(cmd);

        console.log("Image placed successfully.");
    } catch (err) {
        console.error("Error placing image:", err);
        displayMessage("Failed to place image: " + err.message);
    }
}
TOPICS
Actions and scripting , SDK , Windows
112
Translate
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
Enthusiast ,
Mar 25, 2025 Mar 25, 2025

I speak as a non-UXP expert, but I have been trying to learn and understand for a while. However, from what I see it seems that a token is missing, With uxp this is important, try to implement it and see if you can make it work, Another important thing is the permissions in the manifest file. If it is not a problem for you, you can share the project and see if with the help of someone you can solve it.

Translate
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
Explorer ,
Mar 26, 2025 Mar 26, 2025

I almost finish, now I want create thumnails cache, but I dont know how ;)w

Translate
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
Enthusiast ,
Mar 26, 2025 Mar 26, 2025

We are not fortune tellers and we can't help anyone if we don't know what they are looking for. You posted some code above, which is ultimately not useful. Sorry for the question, But what is the difference between your panel and going to the photoshop file open menu. Both open a folder to select images. Why is your plugin important?

Translate
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
Explorer ,
Mar 26, 2025 Mar 26, 2025

Speed - you dont must open any extra window, I can see whole my library with all objects, its should works like Adobe Library but faster and locally 🙂 double click and I have object in my project, thats all. My plugin is almost done. Maybe I publish soon 

Translate
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
Enthusiast ,
Mar 26, 2025 Mar 26, 2025
LATEST

Since that's the case, I can't wait to see it in action. Sorry I couldn't help.

Translate
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