Code Monkey home page Code Monkey logo

ag-psd's People

Contributors

agamnentzar avatar hoomanaskari avatar msabramo avatar noahlam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ag-psd's Issues

[feature request] support for web workers

Rendering PSD files can be quite slow and the current implementation in this module is synchronous and blocking. I'd like to hand off this work to a web worker, but that is currently not possible due to the use of canvas in the module.

I currently have 2 ideas for this:

  • use OffscreenCanvas where available. Unfortunately, "where available" is only Chromium browsers, so that's certainly not ideal.
  • best I can tell (I read some of this code for maybe 20 minutes, but I could have missed something), the canvas is used to insert data into using ImageData, and then exposed as the public API result so that it can be exported by the user using toDataURL(), toBlob(), or toBuffer() in node. However, ImageData is just a wrapper around Uint8ClampedArray, which can be used throughout the code instead of ImageData. The API could then be updated to specify whether to provide a canvas or to provide this Uint8ClampedArray along with the width and height directly. This array can be transferred across the worker and rendered on the other side (either by copying it into a new ImageData object or through various other means like jimp or sharp -- this is all up to the user, of course) doing only a small trivial portion in the main thread. I think this is the preferred option, but obviously quite a bit more work.

I am happy to help with all this, but I am hoping to get your input before starting.

Text change not reflected in output canvas

Thank you for the great library!

I'm trying to make programmatic edits to text in a .psd file, and then write the updated document to a .png file, without ever needing a human to open Photoshop.

This is my code:

const bufferIn = fs.readFileSync('input.psd');
const psdIn = readPsd(bufferIn);
// console.log(psdIn.children[4].children[0].text.text); // => "Lorem ipsum"
psdIn.children[4].children[0].text.text = "TEST";
psdIn.children[4].children[0].canvas = undefined;
const bufferOut = writePsd(psdIn, {invalidateTextLayers: true});
const psdOut = readPsd(bufferOut);
fs.writeFileSync('output.png', (psdOut.canvas as any).toBuffer());

When I run this code, output.png still has the original content ("Lorem ipsum" instead of "TEST").

Sorry if this is noise—I've read the docs and I'm not 100% clear whether what I'm trying to do is possible or not. Is it?

Layer style effect, incomplete reading

I tried to add two layers of stroke layer styles to one layer, but only one layer of stroke data can be read,The layer style in ps can be added repeatedly, lmfx doesn't seem to handle

wrong font-size

Hi.

i have psd file and parse with ag-psd

obj['PSD']['psd'] = PSD.readPsd(p, { skipLayerImageData: false, skipCompositeImageData: false, skipThumbnail: true });

And create html file. But two text cells have the wrong font size.

image

it is ORG and erase. ORG and erase for some reason is twice the size.

Tell me please it is error in ag-psd module or it is in psd file ?

in psd file css mode font-size is true.

image

It is page where it is file

https://zababurinsv.github.io/ide-design/

Standalone browser version

I'm currently trying to use the browser version for this library.

Doing the following:

npm install ag-psd
<script src="ag-psd/dist/browser.js" /> or <script src="ag-psd/dist/index.js" />

Gives me the error: Uncaught ReferenceError: exports is not defined
on line: Object.defineProperty(exports, "__esModule", { value: true });

It seems something related to typescript building, do i have to include some special lib in order to this build work properly?

Also, would it not be nice to provide a standalone version?

How add filter for css ?

I have psd. In text field i have filter.

dropShadow:
angle: 90
antialiased: true
blendMode: "normal"
choke: {value: 11, units: "Pixels"}
color: {r: 0, g: 0, b: 0}
contour: {name: "Линейный", curve: Array(2)}
distance: {value: 0, units: "Pixels"}
enabled: true
layerConceals: true
noise: 0
opacity: 0.3
size: {value: 150, units: "Pixels"}
useGlobalLight: true

size 150px

But redactor get me

filter: drop-shadow(0 0 75px rgba(0,0,0,0.3));

The filter does not work like in psd

Gradient scale is lost when writing

If you read this file: gradient-scale.zip, you get the scale value as expected.
Capture d’écran 2021-02-09 152227
But if you try to write the content to a new file, the scale value is lost.

Before:
Capture d’écran 2021-02-09 151909
After:
Capture d’écran 2021-02-09 151918

The scale value is settable using the UI in the following panel:
Untitled-1

Does library support layer mask and gradient?

Hi,

Does library support layer mask and gradient? basically we wanted to achieve reflection effect, we tried reading the psd files containing layer mask and gradient but these properties does not found. if that does not support then is there any plan to add these functionality?

Layer left, top, bottom, right, width and height can not be set

Hi

First of all thank you very much for this fantastically useful lib.

I have one issue with it though. I got everything to work for me in a layered canvas except for positioning my layers.

I am trying to export my HTML5 canvas (fabricJS) as PSD file and keep all the layers. The problem is that no matter what I set for left, top, bottom, right, width or height, ag-psd is going to modify those numbers, crop the layers etc.

The only numbers that work are left: 0, top: 0, right: canvas.width, bottom: canvas.height but these are not the positions I want.
Even if I hard code top, left etc. then I use writePsd(psdObject) it mutates my PSD object and changes the layer positioning. I did dig into the source code, but could not find out why it changes those numbers.

