Skip to content

Commit 4405b7d

Browse files
committed
-update docs
- fix python example
1 parent 0238794 commit 4405b7d

23 files changed

+146
-182
lines changed

PhotoshopAPI/src/Core/Geometry/BezierSurface.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ PSAPI_NAMESPACE_BEGIN
1515
namespace Geometry
1616
{
1717

18-
/// A generic Bezier surface struct with
18+
/// A generic implementation of a cubic bezier surface. In the context of the PhotoshopAPI we use this to evaluate
19+
/// warps stored as cubic bezier surfaces. This struct is specialized for use within Photoshop.
1920
struct BezierSurface
2021
{
2122

PhotoshopAPI/src/LayeredFile/LayerTypes/Layer.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,16 @@ struct Layer : public MaskMixin<T>
107107
///
108108
/// In photoshop this is stored as a `uint8_t` from 0-255 but access and write is
109109
/// in terms of a float for better consistency.
110-
void opacity(float value) noexcept { m_Opacity = static_cast<uint8_t>(value * 255.0f); }
110+
void opacity(float value) noexcept
111+
{
112+
if (value < 0.0f || value > 1.0f)
113+
{
114+
PSAPI_LOG_WARNING("Layer", "Encountered opacity value not between 0-1. Clamping this to fit into that range");
115+
}
116+
value = std::clamp<float>(value, 0.0f, 1.0f);
117+
118+
m_Opacity = static_cast<uint8_t>(value * 255.0f);
119+
}
111120

112121
/// The layers' width from 0 - 300,000
113122
virtual uint32_t width() const noexcept { return m_Width; }

PhotoshopAPI/src/LayeredFile/LayeredFile.h

+6-23
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,12 @@ struct LayeredFile
7777
ICCProfile icc_profile() const noexcept { return m_ICCProfile; }
7878
void icc_profile(ICCProfile profile) noexcept { m_ICCProfile = std::move(profile); }
7979

80-
/// \defgroup dpi The files' dots per inch (dpi) resolution
81-
/// @{
80+
/// The files' dots per inch (dpi) resolution
8281
float& dpi() noexcept { return m_DotsPerInch; }
8382
float dpi() const noexcept { return m_DotsPerInch; }
8483
void dpi(float resolution) { m_DotsPerInch = resolution; }
85-
/// @}
8684

87-
/// \defgroup width The files' width from 1 - 300,000
88-
/// @{
85+
/// The files' width from 1 - 300,000
8986
uint64_t& width() noexcept { return m_Width; }
9087
uint64_t width() const noexcept { return m_Width; }
9188
void width(uint64_t file_width)
@@ -100,10 +97,8 @@ struct LayeredFile
10097
}
10198
m_Width = file_width;
10299
}
103-
/// @}
104100

105-
/// \defgroup height The files' height from 1 - 300,000
106-
/// @{
101+
/// The files' height from 1 - 300,000
107102
uint64_t& height() noexcept { return m_Height; }
108103
uint64_t height() const noexcept { return m_Height; }
109104
void height(uint64_t file_height)
@@ -118,7 +113,6 @@ struct LayeredFile
118113
}
119114
m_Height = file_height;
120115
}
121-
/// @}
122116

123117
/// Retrieve the bounding box describing the canvas, will always have a minimum of 0, 0
124118
Geometry::BoundingBox<double> bbox() const noexcept
@@ -128,38 +122,27 @@ struct LayeredFile
128122
Geometry::Point2D<double>(static_cast<double>(width()), static_cast<double>(height())));
129123
}
130124

131-
/// \defgroup colormode The files' colormode
125+
/// \brief The files' colormode
132126
///
133127
/// Currently we only fully support RGB, CMYK and Greyscale.
134-
///
135-
/// @{
136128
Enum::ColorMode& colormode() noexcept { return m_ColorMode; }
137129
Enum::ColorMode colormode() const noexcept { return m_ColorMode; }
138130
void colormode(Enum::ColorMode color_mode) noexcept { m_ColorMode = color_mode; }
139-
/// @}
140131

141-
/// \defgroup bitdepth The files' bitdepth
132+
/// \brief The files' bitdepth
142133
///
143134
/// As this is managed by the template type T we do not actually allow users
144135
/// to set this.
145-
///
146-
/// @{
147136
Enum::BitDepth bitdepth() const noexcept { return m_BitDepth; }
148-
/// @}
149137

