toto10's picture
Upload folder using huggingface_hub (#1)
34097e9
raw
history blame
27.7 kB
const psapi = require('../psapi')
// const sdapi = require('../sdapi_py_re')
const layer_util = require('../utility/layer')
const general = require('./general')
const Jimp = require('../jimp/browser/lib/jimp.min')
const { executeAsModal } = require('photoshop').core
const batchPlay = require('photoshop').action.batchPlay
const formats = require('uxp').storage.formats
const storage = require('uxp').storage
const fs = storage.localFileSystem
async function isBlackAndWhiteImage(base64EncodedImage) {
try {
// Load your base64 encoded image
const image = await Jimp.read(Buffer.from(base64EncodedImage, 'base64'))
console.log(
'isBlackAndWhiteImage(): image.bitmap.width, image.bitmap.height: ',
image.bitmap.width,
image.bitmap.height
)
// Check if your image only has one channel
return (
image.bitmap.width === image.bitmap.height &&
image.bitmap.width === 1
)
} catch (e) {
console.warn(e)
}
}
async function convertBlackAndWhiteImageToRGBChannels(base64EncodedImage) {
// Load your base64 encoded image
const image = await Jimp.read(Buffer.from(base64EncodedImage, 'base64'))
// Convert your black and white image to RGB channels
image.color([
{ apply: 'red', params: [255] },
{ apply: 'green', params: [255] },
{ apply: 'blue', params: [255] },
])
// Get your base64 encoded black and white image with RGB channels
const base64EncodedImageWithRGBChannels = await image.getBase64Async(
Jimp.MIME_JPEG
)
return base64EncodedImageWithRGBChannels
}
async function convertBlackAndWhiteImageToRGBChannels2(base64EncodedImage) {
try {
// Load your base64 encoded image
const image = await Jimp.read(Buffer.from(base64EncodedImage, 'base64'))
// Convert your black and white image to RGB channels
image.color([{ apply: 'mix', params: ['#ffffff', 100] }])
// Get your base64 encoded black and white image with RGB channels
const base64EncodedImageWithRGBChannels = await image.getBase64Async(
Jimp.MIME_JPEG
)
return base64EncodedImageWithRGBChannels
} catch (e) {
console.warn(e)
}
}
async function convertBlackAndWhiteImageToRGBChannels3(base64EncodedImage) {
try {
// Load your base64 encoded image
const image = await Jimp.read(Buffer.from(base64EncodedImage, 'base64'))
// Convert your black and white image to RGB channels
// image.color([{ apply: 'mix', params: ['#ffffff', 100] }])
// Get your base64 encoded black and white image with RGB channels
const base64EncodedImageWithRGBChannels = await image.getBase64Async(
Jimp.MIME_PNG
)
return base64EncodedImageWithRGBChannels
} catch (e) {
console.warn(e)
}
}
async function snapShotLayer() {
//snapshot layer with no mask
let command = [
// Select All Layers current layer
{
_obj: 'selectAllLayers',
_target: [
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
],
},
// Duplicate current layer
// {"ID":[459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513],"_obj":"duplicate","_target":[{"_enum":"ordinal","_ref":"layer","_value":"targetEnum"}],"version":5},
{
// ID: ids,
_obj: 'duplicate',
_target: [
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
],
// version: 5
},
// Merge Layers
{ _obj: 'mergeLayersNew' },
// Make
{
_obj: 'make',
at: { _enum: 'channel', _ref: 'channel', _value: 'mask' },
new: { _class: 'channel' },
using: { _enum: 'userMaskEnabled', _value: 'revealSelection' },
},
// Set Selection
{
_obj: 'set',
_target: [{ _property: 'selection', _ref: 'channel' }],
to: { _enum: 'ordinal', _ref: 'channel', _value: 'targetEnum' },
},
//make a group
{
_obj: 'make',
_target: [
{
_ref: 'layerSection',
},
],
from: {
_ref: 'layer',
_enum: 'ordinal',
_value: 'targetEnum',
},
layerSectionStart: 512,
layerSectionEnd: 513,
name: 'Group 2',
_options: {
dialogOptions: 'dontDisplay',
},
},
{
_obj: 'mergeLayersNew',
_options: {
dialogOptions: 'dontDisplay',
},
},
]
const result = await batchPlay(command, {
synchronousExecution: true,
modalBehavior: 'execute',
})
return result
}
async function snapShotLayerExe() {
await executeAsModal(async () => {
//create a fill layer above the background layer, so that it's present in the snapshot
try {
const selectionInfo = await psapi.getSelectionInfoExe()
// const backgroundLayer = await app.activeDocument.backgroundLayer
await psapi.createSolidLayer(255, 255, 255)
const solid_layer = await app.activeDocument.activeLayers[0]
// await psapi.unSelectMarqueeExe()//unselect the
// await solid_layer.moveAbove(backgroundLayer)
// await snapShotLayer() //create a layer with only the opaque pixels
// await psapi.reSelectMarqueeExe(selectionInfo)
// await solid_layer.delete()
} catch (e) {
console.warn(e)
}
})
await executeAsModal(async () => {
//create a fill layer above the background layer, so that it's present in the snapshot
try {
const solid_layer = await app.activeDocument.activeLayers[0]
const backgroundLayer = await app.activeDocument.backgroundLayer
await solid_layer.moveAbove(backgroundLayer)
await psapi.unselectActiveLayersExe()
await snapShotLayer() //create a layer with only the opaque pixels
// await psapi.reSelectMarqueeExe(selectionInfo)
// await psapi.unSelectMarqueeExe()//unselect the
await solid_layer.delete()
} catch (e) {
console.warn(e)
}
})
}
class IO {
// constructor() {}
static async exportWebp(layer, export_width, export_height) {
await executeAsModal(async () => {
//we assume we have a valid layer rectangular image/layer, no transparency
const doc_entry = await getCurrentDocFolder() //get the main document folder before we switch doc
const layer_info = await layer_util.Layer.getLayerInfo(layer)
//*) create a new document
const new_doc = await IOHelper.createDocumentExe(
export_width,
export_height
)
const new_layer = await layer_util.Layer.duplicateToDoc(
layer,
new_doc
)
//*) resize the layer to the same dimension as the document
await layer_util.Layer.scaleTo(
new_layer,
new_doc.width,
new_doc.height
) //
await layer_util.Layer.moveTo(new_layer, 0, 0) //move to the top left corner
//
await IOHelper.saveAsWebpExe(doc_entry) //save current document as .webp file, save it into doc_entry folder
await new_doc.closeWithoutSaving()
})
}
static async exportPng() {}
static async exportDoc() {}
static async exportLayer() {}
static async base64PngToPngFile(
base64_png,
folder,
image_name = 'temp_base64Png.png'
) {
const arrayBuffer = _base64ToArrayBuffer(base64_png)
// const folder = await storage.localFileSystem.getTemporaryFolder()
const file = await folder.createFile(image_name, { overwrite: true })
await file.write(arrayBuffer, { format: storage.formats.binary })
return file
}
static async openImageFileAsDocument(file_entry) {
const new_doc = await app.open(file_entry)
return new_doc
}
static async base64PngToBase64Webp(base64_png) {
let base64_webp
try {
await executeAsModal(async () => {
try {
const main_doc_entry = await getCurrentDocFolder()
//save the base64_png to .png file
const temp_folder = await fs.getTemporaryFolder()
const png_file = await this.base64PngToPngFile(
base64_png,
temp_folder
)
//load the .png file as a layer in new document
const new_doc = await this.openImageFileAsDocument(png_file)
//save document as .webp
const [_, webp_file] = await IOHelper.saveAsWebpExe(
main_doc_entry
) //save current document as .webp file, save it into doc_entry folder
await new_doc.closeWithoutSaving()
//load/read the .webp file as an arraybuffer
const ArrayBufferWebp = await webp_file.read({
format: formats.binary,
})
//convert the arraybuffer to base64Webp string
base64_webp = _arrayBufferToBase64(ArrayBufferWebp)
} catch (e) {
console.warn(e)
}
})
return base64_webp
} catch (e) {
console.warn(e)
}
}
static async base64WebpFromFile(file_entry) {
//file_entry most be .webp
let webp_base64
try {
await executeAsModal(async () => {
const arrayBuffer = await file_entry.read({
format: formats.binary,
})
console.log('webp arrayBuffer:', arrayBuffer)
const base64_image = _arrayBufferToBase64(arrayBuffer) //convert the buffer to base64
console.log('base64_image:', base64_image)
webp_base64 = base64_image
})
return [webp_base64, webp_arrayBuffer]
} catch (e) {
console.warn(e)
}
}
static async base64ToLayer(
base64_png,
image_name = 'base64_to_layer.png',
to_x = 0,
to_y = 0,
width = 512,
height = 512,
format = 'png'
) {
let layer
if (format === 'png') {
layer = await IOBase64ToLayer.base64PngToLayer(
base64_png,
image_name
)
psapi.setVisibleExe(layer, true)
await layer_util.Layer.scaleTo(layer, width, height) //
await layer_util.Layer.moveTo(layer, to_x, to_y) //move to the top left corner
psapi.setVisibleExe(layer, true)
}
return layer
}
static async getSelectionFromCanvasAsBase64Silent(
selectionInfo,
b_resize = false,
resize_width = 0,
resize_height = 0
) {
//it will save the document then crop it so that only the selection area are left.
//return arrayBuffer or base64Png?
try {
let file
const folder = await fs.getTemporaryFolder()
await executeAsModal(
async () => {
const canvas_image_name = 'canvas_image.png'
file = await folder.createFile(canvas_image_name, {
overwrite: true,
})
const currentDocument = app.activeDocument
await currentDocument.saveAs.png(file, null, true)
//save file end
//read the saved image.png
},
{ commandName: 'readPng' }
)
const arrayBuffer = await file.read({
format: formats.binary,
})
// const selectionInfo = g_generation_session.selectionInfo
// const selectionInfo = await psapi.getSelectionInfoExe()
const cropped_base64_url = await IOHelper.cropPng(
arrayBuffer,
selectionInfo,
true,
resize_width,
resize_height
)
const cropped_base64 = general.base64UrlToBase64(cropped_base64_url)
// html_manip.setInitImageSrc(cropped_base64_url)
return cropped_base64
} catch (e) {
console.warn(e)
}
}
static async getSelectionFromCanvasAsBase64NonSilent(
layer,
image_name,
width,
height
) {
try {
const image_buffer = await psapi.newExportPng(
layer,
image_name,
width,
height
)
const base64_image = _arrayBufferToBase64(image_buffer) //convert the buffer to base64
//send the base64 to the server to save the file in the desired directory
// await sdapi.requestSavePng(base64_image, image_name)
// await saveFileInSubFolder(base64_image, document_name, image_name)
// debugger
const { requestSavePng } = require('../sdapi_py_re')
await requestSavePng(base64_image, image_name)
return base64_image
} catch (e) {
console.warn(e)
}
}
static async getSelectionFromCanvasAsBase64Interface(
width,
height,
layer,
selectionInfo,
resize = true,
use_silent_mode = true,
image_name = 'temp.png'
) {
let base64_image
if (use_silent_mode) {
base64_image = await this.getSelectionFromCanvasAsBase64Silent(
selectionInfo,
resize,
width,
height
)
} else {
base64_image = await this.getSelectionFromCanvasAsBase64NonSilent(
layer,
image_name,
width,
height
)
}
return base64_image
}
static async getSelectionFromCanvasAsBase64Interface_New(
width,
height,
selectionInfo,
resize = true,
image_name = 'temp.png'
) {
//use this version, it has less parameters
const use_silent_mode = html_manip.getUseSilentMode()
let layer = null
if (!use_silent_mode) {
await psapi.snapshot_layerExe()
const snapshotLayer = await app.activeDocument.activeLayers[0]
layer = snapshotLayer
}
let base64_image
if (use_silent_mode) {
base64_image = await this.getSelectionFromCanvasAsBase64Silent(
selectionInfo,
resize,
width,
height
)
} else {
base64_image = await this.getSelectionFromCanvasAsBase64NonSilent(
layer,
image_name,
width,
height
)
}
await layer_util.deleteLayers([layer]) //delete the snapshot layer if it exists
return base64_image
}
static async urlToLayer(image_url, image_file_name = 'image_from_url.png') {
try {
await psapi.unselectActiveLayersExe()
const temp_entry = await fs.getTemporaryFolder()
await downloadItExe(image_url, temp_entry, image_file_name)
} catch (e) {
console.warn('urlToLayer()', image_url, image_file_name, e)
}
}
}
class IOHelper {
static async saveAsWebp(doc_entry) {
//doc_entry must be in dataFolder or tempFolder
//save document as webp
const document_id = app.activeDocument.id
// doc_entry = await getCurrentDocFolder()
const file_entry = await doc_entry.createFile('temp.webp', {
overwrite: true,
})
const token = await fs.createSessionToken(file_entry)
const result = await batchPlay(
[
{
_obj: 'save',
as: {
_obj: 'WebPFormat',
compression: {
_enum: 'WebPCompression',
_value: 'compressionLossless',
},
includeXMPData: false,
includeEXIFData: false,
includePsExtras: false,
},
in: {
_path: token,
_kind: 'local',
},
documentID: 59,
copy: true,
lowerCase: true,
saveStage: {
_enum: 'saveStageType',
_value: 'saveBegin',
},
_options: {
dialogOptions: 'dontDisplay',
},
},
],
{
synchronousExecution: true,
modalBehavior: 'execute',
}
)
return [result, file_entry]
}
static async saveAsWebpExe(doc_entry) {
let result
let file_entry
await executeAsModal(async () => {
;[result, file_entry] = await this.saveAsWebp(doc_entry)
})
return [result, file_entry]
}
static async createDocumentExe(width, height) {
let new_doc
try {
await executeAsModal(async () => {
new_doc = await app.documents.add({
width: width,
height: height,
resolution: await app.activeDocument.resolution,
mode: 'RGBColorMode',
fill: 'transparent',
})
})
} catch (e) {
console.warn(e)
}
return new_doc
}
static async cropPng(
arrayBuffer,
selectionInfo,
b_resize = false,
resize_width = 0,
resize_height = 0
) {
//crop png from array buffer
//have the option to resize the after cropping
const crop_x = selectionInfo.left
const crop_y = selectionInfo.top
const crop_w = selectionInfo.width
const crop_h = selectionInfo.height
const base64_url_result = await Jimp.read(arrayBuffer)
.then(async (img) => {
let cropped_img = await img.crop(crop_x, crop_y, crop_w, crop_h)
let resized_img
if (b_resize) {
resized_img = await cropped_img.resize(
resize_width,
resize_height
)
} else {
resized_img = cropped_img
}
const base64_url = await resized_img.getBase64Async(
Jimp.MIME_PNG
)
// console.log('jimp: base64_url: ', base64_url)
// document.getElementById("image").setAttribute("src", data);
return base64_url
})
.catch((error) => {
console.error(error)
})
return base64_url_result
}
}
class IOBase64ToLayer {
static {}
static async base64PngToLayer(base64_png, image_name) {
//unselect all layers so that the imported layer get place at the top of the document
await psapi.unselectActiveLayersExe()
const imported_layer = await base64ToFile(base64_png, image_name) //silent import into the document
return imported_layer
}
}
class IOFolder {
static {}
static async createSettingsFolder() {
//create a folder named "Settings" in the DataFolder
let settings_entry
await executeAsModal(async () => {
settings_entry = await this.createFolderSafe('Settings')
})
return settings_entry
}
static async findOrCreateFolderExe(folder_name) {
//create a folder named "Settings" in the DataFolder
let folder_entry
await executeAsModal(async () => {
folder_entry = await this.createFolderSafe(folder_name)
})
return folder_entry
}
static async doesFolderExist(folder_name) {
//check if folder exist. return true if it does. false if it doesn't.
const data_folder = await fs.getDataFolder()
let b_exist = false
let folder
try {
folder = await data_folder.getEntry(folder_name)
b_exist = true
} catch (e) {
// console.warn(e)
b_exist = false
}
return b_exist
}
static async createFolderSafe(folder_name) {
//will always return a folder. it will create the folder if it doesn't exist.
try {
// const uuid = await getUniqueDocumentId()
const data_folder = await fs.getDataFolder()
let folder_entry
try {
folder_entry = await data_folder.getEntry(folder_name)
} catch (e) {
console.warn(e)
//create document folder
folder_entry = await data_folder.createFolder(folder_name)
}
return folder_entry
} catch (e) {
console.warn(e)
}
}
static async getDocumentFolderNativePath() {
try {
const uuid = await getUniqueDocumentId()
let doc_folder = await this.getDocFolder(uuid)
const path = general.fixNativePath(doc_folder.nativePath)
return path
} catch (e) {
console.warn(e)
}
return ''
}
static async getDocFolder(doc_uuid) {
//will create folder if does not exist. always return a folder entry
const doc_entry = await getDocFolder(doc_uuid)
return doc_entry
}
static async getSettingsFolder() {
//will create folder if does not exist. always return a folder entry
const settings_entry = await this.createSettingsFolder()
return settings_entry
}
static async getPresetFolder() {
//will create folder if does not exist. always return a folder entry
const preset_entry = await this.findOrCreateFolderExe('Preset')
return preset_entry
}
static async getCustomPresetFolder(
custom_preset_folder_name = 'custom_preset'
) {
//will create folder if does not exist. always return a folder entry
const preset_entry = await this.findOrCreateFolderExe(
custom_preset_folder_name
)
return preset_entry
}
static async createFolderIfDoesNotExist(folder_name) {
try {
await executeAsModal(async () => {
try {
const folder = await fs.getDataFolder()
const sub_folder = await folder.createFolder(folder_name)
} catch (e) {
console.warn(e)
}
})
} catch (e) {
console.warn(e)
}
}
}
class IOLog {
static {}
static async saveLogToFile(json, file_name) {
try {
const plugin_folder = await fs.getDataFolder()
const file = await plugin_folder.createFile(file_name, {
type: storage.types.file,
overwrite: true,
})
const JSONInPrettyFormat = JSON.stringify(json, undefined, 4)
await file.write(JSONInPrettyFormat, {
format: storage.formats.utf8,
append: true,
})
} catch (e) {
console.warn(e)
}
}
}
class IOJson {
static {}
static async saveJsonToFile(json, folder_entry, file_name) {
try {
const file = await folder_entry.createFile(file_name, {
type: storage.types.file,
overwrite: true,
})
const JSONInPrettyFormat = JSON.stringify(json, undefined, 4)
await file.write(JSONInPrettyFormat, {
format: storage.formats.utf8,
append: false,
})
} catch (e) {
console.warn(e)
}
}
static async saveJsonToFileExe(json, folder_entry, file_name) {
await executeAsModal(async () => {
await this.saveJsonToFile(json, folder_entry, file_name)
})
}
static async loadJsonFromFile(folder_entry, file_name) {
const json_file_name = file_name
try {
const json_entry = await folder_entry.getEntry(json_file_name)
if (json_entry) {
const json = JSON.parse(
await json_entry.read({
format: storage.formats.utf8,
})
)
return json
}
} catch (e) {
console.warn(e)
}
}
static async saveSettingsToFile(settings_json, settings_file_name) {
await executeAsModal(async () => {
// debugger
const folder_entry = await IOFolder.getSettingsFolder('Settings')
await this.saveJsonToFile(
settings_json,
folder_entry,
settings_file_name
)
})
}
static async loadSettingsFromFile(settings_file_name) {
const folder_entry = await IOFolder.getSettingsFolder('Settings')
const settings_json = await this.loadJsonFromFile(
folder_entry,
settings_file_name
)
return settings_json
}
static async saveHordeSettingsToFile(settings_json) {
const settings_file_name = 'horde_settings.json'
await this.saveSettingsToFile(settings_json, settings_file_name)
}
static async loadHordeSettingsFromFile() {
const settings_file_name = 'horde_settings.json'
const settings_json = await this.loadSettingsFromFile(
settings_file_name
)
return settings_json
}
static async getJsonEntries(doc_entry) {
let entries = await doc_entry.getEntries()
const json_entries = entries.filter(
(e) => e.isFile && e.name.toLowerCase().includes('.json') // must be a file and has the of the type .json
)
console.log('json_entries: ', json_entries)
// .forEach((e) => console.log(e.name))
return json_entries
}
static async deleteFile(doc_entry, file_name) {
try {
const file_entry = await doc_entry.getEntry(file_name)
file_entry.delete()
} catch (e) {}
}
}
module.exports = {
IO,
snapShotLayerExe,
IOHelper,
IOJson,
IOFolder,
IOLog,
convertBlackAndWhiteImageToRGBChannels,
convertBlackAndWhiteImageToRGBChannels2,
convertBlackAndWhiteImageToRGBChannels3,
isBlackAndWhiteImage,
}