Any help is more than helpful.

Add 'Grid and Guides Information' and 'Resolution Information' image resource blocks parsers

hello @Agamnentzar, as promissed here is the implementation for parsing the image resource blocks.

also the psd i've been used here on my tests.

Grid and Guides Information

addHandler({
    key: 1032,
    has: function (target) { return typeof target.gridAndGuidesInformation !== 'undefined'; },
    read: function (reader, target) {
        var guides = [];
        target.gridAndGuidesInformation = {
          version: reader.readUint32(),
          grid: {
            horizontal: reader.readUint32(),
            vertical  : reader.readUint32()
          },
          guides: guides
        };

        guideCount = reader.readUint32();
        offset = 0

        while (offset < guideCount) {
          guides.push({
            location : reader.readUint32( ) / 32,
            direction: reader.readBytes(1)[0] ? 'horizontal' : 'vertical'
          });
          offset++;
        }
    },
    write: function (writer, target) {
        var info = target.gridAndGuidesInformation,
        version = info.version || 1, grid = info.grid || {horizontal: 18 * 32, vertical: 18 * 32},
        guides = info.guides || [], directionByte;

        writer.writeUint32(version);
        writer.writeUint32(grid.horizontal);
        writer.writeUint32(grid.vertical);
        writer.writeUint32(guides.length);
        guides.forEach(function (guide) {
          writer.writeUint32(guide.location * 32);
          directionByte = guide.direction == 'horizontal' ? 1 : 0
          writer.writeBytes(new Uint8Array([directionByte]));
        });
    }
});

Resolution Information

// http://www.fileformat.info/format/psd/egff.htm
addHandler({
    key: 1005,
    resolutionUnits: ['PPI', 'PPCM'],
    measurementUnits: ['Inchs', 'Centimeters', 'Points', 'Picas', 'Columns'],
    has: function (target) { return typeof target.resolutionInfo !== 'undefined'; },
    read: function (reader, target) {
        target.resolutionInfo = this.decode({
          // pixels per inch (32-bit fixed-point number 16.16)
          horizontalResolution    : reader.readUint32() / (1 << 16),
          horizontalResolutionUnit: reader.readUint16(),
          widthUnit               : reader.readUint16(),

          // pixels per inch (32-bit fixed-point number 16.16)
          verticalResolution     : reader.readUint32() / (1 << 16),
          verticalResolutionUnit : reader.readUint16(),
          heightUnit             : reader.readUint16()
        });
    },
    write: function (writer, target) {
      var resolutionInfo = this.encode(target.resolutionInfo);

      // pixels per inch (32-bit fixed-point number 16.16)
      writer.writeUint32(resolutionInfo.horizontalResolution * (1 << 16));
      writer.writeUint16(resolutionInfo.horizontalResolutionUnit);
      writer.writeUint16(resolutionInfo.widthUnit);

      // pixels per inch (32-bit fixed-point number 16.16)
      writer.writeUint32(resolutionInfo.verticalResolution * (1 << 16));
      writer.writeUint16(resolutionInfo.verticalResolutionUnit);
      writer.writeUint16(resolutionInfo.heightUnit);
    },
    decode: function (resolutionInfo) {
      resolutionInfo.horizontalResolutionUnit = this.resolutionUnits[resolutionInfo.horizontalResolutionUnit - 1];
      resolutionInfo.verticalResolutionUnit = this.resolutionUnits[resolutionInfo.verticalResolutionUnit - 1];
      resolutionInfo.widthUnit = this.measurementUnits[resolutionInfo.widthUnit - 1];
      resolutionInfo.heightUnit = this.measurementUnits[resolutionInfo.heightUnit - 1];
      return resolutionInfo;
    },
    encode: function (resolutionInfo) {
      resolutionInfo = Object.assign({}, resolutionInfo);
      resolutionInfo.horizontalResolutionUnit = this.resolutionUnits.indexOf(resolutionInfo.horizontalResolutionUnit) + 1
      resolutionInfo.verticalResolutionUnit = this.resolutionUnits.indexOf(resolutionInfo.verticalResolutionUnit) + 1
      resolutionInfo.widthUnit = this.measurementUnits.indexOf(resolutionInfo.widthUnit) + 1
      resolutionInfo.heightUnit = this.measurementUnits.indexOf(resolutionInfo.heightUnit) + 1
      return resolutionInfo;
    }
});

Details

The final parsed structure should look something like this:

document.resources = {
  resolutionInfo: {
    horizontalResolution: 300,
    horizontalResolutionUnit: 'PPCM',
    widthUnit: 'Centimeters',
    verticalResolution: 300,
    verticalResolutionUnit: 'PPCM',
    heightUnit: 'Centimeters'
  },
  gridAndGuidesInformation: {
    guides: [
      {
        direction: 'horizontal',
        location: 512
      }, {
        direction: 'vertical',
        location: 364
      }
    ]
  }
};

Testing

This document have 4 guides, and other-than-default resolution info block:
Sample Document For Testing

Missing font prevent the text layers update popup from appearing

As mentioned in the documentation, when creating a file from scratch, in order for text layers to be displayed properly, we need to update text layers data when opening the file.

