MagickCore 7.1.1
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
decorate.c
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% DDDD EEEEE CCCC OOO RRRR AAA TTTTT EEEEE %
7% D D E C O O R R A A T E %
8% D D EEE C O O RRRR AAAAA T EEE %
9% D D E C O O R R A A T E %
10% DDDD EEEEE CCCC OOO R R A A T EEEEE %
11% %
12% %
13% MagickCore Image Decoration Methods %
14% %
15% Software Design %
16% Cristy %
17% July 1992 %
18% %
19% %
20% Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
21% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% https://imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "MagickCore/studio.h"
44#include "MagickCore/cache-view.h"
45#include "MagickCore/color-private.h"
46#include "MagickCore/colorspace-private.h"
47#include "MagickCore/composite.h"
48#include "MagickCore/decorate.h"
49#include "MagickCore/exception.h"
50#include "MagickCore/exception-private.h"
51#include "MagickCore/image.h"
52#include "MagickCore/memory_.h"
53#include "MagickCore/monitor.h"
54#include "MagickCore/monitor-private.h"
55#include "MagickCore/pixel-accessor.h"
56#include "MagickCore/quantum.h"
57#include "MagickCore/quantum-private.h"
58#include "MagickCore/resource_.h"
59#include "MagickCore/thread-private.h"
60#include "MagickCore/transform.h"
61
62/*
63 Define declarations.
64*/
65#define AccentuateModulate ScaleCharToQuantum(80)
66#define HighlightModulate ScaleCharToQuantum(125)
67#define ShadowModulate ScaleCharToQuantum(135)
68#define DepthModulate ScaleCharToQuantum(185)
69#define TroughModulate ScaleCharToQuantum(110)
70
71/*
72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73% %
74% %
75% %
76% B o r d e r I m a g e %
77% %
78% %
79% %
80%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81%
82% BorderImage() surrounds the image with a border of the color defined by
83% the bordercolor member of the image structure. The width and height
84% of the border are defined by the corresponding members of the border_info
85% structure.
86%
87% The format of the BorderImage method is:
88%
89% Image *BorderImage(const Image *image,const RectangleInfo *border_info,
90% const CompositeOperator compose,ExceptionInfo *exception)
91%
92% A description of each parameter follows:
93%
94% o image: the image.
95%
96% o border_info: define the width and height of the border.
97%
98% o compose: the composite operator.
99%
100% o exception: return any errors or warnings in this structure.
101%
102*/
103MagickExport Image *BorderImage(const Image *image,
104 const RectangleInfo *border_info,const CompositeOperator compose,
105 ExceptionInfo *exception)
106{
107 Image
108 *border_image,
109 *clone_image;
110
112 frame_info;
113
114 assert(image != (const Image *) NULL);
115 assert(image->signature == MagickCoreSignature);
116 assert(border_info != (RectangleInfo *) NULL);
117 if (IsEventLogging() != MagickFalse)
118 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
119 frame_info.width=image->columns+(border_info->width << 1);
120 frame_info.height=image->rows+(border_info->height << 1);
121 frame_info.x=(ssize_t) border_info->width;
122 frame_info.y=(ssize_t) border_info->height;
123 frame_info.inner_bevel=0;
124 frame_info.outer_bevel=0;
125 clone_image=CloneImage(image,0,0,MagickTrue,exception);
126 if (clone_image == (Image *) NULL)
127 return((Image *) NULL);
128 clone_image->matte_color=image->border_color;
129 border_image=FrameImage(clone_image,&frame_info,compose,exception);
130 clone_image=DestroyImage(clone_image);
131 if (border_image != (Image *) NULL)
132 border_image->matte_color=image->matte_color;
133 return(border_image);
134}
135
136/*
137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138% %
139% %
140% %
141% F r a m e I m a g e %
142% %
143% %
144% %
145%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146%
147% FrameImage() adds a simulated three-dimensional border around the image.
148% The color of the border is defined by the matte_color member of image.
149% Members width and height of frame_info specify the border width of the
150% vertical and horizontal sides of the frame. Members inner and outer
151% indicate the width of the inner and outer shadows of the frame.
152%
153% The format of the FrameImage method is:
154%
155% Image *FrameImage(const Image *image,const FrameInfo *frame_info,
156% const CompositeOperator compose,ExceptionInfo *exception)
157%
158% A description of each parameter follows:
159%
160% o image: the image.
161%
162% o frame_info: Define the width and height of the frame and its bevels.
163%
164% o compose: the composite operator.
165%
166% o exception: return any errors or warnings in this structure.
167%
168*/
169MagickExport Image *FrameImage(const Image *image,const FrameInfo *frame_info,
170 const CompositeOperator compose,ExceptionInfo *exception)
171{
172#define FrameImageTag "Frame/Image"
173
175 *image_view,
176 *frame_view;
177
178 Image
179 *frame_image;
180
181 MagickBooleanType
182 status;
183
184 MagickOffsetType
185 progress;
186
188 accentuate,
189 highlight,
190 matte,
191 shadow,
192 trough;
193
194 size_t
195 bevel_width,
196 height;
197
198 ssize_t
199 x_offset,
200 y,
201 y_offset;
202
203 /*
204 Check frame geometry.
205 */
206 assert(image != (Image *) NULL);
207 assert(image->signature == MagickCoreSignature);
208 assert(frame_info != (FrameInfo *) NULL);
209 if (IsEventLogging() != MagickFalse)
210 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
211 if ((frame_info->outer_bevel < 0) || (frame_info->inner_bevel < 0))
212 ThrowImageException(OptionError,"FrameIsLessThanImageSize");
213 bevel_width=(size_t) (frame_info->outer_bevel+frame_info->inner_bevel);
214 x_offset=(ssize_t) frame_info->width-frame_info->x-(ssize_t) bevel_width;
215 y_offset=(ssize_t) frame_info->height-frame_info->y-(ssize_t) bevel_width;
216 if ((x_offset < (ssize_t) image->columns) ||
217 (y_offset < (ssize_t) image->rows))
218 ThrowImageException(OptionError,"FrameIsLessThanImageSize");
219 /*
220 Initialize framed image attributes.
221 */
222 frame_image=CloneImage(image,frame_info->width,frame_info->height,MagickTrue,
223 exception);
224 if (frame_image == (Image *) NULL)
225 return((Image *) NULL);
226 if (SetImageStorageClass(frame_image,DirectClass,exception) == MagickFalse)
227 {
228 frame_image=DestroyImage(frame_image);
229 return((Image *) NULL);
230 }
231 if ((IsPixelInfoGray(&frame_image->border_color) == MagickFalse) &&
232 (IsGrayColorspace(frame_image->colorspace) != MagickFalse))
233 (void) SetImageColorspace(frame_image,sRGBColorspace,exception);
234 if ((frame_image->matte_color.alpha_trait != UndefinedPixelTrait) &&
235 (frame_image->alpha_trait == UndefinedPixelTrait))
236 (void) SetImageAlpha(frame_image,OpaqueAlpha,exception);
237 frame_image->page=image->page;
238 if ((image->page.width != 0) && (image->page.height != 0))
239 {
240 frame_image->page.width+=frame_image->columns-image->columns;
241 frame_image->page.height+=frame_image->rows-image->rows;
242 }
243 /*
244 Initialize 3D effects color.
245 */
246 matte=image->matte_color;
247 accentuate=matte;
248 accentuate.red=(QuantumScale*(((double) QuantumRange-(double)
249 AccentuateModulate)*matte.red+((double) QuantumRange*(double)
250 AccentuateModulate)));
251 accentuate.green=(QuantumScale*(((double) QuantumRange-(double)
252 AccentuateModulate)*matte.green+((double) QuantumRange*(double)
253 AccentuateModulate)));
254 accentuate.blue=(QuantumScale*(((double) QuantumRange-(double)
255 AccentuateModulate)*matte.blue+((double) QuantumRange*(double)
256 AccentuateModulate)));
257 accentuate.black=(QuantumScale*(((double) QuantumRange-(double)
258 AccentuateModulate)*matte.black+((double) QuantumRange*(double)
259 AccentuateModulate)));
260 accentuate.alpha=matte.alpha;
261 highlight=matte;
262 highlight.red=(QuantumScale*(((double) QuantumRange-(double)
263 HighlightModulate)*matte.red+((double) QuantumRange*(double)
264 HighlightModulate)));
265 highlight.green=(QuantumScale*(((double) QuantumRange-(double)
266 HighlightModulate)*matte.green+((double) QuantumRange*(double)
267 HighlightModulate)));
268 highlight.blue=(QuantumScale*(((double) QuantumRange-(double)
269 HighlightModulate)*matte.blue+((double) QuantumRange*(double)
270 HighlightModulate)));
271 highlight.black=(QuantumScale*(((double) QuantumRange-(double)
272 HighlightModulate)*matte.black+((double) QuantumRange*(double)
273 HighlightModulate)));
274 highlight.alpha=matte.alpha;
275 shadow=matte;
276 shadow.red=QuantumScale*matte.red*(double) ShadowModulate;
277 shadow.green=QuantumScale*matte.green*(double) ShadowModulate;
278 shadow.blue=QuantumScale*matte.blue*(double) ShadowModulate;
279 shadow.black=QuantumScale*matte.black*(double) ShadowModulate;
280 shadow.alpha=matte.alpha;
281 trough=matte;
282 trough.red=QuantumScale*matte.red*(double) TroughModulate;
283 trough.green=QuantumScale*matte.green*(double) TroughModulate;
284 trough.blue=QuantumScale*matte.blue*(double) TroughModulate;
285 trough.black=QuantumScale*matte.black*(double) TroughModulate;
286 trough.alpha=matte.alpha;
287 status=MagickTrue;
288 progress=0;
289 image_view=AcquireVirtualCacheView(image,exception);
290 frame_view=AcquireAuthenticCacheView(frame_image,exception);
291 height=(size_t) (frame_info->outer_bevel+(frame_info->y-(ssize_t)
292 bevel_width)+frame_info->inner_bevel);
293 if (height != 0)
294 {
295 Quantum
296 *magick_restrict q;
297
298 ssize_t
299 x;
300
301 size_t
302 width;
303
304 /*
305 Draw top of ornamental border.
306 */
307 q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns,
308 height,exception);
309 if (q != (Quantum *) NULL)
310 {
311 /*
312 Draw top of ornamental border.
313 */
314 for (y=0; y < (ssize_t) frame_info->outer_bevel; y++)
315 {
316 for (x=0; x < ((ssize_t) frame_image->columns-y); x++)
317 {
318 if (x < y)
319 SetPixelViaPixelInfo(frame_image,&highlight,q);
320 else
321 SetPixelViaPixelInfo(frame_image,&accentuate,q);
322 q+=(ptrdiff_t) GetPixelChannels(frame_image);
323 }
324 for ( ; x < (ssize_t) frame_image->columns; x++)
325 {
326 SetPixelViaPixelInfo(frame_image,&shadow,q);
327 q+=(ptrdiff_t) GetPixelChannels(frame_image);
328 }
329 }
330 for (y=0; y < (frame_info->y-(ssize_t) bevel_width); y++)
331 {
332 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
333 {
334 SetPixelViaPixelInfo(frame_image,&highlight,q);
335 q+=(ptrdiff_t) GetPixelChannels(frame_image);
336 }
337 width=frame_image->columns-2*(size_t) frame_info->outer_bevel;
338 for (x=0; x < (ssize_t) width; x++)
339 {
340 SetPixelViaPixelInfo(frame_image,&matte,q);
341 q+=(ptrdiff_t) GetPixelChannels(frame_image);
342 }
343 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
344 {
345 SetPixelViaPixelInfo(frame_image,&shadow,q);
346 q+=(ptrdiff_t) GetPixelChannels(frame_image);
347 }
348 }
349 for (y=0; y < (ssize_t) frame_info->inner_bevel; y++)
350 {
351 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
352 {
353 SetPixelViaPixelInfo(frame_image,&highlight,q);
354 q+=(ptrdiff_t) GetPixelChannels(frame_image);
355 }
356 for (x=0; x < (frame_info->x-(ssize_t) bevel_width); x++)
357 {
358 SetPixelViaPixelInfo(frame_image,&matte,q);
359 q+=(ptrdiff_t) GetPixelChannels(frame_image);
360 }
361 width=image->columns+((size_t) frame_info->inner_bevel << 1)-
362 (size_t) y;
363 for (x=0; x < (ssize_t) width; x++)
364 {
365 if (x < y)
366 SetPixelViaPixelInfo(frame_image,&shadow,q);
367 else
368 SetPixelViaPixelInfo(frame_image,&trough,q);
369 q+=(ptrdiff_t) GetPixelChannels(frame_image);
370 }
371 for ( ; x < ((ssize_t) image->columns+2*frame_info->inner_bevel); x++)
372 {
373 SetPixelViaPixelInfo(frame_image,&highlight,q);
374 q+=(ptrdiff_t) GetPixelChannels(frame_image);
375 }
376 width=frame_info->width-(size_t) frame_info->x-
377 image->columns-bevel_width;
378 for (x=0; x < (ssize_t) width; x++)
379 {
380 SetPixelViaPixelInfo(frame_image,&matte,q);
381 q+=(ptrdiff_t) GetPixelChannels(frame_image);
382 }
383 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
384 {
385 SetPixelViaPixelInfo(frame_image,&shadow,q);
386 q+=(ptrdiff_t) GetPixelChannels(frame_image);
387 }
388 }
389 (void) SyncCacheViewAuthenticPixels(frame_view,exception);
390 }
391 }
392 /*
393 Draw sides of ornamental border.
394 */
395#if defined(MAGICKCORE_OPENMP_SUPPORT)
396 #pragma omp parallel for schedule(static) shared(progress,status) \
397 magick_number_threads(image,frame_image,image->rows,1)
398#endif
399 for (y=0; y < (ssize_t) image->rows; y++)
400 {
401 ssize_t
402 x;
403
404 Quantum
405 *magick_restrict q;
406
407 size_t
408 width;
409
410 /*
411 Initialize scanline with matte color.
412 */
413 if (status == MagickFalse)
414 continue;
415 q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y,
416 frame_image->columns,1,exception);
417 if (q == (Quantum *) NULL)
418 {
419 status=MagickFalse;
420 continue;
421 }
422 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
423 {
424 SetPixelViaPixelInfo(frame_image,&highlight,q);
425 q+=(ptrdiff_t) GetPixelChannels(frame_image);
426 }
427 for (x=0; x < (frame_info->x-(ssize_t) bevel_width); x++)
428 {
429 SetPixelViaPixelInfo(frame_image,&matte,q);
430 q+=(ptrdiff_t) GetPixelChannels(frame_image);
431 }
432 for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
433 {
434 SetPixelViaPixelInfo(frame_image,&shadow,q);
435 q+=(ptrdiff_t) GetPixelChannels(frame_image);
436 }
437 /*
438 Set frame interior pixels.
439 */
440 for (x=0; x < (ssize_t) image->columns; x++)
441 {
442 SetPixelViaPixelInfo(frame_image,&frame_image->border_color,q);
443 q+=(ptrdiff_t) GetPixelChannels(frame_image);
444 }
445 for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
446 {
447 SetPixelViaPixelInfo(frame_image,&highlight,q);
448 q+=(ptrdiff_t) GetPixelChannels(frame_image);
449 }
450 width=frame_info->width-(size_t) frame_info->x-image->columns-bevel_width;
451 for (x=0; x < (ssize_t) width; x++)
452 {
453 SetPixelViaPixelInfo(frame_image,&matte,q);
454 q+=(ptrdiff_t) GetPixelChannels(frame_image);
455 }
456 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
457 {
458 SetPixelViaPixelInfo(frame_image,&shadow,q);
459 q+=(ptrdiff_t) GetPixelChannels(frame_image);
460 }
461 if (SyncCacheViewAuthenticPixels(frame_view,exception) == MagickFalse)
462 status=MagickFalse;
463 if (image->progress_monitor != (MagickProgressMonitor) NULL)
464 {
465 MagickBooleanType
466 proceed;
467
468#if defined(MAGICKCORE_OPENMP_SUPPORT)
469 #pragma omp atomic
470#endif
471 progress++;
472 proceed=SetImageProgress(image,FrameImageTag,progress,image->rows);
473 if (proceed == MagickFalse)
474 status=MagickFalse;
475 }
476 }
477 height=(size_t) (frame_info->inner_bevel+(ssize_t) frame_info->height-
478 frame_info->y-(ssize_t) image->rows-(ssize_t) bevel_width+
479 frame_info->outer_bevel);
480 if (height != 0)
481 {
482 size_t
483 width;
484
485 ssize_t
486 x;
487
488 Quantum
489 *magick_restrict q;
490
491 /*
492 Draw bottom of ornamental border.
493 */
494 q=QueueCacheViewAuthenticPixels(frame_view,0,(ssize_t) (frame_image->rows-
495 height),frame_image->columns,height,exception);
496 if (q != (Quantum *) NULL)
497 {
498 /*
499 Draw bottom of ornamental border.
500 */
501 for (y=frame_info->inner_bevel-1; y >= 0; y--)
502 {
503 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
504 {
505 SetPixelViaPixelInfo(frame_image,&highlight,q);
506 q+=(ptrdiff_t) GetPixelChannels(frame_image);
507 }
508 for (x=0; x < (frame_info->x-(ssize_t) bevel_width); x++)
509 {
510 SetPixelViaPixelInfo(frame_image,&matte,q);
511 q+=(ptrdiff_t) GetPixelChannels(frame_image);
512 }
513 for (x=0; x < y; x++)
514 {
515 SetPixelViaPixelInfo(frame_image,&shadow,q);
516 q+=(ptrdiff_t) GetPixelChannels(frame_image);
517 }
518 for ( ; x < ((ssize_t) image->columns+2*frame_info->inner_bevel); x++)
519 {
520 if (x >= ((ssize_t) image->columns+2*frame_info->inner_bevel-y))
521 SetPixelViaPixelInfo(frame_image,&highlight,q);
522 else
523 SetPixelViaPixelInfo(frame_image,&accentuate,q);
524 q+=(ptrdiff_t) GetPixelChannels(frame_image);
525 }
526 width=(size_t) ((ssize_t) frame_info->width-frame_info->x-
527 (ssize_t) image->columns-(ssize_t) bevel_width);
528 for (x=0; x < (ssize_t) width; x++)
529 {
530 SetPixelViaPixelInfo(frame_image,&matte,q);
531 q+=(ptrdiff_t) GetPixelChannels(frame_image);
532 }
533 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
534 {
535 SetPixelViaPixelInfo(frame_image,&shadow,q);
536 q+=(ptrdiff_t) GetPixelChannels(frame_image);
537 }
538 }
539 height=(size_t) ((ssize_t) frame_info->height-frame_info->y-(ssize_t)
540 image->rows-(ssize_t) bevel_width);
541 for (y=0; y < (ssize_t) height; y++)
542 {
543 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
544 {
545 SetPixelViaPixelInfo(frame_image,&highlight,q);
546 q+=(ptrdiff_t) GetPixelChannels(frame_image);
547 }
548 width=(size_t) ((ssize_t) frame_image->columns-2*(ssize_t)
549 frame_info->outer_bevel);
550 for (x=0; x < (ssize_t) width; x++)
551 {
552 SetPixelViaPixelInfo(frame_image,&matte,q);
553 q+=(ptrdiff_t) GetPixelChannels(frame_image);
554 }
555 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
556 {
557 SetPixelViaPixelInfo(frame_image,&shadow,q);
558 q+=(ptrdiff_t) GetPixelChannels(frame_image);
559 }
560 }
561 for (y=frame_info->outer_bevel-1; y >= 0; y--)
562 {
563 for (x=0; x < y; x++)
564 {
565 SetPixelViaPixelInfo(frame_image,&highlight,q);
566 q+=(ptrdiff_t) GetPixelChannels(frame_image);
567 }
568 for ( ; x < (ssize_t) frame_image->columns; x++)
569 {
570 if (x >= ((ssize_t) frame_image->columns-y))
571 SetPixelViaPixelInfo(frame_image,&shadow,q);
572 else
573 SetPixelViaPixelInfo(frame_image,&trough,q);
574 q+=(ptrdiff_t) GetPixelChannels(frame_image);
575 }
576 }
577 (void) SyncCacheViewAuthenticPixels(frame_view,exception);
578 }
579 }
580 frame_view=DestroyCacheView(frame_view);
581 image_view=DestroyCacheView(image_view);
582 x_offset=frame_info->outer_bevel+(frame_info->x-(ssize_t) bevel_width)+
583 frame_info->inner_bevel;
584 y_offset=frame_info->outer_bevel+(frame_info->y-(ssize_t) bevel_width)+
585 frame_info->inner_bevel;
586 if (status != MagickFalse)
587 status=CompositeImage(frame_image,image,compose,MagickTrue,x_offset,
588 y_offset,exception);
589 if (status == MagickFalse)
590 frame_image=DestroyImage(frame_image);
591 return(frame_image);
592}
593
594/*
595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
596% %
597% %
598% %
599% R a i s e I m a g e %
600% %
601% %
602% %
603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
604%
605% RaiseImage() creates a simulated three-dimensional button-like effect
606% by lightening and darkening the edges of the image. Members width and
607% height of raise_info define the width of the vertical and horizontal
608% edge of the effect.
609%
610% The format of the RaiseImage method is:
611%
612% MagickBooleanType RaiseImage(const Image *image,
613% const RectangleInfo *raise_info,const MagickBooleanType raise,
614% ExceptionInfo *exception)
615%
616% A description of each parameter follows:
617%
618% o image: the image.
619%
620% o raise_info: Define the width and height of the raise area.
621%
622% o raise: A value other than zero creates a 3-D raise effect,
623% otherwise it has a lowered effect.
624%
625% o exception: return any errors or warnings in this structure.
626%
627*/
628MagickExport MagickBooleanType RaiseImage(Image *image,
629 const RectangleInfo *raise_info,const MagickBooleanType raise,
630 ExceptionInfo *exception)
631{
632#define AccentuateFactor ScaleCharToQuantum(135)
633#define HighlightFactor ScaleCharToQuantum(190)
634#define ShadowFactor ScaleCharToQuantum(190)
635#define RaiseImageTag "Raise/Image"
636#define TroughFactor ScaleCharToQuantum(135)
637
639 *image_view;
640
641 MagickBooleanType
642 status;
643
644 MagickOffsetType
645 progress;
646
647 Quantum
648 foreground,
649 background;
650
651 ssize_t
652 y;
653
654 assert(image != (Image *) NULL);
655 assert(image->signature == MagickCoreSignature);
656 assert(raise_info != (RectangleInfo *) NULL);
657 if (IsEventLogging() != MagickFalse)
658 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
659 if ((image->columns <= (raise_info->width << 1)) ||
660 (image->rows <= (raise_info->height << 1)))
661 ThrowBinaryException(OptionError,"ImageSizeMustExceedBevelWidth",
662 image->filename);
663 foreground=QuantumRange;
664 background=(Quantum) 0;
665 if (raise == MagickFalse)
666 {
667 foreground=(Quantum) 0;
668 background=QuantumRange;
669 }
670 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
671 return(MagickFalse);
672 /*
673 Raise image.
674 */
675 status=MagickTrue;
676 progress=0;
677 image_view=AcquireAuthenticCacheView(image,exception);
678#if defined(MAGICKCORE_OPENMP_SUPPORT)
679 #pragma omp parallel for schedule(static) shared(progress,status) \
680 magick_number_threads(image,image,raise_info->height,1)
681#endif
682 for (y=0; y < (ssize_t) raise_info->height; y++)
683 {
684 ssize_t
685 i,
686 x;
687
688 Quantum
689 *magick_restrict q;
690
691 if (status == MagickFalse)
692 continue;
693 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
694 if (q == (Quantum *) NULL)
695 {
696 status=MagickFalse;
697 continue;
698 }
699 for (x=0; x < y; x++)
700 {
701 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
702 {
703 PixelChannel channel = GetPixelChannelChannel(image,i);
704 PixelTrait traits = GetPixelChannelTraits(image,channel);
705 if ((traits & UpdatePixelTrait) == 0)
706 continue;
707 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*(double)
708 HighlightFactor+(double) foreground*((double) QuantumRange-(double)
709 HighlightFactor)));
710 }
711 q+=(ptrdiff_t) GetPixelChannels(image);
712 }
713 for ( ; x < ((ssize_t) image->columns-y); x++)
714 {
715 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
716 {
717 PixelChannel channel = GetPixelChannelChannel(image,i);
718 PixelTrait traits = GetPixelChannelTraits(image,channel);
719 if ((traits & UpdatePixelTrait) == 0)
720 continue;
721 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*(double)
722 AccentuateFactor+(double) foreground*((double) QuantumRange-(double)
723 AccentuateFactor)));
724 }
725 q+=(ptrdiff_t) GetPixelChannels(image);
726 }
727 for ( ; x < (ssize_t) image->columns; x++)
728 {
729 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
730 {
731 PixelChannel channel = GetPixelChannelChannel(image,i);
732 PixelTrait traits = GetPixelChannelTraits(image,channel);
733 if ((traits & UpdatePixelTrait) == 0)
734 continue;
735 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*(double) ShadowFactor+
736 (double) background*((double) QuantumRange-(double) ShadowFactor)));
737 }
738 q+=(ptrdiff_t) GetPixelChannels(image);
739 }
740 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
741 status=MagickFalse;
742 if (image->progress_monitor != (MagickProgressMonitor) NULL)
743 {
744 MagickBooleanType
745 proceed;
746
747#if defined(MAGICKCORE_OPENMP_SUPPORT)
748 #pragma omp atomic
749#endif
750 progress++;
751 proceed=SetImageProgress(image,RaiseImageTag,progress,image->rows);
752 if (proceed == MagickFalse)
753 status=MagickFalse;
754 }
755 }
756#if defined(MAGICKCORE_OPENMP_SUPPORT)
757 #pragma omp parallel for schedule(static) shared(progress,status) \
758 magick_number_threads(image,image,image->rows-2*raise_info->height,1)
759#endif
760 for (y=(ssize_t) raise_info->height; y < (ssize_t) (image->rows-raise_info->height); y++)
761 {
762 ssize_t
763 i,
764 x;
765
766 Quantum
767 *magick_restrict q;
768
769 if (status == MagickFalse)
770 continue;
771 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
772 if (q == (Quantum *) NULL)
773 {
774 status=MagickFalse;
775 continue;
776 }
777 for (x=0; x < (ssize_t) raise_info->width; x++)
778 {
779 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
780 {
781 PixelChannel channel = GetPixelChannelChannel(image,i);
782 PixelTrait traits = GetPixelChannelTraits(image,channel);
783 if ((traits & UpdatePixelTrait) == 0)
784 continue;
785 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*(double)
786 HighlightFactor+(double) foreground*((double) QuantumRange-(double)
787 HighlightFactor)));
788 }
789 q+=(ptrdiff_t) GetPixelChannels(image);
790 }
791 for ( ; x < (ssize_t) (image->columns-raise_info->width); x++)
792 q+=(ptrdiff_t) GetPixelChannels(image);
793 for ( ; x < (ssize_t) image->columns; x++)
794 {
795 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
796 {
797 PixelChannel channel = GetPixelChannelChannel(image,i);
798 PixelTrait traits = GetPixelChannelTraits(image,channel);
799 if ((traits & UpdatePixelTrait) == 0)
800 continue;
801 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*(double) ShadowFactor+
802 (double) background*((double) QuantumRange-(double) ShadowFactor)));
803 }
804 q+=(ptrdiff_t) GetPixelChannels(image);
805 }
806 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
807 status=MagickFalse;
808 if (image->progress_monitor != (MagickProgressMonitor) NULL)
809 {
810 MagickBooleanType
811 proceed;
812
813#if defined(MAGICKCORE_OPENMP_SUPPORT)
814 #pragma omp atomic
815#endif
816 progress++;
817 proceed=SetImageProgress(image,RaiseImageTag,progress,image->rows);
818 if (proceed == MagickFalse)
819 status=MagickFalse;
820 }
821 }
822#if defined(MAGICKCORE_OPENMP_SUPPORT)
823 #pragma omp parallel for schedule(static) shared(progress,status) \
824 magick_number_threads(image,image,image->rows-raise_info->height,1)
825#endif
826 for (y=(ssize_t) (image->rows-raise_info->height); y < (ssize_t) image->rows; y++)
827 {
828 ssize_t
829 i,
830 x;
831
832 Quantum
833 *magick_restrict q;
834
835 if (status == MagickFalse)
836 continue;
837 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
838 if (q == (Quantum *) NULL)
839 {
840 status=MagickFalse;
841 continue;
842 }
843 for (x=0; x < ((ssize_t) image->rows-y); x++)
844 {
845 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
846 {
847 PixelChannel channel = GetPixelChannelChannel(image,i);
848 PixelTrait traits = GetPixelChannelTraits(image,channel);
849 if ((traits & UpdatePixelTrait) == 0)
850 continue;
851 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*(double)
852 HighlightFactor+(double) foreground*((double) QuantumRange-
853 (double) HighlightFactor)));
854 }
855 q+=(ptrdiff_t) GetPixelChannels(image);
856 }
857 for ( ; x < ((ssize_t) image->columns-((ssize_t) image->rows-y)); x++)
858 {
859 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
860 {
861 PixelChannel channel = GetPixelChannelChannel(image,i);
862 PixelTrait traits = GetPixelChannelTraits(image,channel);
863 if ((traits & UpdatePixelTrait) == 0)
864 continue;
865 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*(double) TroughFactor+
866 (double) background*((double) QuantumRange-(double) TroughFactor)));
867 }
868 q+=(ptrdiff_t) GetPixelChannels(image);
869 }
870 for ( ; x < (ssize_t) image->columns; x++)
871 {
872 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
873 {
874 PixelChannel channel = GetPixelChannelChannel(image,i);
875 PixelTrait traits = GetPixelChannelTraits(image,channel);
876 if ((traits & UpdatePixelTrait) == 0)
877 continue;
878 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*(double) ShadowFactor+
879 (double) background*((double) QuantumRange-(double) ShadowFactor)));
880 }
881 q+=(ptrdiff_t) GetPixelChannels(image);
882 }
883 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
884 status=MagickFalse;
885 if (image->progress_monitor != (MagickProgressMonitor) NULL)
886 {
887 MagickBooleanType
888 proceed;
889
890#if defined(MAGICKCORE_OPENMP_SUPPORT)
891 #pragma omp atomic
892#endif
893 progress++;
894 proceed=SetImageProgress(image,RaiseImageTag,progress,image->rows);
895 if (proceed == MagickFalse)
896 status=MagickFalse;
897 }
898 }
899 image_view=DestroyCacheView(image_view);
900 return(status);
901}