Auto-Photoshop-StableDiffus.../utility/io.js

433 lines
14 KiB
JavaScript

const batchPlay = require('photoshop').action.batchPlay
const psapi = require('../psapi')
const layer_util = require('../utility/layer')
const general = require('./general')
const Jimp = require('../jimp/browser/lib/jimp')
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 getSelectionFromCanvasAsBase64(
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)
}
}
}
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
}
}
module.exports = {
IO,
snapShotLayerExe,
IOHelper,
}