When you add text layer to PSD file it is missing image data and additional text engine information. When you open file created this way in Photoshop it will display this error message, prompting you to update layer image data. You should choose "Update" which will force Photoshop to redraw text layers from text data. Clicking "No" will result in text layers being left in broken state.

This works perfectly fine for common case but I just discovered that if you open a file that has missing fonts, Photoshop displays a popup dedicated to replacing the missing fonts instead (file-with-2-fonts.zip).

Capture d’écran 2021-03-15 091915
And whatever you do (cancel or replace), you never get the chance to update text layers data.

I also discovered than we can trigger text layers update from the menu:
Capture d’écran 2021-03-15 092116
So we have a possible manual workaround for this case even it is not ideal.

So my question is, could you, by any chance, do something that would either make the text layers update popup still appear or trigger the update in another way ?

Thank you in advance.

Corrupt PSD with Smart Objects

Hey @Agamnentzar, thank you for this handy lib!

I'm having issues saving an existing PSD with Smart Object in it.

My main goal is to actually read a PSD (myPsd.psd inside this psds.zip), duplicate a specific layer group, and save it as a new one.

If I have a PSD that contains only text layers, it works. Even if I have an image (not as Smart Object) also works. When I include a Smart Object, the saved PSD is corrupt no matter the type of that Smart Object (PSB, JPG, etc).

I'm on macOS Catalina and my Node version is 10.19.0, so I had to stick with ES5. I also tried to update to the latest Node version - faced the same issues.

This is my code:

const fs = require( 'fs-extra' );
const agPsd = require( 'ag-psd' );
require( 'ag-psd/initialize-canvas' );


// read document structure and image data
const bufferRead = fs.readFileSync( 'myPsd.psd' );

const psdRead = agPsd.readPsd( bufferRead, {
	skipLayerImageData:false,
	skipCompositeImageData:false,
	skipThumbnail:false,
	skipLinkedFilesData:false,
	throwForMissingFeatures:false,
	logMissingFeatures:true,
	useImageData:true,
	useRawThumbnail:true,
	logDevFeatures:true
} );

// manipulate psd
var txtTemplate = getTemplate( psdRead );
var psdWrite = appendTemplate( txtTemplate, psdRead, psdRead );

// write psd
const bufferWrite = agPsd.writePsdBuffer( psdWrite, {
	generateThumbnail:true,
	trimImageData:false,
	invalidateTextLayers:false,
	logMissingFeatures:true,
	noBackground:true
} );

fs.writeFileSync( 'myPsd_duplicated.psd', bufferWrite );


// Get template
function getTemplate( arr ){
	var list = arr.children || [];

	for( var i = 0; i < list.length; i++ ){
		if( list[ i ].name.indexOf( 'TXT-TEMPLATE' ) != -1 ){
			return list[ i ];
		} else {
			var result = getTemplate( list[ i ] );
			if( result ) return result;
		}
	};

	return null;
};

// Append template
function appendTemplate( template, target, originalPSD ){
	var list = target.children || [];

	for( var i = 0; i < list.length; i++ ){
		if( list[ i ].name.indexOf( 'TXT-TEMPLATE' ) != -1 ){
			list.splice( i, 0, template );

			return originalPSD;
		} else {
			var result = appendTemplate( template, list[ i ], target );
			if( result ) return result;
		}
	};

	return null;
};

When I run the code above and the PSD has a Smart Object, I get this (corrupted PSD):

Unread 3 bytes left for tag: PlLd
Unread 1 bytes left for tag: SoLd
Unhandled additional info: lnkE
Unhandled additional info: extn

If the PSD doesn't have a Smart Object, this happens (working PSD):

Unhandled additional info: extn

I ran gulp cov and this is the result:

$ gulp cov
Using gulpfile node_modules/ag-psd/gulpfile.js
Starting 'cov'...
Starting 'build-js'...
Finished 'build-js' after 7.59 s
Starting 'coverage'...


  ,․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․
  ․․․․․․․․․․․․․․․․․․․Unhandled additional info: lnkE
․․․․․,,,,,,,,․․․․․․․․․․․․․․․․․․․․․․․․․․․․
  ․․

  113 passing (16s)
  9 pending

Finished 'coverage' after 17 s
Starting 'remap'...
Finished 'remap' after 453 ms
Finished 'cov' after 25 s

The test.psd is also attached.

Please let me know if you need more info regarding my environment.

Do you have any idea how can I get this to work?

Cheers!

How to get the `Copy CSS` output from ps?

In ps on every layer if we right click we have a Copy CSS menu which gives us the css output. However, I do not find a way to get the exactly same result as the css output. e.g., below is the css output of a text layer.

  font-size: 18px;
  font-family: "HYe3gj";
  color: rgb(102, 102, 102);
  line-height: 1.485;
  text-align: left;
  position: absolute;
  left: 120.927px;
  top: 544.91px;
  z-index: 15;

Here is the parsed data of this layer from ag-psd

