PluginProbe
Sharing Image / 3.7
Sharing Image v3.7
3.10 trunk 2.0 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.17 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 3.0 3.1 3.2 3.3 All 29 releases
← All changes | classes/class-generator.php +338 -322 2.0.113.7 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * Poster generator class
3 + * Poster generator class.
4 4 *
5 5 * @package sharing-image
6 6 * @author Anton Lukin
7 7 */
@@ -16,227 +16,46 @@
16 16 die;
17 17 }
18 18
19 19 /**
20 - * Poster generator class
20 + * Generator class.
21 21 *
22 22 * @class Generator
23 23 */
24 24 class Generator {
25 25 /**
26 - * The instance of Settings class.
26 + * Check requred template values.
27 27 *
28 - * @var instance
29 - */
30 - private $settings;
31 -
32 - /**
33 - * Generator constructor.
34 - */
35 - public function __construct() {
36 - $this->settings = new Settings();
37 - }
38 -
39 - /**
40 - * Autogenerate new poster using post data for preset fields.
28 + * @param array $template List of template settings.
41 29 *
42 - * @param integer $id Template id using for poster generator.
43 - * @param integer $post_id Post id.
44 - *
45 - * @return array|false New poster url or false on failure.
30 + * @return bool Whether all required values isset.
46 31 */
47 - public function autogenerate( $id, $post_id ) {
48 - // Get templates list from settings.
49 - $templates = $this->settings->get_templates();
32 + public static function check_required( $template ) {
33 + $required = array( 'width', 'height', 'fill' );
50 34
51 - if ( ! isset( $templates[ $id ] ) ) {
52 - return false;
53 - }
35 + // Count intersected values.
36 + $prepared = count( self::prepare_args( $template, $required ) );
54 37
55 - $template = $this->generate_template( $templates[ $id ], $post_id );
56 -
57 - if ( ! $this->check_required( $template ) ) {
58 - return false;
38 + if ( count( $required ) === $prepared ) {
39 + return true;
59 40 }
60 41
61 - list( $path, $url ) = $this->get_upload_file();
62 -
63 - // Generate image and save it.
64 - $poster = $this->create_poster( $template, $path );
65 -
66 - if ( is_wp_error( $poster ) ) {
67 - return false;
68 - }
69 -
70 - $source = array(
71 - 'poster' => $url,
72 - 'width' => $template['width'],
73 - 'height' => $template['height'],
74 - );
75 -
76 - return $source;
42 + return false;
77 43 }
78 44
79 45 /**
80 - * Compose image using picker data.
81 - *
82 - * @param array $picker Picker data from metabox.
83 - *
84 - * @return array|WP_Error Poster url, width and height or WP_Error on failure.
85 - */
86 - public function compose( $picker ) {
87 - if ( ! isset( $picker['template'] ) ) {
88 - return new WP_Error( 'validate', esc_html__( 'Template id cannot be empty', 'sharing-image' ) );
89 - }
90 -
91 - $id = absint( $picker['template'] );
92 -
93 - // Get templates list from settings.
94 - $templates = $this->settings->get_templates();
95 -
96 - if ( ! isset( $templates[ $id ] ) ) {
97 - return new WP_Error( 'validate', esc_html__( 'Wrong template id', 'sharing-image' ) );
98 - }
99 -
100 - $fieldset = array();
101 -
102 - if ( isset( $picker['fieldset'][ $id ] ) ) {
103 - $fieldset = $picker['fieldset'][ $id ];
104 - }
105 -
106 - $template = $this->prepare_template( $templates[ $id ], $fieldset );
107 -
108 - if ( ! $this->check_required( $template ) ) {
109 - return new WP_Error( 'generate', esc_html__( 'Wrong template settings', 'sharing-image' ) );
110 - }
111 -
112 - list( $path, $url ) = $this->get_upload_file();
113 -
114 - // Generate image and save it to given path.
115 - $poster = $this->create_poster( $template, $path );
116 -
117 - if ( is_wp_error( $poster ) ) {
118 - return $poster;
119 - }
120 -
121 - $source = array(
122 - 'poster' => $url,
123 - 'width' => $template['width'],
124 - 'height' => $template['height'],
125 - );
126 -
127 - return $source;
128 - }
129 -
130 - /**
131 - * Show image for settings page using template data.
132 - *
133 - * @param array $template Templates data from settings page.
134 - * @param int $index Template index.
135 - *
136 - * @return void|WP_Error WP_Error on failure.
137 - */
138 - public function show( $template, $index ) {
139 - $template = $this->prepare_template( $template, null, $index );
140 -
141 - if ( ! $this->check_required( $template ) ) {
142 - return new WP_Error( 'generate', esc_html__( 'Wrong template settings', 'sharing-image' ) );
143 - }
144 -
145 - // Generate image and show it immediately.
146 - $poster = $this->create_poster( $template );
147 -
148 - if ( is_wp_error( $poster ) ) {
149 - return $poster;
150 - }
151 -
152 - exit; // It's ok to exit here. Just cause we show an image above.
153 - }
154 -
155 - /**
156 - * Save image for settings page using template data.
157 - *
158 - * @param array $template Templates data from settings page.
159 - * @param int $index Template index.
160 - *
161 - * @return string|WP_Error Generated poster url or WP_Error on failure.
162 - */
163 - public function save( $template, $index ) {
164 - $template = $this->prepare_template( $template, null, $index );
165 -
166 - if ( ! $this->check_required( $template ) ) {
167 - return new WP_Error( 'generate', esc_html__( 'Wrong template settings', 'sharing-image' ) );
168 - }
169 -
170 - list( $path, $url ) = $this->get_upload_file();
171 -
172 - // Generate image and save it.
173 - $poster = $this->create_poster( $template, $path );
174 -
175 - if ( is_wp_error( $poster ) ) {
176 - return $poster;
177 - }
178 -
179 - return $url;
180 - }
181 -
182 - /**
183 - * Update template with post data for preset fields.
184 - *
185 - * @param array $template Templates data from settings page.
186 - * @param int $post_id Post id.
187 - *
188 - * @return array List of template data.
189 - */
190 - private function generate_template( $template, $post_id ) {
191 - $layers = array();
192 -
193 - if ( isset( $template['layers'] ) ) {
194 - $layers = $template['layers'];
195 - }
196 -
197 - $fieldset = array();
198 -
199 - foreach ( $layers as $i => $layer ) {
200 - if ( empty( $layer['type'] ) || 'text' !== $layer['type'] ) {
201 - continue;
202 - }
203 -
204 - if ( empty( $layer['dynamic'] ) || empty( $layer['preset'] ) ) {
205 - continue;
206 - }
207 -
208 - if ( 'title' === $layer['preset'] ) {
209 - $fieldset['captions'][ $i ] = get_the_title( $post_id );
210 - }
211 -
212 - if ( 'excerpt' === $layer['preset'] ) {
213 - $fieldset['captions'][ $i ] = get_the_excerpt( $post_id );
214 - }
215 - }
216 -
217 - $thumbnail_id = get_post_thumbnail_id( $post_id );
218 -
219 - if ( ! empty( $thumbnail_id ) ) {
220 - $fieldset['attachment'] = $thumbnail_id;
221 - }
222 -
223 - $template = $this->prepare_template( $template, $fieldset );
224 -
225 - return $template;
226 - }
227 -
228 - /**
229 46 * Prepare template before creating poster.
230 47 * Used to fill fieldset texts and background image.
231 48 *
232 - * @param array $template List of template data.
233 - * @param array $fieldset Optional. Fieldset data from picker.
234 - * @param integer $index Optional. Template index from editor.
49 + * @param array $template List of template data.
50 + * @param array $fieldset Optional. Fieldset data from widget.
51 + * @param string $index Optional. Template index from editor.
52 + * @param int $screen_id Optional. Post or term ID from admin screen.
53 + * @param string $context Optional. Screen ID context field. Can be settings, post or term.
235 54 *
236 55 * @return array List of template data.
237 56 */
238 - private function prepare_template( $template, $fieldset = array(), $index = null ) {
57 + public static function prepare_template( $template, $fieldset = array(), $index = null, $screen_id = 0, $context = 'settings' ) {
239 58 $layers = array();
240 59
241 60 if ( isset( $template['layers'] ) ) {
242 61 $layers = $template['layers'];
@@ -241,54 +60,40 @@
241 60 if ( isset( $template['layers'] ) ) {
242 61 $layers = $template['layers'];
243 62 }
244 63
245 - foreach ( $layers as $i => &$layer ) {
246 - if ( empty( $layer['type'] ) || 'text' !== $layer['type'] ) {
247 - continue;
64 + foreach ( $layers as $key => &$layer ) {
65 + if ( 'settings' === $context && ! empty( $template['debug'] ) ) {
66 + $layer['debug'] = true;
248 67 }
249 68
250 - if ( empty( $layer['dynamic'] ) ) {
69 + if ( empty( $layer['type'] ) || empty( $layer['dynamic'] ) ) {
251 70 continue;
252 71 }
253 72
254 - $layer['content'] = null;
73 + switch ( $layer['type'] ) {
74 + case 'image':
75 + $layer = self::prepare_image_layer( $layer, $fieldset, $key, $context );
76 + break;
255 77
256 - if ( isset( $layer['sample'] ) ) {
257 - $layer['content'] = $layer['sample'];
78 + case 'text':
79 + $layer = self::prepare_text_layer( $layer, $fieldset, $key, $context );
80 + break;
258 81 }
259 -
260 - if ( isset( $fieldset['captions'][ $i ] ) ) {
261 - $layer['content'] = $fieldset['captions'][ $i ];
262 - }
263 82 }
264 83
265 84 $template['layers'] = $layers;
266 85
267 - if ( 'dynamic' === $template['background'] ) {
268 - if ( null !== $index ) {
269 - $template['image'] = sprintf( SHARING_IMAGE_DIR . 'assets/images/%d.jpg', ( $index % 12 ) + 1 );
270 - }
271 -
272 - if ( ! empty( $fieldset['attachment'] ) ) {
273 - $template['image'] = get_attached_file( $fieldset['attachment'] );
274 - }
275 - }
276 -
277 - if ( 'permanent' === $template['background'] ) {
278 - if ( ! empty( $template['attachment'] ) ) {
279 - $template['image'] = get_attached_file( $template['attachment'] );
280 - }
281 - }
282 -
283 86 /**
284 87 * Filters template before generation.
285 88 *
286 - * @param array $template List of template data.
287 - * @param array $fieldset Fieldset data from picker.
288 - * @param integer $index Template index from editor.
89 + * @param array $template List of template data.
90 + * @param array $fieldset Fieldset data from widget or sidebars.
91 + * @param string $index Template index from editor.
92 + * @param int $screen_id Post or term ID from admin screen.
93 + * @param string $context Screen ID context field. Can be settings, post or term.
289 94 */
290 - return apply_filters( 'sharing_image_prepare_template', $template, $fieldset, $index );
95 + return apply_filters( 'sharing_image_prepare_template', $template, $fieldset, $index, $screen_id, $context );
291 96 }
292 97
293 98 /**
294 99 * Create poster using template data.
@@ -297,35 +102,30 @@
297 102 * @param string $path Optional. File path to save.
298 103 *
299 104 * @return void|WP_Error WP_Error on failure.
300 105 */
301 - private function create_poster( $template, $path = null ) {
106 + public static function create_poster( $template, $path = null ) {
302 107 try {
303 108 $poster = new PosterEditor();
304 109
305 110 // Set color canvas options.
306 - $options = array( 'color' => $template['fill'] );
111 + $options = array(
112 + 'color' => $template['fill'],
113 + 'opacity' => 0,
114 + );
307 115
308 116 // Create empty poster.
309 117 $poster->canvas( $template['width'], $template['height'], $options );
310 118
311 - // Recreate poster with image if exists.
312 - if ( ! empty( $template['image'] ) ) {
313 - $poster->make( $template['image'] )->fit( $template['width'], $template['height'] );
314 - }
315 -
316 119 if ( ! empty( $template['layers'] ) ) {
317 - $poster = $this->append_layers( $poster, $template['layers'] );
120 + $poster = self::append_layers( $poster, $template['layers'] );
318 121 }
319 122
320 - $settings = $this->settings;
321 -
322 - if ( null === $path ) {
323 - return $poster->show( $settings->get_file_format(), $settings->get_quality() );
123 + if ( is_null( $path ) ) {
124 + return $poster->show( Config::get_file_format(), Config::get_quality() );
324 125 }
325 126
326 - $poster->save( $path, $settings->get_quality() );
327 -
127 + $poster->save( $path, Config::get_quality() );
328 128 } catch ( Exception $e ) {
329 129 return new WP_Error( 'generate', $e->getMessage() );
330 130 }
331 131 }
@@ -330,8 +130,34 @@
330 130 }
331 131 }
332 132
333 133 /**
134 + * Get upload file path and url.
135 + *
136 + * @return array Server file path and url to uploaded image.
137 + */
138 + public static function get_upload_file() {
139 + // Get uploads directory url and path array.
140 + list( $path, $url ) = Config::get_upload_dir();
141 +
142 + // Create random file name with proper extension.
143 + $name = wp_unique_filename( $path, uniqid() . '.' . Config::get_file_format() );
144 +
145 + $file = array(
146 + trailingslashit( $path ) . $name,
147 + trailingslashit( $url ) . $name,
148 + );
149 +
150 + /**
151 + * Filters upload file path and url
152 + *
153 + * @param array $file Server file path and url to image.
154 + * @param string $name Unique file name.
155 + */
156 + return apply_filters( 'sharing_image_get_upload_file', $file, $name );
157 + }
158 +
159 + /**
334 160 * Append layers to image.
335 161 *
336 162 * @param PosterEditor $poster Instance of PosterEditor class.
337 163 * @param array $layers List of layers options.
@@ -337,10 +163,10 @@
337 163 * @param array $layers List of layers options.
338 164 *
339 165 * @return PosterEditor PosterEditor instance.
340 166 */
341 - private function append_layers( $poster, $layers ) {
342 - $layers = array_reverse( $layers );
167 + private static function append_layers( $poster, $layers ) {
168 + $boundary = array();
343 169
344 170 foreach ( $layers as $layer ) {
345 171 if ( empty( $layer['type'] ) ) {
346 172 continue;
@@ -347,21 +173,21 @@
347 173 }
348 174
349 175 switch ( $layer['type'] ) {
350 176 case 'filter':
351 - $poster = $this->draw_filter( $poster, $layer );
177 + $poster = self::draw_filter( $poster, $layer );
352 178 break;
353 179
354 180 case 'rectangle':
355 - $poster = $this->draw_rectangle( $poster, $layer );
181 + $poster = self::draw_rectangle( $poster, $layer, $boundary );
356 182 break;
357 183
358 - case 'text':
359 - $poster = $this->draw_text( $poster, $layer );
184 + case 'image':
185 + $poster = self::draw_image( $poster, $layer, $boundary );
360 186 break;
361 187
362 - case 'image':
363 - $poster = $this->draw_image( $poster, $layer );
188 + case 'text':
189 + $poster = self::draw_text( $poster, $layer, $boundary );
364 190 break;
365 191 }
366 192 }
367 193
@@ -368,8 +194,70 @@
368 194 return $poster;
369 195 }
370 196
371 197 /**
198 + * Prepare image layer template.
199 + *
200 + * @param array $layer Image layer data.
201 + * @param array $fieldset Fieldset data from widget or sidebar.
202 + * @param string $key Layer key.
203 + * @param string $context Screen ID context field. Can be settings, post or term.
204 + *
205 + * @return array List of image layer data.
206 + */
207 + private static function prepare_image_layer( $layer, $fieldset, $key, $context ) {
208 + if ( 'settings' !== $context ) {
209 + unset( $layer['attachment'] );
210 + }
211 +
212 + if ( ! empty( $fieldset[ $key ] ) ) {
213 + $layer['attachment'] = $fieldset[ $key ];
214 + }
215 +
216 + return $layer;
217 + }
218 +
219 + /**
220 + * Prepare text layer template.
221 + *
222 + * @param array $layer Text layer data.
223 + * @param array $fieldset Fieldset data from widget or sidebar.
224 + * @param string $key Layer key.
225 + * @param string $context Screen ID context field. Can be settings, post or term.
226 + *
227 + * @return array List of text layer data.
228 + */
229 + private static function prepare_text_layer( $layer, $fieldset, $key, $context ) {
230 + $layer['content'] = null;
231 +
232 + if ( isset( $layer['sample'] ) && 'settings' === $context ) {
233 + $layer['content'] = $layer['sample'];
234 + }
235 +
236 + if ( isset( $fieldset[ $key ] ) ) {
237 + $layer['content'] = $fieldset[ $key ];
238 + }
239 +
240 + if ( isset( $layer['textconvert'] ) && 'default' !== $layer['textconvert'] ) {
241 + if ( 'uppercase' === $layer['textconvert'] ) {
242 + if ( function_exists( 'mb_strtoupper' ) ) {
243 + $layer['content'] = mb_strtoupper( $layer['content'] );
244 + } else {
245 + $layer['content'] = strtoupper( $layer['content'] );
246 + }
247 + } elseif ( 'lowercase' === $layer['textconvert'] ) {
248 + if ( function_exists( 'mb_strtolower' ) ) {
249 + $layer['content'] = mb_strtolower( $layer['content'] );
250 + } else {
251 + $layer['content'] = strtolower( $layer['content'] );
252 + }
253 + }
254 + }
255 +
256 + return $layer;
257 + }
258 +
259 + /**
372 260 * Draw filter layer
373 261 *
374 262 * @param PosterEditor $poster Instance of PosterEditor class.
375 263 * @param array $layer Filter layer options.
@@ -375,9 +263,9 @@
375 263 * @param array $layer Filter layer options.
376 264 *
377 265 * @return PosterEditor PosterEditor instance.
378 266 */
379 - private function draw_filter( $poster, $layer ) {
267 + private static function draw_filter( $poster, $layer ) {
380 268 if ( ! empty( $layer['grayscale'] ) ) {
381 269 $poster->grayscale();
382 270 }
383 271
@@ -402,20 +290,21 @@
402 290
403 291 /**
404 292 * Draw rectangle layer.
405 293 *
406 - * @param PosterEditor $poster Instance of PosterEditor class.
407 - * @param array $layer Rectangle layer options.
294 + * @param PosterEditor $poster Instance of PosterEditor class.
295 + * @param array $layer Rectangle layer options.
296 + * @param array $boundary Optional. List of previous layer boundaries.
408 297 *
409 298 * @return PosterEditor PosterEditor instance.
410 299 */
411 - private function draw_rectangle( $poster, $layer ) {
300 + private static function draw_rectangle( $poster, $layer, &$boundary = array() ) {
412 301 // Both x and y should be set.
413 302 if ( ! isset( $layer['x'], $layer['y'] ) ) {
414 303 return $poster;
415 304 }
416 305
417 - $args = $this->prepare_args( $layer, array( 'color', 'opacity', 'thickness' ) );
306 + $args = self::prepare_args( $layer, array( 'color', 'opacity', 'thickness' ) );
418 307
419 308 if ( ! empty( $layer['outline'] ) ) {
420 309 $args['outline'] = true;
421 310 }
@@ -420,18 +309,27 @@
420 309 $args['outline'] = true;
421 310 }
422 311
423 312 if ( ! isset( $layer['width'] ) ) {
424 - $layer['width'] = 0;
313 + $layer['width'] = 1;
425 314 }
426 315
427 316 if ( ! isset( $layer['height'] ) ) {
428 - $layer['height'] = 0;
317 + $layer['height'] = 1;
429 318 }
430 319
320 + // Update layer position and dimensions.
321 + $layer = self::update_layer_position( $layer, $boundary );
322 + $layer = self::update_layer_dimensions( $layer, $poster );
323 +
431 324 // Draw rectangle.
432 325 $poster->rectangle( $layer['x'], $layer['y'], $layer['width'], $layer['height'], $args );
433 326
327 + // Set boundary from layer dimensions.
328 + foreach ( array( 'x', 'y', 'width', 'height' ) as $param ) {
329 + $boundary[ $param ] = $layer[ $param ];
330 + }
331 +
434 332 return $poster;
435 333 }
436 334
437 335 /**
@@ -436,15 +334,15 @@
436 334
437 335 /**
438 336 * Draw image layer
439 337 *
440 - * @param PosterEditor $poster Instance of PosterEditor class.
441 - * @param object $layer Option name.
338 + * @param PosterEditor $poster Instance of PosterEditor class.
339 + * @param array $layer Image layer options.
340 + * @param array $boundary Optional. List of previous layer boundaries.
442 341 *
443 342 * @return PosterEditor PosterEditor instance.
444 343 */
445 - private function draw_image( $poster, $layer ) {
446 - // Attachment id is required.
344 + private static function draw_image( $poster, $layer, &$boundary = array() ) {
447 345 if ( ! isset( $layer['attachment'] ) ) {
448 346 return $poster;
449 347 }
450 348
@@ -449,45 +347,65 @@
449 347 }
450 348
451 349 $image = new PosterEditor();
452 350
453 - // Prepare common layer args.
454 - $args = $this->prepare_args( $layer, array( 'x', 'y' ) );
351 + // Update layer position and dimensions.
352 + $layer = self::update_layer_position( $layer, $boundary );
353 + $layer = self::update_layer_dimensions( $layer, $poster );
455 354
456 - // Create new editor instance by attachment id.
457 - $attachment = $image->make( get_attached_file( $layer['attachment'] ) );
355 + $args = self::prepare_args( $layer, array( 'x', 'y', 'opacity' ) );
458 356
459 - if ( isset( $layer['width'], $layer['height'] ) ) {
460 - return $poster->insert( $attachment->resize( $layer['width'], $layer['height'] ), $args );
461 - }
357 + // Try to get file from attachment id.
358 + $file = get_attached_file( $layer['attachment'] );
462 359
463 - if ( ! isset( $layer['width'] ) ) {
464 - $layer['width'] = null;
360 + if ( empty( $file ) ) {
361 + return $poster;
465 362 }
466 363
467 - if ( ! isset( $layer['height'] ) ) {
468 - $layer['height'] = null;
469 - }
364 + // Create new editor instance by attachment id.
365 + $attachment = $image->make( $file );
470 366
471 - return $poster->insert( $attachment->downsize( $layer['width'], $layer['height'] ), $args );
367 + return $poster->insert( self::resize_attachment( $attachment, $layer ), $args, $boundary );
472 368 }
473 369
474 370 /**
475 371 * Draw text layer.
476 372 *
477 - * @param PosterEditor $poster Instance of PosterEditor class.
478 - * @param array $layer Rectangle layer options.
373 + * @param PosterEditor $poster Instance of PosterEditor class.
374 + * @param array $layer Text layer options.
375 + * @param array $boundary Optional. List of previous layer boundaries.
479 376 *
480 377 * @return PosterEditor PosterEditor instance.
481 378 */
482 - private function draw_text( $poster, $layer ) {
483 - $args = $this->prepare_args( $layer, array( 'x', 'y', 'width', 'height', 'fontsize', 'color', 'lineheight', 'opacity', 'horizontal', 'vertical' ) );
379 + private static function draw_text( $poster, $layer, &$boundary = array() ) {
380 + $allowed = array(
381 + 'x',
382 + 'y',
383 + 'width',
384 + 'height',
385 + 'fontsize',
386 + 'color',
387 + 'lineheight',
388 + 'opacity',
389 + 'horizontal',
390 + 'vertical',
391 + 'debug',
392 + );
484 393
394 + // Update layer position and dimensions.
395 + $layer = self::update_layer_position( $layer, $boundary );
396 + $layer = self::update_layer_dimensions( $layer, $poster );
397 +
398 + // Prepare common layer args.
399 + $args = self::prepare_args( $layer, $allowed );
400 +
485 401 // Try to set font file by name or attachment path.
486 - $args['fontpath'] = $this->get_fontpath( $layer );
402 + $args['fontpath'] = self::get_fontpath( $layer );
487 403
404 + $boundary = self::set_empty_boundary( $args );
405 +
488 406 if ( ! empty( $layer['content'] ) ) {
489 - $poster->text( $layer['content'], $args );
407 + $poster->text( $layer['content'], $args, $boundary );
490 408 }
491 409
492 410 return $poster;
493 411 }
@@ -492,8 +410,80 @@
492 410 return $poster;
493 411 }
494 412
495 413 /**
414 + * Set empty boundary list to reset boundary for empty layers.
415 + *
416 + * @since 3.0
417 + *
418 + * @param array $args List of common layer args.
419 + */
420 + private static function set_empty_boundary( $args ) {
421 + $boundary = array(
422 + 'x' => 0,
423 + 'y' => 0,
424 + 'width' => 0,
425 + 'height' => 0,
426 + );
427 +
428 + if ( isset( $args['x'] ) ) {
429 + $boundary['x'] = $args['x'];
430 + }
431 +
432 + if ( isset( $args['y'] ) ) {
433 + $boundary['y'] = $args['y'];
434 + }
435 +
436 + return $boundary;
437 + }
438 +
439 + /**
440 + * Smart resizing of image layer attachment according to selected options.
441 + *
442 + * @param PosterEditor $attachment Instance of PosterEditor class.
443 + * @param array $layer Layer settings.
444 + *
445 + * @return PosterEditor PosterEditor instance.
446 + */
447 + private static function resize_attachment( $attachment, $layer ) {
448 + $width = null;
449 +
450 + if ( isset( $layer['width'] ) ) {
451 + $width = $layer['width'];
452 + }
453 +
454 + $height = null;
455 +
456 + if ( isset( $layer['height'] ) ) {
457 + $height = $layer['height'];
458 + }
459 +
460 + // Reduce the image size if width or height dimensions are not specified.
461 + if ( is_null( $width ) || is_null( $height ) ) {
462 + return $attachment->downsize( $width, $height );
463 + }
464 +
465 + if ( 'top' === $layer['resize'] ) {
466 + return $attachment->fit( $width, $height, 'top' );
467 + }
468 +
469 + if ( 'bottom' === $layer['resize'] ) {
470 + return $attachment->fit( $width, $height, 'bottom' );
471 + }
472 +
473 + if ( 'ignore' === $layer['resize'] ) {
474 + return $attachment->resize( $width, $height );
475 + }
476 +
477 + if ( 'crop' === $layer['resize'] ) {
478 + return $attachment->crop( $width, $height );
479 + }
480 +
481 + // Fit center by default.
482 + return $attachment->fit( $width, $height );
483 + }
484 +
485 + /**
496 486 * Get font file path by layer data.
497 487 *
498 488 * @param array $layer Layer data.
499 489 * @param string $path Default file path.
@@ -499,11 +489,11 @@
499 489 * @param string $path Default file path.
500 490 *
501 491 * @return string Filtered path to font file.
502 492 */
503 - private function get_fontpath( $layer, $path = '' ) {
493 + private static function get_fontpath( $layer, $path = '' ) {
504 494 if ( isset( $layer['fontname'] ) ) {
505 - $path = sprintf( SHARING_IMAGE_DIR . 'assets/fonts/%s.ttf', $layer['fontname'] );
495 + $path = sprintf( SHARING_IMAGE_DIR . 'fonts/%s.ttf', $layer['fontname'] );
506 496 }
507 497
508 498 if ( isset( $layer['fontfile'] ) ) {
509 499 $path = get_attached_file( $layer['fontfile'] );
@@ -518,61 +508,87 @@
518 508 return apply_filters( 'sharing_image_get_fontpath', $path, $layer );
519 509 }
520 510
521 511 /**
522 - * Generate upload file path and url.
512 + * Update layer position using boundary settings.
523 513 *
524 - * @return array Server file path and url to uploaded image.
514 + * @param array $layer List of layer options.
515 + * @param array $boundary List of previous layer boundaries.
516 + *
517 + * @return array List of layer settings.
525 518 */
526 - private function get_upload_file() {
527 - // Get uploads directory url and path array.
528 - list( $path, $url ) = $this->settings->get_upload_dir();
519 + private static function update_layer_position( $layer, $boundary ) {
520 + if ( empty( $layer['boundary'] ) || 'absolute' === $layer['boundary'] ) {
521 + return $layer;
522 + }
529 523
530 - // Create random file name with proper extension.
531 - $name = wp_unique_filename( $path, uniqid() . '.' . $this->settings->get_file_format() );
524 + // Check if boundary sizes exist.
525 + foreach ( array( 'x', 'y', 'width', 'height' ) as $size ) {
526 + if ( ! isset( $boundary[ $size ] ) ) {
527 + return $layer;
528 + }
529 + }
532 530
533 - $file = array(
534 - trailingslashit( $path ) . $name,
535 - trailingslashit( $url ) . $name,
536 - );
531 + $x = $layer['x'] + $boundary['width'] + $boundary['x'];
532 + $y = $layer['y'] + $boundary['height'] + $boundary['y'];
537 533
538 - /**
539 - * Filters upload file path and url
540 - *
541 - * @param array $file Server file path and url to image.
542 - * @param string $name Unique file name.
543 - */
544 - return apply_filters( 'sharing_image_get_upload_file', $file, $name );
534 + switch ( $layer['boundary'] ) {
535 + case 'horizontally':
536 + $layer['x'] = $x;
537 + break;
538 +
539 + case 'vertically':
540 + $layer['y'] = $y;
541 + break;
542 +
543 + default:
544 + $layer['x'] = $x;
545 + $layer['y'] = $y;
546 + }
547 +
548 + return $layer;
545 549 }
546 550
547 551 /**
548 - * Prepare args and remove not-allowed keys.
552 + * Update layer sizes for negative dimensions.
549 553 *
550 - * @param array $args List of source arguments.
551 - * @param array $allowed List of allowed keys.
554 + * @param array $layer List of layer options.
555 + * @param PosterEditor $poster Instance of PosterEditor class.
552 556 *
553 - * @return array List of prepared args.
557 + * @return array List of layer settings.
554 558 */
555 - private function prepare_args( $args, $allowed ) {
556 - return wp_array_slice_assoc( $args, $allowed );
559 + private static function update_layer_dimensions( $layer, $poster ) {
560 + if ( ! isset( $layer['width'] ) ) {
561 + $layer['width'] = 0;
562 + }
563 +
564 + if ( ! isset( $layer['height'] ) ) {
565 + $layer['height'] = 0;
566 + }
567 +
568 + $width = absint( $poster->width() );
569 +
570 + if ( $layer['width'] <= 0 ) {
571 + $layer['width'] = $width + $layer['width'] - $layer['x'];
572 + }
573 +
574 + $height = absint( $poster->height() );
575 +
576 + if ( $layer['height'] <= 0 ) {
577 + $layer['height'] = $height + $layer['height'] - $layer['y'];
578 + }
579 +
580 + return $layer;
557 581 }
558 582
559 583 /**
560 - * Check requred template values.
584 + * Prepare args and remove not-allowed keys.
561 585 *
562 - * @param array $template List of template settings.
586 + * @param array $args List of source arguments.
587 + * @param array $allowed List of allowed keys.
563 588 *
564 - * @return bool Whether all required values isset.
589 + * @return array List of prepared args.
565 590 */
566 - private function check_required( $template ) {
567 - $required = array( 'width', 'height', 'fill' );
568 -
569 - // Count intersected values.
570 - $prepared = count( $this->prepare_args( $template, $required ) );
571 -
572 - if ( count( $required ) === $prepared ) {
573 - return true;
574 - }
575 -
576 - return false;
591 + private static function prepare_args( $args, $allowed ) {
592 + return wp_array_slice_assoc( $args, $allowed );
577 593 }
578 594 }