1201 lines
36 KiB
JavaScript
1201 lines
36 KiB
JavaScript
const psapi = require('./psapi')
|
|
|
|
const html_manip = require('./utility/html_manip')
|
|
function finalWidthHeight(
|
|
selectionWidth,
|
|
selectionHeight,
|
|
minWidth,
|
|
minHeight
|
|
) {
|
|
// const minWidth = 512
|
|
// const minHeight = 512
|
|
|
|
// const selectionWidth = 256
|
|
// const selectionHeight = 1000
|
|
|
|
let finalWidth = 0
|
|
let finalHeight = 0
|
|
|
|
if (selectionWidth <= selectionHeight) {
|
|
//do operation on the smaller dimension
|
|
const scaleRatio = selectionWidth / minWidth
|
|
|
|
finalWidth = minWidth
|
|
finalHeight = selectionHeight / scaleRatio
|
|
} else {
|
|
const scaleRatio = selectionHeight / minHeight
|
|
|
|
finalHeight = minHeight
|
|
finalWidth = selectionWidth / scaleRatio
|
|
}
|
|
return [finalWidth, finalHeight]
|
|
}
|
|
|
|
async function selectionToFinalWidthHeight(
|
|
selectionInfo,
|
|
minWidth = 512,
|
|
minHeight = 512
|
|
) {
|
|
// const { getSelectionInfoExe } = require('./psapi')
|
|
try {
|
|
// const selectionInfo = await psapi.getSelectionInfoExe()
|
|
const [finalWidth, finalHeight] = finalWidthHeight(
|
|
selectionInfo.width,
|
|
selectionInfo.height,
|
|
minWidth,
|
|
minHeight
|
|
)
|
|
|
|
return [
|
|
parseInt(finalWidth),
|
|
parseInt(finalHeight),
|
|
selectionInfo.width,
|
|
selectionInfo.height,
|
|
]
|
|
} catch (e) {
|
|
console.warn('you need a rectangular selection', e)
|
|
}
|
|
}
|
|
|
|
async function selectBoundingBox() {
|
|
let l = await app.activeDocument.activeLayers[0]
|
|
let bounds = await l.boundsNoEffects
|
|
let selectionInfo = convertSelectionObjectToSelectionInfo(bounds)
|
|
await psapi.reSelectMarqueeExe(selectionInfo)
|
|
return selectionInfo
|
|
}
|
|
function convertSelectionObjectToSelectionInfo(selection_obj) {
|
|
let selection_info = {
|
|
left: selection_obj._left,
|
|
right: selection_obj._right,
|
|
bottom: selection_obj._bottom,
|
|
top: selection_obj._top,
|
|
height: selection_obj._bottom - selection_obj._top,
|
|
width: selection_obj._right - selection_obj._left,
|
|
}
|
|
return selection_info
|
|
}
|
|
|
|
const SelectionInfoDesc = () => ({
|
|
_obj: 'get',
|
|
_target: [
|
|
{
|
|
_property: 'selection',
|
|
},
|
|
{
|
|
_ref: 'document',
|
|
_id: app.activeDocument._id,
|
|
},
|
|
],
|
|
_options: {
|
|
dialogOptions: 'dontDisplay',
|
|
},
|
|
})
|
|
|
|
async function createChannelIfNotExists(channelName) {
|
|
// const photoshop = require('photoshop')
|
|
// const app = photoshop.app
|
|
// const batchPlay = photoshop.action.batchPlay
|
|
|
|
// // Check if the channel exists
|
|
// let channelExists = false
|
|
// for (const channel of app.activeDocument.channels) {
|
|
// if (channel.name === channelName) {
|
|
// channelExists = true
|
|
// break
|
|
// }
|
|
// }
|
|
|
|
// // Create the channel if it doesn't exist
|
|
// if (!channelExists) {
|
|
// await batchPlay(
|
|
// [
|
|
// {
|
|
// _obj: 'make',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'channel',
|
|
// },
|
|
// ],
|
|
// using: {
|
|
// _obj: 'channel',
|
|
// name: channelName,
|
|
// },
|
|
// },
|
|
// ],
|
|
// {}
|
|
// )
|
|
// }
|
|
if (!app.activeDocument.channels.getByName(channelName)) {
|
|
}
|
|
}
|
|
|
|
const deleteChannel = (channel_name = 'mask') =>
|
|
app.activeDocument.channels.getByName(channel_name)
|
|
? [
|
|
{
|
|
_obj: 'delete',
|
|
_target: { _ref: 'channel', _name: channel_name },
|
|
options: {
|
|
failOnMissingProperty: false,
|
|
failOnMissingElement: false,
|
|
},
|
|
},
|
|
]
|
|
: []
|
|
const makeMaskChannel = (channel_name = 'mask') => ({
|
|
// _obj: 'set',
|
|
// _target: { _ref: 'channel', _property: 'selection' },
|
|
// to: { _ref: 'channel', _name: channel_name },
|
|
|
|
_obj: 'duplicate',
|
|
_target: [
|
|
{
|
|
_ref: 'channel',
|
|
_property: 'selection',
|
|
},
|
|
],
|
|
name: channel_name,
|
|
_isCommand: true,
|
|
options: { failOnMissingProperty: false, failOnMissingElement: false },
|
|
})
|
|
async function makeMaskChannelExe(channel_name = 'mask') {
|
|
await executeAsModal(async () => {
|
|
// const channel = app.activeDocument.channels.getByName(channel_name)
|
|
// channel?.remove()
|
|
const result = await batchPlay(
|
|
[...deleteChannel(channel_name), makeMaskChannel(channel_name)],
|
|
// [
|
|
// {
|
|
// _obj: 'duplicate',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'channel',
|
|
// _property: 'selection',
|
|
// },
|
|
// ],
|
|
// name: channel_name,
|
|
// _isCommand: true,
|
|
// },
|
|
|
|
// {
|
|
// _obj: 'make',
|
|
// new: { _class: 'channel' },
|
|
// at: { _ref: 'channel', _enum: 'channel', _value: 'mask' },
|
|
// using: {
|
|
// _enum: 'userMaskEnabled',
|
|
// _value: 'revealSelection',
|
|
// },
|
|
// },
|
|
// ],
|
|
{
|
|
synchronousExecution: true,
|
|
modalBehavior: 'execute',
|
|
}
|
|
)
|
|
console.log('result: ', result)
|
|
})
|
|
}
|
|
async function multiGetExe() {
|
|
desc = {
|
|
_obj: 'multiGet',
|
|
_target: { _ref: 'layer', _enum: 'ordinal', _value: 'targetEnum' },
|
|
extendedReference: [['layerID', 'itemIndex', 'count']],
|
|
options: { failOnMissingProperty: false, failOnMissingElement: false },
|
|
}
|
|
|
|
try {
|
|
const result = await batchPlay([desc], {
|
|
modalBehavior: 'execute',
|
|
synchronousExecution: true,
|
|
})
|
|
console.log('multiGetExe result: ', result)
|
|
// await executeAsModal(async () => {})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
async function applyMaskChannelExe(channel_name = 'mask') {
|
|
await executeAsModal(async () => {
|
|
const result = await batchPlay(
|
|
[
|
|
// SelectionInfoDesc(),
|
|
// makeMaskChannel(),
|
|
|
|
{
|
|
_obj: 'set',
|
|
_target: { _ref: 'channel', _property: 'selection' },
|
|
to: { _ref: 'channel', _name: channel_name },
|
|
},
|
|
{
|
|
_obj: 'make',
|
|
new: { _class: 'channel' },
|
|
at: { _ref: 'channel', _enum: 'channel', _value: 'mask' },
|
|
using: {
|
|
_enum: 'userMaskEnabled',
|
|
_value: 'revealSelection',
|
|
_name: channel_name,
|
|
},
|
|
},
|
|
],
|
|
{
|
|
synchronousExecution: true,
|
|
modalBehavior: 'execute',
|
|
}
|
|
)
|
|
console.log('result: ', result)
|
|
})
|
|
}
|
|
|
|
async function selectionToChannel(channel_name) {
|
|
const channelToSelection = {
|
|
_obj: 'set',
|
|
_target: { _ref: 'channel', _property: 'selection' },
|
|
to: { _ref: 'channel', _name: channel_name },
|
|
}
|
|
let result
|
|
try {
|
|
await executeAsModal(async () => {
|
|
result = await batchPlay(
|
|
[
|
|
...deleteChannel(channel_name),
|
|
makeMaskChannel(channel_name),
|
|
channelToSelection,
|
|
],
|
|
{ modalBehavior: 'execute', synchronousExecution: true }
|
|
)
|
|
})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
return result
|
|
}
|
|
async function createLayerFromMaskChannel(channel_name = 'mask') {
|
|
await executeAsModal(async () => {
|
|
const result = await batchPlay(
|
|
[
|
|
// SelectionInfoDesc(),
|
|
// makeMaskChannel(),
|
|
// {
|
|
// _obj: 'set',
|
|
// _target: { _ref: 'channel', _property: 'selection' },
|
|
// to: { _ref: 'channel', _name: channel_name },
|
|
// },
|
|
// {
|
|
// _obj: 'make',
|
|
// new: { _class: 'channel' },
|
|
// at: { _ref: 'channel', _enum: 'channel', _value: 'mask' },
|
|
// using: {
|
|
// _enum: 'userMaskEnabled',
|
|
// _value: 'revealSelection',
|
|
// _name: channel_name,
|
|
// },
|
|
// },
|
|
{
|
|
_obj: 'set',
|
|
_target: { _ref: 'layer' },
|
|
to: { _ref: 'channel', _name: channel_name },
|
|
},
|
|
],
|
|
{
|
|
synchronousExecution: true,
|
|
modalBehavior: 'execute',
|
|
}
|
|
)
|
|
console.log('result: ', result)
|
|
})
|
|
}
|
|
|
|
async function channelToSelectionExe(channel_name = 'mask') {
|
|
const channelToSelection = {
|
|
_obj: 'set',
|
|
_target: { _ref: 'channel', _property: 'selection' },
|
|
to: { _ref: 'channel', _name: channel_name },
|
|
}
|
|
try {
|
|
await executeAsModal(async () => {
|
|
const result = await batchPlay([channelToSelection], {
|
|
modalBehavior: 'execute',
|
|
synchronousExecution: true,
|
|
})
|
|
})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
|
|
function keepRatio(selectionInfo, offset) {
|
|
// Calculate the current width and height
|
|
let width = selectionInfo.right - selectionInfo.left
|
|
let height = selectionInfo.bottom - selectionInfo.top
|
|
|
|
// Calculate the new coordinates with the offset
|
|
selectionInfo.right += offset
|
|
selectionInfo.left -= offset
|
|
selectionInfo.bottom += offset
|
|
selectionInfo.top -= offset
|
|
|
|
// Update width and height
|
|
selectionInfo.width = width + 2 * offset
|
|
selectionInfo.height = height + 2 * offset
|
|
|
|
return selectionInfo
|
|
}
|
|
|
|
function makeSquare(selectionInfo, offset) {
|
|
// Calculate the current width and height
|
|
let width = selectionInfo.right - selectionInfo.left
|
|
let height = selectionInfo.bottom - selectionInfo.top
|
|
|
|
// Determine the maximum dimension
|
|
let maxDim = Math.max(width, height)
|
|
|
|
// Calculate the difference for width and height
|
|
let diffWidth = maxDim - width
|
|
let diffHeight = maxDim - height
|
|
|
|
// Add half the difference to 'right' and 'bottom', subtract the rest from 'left' and 'top'
|
|
selectionInfo.right += Math.floor(diffWidth / 2) + offset
|
|
selectionInfo.left -= diffWidth - Math.floor(diffWidth / 2) + offset
|
|
selectionInfo.bottom += Math.floor(diffHeight / 2) + offset
|
|
selectionInfo.top -= diffHeight - Math.floor(diffHeight / 2) + offset
|
|
|
|
// Update width and height
|
|
selectionInfo.width = maxDim + 2 * offset
|
|
selectionInfo.height = maxDim + 2 * offset
|
|
|
|
return selectionInfo
|
|
}
|
|
|
|
async function inpaintLassoInitImageAndMask(
|
|
channel_name = 'mask',
|
|
offset = 0,
|
|
make_square = true
|
|
) {
|
|
const selectionInfo = await psapi.getSelectionInfoExe()
|
|
//convert the selection box into square box so that you have best output results
|
|
|
|
const newSelection = make_square
|
|
? makeSquare(selectionInfo, offset)
|
|
: keepRatio(selectionInfo, offset)
|
|
|
|
//correct width and height sliders, since this is lasso mode.
|
|
await calcWidthHeightFromSelection(newSelection)
|
|
|
|
async function getImageFromCanvas() {
|
|
const width = html_manip.getWidth()
|
|
const height = html_manip.getHeight()
|
|
|
|
const base64 = await io.IO.getSelectionFromCanvasAsBase64Interface_New(
|
|
width,
|
|
height,
|
|
newSelection,
|
|
true
|
|
)
|
|
return base64
|
|
}
|
|
const channelToSelection = {
|
|
_obj: 'set',
|
|
_target: { _ref: 'channel', _property: 'selection' },
|
|
to: { _ref: 'channel', _name: channel_name },
|
|
}
|
|
// await executeAsModal(async () => {
|
|
// const result = await batchPlay(
|
|
// [
|
|
// ...deleteChannel(channel_name),
|
|
// makeMaskChannel(channel_name),
|
|
// channelToSelection,
|
|
// ],
|
|
// { modalBehavior: 'execute', synchronousExecution: true }
|
|
// )
|
|
// const selection_info = await psapi.getSelectionInfoExe()
|
|
// })
|
|
await selectionToChannel(channel_name) //lasso selection to channel called 'mask'
|
|
|
|
const init_base64 = await getImageFromCanvas()
|
|
|
|
html_manip.setInitImageSrc(general.base64ToBase64Url(init_base64))
|
|
let mask_base64
|
|
await executeAsModal(async () => {
|
|
const result = await batchPlay([channelToSelection], {
|
|
modalBehavior: 'execute',
|
|
synchronousExecution: true,
|
|
})
|
|
// const selection_info = await psapi.getSelectionInfoExe()
|
|
mask_base64 = await fillSelectionWhiteOutsideBlack(newSelection)
|
|
})
|
|
|
|
//save laso selection to channel
|
|
//get laso selection
|
|
//make rect selection
|
|
//base64 from selection
|
|
//and display it in init image html element
|
|
//get laso selection:
|
|
//make mask layer
|
|
//get rectangular selection
|
|
//get base64 from selection
|
|
//display it in mask image html element
|
|
// let jimp_mask = await Jimp.read(Buffer.from(mask_base64, 'base64'))
|
|
// html_manip.setInitImageMaskSrc(
|
|
// await jimp_mask.getBase64Async(Jimp.MIME_PNG)
|
|
// )
|
|
html_manip.setInitImageMaskSrc(general.base64ToBase64Url(mask_base64))
|
|
|
|
return [init_base64, mask_base64]
|
|
// //return
|
|
// //init image
|
|
//mask
|
|
}
|
|
|
|
async function fillSelectionWhiteOutsideBlack(selectionInfo) {
|
|
// Create a new layer
|
|
const layer_name = 'mask'
|
|
const getSelectionDesc = () => ({
|
|
_obj: 'get',
|
|
_target: [
|
|
{
|
|
_property: 'selection',
|
|
},
|
|
{
|
|
_ref: 'document',
|
|
_id: app.activeDocument._id,
|
|
},
|
|
],
|
|
_options: {
|
|
dialogOptions: 'dontDisplay',
|
|
},
|
|
})
|
|
const invertSelection = () => ({
|
|
_obj: 'inverse',
|
|
_isCommand: true,
|
|
})
|
|
await psapi.unselectActiveLayers()
|
|
const mask_layer = await layer_util.createNewLayerExe('mask')
|
|
await moveToTopLayerStackExe()
|
|
await batchPlay(
|
|
[
|
|
getSelectionDesc(),
|
|
|
|
{
|
|
_obj: 'fill',
|
|
using: {
|
|
_enum: 'fillContents',
|
|
_value: 'white',
|
|
},
|
|
opacity: {
|
|
_unit: 'percentUnit',
|
|
_value: 100,
|
|
},
|
|
mode: {
|
|
_enum: 'blendMode',
|
|
_value: 'normal',
|
|
},
|
|
},
|
|
// {
|
|
// _obj: 'select',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'channel',
|
|
// _property: 'selection',
|
|
// },
|
|
// ],
|
|
// },
|
|
invertSelection(),
|
|
{
|
|
_obj: 'fill',
|
|
using: {
|
|
_enum: 'fillContents',
|
|
_value: 'black',
|
|
},
|
|
opacity: {
|
|
_unit: 'percentUnit',
|
|
_value: 100,
|
|
},
|
|
mode: {
|
|
_enum: 'blendMode',
|
|
_value: 'normal',
|
|
},
|
|
},
|
|
|
|
// {
|
|
// _obj: 'invert',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'channel',
|
|
// _property: 'selection',
|
|
// },
|
|
// ],
|
|
// },
|
|
|
|
//make new layer
|
|
// {
|
|
// _obj: 'make',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'layer',
|
|
// },
|
|
// ],
|
|
// using: {
|
|
// _obj: 'layer',
|
|
// name: 'Fill Layer',
|
|
// },
|
|
// },
|
|
|
|
{
|
|
_obj: 'set',
|
|
_target: [
|
|
{ _ref: 'layer', _enum: 'ordinal', _value: 'targetEnum' },
|
|
],
|
|
to: { _obj: 'layer', name: layer_name },
|
|
_options: { dialogOptions: 'dontDisplay' },
|
|
_isCommand: true,
|
|
},
|
|
// getSelectionDesc(),
|
|
//undo the first inversion of the selection
|
|
invertSelection(),
|
|
],
|
|
{ modalBehavior: 'execute' }
|
|
)
|
|
|
|
await psapi.reSelectMarqueeExe(selectionInfo)
|
|
const width = html_manip.getWidth()
|
|
const height = html_manip.getHeight()
|
|
|
|
//convert the selection area on the canvas to base64 image
|
|
const base64 = await io.IO.getSelectionFromCanvasAsBase64Interface_New(
|
|
width,
|
|
height,
|
|
selectionInfo,
|
|
true,
|
|
layer_name + '.png'
|
|
)
|
|
|
|
//import the base64 image into the canvas as a new layer
|
|
// await io.IO.base64ToLayer(
|
|
// base64,
|
|
// 'base64_to_layer_temp.png',
|
|
// rect_selection_info.left,
|
|
// rect_selection_info.top,
|
|
// rect_selection_info.width,
|
|
// rect_selection_info.height
|
|
// )
|
|
|
|
await psapi.cleanLayers([mask_layer])
|
|
return base64
|
|
}
|
|
|
|
async function inpaintLasoInitImage() {
|
|
// Create a new layer
|
|
const layer_name = 'inpaint_laso_init_image'
|
|
const getSelectionDesc = () => ({
|
|
_obj: 'get',
|
|
_target: [
|
|
{
|
|
_property: 'selection',
|
|
},
|
|
{
|
|
_ref: 'document',
|
|
_id: app.activeDocument._id,
|
|
},
|
|
],
|
|
_options: {
|
|
dialogOptions: 'dontDisplay',
|
|
},
|
|
})
|
|
const invertSelection = () => ({
|
|
_obj: 'inverse',
|
|
_isCommand: true,
|
|
})
|
|
await batchPlay(
|
|
[
|
|
getSelectionDesc(),
|
|
|
|
{
|
|
_obj: 'fill',
|
|
using: {
|
|
_enum: 'fillContents',
|
|
_value: 'white',
|
|
},
|
|
opacity: {
|
|
_unit: 'percentUnit',
|
|
_value: 100,
|
|
},
|
|
mode: {
|
|
_enum: 'blendMode',
|
|
_value: 'normal',
|
|
},
|
|
},
|
|
// {
|
|
// _obj: 'select',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'channel',
|
|
// _property: 'selection',
|
|
// },
|
|
// ],
|
|
// },
|
|
invertSelection(),
|
|
{
|
|
_obj: 'fill',
|
|
using: {
|
|
_enum: 'fillContents',
|
|
_value: 'black',
|
|
},
|
|
opacity: {
|
|
_unit: 'percentUnit',
|
|
_value: 100,
|
|
},
|
|
mode: {
|
|
_enum: 'blendMode',
|
|
_value: 'normal',
|
|
},
|
|
},
|
|
|
|
// {
|
|
// _obj: 'invert',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'channel',
|
|
// _property: 'selection',
|
|
// },
|
|
// ],
|
|
// },
|
|
|
|
//make new layer
|
|
// {
|
|
// _obj: 'make',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'layer',
|
|
// },
|
|
// ],
|
|
// using: {
|
|
// _obj: 'layer',
|
|
// name: 'Fill Layer',
|
|
// },
|
|
// },
|
|
|
|
{
|
|
_obj: 'set',
|
|
_target: [
|
|
{ _ref: 'layer', _enum: 'ordinal', _value: 'targetEnum' },
|
|
],
|
|
to: { _obj: 'layer', name: layer_name },
|
|
_options: { dialogOptions: 'dontDisplay' },
|
|
_isCommand: true,
|
|
},
|
|
// getSelectionDesc(),
|
|
//undo the first inversion of the selection
|
|
invertSelection(),
|
|
],
|
|
{ modalBehavior: 'execute' }
|
|
)
|
|
|
|
//get the rectangular bounding box selection
|
|
|
|
const rect_selection_info = await psapi.getSelectionInfoExe()
|
|
await psapi.reSelectMarqueeExe(rect_selection_info)
|
|
const width = html_manip.getWidth()
|
|
const height = html_manip.getHeight()
|
|
|
|
//convert the selection area on the canvas to base64 image
|
|
const base64 = await io.IO.getSelectionFromCanvasAsBase64Interface_New(
|
|
width,
|
|
height,
|
|
rect_selection_info,
|
|
true,
|
|
layer_name + '.png'
|
|
)
|
|
|
|
//import the base64 image into the canvas as a new layer
|
|
await io.IO.base64ToLayer(
|
|
base64,
|
|
'base64_to_layer_temp.png',
|
|
rect_selection_info.left,
|
|
rect_selection_info.top,
|
|
rect_selection_info.width,
|
|
rect_selection_info.height
|
|
)
|
|
// Fill the current selection with white
|
|
// await batchPlay(
|
|
// [
|
|
// {
|
|
// _obj: 'fill',
|
|
// using: {
|
|
// _enum: 'fillContents',
|
|
// _value: 'white',
|
|
// },
|
|
// opacity: {
|
|
// _unit: 'percentUnit',
|
|
// _value: 100,
|
|
// },
|
|
// mode: {
|
|
// _enum: 'blendMode',
|
|
// _value: 'normal',
|
|
// },
|
|
// },
|
|
// ],
|
|
// { modalBehavior: 'execute' }
|
|
// )
|
|
|
|
// // Invert the selection
|
|
// await batchPlay(
|
|
// [
|
|
// {
|
|
// _obj: 'invert',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'channel',
|
|
// _property: 'selection',
|
|
// },
|
|
// ],
|
|
// },
|
|
// ],
|
|
// { modalBehavior: 'execute' }
|
|
// )
|
|
|
|
// // Fill the inverted selection with black
|
|
// await batchPlay(
|
|
// [
|
|
// {
|
|
// _obj: 'fill',
|
|
// using: {
|
|
// _enum: 'fillContents',
|
|
// _value: 'black',
|
|
// },
|
|
// opacity: {
|
|
// _unit: 'percentUnit',
|
|
// _value: 100,
|
|
// },
|
|
// mode: {
|
|
// _enum: 'blendMode',
|
|
// _value: 'normal',
|
|
// },
|
|
// },
|
|
// ],
|
|
// { modalBehavior: 'execute' }
|
|
// )
|
|
}
|
|
|
|
class Selection {
|
|
static async getSelectionInfoExe() {
|
|
//return a selectionInfo object or undefined
|
|
try {
|
|
const selection = await executeAsModal(async () => {
|
|
const result = await batchPlay([SelectionInfoDesc()], {
|
|
synchronousExecution: true,
|
|
modalBehavior: 'execute',
|
|
})
|
|
|
|
return result[0]?.selection
|
|
})
|
|
|
|
if (this.isSelectionValid(selection)) {
|
|
let selection_info = {
|
|
left: selection.left._value,
|
|
right: selection.right._value,
|
|
bottom: selection.bottom._value,
|
|
top: selection.top._value,
|
|
height: selection.bottom._value - selection.top._value,
|
|
width: selection.right._value - selection.left._value,
|
|
}
|
|
// console.dir({selection_info})
|
|
return selection_info
|
|
}
|
|
} catch (e) {
|
|
console.warn('selection info error', e)
|
|
}
|
|
}
|
|
|
|
static isSelectionValid(selection) {
|
|
console.warn(
|
|
'isSelectionValid is deprecated use selection.isSelectionValid instead'
|
|
)
|
|
if (
|
|
selection && // check if the selection is defined
|
|
selection.hasOwnProperty('left') &&
|
|
selection.hasOwnProperty('right') &&
|
|
selection.hasOwnProperty('top') &&
|
|
selection.hasOwnProperty('bottom')
|
|
) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
static reselectArea(selection_info) {}
|
|
static isSameSelection(selection_info_1, selection_info_2) {}
|
|
static async getImageToSelectionDifference() {
|
|
// const selectionInfo = await psapi.getSelectionInfoExe()
|
|
// const width = html_manip.getWidth()
|
|
// const height = html_manip.getHeight()
|
|
|
|
const selectionInfo = session_store.data.current_selection_info
|
|
const width = sd_tab_store.data.width
|
|
const height = sd_tab_store.data.height
|
|
let ratio =
|
|
(width * height) / (selectionInfo.width * selectionInfo.height)
|
|
|
|
return ratio
|
|
}
|
|
static {}
|
|
}
|
|
|
|
async function moveToTopLayerStackExe() {
|
|
const moveToTop = {
|
|
_obj: 'move',
|
|
_target: { _ref: 'layer', _enum: 'ordinal', _value: 'targetEnum' },
|
|
to: { _ref: 'layer', _enum: 'ordinal', _value: 'front' },
|
|
// _options: { dialogOptions: 'dontDisplay' },
|
|
options: { failOnMissingProperty: false, failOnMissingElement: false },
|
|
}
|
|
try {
|
|
await executeAsModal(async () => {
|
|
const layer = app.activeDocument.activeLayers[0]
|
|
|
|
while (layer.parent) {
|
|
console.log(layer.parent)
|
|
const result = await batchPlay([moveToTop], {
|
|
modalBehavior: 'execute',
|
|
synchronousExecution: true,
|
|
})
|
|
}
|
|
})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
async function colorRange() {
|
|
// const select_current_layer_cmd = {
|
|
// _obj: 'set',
|
|
// _target: [
|
|
// {
|
|
// _ref: 'channel',
|
|
// _property: 'selection',
|
|
// },
|
|
// ],
|
|
// to: {
|
|
// _ref: 'channel',
|
|
// _enum: 'channel',
|
|
// _value: 'transparencyEnum',
|
|
// },
|
|
// _isCommand: true,
|
|
// }
|
|
const cmd = {
|
|
_obj: 'colorRange',
|
|
fuzziness: 0,
|
|
minimum: {
|
|
_obj: 'labColor',
|
|
luminance: 100,
|
|
a: 0,
|
|
b: 0,
|
|
},
|
|
maximum: {
|
|
_obj: 'labColor',
|
|
luminance: 100,
|
|
a: 0,
|
|
b: 0,
|
|
},
|
|
colorModel: 0,
|
|
_isCommand: true,
|
|
}
|
|
const result = await batchPlay([cmd], {
|
|
modalBehavior: 'execute',
|
|
synchronousExecution: true,
|
|
})
|
|
return result
|
|
}
|
|
|
|
async function colorRangeExe() {
|
|
let result
|
|
try {
|
|
await executeAsModal(
|
|
async () => {
|
|
result = await colorRange()
|
|
},
|
|
{ commandName: 'Convert Black and White Layer to mask selection' }
|
|
)
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
return result
|
|
}
|
|
|
|
async function base64ToLassoSelection(base64, selection_info) {
|
|
//place the mask on the canvas
|
|
const mask_layer = await io.IO.base64ToLayer(
|
|
base64,
|
|
'monochrome_mask.png',
|
|
selection_info.left,
|
|
selection_info.top,
|
|
selection_info.width,
|
|
selection_info.height
|
|
)
|
|
//reselect the selection area
|
|
await psapi.reSelectMarqueeExe(selection_info)
|
|
//reselect the layer
|
|
await psapi.selectLayersExe([mask_layer])
|
|
await executeAsModal(async () => {
|
|
await layer_util.toggleActiveLayer() // undo the toggling operation, active layer will be visible
|
|
//select the white pixels
|
|
await colorRange()
|
|
})
|
|
// await colorRangeExe()
|
|
//delete the mask layer. we only needed to select the white pixels
|
|
await executeAsModal(async () => {
|
|
await layer_util.toggleActiveLayer() // undo the toggling operation, active layer will be visible
|
|
})
|
|
await layer_util.deleteLayers([mask_layer])
|
|
}
|
|
|
|
async function base64ToChannel(base64, selection_info, channel_name) {
|
|
try {
|
|
await executeAsModal(async (context) => {
|
|
const history_id = await context.hostControl.suspendHistory({
|
|
documentID: app.activeDocument.id, //TODO: change this to the session document id
|
|
name: 'Mask Image',
|
|
})
|
|
|
|
const layer = app.activeDocument.activeLayers[0]
|
|
|
|
if (!layer_util.Layer.doesLayerExist(layer)) {
|
|
return null
|
|
}
|
|
await psapi.unSelectMarqueeExe()
|
|
await psapi.unselectActiveLayersExe()
|
|
await base64ToLassoSelection(base64, selection_info)
|
|
|
|
const expand_cmd = {
|
|
_obj: 'expand',
|
|
by: {
|
|
_unit: 'pixelsUnit',
|
|
_value: 10,
|
|
},
|
|
selectionModifyEffectAtCanvasBounds: true,
|
|
_isCommand: true,
|
|
}
|
|
const channelToSelection = {
|
|
_obj: 'set',
|
|
_target: { _ref: 'channel', _property: 'selection' },
|
|
to: { _ref: 'channel', _name: channel_name },
|
|
}
|
|
await executeAsModal(async () => {
|
|
const result = await batchPlay(
|
|
[
|
|
expand_cmd,
|
|
...deleteChannel(channel_name),
|
|
makeMaskChannel(channel_name),
|
|
channelToSelection,
|
|
],
|
|
{ modalBehavior: 'execute', synchronousExecution: true }
|
|
)
|
|
})
|
|
await psapi.selectLayersExe([layer])
|
|
await applyMaskChannelExe(channel_name)
|
|
|
|
// context = stored_context
|
|
await context.hostControl.resumeHistory(history_id)
|
|
})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
|
|
async function black_white_layer_to_mask(mask_id, target_layer_id, mask_name) {
|
|
let result
|
|
let psAction = require('photoshop').action
|
|
|
|
let command = [
|
|
//
|
|
...deleteChannel(mask_name),
|
|
// Select layer “Layer 33”
|
|
{
|
|
_obj: 'select',
|
|
_target: [{ _id: mask_id, _ref: 'layer' }],
|
|
// layerID: [3862],
|
|
makeVisible: false,
|
|
},
|
|
// Set Selection
|
|
{
|
|
_obj: 'set',
|
|
_target: [{ _property: 'selection', _ref: 'channel' }],
|
|
to: {
|
|
_enum: 'channel',
|
|
_ref: 'channel',
|
|
_value: 'transparencyEnum',
|
|
},
|
|
},
|
|
// Color Range
|
|
{
|
|
_obj: 'colorRange',
|
|
colorModel: 0,
|
|
fuzziness: 0,
|
|
maximum: { _obj: 'labColor', a: 0.0, b: 0.0, luminance: 100.0 },
|
|
minimum: { _obj: 'labColor', a: 0.0, b: 0.0, luminance: 100.0 },
|
|
},
|
|
// Duplicate Selection, make sure you delete the any mask that share the same name
|
|
{
|
|
_obj: 'duplicate',
|
|
_target: [{ _property: 'selection', _ref: 'channel' }],
|
|
name: mask_name,
|
|
},
|
|
// Select channel “Alpha 1”
|
|
{ _obj: 'select', _target: [{ _name: mask_name, _ref: 'channel' }] },
|
|
// Set Selection
|
|
{
|
|
_obj: 'set',
|
|
_target: [{ _property: 'selection', _ref: 'channel' }],
|
|
to: { _enum: 'ordinal', _ref: 'channel', _value: 'targetEnum' },
|
|
},
|
|
// Select layer “Layer 43”
|
|
{
|
|
_obj: 'select',
|
|
_target: [{ _id: target_layer_id, _ref: 'layer' }],
|
|
// layerID: [3879],
|
|
makeVisible: false,
|
|
},
|
|
// Make
|
|
{
|
|
_obj: 'make',
|
|
at: { _enum: 'channel', _ref: 'channel', _value: 'mask' },
|
|
new: { _class: 'channel' },
|
|
using: { _enum: 'userMaskEnabled', _value: 'revealSelection' },
|
|
},
|
|
]
|
|
result = await psAction.batchPlay(command, {})
|
|
}
|
|
|
|
async function black_white_layer_to_mask_multi_batchplay(
|
|
mask_id,
|
|
target_layer_id,
|
|
mask_name,
|
|
expand_by = 10
|
|
) {
|
|
let result
|
|
let psAction = require('photoshop').action
|
|
const timer = (ms) => new Promise((res) => setTimeout(res, ms))
|
|
|
|
let command1 = [
|
|
{
|
|
_obj: 'set',
|
|
_target: [{ _property: 'selection', _ref: 'channel' }],
|
|
to: { _enum: 'ordinal', _value: 'none' },
|
|
},
|
|
//
|
|
...deleteChannel(mask_name),
|
|
// Select layer “Layer 33”
|
|
{
|
|
_obj: 'select',
|
|
_target: [{ _id: mask_id, _ref: 'layer' }],
|
|
// layerID: [3862],
|
|
makeVisible: false,
|
|
},
|
|
// Set Selection
|
|
{
|
|
_obj: 'set',
|
|
_target: [{ _property: 'selection', _ref: 'channel' }],
|
|
to: {
|
|
_enum: 'channel',
|
|
_ref: 'channel',
|
|
_value: 'transparencyEnum',
|
|
},
|
|
},
|
|
]
|
|
let command2 = [
|
|
// Color Range
|
|
{
|
|
_obj: 'colorRange',
|
|
colorModel: 0,
|
|
fuzziness: 0,
|
|
maximum: { _obj: 'labColor', a: 0.0, b: 0.0, luminance: 100.0 },
|
|
minimum: { _obj: 'labColor', a: 0.0, b: 0.0, luminance: 100.0 },
|
|
},
|
|
{
|
|
_obj: 'expand',
|
|
by: {
|
|
_unit: 'pixelsUnit',
|
|
_value: expand_by,
|
|
},
|
|
selectionModifyEffectAtCanvasBounds: true,
|
|
_isCommand: true,
|
|
},
|
|
]
|
|
let command3 = [
|
|
// Duplicate Selection, make sure you delete the any mask that share the same name
|
|
{
|
|
_obj: 'duplicate',
|
|
_target: [{ _property: 'selection', _ref: 'channel' }],
|
|
name: mask_name,
|
|
},
|
|
// Select channel “Alpha 1”
|
|
{
|
|
_obj: 'select',
|
|
_target: [{ _name: mask_name, _ref: 'channel' }],
|
|
},
|
|
// Set Selection
|
|
{
|
|
_obj: 'set',
|
|
_target: [{ _property: 'selection', _ref: 'channel' }],
|
|
to: { _enum: 'ordinal', _ref: 'channel', _value: 'targetEnum' },
|
|
},
|
|
// Select layer “Layer 43”
|
|
{
|
|
_obj: 'select',
|
|
_target: [{ _id: target_layer_id, _ref: 'layer' }],
|
|
// layerID: [3879],
|
|
makeVisible: false,
|
|
},
|
|
// Make
|
|
{
|
|
_obj: 'make',
|
|
at: { _enum: 'channel', _ref: 'channel', _value: 'mask' },
|
|
new: { _class: 'channel' },
|
|
using: { _enum: 'userMaskEnabled', _value: 'revealSelection' },
|
|
},
|
|
]
|
|
await timer(g_timer_value)
|
|
// result = await psAction.batchPlay(command, {})
|
|
|
|
await executeAsModal(async () => {
|
|
result = await psAction.batchPlay(command1, {})
|
|
})
|
|
|
|
await timer(g_timer_value)
|
|
await executeAsModal(async () => {
|
|
await layer_util.toggleActiveLayer() // toggle active layer will be visible, note: doesn't solve the issue in outpaint mode
|
|
result = await psAction.batchPlay(command2, {})
|
|
})
|
|
|
|
await timer(g_timer_value)
|
|
await executeAsModal(async () => {
|
|
await layer_util.toggleActiveLayer() // undo the toggling operation, active layer will be visible, note: doesn't solve the issue in outpaint mode
|
|
result = await psAction.batchPlay(command3, {})
|
|
})
|
|
}
|
|
|
|
module.exports = {
|
|
finalWidthHeight,
|
|
selectionToFinalWidthHeight,
|
|
selectBoundingBox,
|
|
convertSelectionObjectToSelectionInfo,
|
|
Selection,
|
|
|
|
makeMaskChannel,
|
|
makeMaskChannelExe,
|
|
fillSelectionWhiteOutsideBlack,
|
|
inpaintLasoInitImage,
|
|
applyMaskChannelExe,
|
|
createLayerFromMaskChannel,
|
|
multiGetExe,
|
|
inpaintLassoInitImageAndMask,
|
|
channelToSelectionExe,
|
|
moveToTopLayerStackExe,
|
|
colorRangeExe,
|
|
base64ToLassoSelection,
|
|
base64ToChannel,
|
|
deleteChannel,
|
|
selectionToChannel,
|
|
black_white_layer_to_mask,
|
|
black_white_layer_to_mask_multi_batchplay,
|
|
}
|