Skip to content

Commit ef50777

Browse files
committed
- update docs
- update stub files - add test for mask mixin
1 parent ff3aa11 commit ef50777

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1008
-662
lines changed

.github/workflows/build-wheels.yml

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ jobs:
101101
python -u {project}/PhotoshopExamples/ModifyLayerStructure/modify_layer_structure.py &&
102102
python -u {project}/PhotoshopExamples/ReplaceImageData/replace_image_data.py &&
103103
python -u {project}/PhotoshopExamples/RescaleCanvas/rescale_canvas.py &&
104+
python -u {project}/PhotoshopExamples/SmartObjects/smart_objects.py &&
104105
nosetests {project}/python/psapi-test --verbose
105106
106107
- name: Verify clean directory

CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ if(PSAPI_BUILD_EXAMPLES)
116116
add_subdirectory (PhotoshopExamples/ProgressCallbacks)
117117
add_subdirectory (PhotoshopExamples/ReplaceImageData)
118118
add_subdirectory (PhotoshopExamples/SmartObjects)
119-
add_subdirectory (PhotoshopExamples/Tmp)
120119
endif()
121120
if(PSAPI_BUILD_DOCS)
122121
if(NOT PSAPI_BUILD_PYTHON)

PhotoshopAPI/src/Core/Geometry/BezierSurface.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,18 @@ namespace Geometry
157157
return { u, v };
158158
}
159159