{
  "top": 523,
  "left": 122,
  "bottom": 541,
  "right": 244,
  "blendMode": "normal",
  "opacity": 1,
  "clipping": false,
  "transparencyProtected": false,
  "hidden": false,
  "name": "邀请10位好友,",
  "text": {
    "transform": [
      1,
      0,
      0,
      1,
      121.85289589553634,
      537.1467138416688
    ],
    "left": 0,
    "top": 0,
    "right": 0,
    "bottom": 0,
    "text": "邀请10位好友,",
    "index": 13,
    "gridding": "none",
    "antiAlias": "sharp",
    "orientation": "horizontal",
    "warp": {
      "style": "none",
      "value": 0,
      "perspective": 0,
      "perspectiveOther": 0,
      "rotate": "horizontal"
    },
    "useFractionalGlyphWidths": true,
    "superscriptSize": 0.583,
    "superscriptPosition": 0.333,
    "subscriptSize": 0.583,
    "subscriptPosition": 0.333,
    "smallCapSize": 0.7,
    "shapeType": "point",
    "pointBase": [
      0,
      0
    ],
    "paragraphStyle": {
      "justification": "left",
      "firstLineIndent": 0,
      "startIndent": 0,
      "endIndent": 0,
      "spaceBefore": 0,
      "spaceAfter": 0,
      "autoHyphenate": true,
      "hyphenatedWordSize": 6,
      "preHyphen": 2,
      "postHyphen": 2,
      "consecutiveHyphens": 8,
      "zone": 36,
      "wordSpacing": [
        0.8,
        1,
        1.33
      ],
      "letterSpacing": [
        0,
        0,
        0
      ],
      "glyphSpacing": [
        1,
        1,
        1
      ],
      "autoLeading": 1.2,
      "leadingType": 0,
      "hanging": false,
      "burasagari": false,
      "kinsokuOrder": 0,
      "everyLineComposer": false
    },
    "style": {
      "font": {
        "name": "HYe3gj",
        "script": 3,
        "type": 1,
        "synthetic": 0
      },
      "fontSize": 18,
      "fauxBold": false,
      "fauxItalic": false,
      "autoLeading": false,
      "leading": 26.72999,
      "horizontalScale": 1,
      "verticalScale": 1,
      "tracking": 60,
      "autoKerning": true,
      "kerning": 0,
      "baselineShift": 0,
      "fontCaps": 0,
      "fontBaseline": 0,
      "underline": false,
      "strikethrough": false,
      "ligatures": true,
      "dLigatures": false,
      "baselineDirection": 2,
      "tsume": 0,
      "styleRunAlignment": 2,
      "language": 0,
      "noBreak": false,
      "fillColor": {
        "r": 101.99745,
        "g": 101.99745,
        "b": 101.99745,
        "a": 1
      },
      "strokeColor": {
        "r": 47.998650000000005,
        "g": 153.00255,
        "b": 119.9979,
        "a": 1
      },
      "yUnderline": 1,
      "hindiNumbers": false,
      "kashida": 1
    }
  },
  "nameSource": "rend",
  "id": 222,
  "blendClippendElements": true,
  "blendInteriorElements": false,
  "knockout": false,
  "protected": {
    "transparency": false,
    "composite": false,
    "position": false
  },
  "layerColor": "none",
  "timestamp": 1590394933.9341743,
  "referencePoint": {
    "x": -109,
    "y": 121
  }
}

As you can see from the result, we can get the correct font-size, font-family, color but not the other properties. The position is very close but not exactly the same.

Is there some information that I'm missing?

Error when reading PSDs created with Autodesk Sketchbook

Here's an example PSD from Sketchbook with the issue:

board-1-KHXDX.zip

Error is:

10:19:20.640 › Error: Invalid RLE data: exceeded buffer size 32/32
    at readDataRLE (…/ag-psd/dist/psdReader.js:577:31)
    at readData (…/ag-psd/dist/psdReader.js:427:9)
    at readLayerChannelImageData (…/ag-psd/dist/psdReader.js:403:13)
    at …/ag-psd/dist/psdReader.js:244:17
    at readSection (…/ag-psd/dist/psdReader.js:591:18)
    at readLayerInfo (…/ag-psd/dist/psdReader.js:229:5)
    at …/ag-psd/dist/psdReader.js:194:23
    at readSection (…/ag-psd/dist/psdReader.js:591:18)
    at Object.readPsd (…/ag-psd/dist/psdReader.js:193:5)
    at readPsd (…/ag-psd/dist/index.js:25:24)

Although my guess is this is a problem with the Autodesk Sketchbook exporter, and not with ag-psd.

Parsing information like distort, warp etc on layers

Hi,

I really love where this library is going. I am still using using a rather older version of the lib, only because I am waiting for 1 specific feature to be added.

I know you have added support for smart objects, but what about information related to distorting, warping etc. of these layers. These could be as simple as before/after coordinates, they can later be fed into a webGL program to edit the warp/distort effect later. The webGL part is of course out of the scope your library, but do you think there is a chance for the mentioned info be parsed for layers?

Test failures on OS X