150-
/// \defgroup linked_layer
151-
///
152-
/// Primarily for internal user or advanced users. Users should usually not have to
138+
/// Primarily for internal use or advanced users. Users should usually not have to
153139
/// touch this as it's handled for them by SmartObjects themselves
154140
///
155141
/// LinkedLayers describe a global state of linked files. Their purpose is to store
156142
/// the raw image data of smart objects such that any layer can have different resolution
157143
/// than the smart object and for deduplication.
158-
///
159-
/// @{
160144
std::shared_ptr<LinkedLayers<T>> linked_layers() noexcept { return m_LinkedLayers; }
161145
const std::shared_ptr<LinkedLayers<T>> linked_layers() const noexcept { return m_LinkedLayers; }
162-
/// @}
163146

164147

165148
LayeredFile() = default;

PhotoshopAPI/src/LayeredFile/LinkedData/LinkedLayerData.h

+3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ PSAPI_NAMESPACE_BEGIN
2929

3030
enum class LinkedLayerType
3131
{
32+
/// Links the data internlly, meaning the raw file bytes will be stored in-file
3233
data,
34+
/// Links the data externally, meaning only the transformed image is stored in-file
35+
/// with the original data residing on disk
3336
external
3437
};
3538

PhotoshopExamples/AddLayerMasks/add_layer_masks.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def main() -> None:
1818
img_data[0] = 255
1919
mask = np.full((height, width), 128, np.uint8)
2020

21-
img_layer = psapi.ImageLayer_8bit(img_data, "Layer Red", layer_mask=mask)
21+
img_layer = psapi.ImageLayer_8bit(img_data, "Layer Red", layer_mask=mask, width=width, height=height)
2222

2323
# Add the layer and write to disk
2424
document.add_layer(img_layer)

PhotoshopExamples/CreateSimpleDocument/create_simple_document.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def main() -> None:
2020

2121
# Similar to the C++ version we can adjust parameters of the layer after it has been added to the document
2222
# as long as it happens before we write to disk
23-
img_layer.opacity = 128
23+
img_layer.opacity = .5
2424

2525
document.write(os.path.join(os.path.dirname(__file__), "WriteSimpleFile.psd"))
2626

PhotoshopExamples/CreateSimpleDocument/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ int main()
3535

3636
// It is perfectly legal to modify a layers properties even after it was added to the document as attributes
3737
// are only finalized on export
38-
layer->opacity(128u);
38+
layer->opacity(.5);
3939

4040
// Convert to PhotoshopFile and write to disk. Note that from this point onwards
4141
// our LayeredFile instance is no longer usable

README.md

+66-80
Original file line numberDiff line numberDiff line change
@@ -45,33 +45,31 @@ Features
4545
=========
4646

4747
Supported:
48-
- Read and write of \*.psd and \*.psb files
49-
- Creating and modifying simple and complex nested layer structures
50-
- Pixel Masks
51-
- Modifying layer attributes (name, blend mode, image data etc.)
52-
- Setting the Display ICC Profile
53-
- Setting the DPI of the document
54-
- 8-, 16- and 32-bit files
55-
- RGB, CMYK and Grayscale color modes
56-
- All compression modes known to Photoshop
48+
- Read and write of \*.psd and \*.psb files
49+
- Creating and modifying simple and complex nested layer structures
50+
- Smart Objects (replacing, warping, extracting)
51+
- Pixel Masks
52+
- Modifying layer attributes (name, blend mode etc.)
53+
- Setting the Display ICC Profile
54+
- 8-, 16- and 32-bit files
55+
- RGB, CMYK and Grayscale color modes
56+
- All compression modes known to Photoshop
5757

5858
Planned:
59-
- Support for Adjustment Layers (planned `v0.6.0`)
60-
- Support for Vector Masks
61-
- Support for Text Layers
62-
- Support for Smart Object Layers (planned `v0.6.0`)
63-
- Indexed and Duotone Color Modes
59+
- Support for Adjustment Layers
60+
- Support for Vector Masks
61+
- Support for Text Layers
62+
- Indexed, Duotone Color Modes
6463

6564
Not Supported:
66-
- Files written by the PhotoshopAPI do not contain a valid merged image in order to save size meaning they will not behave properly when opened in
67-
third party apps requiring these (such as Lightroom)
68-
- Lab and Multichannel Color Modes
69-
65+
- Files written by the PhotoshopAPI do not contain a valid merged image in order to save size meaning they will not behave properly when opened in
66+
third party apps requiring these (such as Lightroom)
67+
- Lab and Multichannel Color Modes
7068

7169
Python
7270
==============
7371

