MagickCore  7.1.1-43
Convert, Edit, Or Compose Bitmap Images
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 */
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  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 */
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  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 */
628 MagickExport 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 
638  CacheView
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 }
_FrameInfo
Definition: decorate.h:27
_RectangleInfo
Definition: geometry.h:129
_CacheView
Definition: cache-view.c:65
_Image
Definition: image.h:131
_PixelInfo
Definition: pixel.h:181
_ExceptionInfo
Definition: exception.h:101