644 lines
18 KiB
JavaScript
644 lines
18 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() {
|
|
// const { getSelectionInfoExe } = require('./psapi')
|
|
try {
|
|
const selectionInfo = await psapi.getSelectionInfoExe()
|
|
const [finalWidth, finalHeight] = finalWidthHeight(
|
|
selectionInfo.width,
|
|
selectionInfo.height,
|
|
512,
|
|
512
|
|
)
|
|
|
|
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 makeMaskChannel = () => ({
|
|
_obj: 'set',
|
|
_target: { _ref: 'channel', _property: 'selection' },
|
|
to: { _ref: 'channel', _name: 'inpaint_mask' },
|
|
})
|
|
async function makeMaskChannelExe() {
|
|
await executeAsModal(async () => {
|
|
const result = await batchPlay(
|
|
[
|
|
// SelectionInfoDesc(),
|
|
// makeMaskChannel(),
|
|
{
|
|
_obj: 'duplicate',
|
|
_target: [
|
|
{
|
|
_ref: 'channel',
|
|
_property: 'selection',
|
|
},
|
|
],
|
|
name: 'inpaint_mask_2',
|
|
_isCommand: true,
|
|
},
|
|
// {
|
|
// _obj: 'set',
|
|
// _target: { _ref: 'channel', _property: 'selection' },
|
|
// to: { _ref: 'channel', _name: 'inpaint_mask' },
|
|
// },
|
|
{
|
|
_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 fillSelectionWhiteOutsideBlack() {
|
|
// Create a new layer
|
|
const layer_name = 'inpaint_laso_mask'
|
|
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' }
|
|
// )
|
|
}
|
|
|
|
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 scale_info_str = `${parseInt(width)}x${parseInt(
|
|
height
|
|
)} => ${parseInt(selectionInfo.width)}x${parseInt(
|
|
selectionInfo.height
|
|
)} `
|
|
let ratio =
|
|
(width * height) / (selectionInfo.width * selectionInfo.height)
|
|
|
|
// const arrow = percentage >= 1 ? '↑' : '↓'
|
|
// percentage = percentage >= 1 ? percentage : 1 / percentage
|
|
|
|
// const percentage_str = `${arrow}X${percentage.toFixed(2)}`
|
|
|
|
// console.log('scale_info_str: ', scale_info_str)
|
|
// console.log('percentage_str: ', percentage_str)
|
|
return ratio
|
|
}
|
|
static {}
|
|
}
|
|
|
|
module.exports = {
|
|
finalWidthHeight,
|
|
selectionToFinalWidthHeight,
|
|
selectBoundingBox,
|
|
convertSelectionObjectToSelectionInfo,
|
|
Selection,
|
|
|
|
makeMaskChannel,
|
|
makeMaskChannelExe,
|
|
fillSelectionWhiteOutsideBlack,
|
|
}
|