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-2016 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 % http://www.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 */
BorderImage(const Image * image,const RectangleInfo * border_info,const CompositeOperator compose,ExceptionInfo * exception)103 MagickExport 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
111 FrameInfo
112 frame_info;
113
114 assert(image != (const Image *) NULL);
115 assert(image->signature == MagickCoreSignature);
116 if (image->debug != MagickFalse)
117 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
118 assert(border_info != (RectangleInfo *) NULL);
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->alpha_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->alpha_color=image->alpha_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 alpha_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 */
FrameImage(const Image * image,const FrameInfo * frame_info,const CompositeOperator compose,ExceptionInfo * exception)169 MagickExport Image *FrameImage(const Image *image,const FrameInfo *frame_info,
170 const CompositeOperator compose,ExceptionInfo *exception)
171 {
172 #define FrameImageTag "Frame/Image"
173
174 CacheView
175 *image_view,
176 *frame_view;
177
178 Image
179 *frame_image;
180
181 MagickBooleanType
182 status;
183
184 MagickOffsetType
185 progress;
186
187 PixelInfo
188 accentuate,
189 highlight,
190 matte,
191 shadow,
192 trough;
193
194 register ssize_t
195 x;
196
197 size_t
198 bevel_width,
199 height,
200 width;
201
202 ssize_t
203 y;
204
205 /*
206 Check frame geometry.
207 */
208 assert(image != (Image *) NULL);
209 assert(image->signature == MagickCoreSignature);
210 if (image->debug != MagickFalse)
211 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
212 assert(frame_info != (FrameInfo *) NULL);
213 if ((frame_info->outer_bevel < 0) || (frame_info->inner_bevel < 0))
214 ThrowImageException(OptionError,"FrameIsLessThanImageSize");
215 bevel_width=(size_t) (frame_info->outer_bevel+frame_info->inner_bevel);
216 x=(ssize_t) frame_info->width-frame_info->x-bevel_width;
217 y=(ssize_t) frame_info->height-frame_info->y-bevel_width;
218 if ((x < (ssize_t) image->columns) | (y < (ssize_t) image->rows))
219 ThrowImageException(OptionError,"FrameIsLessThanImageSize");
220 /*
221 Initialize framed image attributes.
222 */
223 frame_image=CloneImage(image,frame_info->width,frame_info->height,MagickTrue,
224 exception);
225 if (frame_image == (Image *) NULL)
226 return((Image *) NULL);
227 if (SetImageStorageClass(frame_image,DirectClass,exception) == MagickFalse)
228 {
229 frame_image=DestroyImage(frame_image);
230 return((Image *) NULL);
231 }
232 if ((IsPixelInfoGray(&frame_image->border_color) == MagickFalse) &&
233 (IsGrayColorspace(frame_image->colorspace) != MagickFalse))
234 (void) SetImageColorspace(frame_image,sRGBColorspace,exception);
235 if ((frame_image->alpha_color.alpha_trait != UndefinedPixelTrait) &&
236 (frame_image->alpha_trait == UndefinedPixelTrait))
237 (void) SetImageAlpha(frame_image,OpaqueAlpha,exception);
238 frame_image->page=image->page;
239 if ((image->page.width != 0) && (image->page.height != 0))
240 {
241 frame_image->page.width+=frame_image->columns-image->columns;
242 frame_image->page.height+=frame_image->rows-image->rows;
243 }
244 /*
245 Initialize 3D effects color.
246 */
247 matte=image->alpha_color;
248 accentuate=matte;
249 accentuate.red=(double) (QuantumScale*((QuantumRange-
250 AccentuateModulate)*matte.red+(QuantumRange*AccentuateModulate)));
251 accentuate.green=(double) (QuantumScale*((QuantumRange-
252 AccentuateModulate)*matte.green+(QuantumRange*AccentuateModulate)));
253 accentuate.blue=(double) (QuantumScale*((QuantumRange-
254 AccentuateModulate)*matte.blue+(QuantumRange*AccentuateModulate)));
255 accentuate.black=(double) (QuantumScale*((QuantumRange-
256 AccentuateModulate)*matte.black+(QuantumRange*AccentuateModulate)));
257 accentuate.alpha=matte.alpha;
258 highlight=matte;
259 highlight.red=(double) (QuantumScale*((QuantumRange-
260 HighlightModulate)*matte.red+(QuantumRange*HighlightModulate)));
261 highlight.green=(double) (QuantumScale*((QuantumRange-
262 HighlightModulate)*matte.green+(QuantumRange*HighlightModulate)));
263 highlight.blue=(double) (QuantumScale*((QuantumRange-
264 HighlightModulate)*matte.blue+(QuantumRange*HighlightModulate)));
265 highlight.black=(double) (QuantumScale*((QuantumRange-
266 HighlightModulate)*matte.black+(QuantumRange*HighlightModulate)));
267 highlight.alpha=matte.alpha;
268 shadow=matte;
269 shadow.red=QuantumScale*matte.red*ShadowModulate;
270 shadow.green=QuantumScale*matte.green*ShadowModulate;
271 shadow.blue=QuantumScale*matte.blue*ShadowModulate;
272 shadow.black=QuantumScale*matte.black*ShadowModulate;
273 shadow.alpha=matte.alpha;
274 trough=matte;
275 trough.red=QuantumScale*matte.red*TroughModulate;
276 trough.green=QuantumScale*matte.green*TroughModulate;
277 trough.blue=QuantumScale*matte.blue*TroughModulate;
278 trough.black=QuantumScale*matte.black*TroughModulate;
279 trough.alpha=matte.alpha;
280 status=MagickTrue;
281 progress=0;
282 image_view=AcquireVirtualCacheView(image,exception);
283 frame_view=AcquireAuthenticCacheView(frame_image,exception);
284 height=(size_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
285 frame_info->inner_bevel);
286 if (height != 0)
287 {
288 register ssize_t
289 x;
290
291 register Quantum
292 *magick_restrict q;
293
294 /*
295 Draw top of ornamental border.
296 */
297 q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns,
298 height,exception);
299 if (q != (Quantum *) NULL)
300 {
301 /*
302 Draw top of ornamental border.
303 */
304 for (y=0; y < (ssize_t) frame_info->outer_bevel; y++)
305 {
306 for (x=0; x < (ssize_t) (frame_image->columns-y); x++)
307 {
308 if (x < y)
309 SetPixelViaPixelInfo(frame_image,&highlight,q);
310 else
311 SetPixelViaPixelInfo(frame_image,&accentuate,q);
312 q+=GetPixelChannels(frame_image);
313 }
314 for ( ; x < (ssize_t) frame_image->columns; x++)
315 {
316 SetPixelViaPixelInfo(frame_image,&shadow,q);
317 q+=GetPixelChannels(frame_image);
318 }
319 }
320 for (y=0; y < (ssize_t) (frame_info->y-bevel_width); y++)
321 {
322 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
323 {
324 SetPixelViaPixelInfo(frame_image,&highlight,q);
325 q+=GetPixelChannels(frame_image);
326 }
327 width=frame_image->columns-2*frame_info->outer_bevel;
328 for (x=0; x < (ssize_t) width; x++)
329 {
330 SetPixelViaPixelInfo(frame_image,&matte,q);
331 q+=GetPixelChannels(frame_image);
332 }
333 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
334 {
335 SetPixelViaPixelInfo(frame_image,&shadow,q);
336 q+=GetPixelChannels(frame_image);
337 }
338 }
339 for (y=0; y < (ssize_t) frame_info->inner_bevel; y++)
340 {
341 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
342 {
343 SetPixelViaPixelInfo(frame_image,&highlight,q);
344 q+=GetPixelChannels(frame_image);
345 }
346 for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
347 {
348 SetPixelViaPixelInfo(frame_image,&matte,q);
349 q+=GetPixelChannels(frame_image);
350 }
351 width=image->columns+((size_t) frame_info->inner_bevel << 1)-
352 y;
353 for (x=0; x < (ssize_t) width; x++)
354 {
355 if (x < y)
356 SetPixelViaPixelInfo(frame_image,&shadow,q);
357 else
358 SetPixelViaPixelInfo(frame_image,&trough,q);
359 q+=GetPixelChannels(frame_image);
360 }
361 for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
362 {
363 SetPixelViaPixelInfo(frame_image,&highlight,q);
364 q+=GetPixelChannels(frame_image);
365 }
366 width=frame_info->width-frame_info->x-image->columns-bevel_width;
367 for (x=0; x < (ssize_t) width; x++)
368 {
369 SetPixelViaPixelInfo(frame_image,&matte,q);
370 q+=GetPixelChannels(frame_image);
371 }
372 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
373 {
374 SetPixelViaPixelInfo(frame_image,&shadow,q);
375 q+=GetPixelChannels(frame_image);
376 }
377 }
378 (void) SyncCacheViewAuthenticPixels(frame_view,exception);
379 }
380 }
381 /*
382 Draw sides of ornamental border.
383 */
384 #if defined(MAGICKCORE_OPENMP_SUPPORT)
385 #pragma omp parallel for schedule(static,4) shared(progress,status) \
386 magick_threads(image,frame_image,1,1)
387 #endif
388 for (y=0; y < (ssize_t) image->rows; y++)
389 {
390 register ssize_t
391 x;
392
393 register Quantum
394 *magick_restrict q;
395
396 size_t
397 width;
398
399 /*
400 Initialize scanline with matte color.
401 */
402 if (status == MagickFalse)
403 continue;
404 q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y,
405 frame_image->columns,1,exception);
406 if (q == (Quantum *) NULL)
407 {
408 status=MagickFalse;
409 continue;
410 }
411 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
412 {
413 SetPixelViaPixelInfo(frame_image,&highlight,q);
414 q+=GetPixelChannels(frame_image);
415 }
416 for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
417 {
418 SetPixelViaPixelInfo(frame_image,&matte,q);
419 q+=GetPixelChannels(frame_image);
420 }
421 for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
422 {
423 SetPixelViaPixelInfo(frame_image,&shadow,q);
424 q+=GetPixelChannels(frame_image);
425 }
426 /*
427 Set frame interior pixels.
428 */
429 {
430 register const Quantum
431 *p;
432
433 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
434 if (p == (const Quantum *) NULL)
435 {
436 status=MagickFalse;
437 continue;
438 }
439 for (x=0; x < (ssize_t) image->columns; x++)
440 {
441 register ssize_t
442 i;
443
444 if (GetPixelReadMask(image,q) == 0)
445 {
446 SetPixelBackgoundColor(frame_image,q);
447 p+=GetPixelChannels(image);
448 q+=GetPixelChannels(frame_image);
449 continue;
450 }
451 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
452 {
453 PixelChannel channel=GetPixelChannelChannel(image,i);
454 PixelTrait traits=GetPixelChannelTraits(image,channel);
455 PixelTrait frame_traits=GetPixelChannelTraits(frame_image,channel);
456 if ((traits == UndefinedPixelTrait) ||
457 (frame_traits == UndefinedPixelTrait))
458 continue;
459 SetPixelChannel(frame_image,channel,p[i],q);
460 }
461 SetPixelRed(frame_image,GetPixelRed(image,p),q);
462 SetPixelGreen(frame_image,GetPixelGreen(image,p),q);
463 SetPixelBlue(frame_image,GetPixelBlue(image,p),q);
464 SetPixelAlpha(frame_image,GetPixelAlpha(image,p),q);
465 p+=GetPixelChannels(image);
466 q+=GetPixelChannels(frame_image);
467 }
468 }
469 for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
470 {
471 SetPixelViaPixelInfo(frame_image,&highlight,q);
472 q+=GetPixelChannels(frame_image);
473 }
474 width=frame_info->width-frame_info->x-image->columns-bevel_width;
475 for (x=0; x < (ssize_t) width; x++)
476 {
477 SetPixelViaPixelInfo(frame_image,&matte,q);
478 q+=GetPixelChannels(frame_image);
479 }
480 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
481 {
482 SetPixelViaPixelInfo(frame_image,&shadow,q);
483 q+=GetPixelChannels(frame_image);
484 }
485 if (SyncCacheViewAuthenticPixels(frame_view,exception) == MagickFalse)
486 status=MagickFalse;
487 if (image->progress_monitor != (MagickProgressMonitor) NULL)
488 {
489 MagickBooleanType
490 proceed;
491
492 #if defined(MAGICKCORE_OPENMP_SUPPORT)
493 #pragma omp critical (MagickCore_FrameImage)
494 #endif
495 proceed=SetImageProgress(image,FrameImageTag,progress++,image->rows);
496 if (proceed == MagickFalse)
497 status=MagickFalse;
498 }
499 }
500 height=(size_t) (frame_info->inner_bevel+frame_info->height-
501 frame_info->y-image->rows-bevel_width+frame_info->outer_bevel);
502 if (height != 0)
503 {
504 register ssize_t
505 x;
506
507 register Quantum
508 *magick_restrict q;
509
510 /*
511 Draw bottom of ornamental border.
512 */
513 q=QueueCacheViewAuthenticPixels(frame_view,0,(ssize_t) (frame_image->rows-
514 height),frame_image->columns,height,exception);
515 if (q != (Quantum *) NULL)
516 {
517 /*
518 Draw bottom of ornamental border.
519 */
520 for (y=frame_info->inner_bevel-1; y >= 0; y--)
521 {
522 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
523 {
524 SetPixelViaPixelInfo(frame_image,&highlight,q);
525 q+=GetPixelChannels(frame_image);
526 }
527 for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
528 {
529 SetPixelViaPixelInfo(frame_image,&matte,q);
530 q+=GetPixelChannels(frame_image);
531 }
532 for (x=0; x < y; x++)
533 {
534 SetPixelViaPixelInfo(frame_image,&shadow,q);
535 q+=GetPixelChannels(frame_image);
536 }
537 for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
538 {
539 if (x >= (ssize_t) (image->columns+2*frame_info->inner_bevel-y))
540 SetPixelViaPixelInfo(frame_image,&highlight,q);
541 else
542 SetPixelViaPixelInfo(frame_image,&accentuate,q);
543 q+=GetPixelChannels(frame_image);
544 }
545 width=frame_info->width-frame_info->x-image->columns-bevel_width;
546 for (x=0; x < (ssize_t) width; x++)
547 {
548 SetPixelViaPixelInfo(frame_image,&matte,q);
549 q+=GetPixelChannels(frame_image);
550 }
551 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
552 {
553 SetPixelViaPixelInfo(frame_image,&shadow,q);
554 q+=GetPixelChannels(frame_image);
555 }
556 }
557 height=frame_info->height-frame_info->y-image->rows-bevel_width;
558 for (y=0; y < (ssize_t) height; y++)
559 {
560 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
561 {
562 SetPixelViaPixelInfo(frame_image,&highlight,q);
563 q+=GetPixelChannels(frame_image);
564 }
565 width=frame_image->columns-2*frame_info->outer_bevel;
566 for (x=0; x < (ssize_t) width; x++)
567 {
568 SetPixelViaPixelInfo(frame_image,&matte,q);
569 q+=GetPixelChannels(frame_image);
570 }
571 for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
572 {
573 SetPixelViaPixelInfo(frame_image,&shadow,q);
574 q+=GetPixelChannels(frame_image);
575 }
576 }
577 for (y=frame_info->outer_bevel-1; y >= 0; y--)
578 {
579 for (x=0; x < y; x++)
580 {
581 SetPixelViaPixelInfo(frame_image,&highlight,q);
582 q+=GetPixelChannels(frame_image);
583 }
584 for ( ; x < (ssize_t) frame_image->columns; x++)
585 {
586 if (x >= (ssize_t) (frame_image->columns-y))
587 SetPixelViaPixelInfo(frame_image,&shadow,q);
588 else
589 SetPixelViaPixelInfo(frame_image,&trough,q);
590 q+=GetPixelChannels(frame_image);
591 }
592 }
593 (void) SyncCacheViewAuthenticPixels(frame_view,exception);
594 }
595 }
596 frame_view=DestroyCacheView(frame_view);
597 image_view=DestroyCacheView(image_view);
598 x=(ssize_t) (frame_info->outer_bevel+(frame_info->x-bevel_width)+
599 frame_info->inner_bevel);
600 y=(ssize_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
601 frame_info->inner_bevel);
602 if (status != MagickFalse)
603 status=CompositeImage(frame_image,image,compose,MagickTrue,x,y,
604 exception);
605 if (status == MagickFalse)
606 frame_image=DestroyImage(frame_image);
607 return(frame_image);
608 }
609
610 /*
611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
612 % %
613 % %
614 % %
615 % R a i s e I m a g e %
616 % %
617 % %
618 % %
619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620 %
621 % RaiseImage() creates a simulated three-dimensional button-like effect
622 % by lightening and darkening the edges of the image. Members width and
623 % height of raise_info define the width of the vertical and horizontal
624 % edge of the effect.
625 %
626 % The format of the RaiseImage method is:
627 %
628 % MagickBooleanType RaiseImage(const Image *image,
629 % const RectangleInfo *raise_info,const MagickBooleanType raise,
630 % ExceptionInfo *exception)
631 %
632 % A description of each parameter follows:
633 %
634 % o image: the image.
635 %
636 % o raise_info: Define the width and height of the raise area.
637 %
638 % o raise: A value other than zero creates a 3-D raise effect,
639 % otherwise it has a lowered effect.
640 %
641 % o exception: return any errors or warnings in this structure.
642 %
643 */
RaiseImage(Image * image,const RectangleInfo * raise_info,const MagickBooleanType raise,ExceptionInfo * exception)644 MagickExport MagickBooleanType RaiseImage(Image *image,
645 const RectangleInfo *raise_info,const MagickBooleanType raise,
646 ExceptionInfo *exception)
647 {
648 #define AccentuateFactor ScaleCharToQuantum(135)
649 #define HighlightFactor ScaleCharToQuantum(190)
650 #define ShadowFactor ScaleCharToQuantum(190)
651 #define RaiseImageTag "Raise/Image"
652 #define TroughFactor ScaleCharToQuantum(135)
653
654 CacheView
655 *image_view;
656
657 MagickBooleanType
658 status;
659
660 MagickOffsetType
661 progress;
662
663 Quantum
664 foreground,
665 background;
666
667 ssize_t
668 y;
669
670 assert(image != (Image *) NULL);
671 assert(image->signature == MagickCoreSignature);
672 if (image->debug != MagickFalse)
673 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
674 assert(raise_info != (RectangleInfo *) NULL);
675 if ((image->columns <= (raise_info->width << 1)) ||
676 (image->rows <= (raise_info->height << 1)))
677 ThrowBinaryException(OptionError,"ImageSizeMustExceedBevelWidth",
678 image->filename);
679 foreground=QuantumRange;
680 background=(Quantum) 0;
681 if (raise == MagickFalse)
682 {
683 foreground=(Quantum) 0;
684 background=QuantumRange;
685 }
686 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
687 return(MagickFalse);
688 /*
689 Raise image.
690 */
691 status=MagickTrue;
692 progress=0;
693 image_view=AcquireAuthenticCacheView(image,exception);
694 #if defined(MAGICKCORE_OPENMP_SUPPORT)
695 #pragma omp parallel for schedule(static,4) shared(progress,status) \
696 magick_threads(image,image,1,1)
697 #endif
698 for (y=0; y < (ssize_t) raise_info->height; y++)
699 {
700 register ssize_t
701 i,
702 x;
703
704 register Quantum
705 *magick_restrict q;
706
707 if (status == MagickFalse)
708 continue;
709 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
710 if (q == (Quantum *) NULL)
711 {
712 status=MagickFalse;
713 continue;
714 }
715 for (x=0; x < y; x++)
716 {
717 if (GetPixelReadMask(image,q) == 0)
718 {
719 q+=GetPixelChannels(image);
720 continue;
721 }
722 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
723 {
724 PixelChannel channel=GetPixelChannelChannel(image,i);
725 PixelTrait traits=GetPixelChannelTraits(image,channel);
726 if ((traits & UpdatePixelTrait) == 0)
727 continue;
728 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*HighlightFactor+(double)
729 foreground*(QuantumRange-HighlightFactor)));
730 }
731 q+=GetPixelChannels(image);
732 }
733 for ( ; x < (ssize_t) (image->columns-y); x++)
734 {
735 if (GetPixelReadMask(image,q) == 0)
736 {
737 q+=GetPixelChannels(image);
738 continue;
739 }
740 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
741 {
742 PixelChannel channel=GetPixelChannelChannel(image,i);
743 PixelTrait traits=GetPixelChannelTraits(image,channel);
744 if ((traits & UpdatePixelTrait) == 0)
745 continue;
746 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*AccentuateFactor+
747 (double) foreground*(QuantumRange-AccentuateFactor)));
748 }
749 q+=GetPixelChannels(image);
750 }
751 for ( ; x < (ssize_t) image->columns; x++)
752 {
753 if (GetPixelReadMask(image,q) == 0)
754 {
755 q+=GetPixelChannels(image);
756 continue;
757 }
758 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
759 {
760 PixelChannel channel=GetPixelChannelChannel(image,i);
761 PixelTrait traits=GetPixelChannelTraits(image,channel);
762 if ((traits & UpdatePixelTrait) == 0)
763 continue;
764 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*ShadowFactor+(double)
765 background*(QuantumRange-ShadowFactor)));
766 }
767 q+=GetPixelChannels(image);
768 }
769 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
770 status=MagickFalse;
771 if (image->progress_monitor != (MagickProgressMonitor) NULL)
772 {
773 MagickBooleanType
774 proceed;
775
776 #if defined(MAGICKCORE_OPENMP_SUPPORT)
777 #pragma omp critical (MagickCore_RaiseImage)
778 #endif
779 proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
780 if (proceed == MagickFalse)
781 status=MagickFalse;
782 }
783 }
784 #if defined(MAGICKCORE_OPENMP_SUPPORT)
785 #pragma omp parallel for schedule(static,4) shared(progress,status) \
786 magick_threads(image,image,1,1)
787 #endif
788 for (y=(ssize_t) raise_info->height; y < (ssize_t) (image->rows-raise_info->height); y++)
789 {
790 register ssize_t
791 i,
792 x;
793
794 register Quantum
795 *magick_restrict q;
796
797 if (status == MagickFalse)
798 continue;
799 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
800 if (q == (Quantum *) NULL)
801 {
802 status=MagickFalse;
803 continue;
804 }
805 for (x=0; x < (ssize_t) raise_info->width; x++)
806 {
807 if (GetPixelReadMask(image,q) == 0)
808 {
809 q+=GetPixelChannels(image);
810 continue;
811 }
812 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
813 {
814 PixelChannel channel=GetPixelChannelChannel(image,i);
815 PixelTrait traits=GetPixelChannelTraits(image,channel);
816 if ((traits & UpdatePixelTrait) == 0)
817 continue;
818 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*HighlightFactor+(double)
819 foreground*(QuantumRange-HighlightFactor)));
820 }
821 q+=GetPixelChannels(image);
822 }
823 for ( ; x < (ssize_t) (image->columns-raise_info->width); x++)
824 q+=GetPixelChannels(image);
825 for ( ; x < (ssize_t) image->columns; x++)
826 {
827 if (GetPixelReadMask(image,q) == 0)
828 {
829 q+=GetPixelChannels(image);
830 continue;
831 }
832 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
833 {
834 PixelChannel channel=GetPixelChannelChannel(image,i);
835 PixelTrait traits=GetPixelChannelTraits(image,channel);
836 if ((traits & UpdatePixelTrait) == 0)
837 continue;
838 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*ShadowFactor+(double)
839 background*(QuantumRange-ShadowFactor)));
840 }
841 q+=GetPixelChannels(image);
842 }
843 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
844 status=MagickFalse;
845 if (image->progress_monitor != (MagickProgressMonitor) NULL)
846 {
847 MagickBooleanType
848 proceed;
849
850 #if defined(MAGICKCORE_OPENMP_SUPPORT)
851 #pragma omp critical (MagickCore_RaiseImage)
852 #endif
853 proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
854 if (proceed == MagickFalse)
855 status=MagickFalse;
856 }
857 }
858 #if defined(MAGICKCORE_OPENMP_SUPPORT)
859 #pragma omp parallel for schedule(static,4) shared(progress,status) \
860 magick_threads(image,image,1,1)
861 #endif
862 for (y=(ssize_t) (image->rows-raise_info->height); y < (ssize_t) image->rows; y++)
863 {
864 register ssize_t
865 i,
866 x;
867
868 register Quantum
869 *magick_restrict q;
870
871 if (status == MagickFalse)
872 continue;
873 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
874 if (q == (Quantum *) NULL)
875 {
876 status=MagickFalse;
877 continue;
878 }
879 for (x=0; x < (ssize_t) (image->rows-y); x++)
880 {
881 if (GetPixelReadMask(image,q) == 0)
882 {
883 q+=GetPixelChannels(image);
884 continue;
885 }
886 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
887 {
888 PixelChannel channel=GetPixelChannelChannel(image,i);
889 PixelTrait traits=GetPixelChannelTraits(image,channel);
890 if ((traits & UpdatePixelTrait) == 0)
891 continue;
892 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*HighlightFactor+(double)
893 foreground*(QuantumRange-HighlightFactor)));
894 }
895 q+=GetPixelChannels(image);
896 }
897 for ( ; x < (ssize_t) (image->columns-(image->rows-y)); x++)
898 {
899 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
900 {
901 PixelChannel channel=GetPixelChannelChannel(image,i);
902 PixelTrait traits=GetPixelChannelTraits(image,channel);
903 if ((traits & UpdatePixelTrait) == 0)
904 continue;
905 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*TroughFactor+
906 (double) background*(QuantumRange-TroughFactor)));
907 }
908 q+=GetPixelChannels(image);
909 }
910 for ( ; x < (ssize_t) image->columns; x++)
911 {
912 if (GetPixelReadMask(image,q) == 0)
913 {
914 q+=GetPixelChannels(image);
915 continue;
916 }
917 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
918 {
919 PixelChannel channel=GetPixelChannelChannel(image,i);
920 PixelTrait traits=GetPixelChannelTraits(image,channel);
921 if ((traits & UpdatePixelTrait) == 0)
922 continue;
923 q[i]=ClampToQuantum(QuantumScale*((double) q[i]*ShadowFactor+(double)
924 background*(QuantumRange-ShadowFactor)));
925 }
926 q+=GetPixelChannels(image);
927 }
928 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
929 status=MagickFalse;
930 if (image->progress_monitor != (MagickProgressMonitor) NULL)
931 {
932 MagickBooleanType
933 proceed;
934
935 #if defined(MAGICKCORE_OPENMP_SUPPORT)
936 #pragma omp critical (MagickCore_RaiseImage)
937 #endif
938 proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
939 if (proceed == MagickFalse)
940 status=MagickFalse;
941 }
942 }
943 image_view=DestroyCacheView(image_view);
944 return(status);
945 }
946