Not sure why but several tests fail on OS X because the file sizes aren't what it's expecting. When I run it in a Docker container, all the tests pass.

  12) PsdWriter
       writes PSD file (layer-mask):
     Error: Buffers differ in size actual: 29591 expected: 29585 (ArrayBufferPsdWriter)
      at Object.compareBuffers (src/test/common.ts:149:9)
      at Context.<anonymous> (src/test/psdWriter.spec.ts:348:4)

  13) PsdWriter
       writes PSD file (layer-offsets):
     Error: Buffers differ in size actual: 20053 expected: 20031 (ArrayBufferPsdWriter)
      at Object.compareBuffers (src/test/common.ts:149:9)
      at Context.<anonymous> (src/test/psdWriter.spec.ts:348:4)

  14) PsdWriter
       writes PSD file (no-background):
     Error: Buffers differ in size actual: 119561 expected: 119537 (ArrayBufferPsdWriter)
      at Object.compareBuffers (src/test/common.ts:149:9)
      at Context.<anonymous> (src/test/psdWriter.spec.ts:348:4)

  15) PsdWriter
       writes PSD file (simple):
     Error: Buffers differ in size actual: 84299 expected: 84281 (ArrayBufferPsdWriter)
      at Object.compareBuffers (src/test/common.ts:149:9)
      at Context.<anonymous> (src/test/psdWriter.spec.ts:348:4)

Text Layer Style Missing

Hi,

Thanks for creating such a wonderful plugin.

When i fetch text layers from psd, some text layers have missing style object.

{
top: 213,
left: 1352,
bottom: 308,
right: 1828,
blendMode: 'normal',
opacity: 1,
clipping: false,
transparencyProtected: false,
hidden: false,
name: 'ご利用料金',
text: {
transform: [
1.3157875258074918,
0,
0,
1.316233392838027,
1584.8046875,
298.44206040037534
],
left: 0,
top: 0,
right: 0,
bottom: 0,
text: 'ご利用料金',
index: 1,
gridding: 'none',
antiAlias: 'strong',
orientation: 'horizontal',
warp: {
style: 'none',
value: 0,
perspective: 0,
perspectiveOther: 0,
rotate: 'horizontal'
}
},
nameSource: 'rend',
id: 8,
blendClippendElements: true,
blendInteriorElements: false,
knockout: false,
protected: { transparency: false, composite: false, position: false },
layerColor: 'none',
timestamp: 1588305488.703038,
referencePoint: { x: 1100.8518677539773, y: -653.8262456683206 },
canvas: [Canvas 476x95],
}

How can we add Paragraph Text?

Hi,

I am creating a psd file which contains multiple text and image layers. but I am looking for the support of paragraph text instead of pointText. I looked over the documentation but not able to find any such document for paragraph Text. so my question is- How can we add paragraph text inside the Text layer! Please let me know if there is any way to achieve this.

Generate image from layer

Hello,

First of all, thanks for making ag-psd!
Can we generate an output image from a layer?

In README, I see an example with canvas only:

const buffer = fs.readFileSync('my-file.psd');
const psd2 = readPsd(buffer);
fs.writeFileSync('layer-1.png', psd2.children[0].canvas.toBuffer());

Smart object support

Is there any plan to add smart object support? Or do you have any hack for this?

writeEffects not implemented

Given the code:

import 'ag-psd/initialize-canvas'

import * as fs from 'fs'
import { readPsd, writePsdBuffer } from 'ag-psd'

const buffer = fs.readFileSync(TEMPLATE_PATH)
const psd = readPsd(buffer)

const buffer = writePsdBuffer(psd);
fs.writeFileSync('output.psd', buffer);

I am running into this error thrown within writeEffects:

function writeEffects(_writer, _effects) {
    throw new Error('Not implemented');
}

Can you help me better understand what "effects" is referring to and if there is a way to get around this not being implemented yet?

Furthermore; I will dig in to this and if I haven't found a workaround, I may dive in and attempt a PR.

new text cropping

Hi,

running into an issue changing text, where the new text layer moves position, and changes font colour and size after a certain point.

here's the starting point:

image

here's how it returns:

image

here's the code:

const fs = require('fs');
const {
    readPsd, writePsdBuffer, writePsd
} = require('ag-psd');
require('ag-psd/initialize-canvas');
const inputBuffer = fs.readFileSync('read.psd');
const psd = readPsd(inputBuffer);


psd.children[1].text.text = "Goodbyeeeeee"


   const buffer = writePsdBuffer(psd, { invalidateTextLayers: true });
   fs.writeFileSync('TEST.psd', buffer);

i tried grabbing the whole object and then changing the text, but the result was the same

const fs = require('fs');
const {
    readPsd, writePsdBuffer, writePsd
} = require('ag-psd');
require('ag-psd/initialize-canvas');
const inputBuffer = fs.readFileSync('read.psd');
const psd = readPsd(inputBuffer);






let newData = psd.children[1]
newData.text.text = "Goodbyeeeeee"
psd.children[1] = newData;

   const buffer = writePsdBuffer(psd, { invalidateTextLayers: true });
   fs.writeFileSync('TEST.psd', buffer);

When indexing fillColor, color properties do not exist?

image
The weird thing about this is if I go into the source and change the Color type to

export declare type Color = RGBA | RGB | HSB;

it will say that FillColor.b exists since all other types (RGBA & RGB) both share that property.
Now if I were to just change it to RGBA | RGB since they share r, g. & b, it says that those are the only properties that exist, although it should also let me index a, but again... it says that it doesn't exist.

Invalid effect key

There are some output in the console when I parse some psd files, see below