160-
// Evaluate any patch at (u, v) based on subdivisions across x and y
160+
/// Evaluate any patch at (u, v) based on the subdivisions across x and y.
161+
/// This will return the screen-space coordinate from the given mesh.
162+
///
163+
/// If the bezier surface is made up of non-uniform slices (i.e. the bezier isn't
164+
/// split at .33, .66 etc for a 4x4 bezier) one should use `bias_uv()` to account
165+
/// for this. In fact because it evaluates to a no-op if that isn't the case the UV
166+
/// should always first be biased before calling this function.
167+
///
168+
/// \param u The u value to sample the bezier at. This should be from 0-1
169+
/// \param v The v value to sample the bezier at. This should be from 0-1
170+
///
171+
/// \returns The screen-space coordinate for the mesh at the given uv coordinate.
161172
Point2D<double> evaluate(double u, double v) const
162173
{
163174
double patch_size_u = 1.0 / m_NumPatchesX;

PhotoshopAPI/src/Core/Geometry/Mesh.h

+20-7
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
#include <vector>
88
#include <memory>
99
#include <cmath>
10+
#include <span>
1011

1112
#include "BoundingBox.h"
1213
#include "MeshOperations.h"
1314

1415
#include <Eigen/Dense>
15-
16-
#include <span>
16+
#include <fmt/format.h>
1717

1818

1919
PSAPI_NAMESPACE_BEGIN
@@ -387,7 +387,7 @@ namespace Geometry
387387
for (size_t face_index : face_indices)
388388
{
389389
Face<T, 4> face = m_Faces[face_index];
390-
390+
391391
// Check if the position is within this face, we first check based on bbox as that is as faster operation
392392
// for rejecting false positives
393393
const auto& face_bbox = face.bbox();
@@ -417,9 +417,9 @@ namespace Geometry
417417
return Point2D<double>(-1.0, -1.0); // No valid UV coordinate found
418418
}
419419

420-
BoundingBox<T> bbox() const noexcept
421-
{
422-
return m_BoundingBox;
420+
BoundingBox<T> bbox() const noexcept
421+
{
422+
return m_BoundingBox;
423423
}
424424

425425
private:
@@ -432,14 +432,27 @@ namespace Geometry
432432
/// Initialize the mesh for a given number of vertices
433433
void initialize_mesh(
434434
const std::vector<Vertex<T>>& vertices,
435-
size_t x_divisions,
435+
size_t x_divisions,
436436
size_t y_divisions
437437
)
438438
{
439439
PSAPI_PROFILE_FUNCTION();
440440
m_Vertices = vertices;
441441
m_BoundingBox = BoundingBox<T>::compute(m_Vertices);
442442

443+
// Our octree would fail due to floating point precision issues as the mesh approaches closer to .01 in size
444+
// hence the failure condition.
445+
if (m_BoundingBox.size().x < 1e-2 || m_BoundingBox.size().y < 1e-2)
446+
{
447+
throw std::runtime_error(
448+
fmt::format(
449+
"Tried to construct the mesh with vertices that are less than 1e-2 (0.01) across one of the axis. " \
450+
"Trying to construct this mesh would cause the Octree calculation to fail. If called from the context " \
451+
"of a layer this is likely a mistake in the transformation. The bounding box of the vertices is [{}, {}]",
452+
m_BoundingBox.size().x, m_BoundingBox.size().y
453+
));
454+
}
455+
443456
m_Faces.reserve((x_divisions - 1) * (y_divisions - 1));
444457

445458
// Generate the faces and populate the vertex indices.

PhotoshopAPI/src/Core/Geometry/MeshOperations.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ namespace Geometry
319319
/// Compute a 3x3 homography transformation matrix based on the given source and destination quad
320320
///
321321
/// \param source_points The points from which we want to compute the homography
322-
/// \param destination points The points to which we want to transform.
322+
/// \param destination_points The points to which we want to transform.
323323
template<typename T>
324324
Eigen::Matrix3d create_homography_matrix(const std::array<Point2D<T>, 4>& source_points, const std::array<Point2D<T>, 4>& destination_points)
325325
{

PhotoshopAPI/src/Core/Render/Composite.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ namespace Composite
155155
/// The canvas onto which to draw the layer with the given kernel.
156156
/// \param layer
157157
/// The layer to compose on top of the canvas
158-
/// \param kernel
158+
/// \param kernel_func
159159
/// The kernel to apply to the color channels of the image (alpha is handled separately)
160160
///
161161
/// \throws std::invalid_argument If the canvas has a mask channel.

PhotoshopAPI/src/Core/Struct/DescriptorStructure.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ namespace Descriptors
328328
/// \param document The File object to write to.
329329
/// \param key The key to write to disk, will be ignored if writeKey is set to false
330330
/// \param value The value you intend to write to disk, will write the child items as well if present
331-
/// \param readKey Whether to write the key to disk or discard it (such as with lists), this does not propagate to any child
331+
/// \param writeKey Whether to write the key to disk or discard it (such as with lists), this does not propagate to any child
332332
/// nodes and only applies to the given node
333333
inline void WriteDescriptor(File& document, const std::string& key, const std::unique_ptr<DescriptorBase>& value, bool writeKey = true)
334334
{

PhotoshopAPI/src/Core/Struct/ResourceBlock.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ struct ResolutionInfoBlock : public ResourceBlock
6666
/// Edit -> Assign Profile which just visually adjusts the colours but does not convert the colours
6767
struct ICCProfileBlock : public ResourceBlock
6868
{
69-
/// Stores the raw bytes of an ICC profile such as the ones found on C:\Windows\System32\spool\drivers\color for Windows.
69+
/// Stores the raw bytes of an ICC profile such as the ones found on C:/Windows/System32/spool/drivers/color for Windows.
7070
/// This does not include the padding bytes which are explicitly written on write
7171
std::vector<uint8_t> m_RawICCProfile;
7272

PhotoshopAPI/src/Core/Warp/SmartObjectWarp.h

+40-20
Original file line numberDiff line numberDiff line change
@@ -128,42 +128,62 @@ namespace SmartObject
128128
// We then bilinearly sample the source image to avoid artifacts from nearest
129129
// neighbour sampling.
130130

131-
bool sampled = false;
132-
float accumulated_color = 0;
133-
134-
for (size_t sy = 0; sy < supersample_resolution; ++sy)
131+
// Simplify the code at compile time already if not supersampling
132+
if constexpr (supersample_resolution == 1)
135133
{
136-
double subpixel_y = y + static_cast<double>(sy) / supersample_resolution;
134+
auto position = Geometry::Point2D<double>(static_cast<double>(x), static_cast<double>(y));
135+
auto uv = warp_mesh.uv_coordinate(position);
137136

138-
for (size_t sx = 0; sx < supersample_resolution; ++sx)
137+
// If the uv coordinate is outside of the image we dont bother with it.
138+
// We can check against the exact -1.0f here as that is what we return
139+
if (uv != failure_condition)
139140
{
140-
double subpixel_x = x + static_cast<double>(sx) / supersample_resolution;
141+
size_t idx = y * buffer.width + x;
142+
buffer.buffer[idx] = image.template sample_bilinear_uv<double>(uv);
143+
}
144+
}
145+
else
146+
{
147+
bool sampled = false;
148+
float accumulated_color = 0;
141149

142-
auto position = Geometry::Point2D<double>(subpixel_x, subpixel_y);
143-
auto uv = warp_mesh.uv_coordinate(position);
150+
// Perform the supersampling steps
151+
for (size_t sy = 0; sy < supersample_resolution; ++sy)
152+
{
153+
double subpixel_y = y + static_cast<double>(sy) / supersample_resolution;
144154

145-
// If the uv coordinate is outside of the image we dont bother with it.
146-
// We can check against the exact -1.0f here as that is what we return
147-
if (uv != failure_condition)
155+
for (size_t sx = 0; sx < supersample_resolution; ++sx)
148156
{
149-
sampled = true;
150-
accumulated_color += image.template sample_bilinear_uv<double>(uv);
157+
double subpixel_x = x + static_cast<double>(sx) / supersample_resolution;
158+
159+
auto position = Geometry::Point2D<double>(subpixel_x, subpixel_y);
160+
auto uv = warp_mesh.uv_coordinate(position);
161+
162+
// If the uv coordinate is outside of the image we dont bother with it.
163+
// We can check against the exact -1.0f here as that is what we return
164+
if (uv != failure_condition)
165+
{
166+
sampled = true;
167+
accumulated_color += image.template sample_bilinear_uv<double>(uv);
168+
}
151169
}
152170
}
153-
}
154171

155-
if (sampled)
156-
{
157-
T final_value = static_cast<T>(std::clamp<double>(accumulated_color / total_supersamples, 0.0, static_cast<double>(max_t)));
172+
if (sampled)
173+
{
174+
T final_value = static_cast<T>(std::clamp<double>(accumulated_color / total_supersamples, 0.0, static_cast<double>(max_t)));
158175

159-
size_t idx = y * buffer.width + x;
160-
buffer.buffer[idx] = final_value;
176+
size_t idx = y * buffer.width + x;
177+
buffer.buffer[idx] = final_value;
178+
}
161179
}
162180
}
163181
});
164182
}
165183

166184

185+
186+
167187
/// Apply the warp by warping the `image` into the `buffer` using the locally stored warp description.
168188
/// The `buffer` passed should match the general resolution of the warp points. So if e.g. the warp points
169189
/// are from { 0 - 4000, 0 - 2000 } the `buffer` parameter should cover these.

PhotoshopAPI/src/LayeredFile/LayerTypes/GroupLayer.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct GroupLayer final: public Layer<T>
4040
/// @}
4141

4242
/// \brief Constructs a GroupLayer with the given layer parameters and collapse state.
43-
/// \param layerParameters The parameters for the group layer.
43+
/// \param parameters The parameters for the group layer.
4444
/// \param isCollapsed Specifies whether the group layer is initially collapsed.
4545
GroupLayer(Layer<T>::Params& parameters, bool isCollapsed = false)
4646
{
@@ -139,8 +139,6 @@ struct GroupLayer final: public Layer<T>
139139
/// This is part of the internal API and as a user you will likely never have to use
140140
/// this function
141141
///
142-
/// \param colorMode The color mode for the conversion.
143-
/// \param header The file header for the conversion.
144142
/// \return A tuple containing layerRecords and imageData.
145143
std::tuple<LayerRecord, ChannelImageData> to_photoshop() override
146144
{

PhotoshopAPI/src/LayeredFile/LayerTypes/ImageDataMixins.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,6 @@ struct ImageDataMixin
156156
///
157157
/// Each Layer type that implement ImageDataMixin must provide an implementation for evaluate_image_data().
158158
///
159-
/// \param document The document the layer is a part of, may be unused during evaluation.
160-
///
161159
/// \returns The evaluated image data for each channel
162160
virtual data_type evaluate_image_data() = 0;
163161

@@ -167,7 +165,7 @@ struct ImageDataMixin
167165
/// so a layer must take care to access these channels together. Similarly, a smart object must apply the warp first
168166
/// before getting the image data.
169167
///
170-
/// \param document The document the layer is a part of, may be unused during evaluation.
168+
/// \param _id The channel to evaluate
171169
///
172170
/// \returns The evaluated image data for each channel
173171
virtual std::vector<T> evaluate_channel(std::variant<int, Enum::ChannelID, Enum::ChannelIDInfo> _id) = 0;

0 commit comments

Comments
 (0)