74-
The PhotoshopAPI comes with fully fledged Python bindings which can be simply installed using
72+
The PhotoshopAPI comes with Python bindings which can be installed using
7573
```
7674
$ py -m pip install PhotoshopAPI
7775
```
@@ -134,77 +132,65 @@ Below is a minimal example to get started with opening a PhotoshopFile, removing
134132
### C++
135133

136134
```cpp
137-
using namespace PhotoshopAPI;
138-
139-
// Initialize an 8-bit layeredFile. This must match the bit depth of the PhotoshopFile.
140-
// To initialize this programmatically please refer to the ExtendedSignature example
141-
LayeredFile<bpp8_t> layeredFile = LayeredFile<bpp8_t>::read("InputFile.psd");
142-
143-
// Do some operation, in this case delete
144-
layeredFile.removeLayer("SomeGroup/SomeNestedLayer");
145-
146-
// One could write out to .psb instead if wanted and the PhotoshopAPI will take
147-
// care of any conversion internally
148-
LayeredFile<bpp8_t>::write(std::move(layeredFile), "OutputFile.psd");
135+
using namespace NAMESPACE_PSAPI;
136+
137+
// Initialize some constants that we will need throughout the program
138+
const static uint32_t width = 64u;
139+
const static uint32_t height = 64u;
140+
141+
// Create an 8-bit LayeredFile as our starting point, 8- 16- and 32-bit are fully supported
142+
LayeredFile<bpp8_t> document = { Enum::ColorMode::RGB, width, height };
143+
// Create our individual channels to add to our image layer. Keep in mind that all these 3 channels need to
144+
// be specified for RGB mode
145+
std::unordered_map <Enum::ChannelID, std::vector<bpp8_t>> channelMap;
146+
channelMap[Enum::ChannelID::Red] = std::vector<bpp8_t>(width * height, 255u);
147+
channelMap[Enum::ChannelID::Green] = std::vector<bpp8_t>(width * height, 0u);
148+
channelMap[Enum::ChannelID::Blue] = std::vector<bpp8_t>(width * height, 0u);
149+
150+
ImageLayer<bpp8_t>::Params layerParams = {};
151+
layerParams.name = "Layer Red";
152+
layerParams.width = width;
153+
layerParams.height = height;
154+
155+
auto layer = std::make_shared<ImageLayer<bpp8_t>>(std::move(channelMap), layerParams);
156+
document.add_layer(layer);
157+
158+
// It is perfectly legal to modify a layers properties even after it was added to the document as attributes
159+
// are only finalized on export
160+
layer->opacity(.5f);
161+
162+
// Convert to PhotoshopFile and write to disk. Note that from this point onwards
163+
// our LayeredFile instance is no longer usable
164+
LayeredFile<bpp8_t>::write(std::move(document), "WriteSimpleFile.psd");
149165
```
150166
151167
152-
The same code for reading and writing can also be used to for example `LayeredFile::moveLayer` or `LayeredFile::addLayer` as well as extracting any image data
168+
The same code for reading and writing can also be used to for example `LayeredFile::move_layer_` or `LayeredFile::add_layer` as well as extracting any image data
153169
154170
### Python
155171
156172
```py
173+
import os
174+
import numpy as np
157175
import psapi
158176
159-
# Read the layered_file using the LayeredFile helper class, this returns a
160-
# psapi.LayeredFile_*bit object with the appropriate bit-depth
161-
layered_file = psapi.LayeredFile.read("InputFile.psd")
162-
163-
# Do some operation, in this case delete
164-
layered_file.remove_layer()
177+
# Initialize some constants that we will need throughout the program
178+
width = 64
179+
height = 64
180+
color_mode = psapi.enum.ColorMode.rgb
165181
166-
# Write back out to disk
167-
layered_file.write("OutFile.psd")
168-
```
182+
# Generate our LayeredFile instance
183+
document = psapi.LayeredFile_8bit(color_mode, width, height)
169184
170-
We can also do much more advanced things such as taking image data from one file and transferring
171-
it to another file, this can be across file sizes, psd/psb and even bit-depth!
172-
173-
```py
174-
import psapi
175-
import numpy as np
176-
import os
185+
img_data = np.zeros((3, height, width), np.uint8)
186+
img_data[0] = 255
187+
# When creating an image layer the width and height parameter are required if its not a zero sized layer
188+
img_layer = psapi.ImageLayer_8bit(img_data, "Layer Red", width=width, height=height)
189+
document.add_layer(img_layer)
177190
191+
# Similar to the C++ version we can adjust parameters of the layer after it has been added to the document
192+
# as long as it happens before we write to disk
193+
img_layer.opacity = .5
178194
179-
def main() -> None:
180-
# Read both our files, they can be open at the same time or we can also read one file,
181-
# extract the layer and return just that layer if we want to save on RAM.
182-
file_src = psapi.LayeredFile.read("GraftSource_16.psb")
183-
file_dest = psapi.LayeredFile.read("GraftDestination_8.psd")
184-
185-
# Extract the image data and convert to 8-bit.
186-
lr_src: psapi.ImageLayer_16bit = file_src["GraftSource"]
187-
img_data_src = lr_src.get_image_data()
188-
img_data_8bit = {}
189-
for key, value in img_data_src.items():
190-
value = value / 256 # Convert from 0-65535 -> 0-255
191-
img_data_8bit[key] = value.astype(np.uint8)
192-
193-
# Reconstruct an 8bit converted layer
194-
img_layer_8bit = psapi.ImageLayer_8bit(
195-
img_data_8bit,
196-
layer_name=lr_src.name,
197-
width=lr_src.width,
198-
height=lr_src.height,
199-
blend_mode=lr_src.blend_mode,
200-
opacity=lr_src.opacity
201-
)
202-
203-
# add the layer and write out to file!
204-
file_dest.add_layer(img_layer_8bit)
205-
file_dest.write("GraftDestination_8_Edited.psd")
206-
207-
208-
if __name__ == "__main__":
209-
main()
210-
```
195+
document.write(os.path.join(os.path.dirname(__file__), "WriteSimpleFile.psd"))
196+
```

docs/doxygen/code/layeredfile.rst

+13-6
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ around internally also very efficient
99
Usage
1010
-----
1111

12-
The code snippets below show some examples of how one would generally use a LayeredFile. For more detailed examples please visit the PhotoshopExamples/ directory
13-
on the github page
12+
The code snippets below show some examples of how one would generally use a LayeredFile.
13+
For more detailed examples please visit :ref:`examples`
1414

1515
.. tab:: Read and Modify
1616

@@ -22,10 +22,10 @@ on the github page
2222
LayeredFile<bpp16_t> layeredFile = LayeredFile<bpp16_t>::read("InFile.psd");
2323
2424
// Move a layer one level up in the hierarchy
25-
layeredFile.moveLayer("Group/NestedGroup/Image", "Group");
25+
layeredFile.move_layer("Group/NestedGroup/Image", "Group");
2626
2727
// Delete the now empty group from the document
28-
layeredFile.removeLayer("Group/NestedGroup");
28+
layeredFile.remove_layer("Group/NestedGroup");
2929
3030
// We can now convert the LayeredFile to a PhotoshopFile and write it out (this is done internally
3131
// but can be exposed, see the ExtendedSignature example for more information)
@@ -57,7 +57,7 @@ on the github page
5757
layerParams.height = height;
5858
5959
auto layer = std::make_shared<ImageLayer<bpp8_t>>(std::move(channelMap), layerParams);
60-
document.addLayer(layer);
60+
document.add_layer(layer);
6161
6262
LayeredFile<bpp8_t>::write(std::move(layeredFile), "OutFile.psd");
6363
@@ -66,7 +66,7 @@ on the github page
6666
Layer Type Derivatives
6767
----------------------
6868

69-
Below you can find a list of layers that one is able to add to the LayeredFile instance. Keep in mind that some of these are not fully implemented yet
69+
Below you can find a list of layers that one is able to add to the LayeredFile instance.
7070

7171
.. toctree::
7272
:maxdepth: 2
@@ -78,6 +78,12 @@ Below you can find a list of layers that one is able to add to the LayeredFile i
7878
layers/sectiondivider.rst
7979
layers/smartobject.rst
8080

81+
.. toctree::
82+
:maxdepth: 2
83+
:caption: Global Data:
84+
85+
util/linked_layer_data.rst
86+
8187

8288

8389
Conversion Functions
@@ -107,6 +113,7 @@ LayeredFile Struct
107113

108114
.. doxygenstruct:: LayeredFile
109115
:members:
116+
:undoc-members:
110117

111118
|
112119

docs/doxygen/code/layers/baselayer.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ Base Layer Type
1111

1212
This is the base definition for all layer types which holds generic data such as name, mask data, opacity etc.
1313
This class is not supposed to be used directly but instead through any of its subclassed layers as this layer type
14-
doesn't exist in Photoshop itself. There is a further specialization `_ImageDataLayerType<T>` which acts as a generic
15-
interface for ImageData types such as `SmartObjectLayer<T>` and `ImageLayer<T>`
14+
doesn't exist in Photoshop itself.
1615

1716
.. _layer:
1817
.. doxygenstruct:: Layer

0 commit comments

Comments
 (0)