498 lines
14 KiB
JavaScript
498 lines
14 KiB
JavaScript
const { batchPlay } = require('photoshop').action
|
|
const { executeAsModal } = require('photoshop').core
|
|
const {
|
|
cleanLayers,
|
|
getLayerIndex,
|
|
selectLayers,
|
|
unSelectMarqueeCommand,
|
|
unSelectMarqueeExe,
|
|
getSelectionInfoExe,
|
|
reSelectMarqueeExe,
|
|
} = require('../psapi')
|
|
|
|
const psapi = require('../psapi')
|
|
// const Jimp = require('../jimp/browser/lib/jimp.min')
|
|
// const { settings_tab_ts } = require('../typescripts/dist/bundle')
|
|
const constants = require('photoshop').constants
|
|
|
|
async function createNewLayerExe(layerName, opacity = 100) {
|
|
await executeAsModal(async () => {
|
|
await createNewLayerCommand(layerName, opacity)
|
|
})
|
|
const new_layer = await app.activeDocument.activeLayers[0]
|
|
return new_layer
|
|
}
|
|
|
|
async function createNewLayerCommand(layerName, opacity = 100) {
|
|
return await app.activeDocument.createLayer({
|
|
name: layerName,
|
|
opacity: opacity,
|
|
mode: 'normal',
|
|
})
|
|
}
|
|
|
|
async function deleteLayers(layers) {
|
|
try {
|
|
await cleanLayers(layers)
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
|
|
async function getIndexCommand() {
|
|
const command = {
|
|
_obj: 'get',
|
|
_target: [
|
|
{
|
|
_property: 'itemIndex',
|
|
},
|
|
{
|
|
_ref: 'layer',
|
|
_enum: 'ordinal',
|
|
_value: 'targetEnum',
|
|
},
|
|
],
|
|
}
|
|
const result = await batchPlay([command], {
|
|
synchronousExecution: true,
|
|
modalBehavior: 'execute',
|
|
})
|
|
|
|
return result
|
|
}
|
|
|
|
async function getIndexExe() {
|
|
let index
|
|
await executeAsModal(async () => {
|
|
index = await getIndexCommand()
|
|
})
|
|
|
|
return index
|
|
}
|
|
const photoshop = require('photoshop')
|
|
|
|
const collapseFolderCommand = async (expand = false, recursive = false) => {
|
|
let result
|
|
try {
|
|
result = await batchPlay(
|
|
[
|
|
{
|
|
_obj: 'set',
|
|
_target: {
|
|
_ref: [
|
|
{ _property: 'layerSectionExpanded' },
|
|
{
|
|
_ref: 'layer',
|
|
_enum: 'ordinal',
|
|
_value: 'targetEnum',
|
|
},
|
|
],
|
|
},
|
|
to: expand,
|
|
recursive,
|
|
_options: { dialogOptions: 'dontDisplay' },
|
|
},
|
|
],
|
|
{ synchronousExecution: true }
|
|
)
|
|
} catch (e) {
|
|
console.error(e.message)
|
|
}
|
|
return result
|
|
}
|
|
async function collapseFolderExe(layers, expand = false, recursive = false) {
|
|
for (let layer of layers) {
|
|
try {
|
|
await executeAsModal(async () => {
|
|
const is_visible = await layer.visible // don't change the visiblity of the layer when collapsing
|
|
await selectLayers([layer])
|
|
await collapseFolderCommand(expand, recursive)
|
|
layer.visible = is_visible
|
|
})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
class Layer {
|
|
static doesLayerExist(layer) {
|
|
let b_exist = false
|
|
try {
|
|
if (typeof layer !== 'undefined' && layer && layer.name) {
|
|
//it will throw an error if the layer has been deleted
|
|
b_exist = true
|
|
// return true
|
|
}
|
|
// b_exist = true
|
|
} catch (e) {
|
|
b_exist = false
|
|
// console.warn(e)
|
|
}
|
|
return b_exist
|
|
}
|
|
static async getLayerInfo(layer) {
|
|
const bounds = layer.bounds
|
|
const height = bounds.bottom - bounds.top
|
|
const width = bounds.right - bounds.left
|
|
const layer_info = {
|
|
height: height,
|
|
width: width,
|
|
left: bounds.left,
|
|
right: bounds.right,
|
|
top: bounds.top,
|
|
bottom: bounds.bottom,
|
|
}
|
|
console.log('layer_info:', layer_info)
|
|
return layer_info
|
|
}
|
|
static async scaleTo(layer, new_width, new_height) {
|
|
await executeAsModal(async () => {
|
|
try {
|
|
const selection_info = await psapi.getSelectionInfoExe()
|
|
await psapi.unSelectMarqueeExe()
|
|
|
|
console.log('scaleLayer got called')
|
|
// const activeLayer = getActiveLayer()
|
|
// const activeLayer = await app.activeDocument.activeLayers[0]
|
|
|
|
const layer_info = await this.getLayerInfo(layer)
|
|
const scale_x_ratio = (new_width / layer_info.width) * 100
|
|
const scale_y_ratio = (new_height / layer_info.height) * 100
|
|
console.log('scale_x_y_ratio:', scale_x_ratio, scale_y_ratio)
|
|
// await layer.scale(
|
|
// scale_x_ratio,
|
|
// scale_y_ratio,
|
|
// constants.ResampleMethod.BILINEAR
|
|
// )
|
|
await layer_util.Layer.resizeImageExe(
|
|
scale_x_ratio,
|
|
scale_y_ratio
|
|
)
|
|
await psapi.reSelectMarqueeExe(selection_info)
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
})
|
|
}
|
|
static async resizeImage(percent_width, percent_height) {
|
|
// let imageSizeDescriptor = {
|
|
// _obj: 'imageSize',
|
|
// scaleStyles: true,
|
|
// constrainProportions: true,
|
|
// interfaceIconFrameDimmed: {
|
|
// _enum: 'interpolationType',
|
|
// // _value: 'automaticInterpolation',
|
|
// _value: 'bilinear',
|
|
// },
|
|
// _options: {
|
|
// dialogOptions: 'dontDisplay',
|
|
// },
|
|
// }
|
|
|
|
// if (width !== undefined && width !== null) {
|
|
// imageSizeDescriptor.width = {
|
|
// _unit: 'pixelsUnit',
|
|
// _value: width,
|
|
// }
|
|
// }
|
|
// if (height !== undefined && height !== null) {
|
|
// imageSizeDescriptor.height = {
|
|
// _unit: 'pixelsUnit',
|
|
// _value: height,
|
|
// }
|
|
// }
|
|
const setInterpolationMethodDesc = {
|
|
_obj: 'set',
|
|
_target: [
|
|
{
|
|
_ref: 'property',
|
|
_property: 'generalPreferences',
|
|
},
|
|
{
|
|
_ref: 'application',
|
|
_enum: 'ordinal',
|
|
_value: 'targetEnum',
|
|
},
|
|
],
|
|
to: {
|
|
_obj: 'generalPreferences',
|
|
interpolationMethod: {
|
|
_enum: 'interpolationType',
|
|
// _value: 'bilinear',
|
|
_value: settings_tab_ts.store.data
|
|
.scale_interpolation_method.photoshop,
|
|
},
|
|
},
|
|
_isCommand: true,
|
|
}
|
|
let imageSizeDescriptor = {
|
|
_obj: 'transform',
|
|
_target: [
|
|
{
|
|
_ref: 'layer',
|
|
_enum: 'ordinal',
|
|
_value: 'targetEnum',
|
|
},
|
|
],
|
|
freeTransformCenterState: {
|
|
_enum: 'quadCenterState',
|
|
_value: 'QCSAverage',
|
|
},
|
|
// offset: {
|
|
// _obj: 'offset',
|
|
// horizontal: {
|
|
// _unit: 'pixelsUnit',
|
|
// _value: 24.4388124547429,
|
|
// },
|
|
// vertical: {
|
|
// _unit: 'pixelsUnit',
|
|
// _value: -24.4388124547429,
|
|
// },
|
|
// },
|
|
width: {
|
|
_unit: 'percentUnit',
|
|
_value: percent_width,
|
|
},
|
|
height: {
|
|
_unit: 'percentUnit',
|
|
_value: percent_height,
|
|
},
|
|
linked: true,
|
|
interfaceIconFrameDimmed: {
|
|
_enum: 'interpolationType',
|
|
// _value: 'bilinear',
|
|
_value: settings_tab_ts.store.data.scale_interpolation_method
|
|
.photoshop,
|
|
},
|
|
_isCommand: true,
|
|
}
|
|
|
|
return batchPlay([setInterpolationMethodDesc, imageSizeDescriptor], {
|
|
synchronousExecution: true,
|
|
modalBehavior: 'execute',
|
|
})
|
|
}
|
|
static async resizeImageExe(percent_width, percent_height) {
|
|
try {
|
|
await executeAsModal(async () => {
|
|
await this.resizeImage(percent_width, percent_height)
|
|
})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
|
|
static async moveTo(layer, to_x, to_y) {
|
|
try {
|
|
await executeAsModal(async () => {
|
|
try {
|
|
//translate doesn't work with selection active. so store the selection and then unselect. move the layer, then reselect the selection info
|
|
const selection_info = await psapi.getSelectionInfoExe()
|
|
await psapi.unSelectMarqueeExe()
|
|
|
|
const layer_info = await this.getLayerInfo(layer)
|
|
const top_dist = layer_info.top - to_y
|
|
const left_dist = layer_info.left - to_x
|
|
console.log('-left_dist, -top_dist', -left_dist, -top_dist)
|
|
await layer.translate(-left_dist, -top_dist)
|
|
|
|
await psapi.reSelectMarqueeExe(selection_info)
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
static resizeTo() {}
|
|
static fitSelection() {}
|
|
static async duplicateToDoc(layer, to_doc) {
|
|
const dupLayer = await layer.duplicate(to_doc)
|
|
// await selectLayers([dupLayer])
|
|
return dupLayer
|
|
}
|
|
|
|
static async duplicateLayerExe(layer) {
|
|
let layer_copy
|
|
try {
|
|
await executeAsModal(async () => {
|
|
layer_copy = await layer.duplicate()
|
|
})
|
|
} catch (e) {
|
|
console.warn('duplication error:', e)
|
|
}
|
|
return layer_copy
|
|
}
|
|
|
|
static {}
|
|
}
|
|
|
|
const hasBackgroundLayerDesc = () => ({
|
|
_obj: 'get',
|
|
_target: [
|
|
{ _property: 'hasBackgroundLayer' },
|
|
{
|
|
_ref: 'document',
|
|
_enum: 'ordinal',
|
|
_value: 'targetEnum',
|
|
},
|
|
],
|
|
})
|
|
async function hasBackgroundLayer() {
|
|
// check if a document has a background layer
|
|
try {
|
|
const result = await batchPlay([hasBackgroundLayerDesc()], {
|
|
synchronousExecution: true,
|
|
modalBehavior: 'execute',
|
|
})
|
|
const b_hasBackgroundLayer = result[0]?.hasBackgroundLayer
|
|
return b_hasBackgroundLayer
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
const makeBackgroundLayerDesc = () => ({
|
|
_obj: 'make',
|
|
_target: [
|
|
{
|
|
_ref: 'backgroundLayer',
|
|
},
|
|
],
|
|
using: {
|
|
_ref: 'layer',
|
|
_enum: 'ordinal',
|
|
_value: 'targetEnum',
|
|
},
|
|
_options: { failOnMissingProperty: false, failOnMissingElement: false },
|
|
// _options: {
|
|
// dialogOptions: 'dontDisplay',
|
|
// },
|
|
})
|
|
|
|
const createSolidLayerDesc = (r, g, b) => ({
|
|
_obj: 'make',
|
|
_target: [
|
|
{
|
|
_ref: 'contentLayer',
|
|
},
|
|
],
|
|
using: {
|
|
_obj: 'contentLayer',
|
|
type: {
|
|
_obj: 'solidColorLayer',
|
|
color: {
|
|
_obj: 'RGBColor',
|
|
red: r,
|
|
grain: g,
|
|
blue: b,
|
|
},
|
|
},
|
|
},
|
|
_options: {
|
|
dialogOptions: 'dontDisplay',
|
|
},
|
|
})
|
|
|
|
async function toggleActiveLayer() {
|
|
const result = await batchPlay(
|
|
[
|
|
{
|
|
_obj: 'show',
|
|
null: [
|
|
{
|
|
_ref: 'layer',
|
|
_enum: 'ordinal',
|
|
_value: 'targetEnum',
|
|
},
|
|
],
|
|
toggleOptionsPalette: true,
|
|
_options: {
|
|
dialogOptions: 'dontDisplay',
|
|
},
|
|
},
|
|
],
|
|
{}
|
|
)
|
|
}
|
|
const toggleBackgroundLayerDesc = () => ({
|
|
_obj: 'show',
|
|
null: [
|
|
{
|
|
_ref: 'layer',
|
|
_property: 'background',
|
|
},
|
|
],
|
|
toggleOptionsPalette: true,
|
|
_options: {
|
|
dialogOptions: 'dontDisplay',
|
|
},
|
|
})
|
|
|
|
async function toggleBackgroundLayerExe() {
|
|
try {
|
|
await executeAsModal(async () => {
|
|
const result = await batchPlay([toggleBackgroundLayerDesc()], {
|
|
synchronousExecution: true,
|
|
modalBehavior: 'execute',
|
|
})
|
|
console.log('toggleBackgroundLayerExe result: ', result)
|
|
})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
|
|
async function createBackgroundLayer(r = 255, g = 255, b = 255) {
|
|
try {
|
|
const has_background = await hasBackgroundLayer()
|
|
if (has_background) {
|
|
//no need to create a background layer
|
|
return null
|
|
}
|
|
|
|
//reselect the selection area if it exist
|
|
|
|
await executeAsModal(async () => {
|
|
//store the selection area and then unselected
|
|
const selectionInfo = await psapi.getSelectionInfoExe()
|
|
await psapi.unSelectMarqueeExe()
|
|
const active_layers = app.activeDocument.activeLayers
|
|
|
|
// await createNewLayerCommand('background') //create layer
|
|
//make the layer into background
|
|
const result = await batchPlay(
|
|
[createSolidLayerDesc(r, g, b), makeBackgroundLayerDesc()],
|
|
{
|
|
synchronousExecution: true,
|
|
modalBehavior: 'execute',
|
|
}
|
|
)
|
|
|
|
await psapi.reSelectMarqueeExe(selectionInfo)
|
|
await psapi.selectLayersExe(active_layers)
|
|
})
|
|
} catch (e) {
|
|
console.warn(e)
|
|
}
|
|
}
|
|
async function fixImageBackgroundLayer() {
|
|
//convert the background layer to a normal layer
|
|
//create a new layer
|
|
//convert the new layer to background
|
|
}
|
|
module.exports = {
|
|
createNewLayerExe,
|
|
deleteLayers,
|
|
getIndexExe,
|
|
collapseFolderExe,
|
|
Layer,
|
|
hasBackgroundLayer,
|
|
createBackgroundLayer,
|
|
createSolidLayerDesc,
|
|
makeBackgroundLayerDesc,
|
|
toggleBackgroundLayerExe,
|
|
toggleActiveLayer,
|
|
}
|