Screen Shot 2020-06-03 at 15 06 11

It does not break anything, at least all the information I need can be extracted successfully. Is there a way to not show these output(just to keep the console clean)?

Exporting to png w/ effects

I'm trying to export each layer as a png using this method
image
I was wondering if it's possible to preserve any layer effects, such as a color overlay?
Is it also possible to merge any clipping/vector masks when exporting the png?
And finally, is it possible to preserve group effects?

psd2.children[0].canvas.getBuffer is not a function

I use ag-psd in nodejs to edit an psd file but when I run example in docs I have this error:
image.
My code:
`const fs = require('fs');

require('ag-psd/initialize-canvas');

const {writePsdBuffer,readPsd} = require('ag-psd');
const buffer = fs.readFileSync('my-file.psd');
const psd2 = readPsd(buffer);
console.log(psd2);
fs.writeFileSync('layer-1.png', psd2.children[0].canvas.getBuffer());`

Vector mask is ignored when a bitmap mask is present

Hi thank you again for the awesome library !

In Photoshop, this is possible to have on a given layer, both a vector mask and a bitmap mask applied:
Capture d’écran 2021-03-05 152836

Taking this file as an example: vector-and-bitmap-mask.zip
Capture d’écran 2021-03-05 152915
The circle with the play icon is made with a bitmap mask and the rectangle cropping is made with a vector mask.
If we try to achieve the same result using the library, only the vector mask is kept when opening the file in Photoshop.
Here is the code demonstrating my point:

import fs from 'fs';
import { writePsdBuffer } from 'ag-psd';
import CanvasUtil from 'canvas';

// Switch value to compare both results.
const DISABLE_VECTOR_MASK = false;

function loadCanvasFromFile(filePath) {
  const img = new CanvasUtil.Image();
  img.src = fs.readFileSync(filePath);
  const canvas = CanvasUtil.createCanvas(img.width, img.height);
  canvas.getContext('2d').drawImage(img, 0, 0);
  return canvas;
}

const psd = {
  width: 101,
  height: 98,
  children: [
    {
      mask: {
        canvas: loadCanvasFromFile('mask.png'),
      },
      vectorFill: {
        type: 'color',
        color: {
          r: 255,
          g: 0,
          b: 0,
        },
      },
      ...(!DISABLE_VECTOR_MASK && {
        vectorMask: {
          paths: [
            {
              knots: [
                { points: [0, 0, 0, 0, 0, 0] },
                { points: [73, 0, 73, 0, 73, 0] },
                { points: [73, 74, 73, 74, 73, 74] },
                { points: [0, 74, 0, 74, 0, 74] },
              ],
            },
          ],
        },
      }),
    },
  ],
};

const buffer = writePsdBuffer(psd);
fs.writeFileSync('debug-write.psd', buffer);

And here is the bitmap mask image source referenced in the code as 'mask.png':
mask

Here is the produced file: debug-write.zip
Capture d’écran 2021-03-05 153828
Capture d’écran 2021-03-05 153835

Hoping that you'll be able to help with this.
Thank you in advance.

Group blend mode is not set

Given this input data:

{
  width: 573,
  height: 351,
  children: [
    {
      children: [
        {
          vectorFill: { type: 'color', color: { r: 255, g: 0, b: 0 } },
          vectorMask: { paths: [{ knots: [{ points: [100, 128, 100, 128, 100, 128] }, { points: [300, 128, 300, 128, 300, 128] }, { points: [300, 228, 300, 228, 300, 228] }, { points: [100, 228, 100, 228, 100, 228] }] }] },
        },
      ],
    },
    {
      name: 'Target group',
      blendMode: 'multiply',
      children: [
        {
          vectorFill: { type: 'color', color: { r: 0, g: 0, b: 255 } },
          vectorMask: {
            paths: [{
              knots: [{ points: [200, 178, 200, 178, 200, 178] }, { points: [400, 178, 400, 178, 400, 178] }, { points: [400, 278, 400, 278, 400, 278] }, { points: [200, 278, 200, 278, 200, 278] }],
            }],
          },
        },
      ],
    },
  ],
}

Here is the generated file:
Capture d’écran 2021-03-24 184542

The "Target group" layer blend mode should be set to "multiply" and produce this output:
Capture d’écran 2021-03-24 184555

Difficulties with smart objects

I'm trying to include smart object in my Photoshop file created from scratch with the help of your library.
In order to do it, I tried following the test case for writing smart object that is present in your test suite: https://github.com/Agamnentzar/ag-psd/tree/master/test/write/smart-object

I discovered that the output is only working as expected if we provide the layers canvases as you're doing it here:

l.canvas = tryLoadCanvasFromFile(path.join(basePath, `layer-${i}.png`));

If we skip this step (which is my case since I'm creating the file from scratch), the resulting layer is empty, even if we provide the linked file data, as done here:

f.data = fs.readFileSync(path.join(basePath, f.name));

And I found no way to trigger an update of the layer from Photoshop UI (I expected to find something similar to the text layers update feature).

Generating the needed canvas would not really be a problem when dealing with linked images, as in your test case, since we can easily generate it by reading the file ; but it becomes one when dealing with other type of linked file. My use case requires me to use smart object to include a Photoshop file in another one as a smart object.
Is there a way to do this with your library somehow ?

Thank you in advance.

Text stroke properties not working

Hi,

I was trying to add text stroke properties like stroke color, stroke width but that is not working? is there any way to achieve this?

Difference with psd.js?

Hi, this library looks very promising. I wonder what is the major difference compared to psd.js?

e.g, what psd.js cannot do that makes you to create this library? I'm just searching for psd parse libs and want to get more info to make decisions.

Thanks!

Vector mask is transformed when document size is not a square

Hi, first I would like to thank you for your library which I just tried and which seems to work great !

Explanation

While working with it, I discovered that vector masks are only working as expected if the document size is a square.
If you make it a rectangle, then the vector shape is scaled in the rectangle direction.
In order to prove the point, I used one of your test case: /test/read/round/data.json.
Here is the default result:
Capture d’écran 2021-01-26 181557
But if you change the document height from 200 to 400, here is the result:
Capture d’écran 2021-01-26 181617

Reproduction

The bug can easily be reproduced by using the following code and switching the SHOW_ISSUE variable value to compare both situations.

import * as fs from 'fs';
import { writePsdBuffer } from 'ag-psd';

const SHOW_ISSUE = true;

const ok = {
  'width': 200,
  'height': 200,
  'children': [
    {
      'top': 22,
      'left': 15,
      'bottom': 190,
      'right': 185,
      'name': 'shape layer',
      'vectorFill': {
        'type': 'color',
        'color': {
          'r': 72.00000330805779,
          'g': 72.00000330805779,
          'b': 72.00000330805779,
        },
      },
      'vectorMask': {
        'paths': [
          {
            'open': false,
            'knots': [
              {
                'linked': true,
                'points': [
                  54.160380363464355,
                  23.000001907348633,
                  100,
                  23.000001907348633,
                  145.83961963653564,
                  23.000001907348633,
                ],
              },
              {
                'linked': true,
                'points': [
                  183.00000429153442,
                  60.16037464141846,
                  183.00000429153442,
                  105.9999942779541,
                  183.00000429153442,
                  151.8396258354187,
                ],
              },
              {
                'linked': true,
                'points': [
                  145.83961963653564,
                  188.99999856948853,
                  100,
                  188.99999856948853,
                  54.160380363464355,
                  188.99999856948853,
                ],
              },
              {
                'linked': true,
                'points': [
                  16.999995708465576,
                  151.8396258354187,
                  16.999995708465576,
                  105.9999942779541,
                  16.999995708465576,
                  60.16037464141846,
                ],
              },
            ],
          },
        ],
      },
    },
  ],
};

const ko = {
  ...ok,
  height: 400,
}


const psd = SHOW_ISSUE ? ko : ok;

const buffer = writePsdBuffer(psd);
fs.writeFileSync('my-file.psd', buffer);

I reduced the original test case to keep only the relevant data but the bug also occurs if you keep the integral data or if you read/edit/write an original Photoshop file.

Environment

I'm running Node v14.15.2 on Windows 10 and Photoshop 20.0.4

Font size calculation issue

Some times the font size of the text layer differs from font size in the PSD

{
top: 443,
left: 249,
bottom: 538,
right: 725,
blendMode: 'normal',
opacity: 1,
clipping: false,
transparencyProtected: false,
hidden: false,
name: 'ご利用料金',
text: {
transform: [
1.3157875258074918,
0,
0,
1.316233392838027,
481.8046875,
528.4420604003753
],
left: 0,
top: 0,
right: 0,
bottom: 0,
text: 'ご利用料金',
index: 0,
gridding: 'none',
antiAlias: 'strong',
orientation: 'horizontal',
warp: {
style: 'none',
value: 0,
perspective: 0,
perspectiveOther: 0,
rotate: 'horizontal'
},
useFractionalGlyphWidths: true,
superscriptSize: 0.583,
superscriptPosition: 0.333,
subscriptSize: 0.583,
subscriptPosition: 0.333,
smallCapSize: 0.7,
paragraphStyle: {
justification: 'center',
autoHyphenate: false,
autoLeading: 1.75,
leadingType: 1
},
style: {
font: [Object],
fontSize: 74.45488,
leading: 21,
autoKerning: true,
kerning: 0,
ligatures: false,
styleRunAlignment: 3,
fillColor: [Object],
strokeColor: [Object]
}
},
nameSource: 'rend',
id: 5,
blendClippendElements: true,
blendInteriorElements: false,
knockout: false,
protected: { transparency: false, composite: false, position: false },
layerColor: 'none',
timestamp: 1588358251.103778,
referencePoint: { x: -2.1481322460226693, y: -423.82624566832055 },
canvas: [Canvas 476x95]
}

Font size i am getting is 74.45488, but font size in PSD is 98
But i am getting approximate value if i multiply it with text transform
Text Transform[0] = 1.3157875258074918
74.45488 * 1.3157875258074918 = 97.96

I have attached Test PSD for your reference
test.psd.zip

Frontend bug, there is no Image in canvas_1

I found a bug on the frontend.
In /ag-psd/dist/initializeCanvas.js line 6
There is no Image in canvas_1
I deleted canvas_1 from var image = new canvas_1.Image();
and leave var image = new Image(); to solve this problem for me.

Deselect all layers

Hi,
First of all great tool!
I have a case that I need to generate PSD and I've done successfully with your library, but I need to deselect all layers/create PSD without any selection. Right now when I open generated psd file I see that by default first layer is selected.
Is possible to create PSD without any selected layer?
Thanks

No spread parameter

Hi

I want to convert drop shadow to css

I have an object like this

dropShadow:
angle: 90
antialiased: true
blendMode: "normal"
choke:
units: "Pixels"
value: 11
__proto__: Object
color: {r: 0, g: 0, b: 0}
contour: {name: "Линейный", curve: Array(2)}
distance: {value: 0, units: "Pixels"}
enabled: true
layerConceals: true
noise: 0
opacity: 0.3
size: {value: 150, units: "Pixels"}
useGlobalLight: true

I found such a transformation on the Internet.

/ Assume we have the following values in Photoshop
// Blend Mode: Normal (no other blend mode is supported in CSS)
// Color: 0,0,0
// Opacity: 25%
// Angle: 135deg
// Distance: 4px
// Spread: 0%
// Size: 4px

// Here's some JavaScript that would do the math
function photoshopDropShadow2CSSBoxShadow(color, opacity, angle, distance, spread, size) {
  // convert the angle to radians
  angle = (180 - angle) * Math.PI / 180;

  // the color is just an rgba() color with the opacity.
  // for simplicity this function expects color to be an rgb string
  // in CSS, opacity is a decimal between 0 and 1 instead of a percentage
  color = "rgba(" + color + "," + opacity/100 + ")";

  // other calculations
  var offsetX = Math.round(Math.cos(angle) * distance) + "px",
      offsetY = Math.round(Math.sin(angle) * distance) + "px",
      spreadRadius = (size * spread / 100) + "px",
      blurRadius = (size - parseInt(spreadRadius, 10)) + "px";
  return offsetX + " " + offsetY + " " + blurRadius + " " + spreadRadius + " " + color;
}

// let's try it
// for simplicity drop all of the units
photoshopDropShadow2CSSBoxShadow("0,0,0", 25, 135, 4, 0, 4);
// -> 3px 3px 4px 0px rgba(0,0,0,0.25)

But in the object I have no spread parameter

Can you call it differently, or can it be calculated like that?

Unlock Background layer

Hi team,
I have an issue when generating PSD file with layers, that the last one (first in ag-psd children) is locked when the image is full-one color. But when I add small dot (even in 99% opacity) to that one-colored image, photoshop won't lock it.

147799307_1383061202029899_5367685294078409653_n

example of Background:
3BACKGROUND

I tried add additional metadata for layer but still the same effect.

{
          name,
          canvas: createCanvasFromImage(parsedImages[index]),
          opacity,
          protected: {
            transparency: false,
            composite: false,
            position: false
          },
          transparencyProtected: false,
          blendMode: blendMode.value
        }

When I open psd file in photoshop, unlock the layer and save, re-open the padlock is missing, so I believe that information is saved to psd file.

I tried some workaround to duplicate the background layer, read once again buffer, delete children and save new configuration but also without a success:

      const children = layers.map((layer, index) => {
        const {name, opacity, blendMode} = layer;
        return {
          name,
          canvas: createCanvasFromImage(parsedImages[index]),
          opacity,
          protected: {
            transparency: false,
            composite: false,
            position: false
          },
          transparencyProtected: false,
          blendMode: blendMode.value
        }
      });

      const firstElement = {
        ...children[0],
        name: 'copyBG'
      }
      const psd = {
        width,
        height,
        children: [firstElement, ...children],
        canvas: fullCanvas
      };
      const outputFile = `${outputName}${folderName}_${sequence}.psd`;
      const generatePsdFile = generatePsd(psd);
      const readFromGeneratedPsd = readPsdFile(generatePsdFile);
      readFromGeneratedPsd.children.shift();
      console.log(`File: ${outputFile} generated`);
      const outputPath = `${output}/${outputFile}`;
      const buffer = writePsdBuffer(readFromGeneratedPsd);
      fs.writeFileSync(outputPath, buffer);

Thanks for any tips :)

invalid font-size for text block

Hi.

i have psd file and parse with ag-psd

obj['PSD']['psd'] = PSD.readPsd(p, { skipLayerImageData: false, skipCompositeImageData: false, skipThumbnail: true });

And create html file. But two text cells have the wrong font size.

image

it is ORG and erase.

Tell me please it is error in ag-psd module or it is in psd file ?

in psd file css mode font-size is true.

image

Merge 2 canvas

My psd file has 2 layers. After reading psd file I uses node-canvas to change my variable( psd2.children[0].canvas). Then I check psd2.canvas, it doesn't change at all. So how can I merge psd2.children[0].canvas and psd2.children[1].canvas to psd2.canvas.

Sorry About My Bad English :(

PSD write metadata

Hi,

wanted to know if it's possible to write PSD metadata with ag-psd. We are interested in writing "Basic" and "IPTC" metadata. Or would it be possible to load the generated PSD with another package and add the metadata?

Also I noticed ag-psd always writes the PSDs with 72 dpi - any way to change that?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.