Coverage Report

Created: 2026-09-13 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/MagickCore/cache.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                      CCCC   AAA    CCCC  H   H  EEEEE                       %
7
%                     C      A   A  C      H   H  E                           %
8
%                     C      AAAAA  C      HHHHH  EEE                         %
9
%                     C      A   A  C      H   H  E                           %
10
%                      CCCC  A   A   CCCC  H   H  EEEEE                       %
11
%                                                                             %
12
%                                                                             %
13
%                       MagickCore Pixel Cache Methods                        %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 July 1999                                   %
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/license/                                         %
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/blob.h"
45
#include "MagickCore/blob-private.h"
46
#include "MagickCore/cache.h"
47
#include "MagickCore/cache-private.h"
48
#include "MagickCore/color-private.h"
49
#include "MagickCore/colorspace-private.h"
50
#include "MagickCore/composite-private.h"
51
#include "MagickCore/distribute-cache-private.h"
52
#include "MagickCore/exception.h"
53
#include "MagickCore/exception-private.h"
54
#include "MagickCore/geometry.h"
55
#include "MagickCore/list.h"
56
#include "MagickCore/log.h"
57
#include "MagickCore/magick.h"
58
#include "MagickCore/memory_.h"
59
#include "MagickCore/memory-private.h"
60
#include "MagickCore/nt-base-private.h"
61
#include "MagickCore/option.h"
62
#include "MagickCore/pixel.h"
63
#include "MagickCore/pixel-accessor.h"
64
#include "MagickCore/pixel-private.h"
65
#include "MagickCore/policy.h"
66
#include "MagickCore/quantum.h"
67
#include "MagickCore/random_.h"
68
#include "MagickCore/registry.h"
69
#include "MagickCore/resource_.h"
70
#include "MagickCore/semaphore.h"
71
#include "MagickCore/splay-tree.h"
72
#include "MagickCore/string_.h"
73
#include "MagickCore/string-private.h"
74
#include "MagickCore/timer-private.h"
75
#include "MagickCore/thread-private.h"
76
#include "MagickCore/utility.h"
77
#include "MagickCore/utility-private.h"
78
#if defined(MAGICKCORE_HAVE_ERRNO_H)
79
#  include <errno.h>
80
#endif
81
#if defined(MAGICKCORE_HAVE_SYS_LOADAVG_H)
82
#  include <sys/loadavg.h>
83
#endif
84
#if defined(MAGICKCORE_ZLIB_DELEGATE)
85
#  include "zlib.h"
86
#endif
87

88
/*
89
  Define declarations.
90
*/
91
0
#define CacheTick(offset,extent)  QuantumTick((MagickOffsetType) offset,extent)
92
124k
#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
93
124k
  GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
94

95
/*
96
  Typedef declarations.
97
*/
98
typedef struct _MagickModulo
99
{
100
  ssize_t
101
    quotient,
102
    remainder;
103
} MagickModulo;
104

105
/*
106
  Forward declarations.
107
*/
108
#if defined(__cplusplus) || defined(c_plusplus)
109
extern "C" {
110
#endif
111
112
static Cache
113
  GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
114
    magick_hot_spot;
115
116
static const Quantum
117
  *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
118
    const ssize_t,const size_t,const size_t,ExceptionInfo *),
119
  *GetVirtualPixelsCache(const Image *);
120
121
static const void
122
  *GetVirtualMetacontentFromCache(const Image *);
123
124
static MagickBooleanType
125
  GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
126
    ExceptionInfo *),
127
  GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
128
    const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
129
  OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
130
  OpenPixelCacheOnDisk(CacheInfo *,const MapMode),
131
  ReadPixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
132
    ExceptionInfo *),
133
  ReadPixelCacheMetacontent(CacheInfo *magick_restrict,
134
    NexusInfo *magick_restrict,ExceptionInfo *),
135
  SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
136
  WritePixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
137
    ExceptionInfo *),
138
  WritePixelCacheMetacontent(CacheInfo *,NexusInfo *magick_restrict,
139
    ExceptionInfo *);
140
141
static Quantum
142
  *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
143
    const size_t,ExceptionInfo *),
144
  *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
145
    const size_t,ExceptionInfo *),
146
  *SetPixelCacheNexusPixels(const CacheInfo *magick_restrict,const MapMode,
147
    const ssize_t,const ssize_t,const size_t,const size_t,
148
    const MagickBooleanType,NexusInfo *magick_restrict,ExceptionInfo *)
149
    magick_hot_spot;
150
151
#if defined(MAGICKCORE_OPENCL_SUPPORT)
152
static void
153
  CopyOpenCLBuffer(CacheInfo *magick_restrict);
154
#endif
155
156
#if defined(__cplusplus) || defined(c_plusplus)
157
}
158
#endif
159

160
/*
161
  Global declarations.
162
*/
163
static SemaphoreInfo
164
  *cache_semaphore = (SemaphoreInfo *) NULL;
165
166
static ssize_t
167
  cache_anonymous_memory = (-1);
168

169
/*
170
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171
%                                                                             %
172
%                                                                             %
173
%                                                                             %
174
+   A c q u i r e P i x e l C a c h e                                         %
175
%                                                                             %
176
%                                                                             %
177
%                                                                             %
178
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179
%
180
%  AcquirePixelCache() acquires a pixel cache.
181
%
182
%  The format of the AcquirePixelCache() method is:
183
%
184
%      Cache AcquirePixelCache(const size_t number_threads)
185
%
186
%  A description of each parameter follows:
187
%
188
%    o number_threads: the number of nexus threads.
189
%
190
*/
191
MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
192
3.02M
{
193
3.02M
  CacheInfo
194
3.02M
    *magick_restrict cache_info;
195
196
3.02M
  char
197
3.02M
    *value;
198
199
3.02M
  cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
200
3.02M
  if (cache_info == (CacheInfo *) NULL)
201
3.02M
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
202
3.02M
  (void) memset(cache_info,0,sizeof(*cache_info));
203
3.02M
  cache_info->type=UndefinedCache;
204
3.02M
  cache_info->mode=IOMode;
205
3.02M
  cache_info->disk_mode=IOMode;
206
3.02M
  cache_info->colorspace=sRGBColorspace;
207
3.02M
  cache_info->file=(-1);
208
3.02M
  cache_info->id=GetMagickThreadId();
209
3.02M
  cache_info->number_threads=number_threads;
210
3.02M
  if (GetOpenMPMaximumThreads() > cache_info->number_threads)
211
2.75M
    cache_info->number_threads=GetOpenMPMaximumThreads();
212
3.02M
  if (cache_info->number_threads == 0)
213
0
    cache_info->number_threads=1;
214
3.02M
  cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
215
3.02M
  value=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
216
3.02M
  if (value != (const char *) NULL)
217
0
    {
218
0
      cache_info->synchronize=IsStringTrue(value);
219
0
      value=DestroyString(value);
220
0
    }
221
3.02M
  value=GetPolicyValue("cache:synchronize");
222
3.02M
  if (value != (const char *) NULL)
223
0
    {
224
0
      cache_info->synchronize=IsStringTrue(value);
225
0
      value=DestroyString(value);
226
0
    }
227
3.02M
  cache_info->width_limit=MagickMin(GetMagickResourceLimit(WidthResource),
228
3.02M
    (MagickSizeType) MAGICK_SSIZE_MAX);
229
3.02M
  cache_info->height_limit=MagickMin(GetMagickResourceLimit(HeightResource),
230
3.02M
    (MagickSizeType) MAGICK_SSIZE_MAX);
231
3.02M
  cache_info->semaphore=AcquireSemaphoreInfo();
232
3.02M
  cache_info->reference_count=1;
233
3.02M
  cache_info->file_semaphore=AcquireSemaphoreInfo();
234
3.02M
  cache_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
235
3.02M
    MagickFalse;
236
3.02M
  cache_info->signature=MagickCoreSignature;
237
3.02M
  return((Cache ) cache_info);
238
3.02M
}
239

240
/*
241
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242
%                                                                             %
243
%                                                                             %
244
%                                                                             %
245
%   A c q u i r e P i x e l C a c h e N e x u s                               %
246
%                                                                             %
247
%                                                                             %
248
%                                                                             %
249
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250
%
251
%  AcquirePixelCacheNexus() allocates the NexusInfo structure.
252
%
253
%  The format of the AcquirePixelCacheNexus method is:
254
%
255
%      NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
256
%
257
%  A description of each parameter follows:
258
%
259
%    o number_threads: the number of nexus threads.
260
%
261
*/
262
MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
263
7.83M
{
264
7.83M
  NexusInfo
265
7.83M
    **magick_restrict nexus_info;
266
267
7.83M
  ssize_t
268
7.83M
    i;
269
270
7.83M
  nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(2*
271
7.83M
    number_threads,sizeof(*nexus_info)));
272
7.83M
  if (nexus_info == (NexusInfo **) NULL)
273
7.83M
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
274
7.83M
  *nexus_info=(NexusInfo *) AcquireQuantumMemory(number_threads,
275
7.83M
    2*sizeof(**nexus_info));
276
7.83M
  if (*nexus_info == (NexusInfo *) NULL)
277
7.83M
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
278
7.83M
  (void) memset(*nexus_info,0,2*number_threads*sizeof(**nexus_info));
279
23.5M
  for (i=0; i < (ssize_t) (2*number_threads); i++)
280
15.6M
  {
281
15.6M
    nexus_info[i]=(*nexus_info+i);
282
15.6M
    if (i < (ssize_t) number_threads)
283
7.83M
      nexus_info[i]->virtual_nexus=(*nexus_info+number_threads+i);
284
15.6M
    nexus_info[i]->signature=MagickCoreSignature;
285
15.6M
  }
286
7.83M
  return(nexus_info);
287
7.83M
}
288

289
/*
290
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291
%                                                                             %
292
%                                                                             %
293
%                                                                             %
294
%   A c q u i r e P i x e l C a c h e P i x e l s                             %
295
%                                                                             %
296
%                                                                             %
297
%                                                                             %
298
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299
%
300
%  AcquirePixelCachePixels() returns the pixels associated with the specified
301
%  image.
302
%
303
%  The format of the AcquirePixelCachePixels() method is:
304
%
305
%      void *AcquirePixelCachePixels(const Image *image,size_t *length,
306
%        ExceptionInfo *exception)
307
%
308
%  A description of each parameter follows:
309
%
310
%    o image: the image.
311
%
312
%    o length: the pixel cache length.
313
%
314
%    o exception: return any errors or warnings in this structure.
315
%
316
*/
317
MagickExport void *AcquirePixelCachePixels(const Image *image,size_t *length,
318
  ExceptionInfo *exception)
319
185k
{
320
185k
  CacheInfo
321
185k
    *magick_restrict cache_info;
322
323
185k
  assert(image != (const Image *) NULL);
324
185k
  assert(image->signature == MagickCoreSignature);
325
185k
  assert(exception != (ExceptionInfo *) NULL);
326
185k
  assert(exception->signature == MagickCoreSignature);
327
185k
  assert(image->cache != (Cache) NULL);
328
185k
  (void) exception;
329
185k
  cache_info=(CacheInfo *) image->cache;
330
185k
  assert(cache_info->signature == MagickCoreSignature);
331
185k
  *length=0;
332
185k
  if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
333
5.01k
    return((void *) NULL);
334
180k
  *length=(size_t) cache_info->length;
335
180k
  return(cache_info->pixels);
336
185k
}
337

338
/*
339
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340
%                                                                             %
341
%                                                                             %
342
%                                                                             %
343
+   C a c h e C o m p o n e n t G e n e s i s                                 %
344
%                                                                             %
345
%                                                                             %
346
%                                                                             %
347
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348
%
349
%  CacheComponentGenesis() instantiates the cache component.
350
%
351
%  The format of the CacheComponentGenesis method is:
352
%
353
%      MagickBooleanType CacheComponentGenesis(void)
354
%
355
*/
356
MagickPrivate MagickBooleanType CacheComponentGenesis(void)
357
294
{
358
294
  if (cache_semaphore == (SemaphoreInfo *) NULL)
359
294
    cache_semaphore=AcquireSemaphoreInfo();
360
294
  return(MagickTrue);
361
294
}
362

363
/*
364
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365
%                                                                             %
366
%                                                                             %
367
%                                                                             %
368
+   C a c h e C o m p o n e n t T e r m i n u s                               %
369
%                                                                             %
370
%                                                                             %
371
%                                                                             %
372
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373
%
374
%  CacheComponentTerminus() destroys the cache component.
375
%
376
%  The format of the CacheComponentTerminus() method is:
377
%
378
%      CacheComponentTerminus(void)
379
%
380
*/
381
MagickPrivate void CacheComponentTerminus(void)
382
0
{
383
0
  if (cache_semaphore == (SemaphoreInfo *) NULL)
384
0
    ActivateSemaphoreInfo(&cache_semaphore);
385
  /* no op-- nothing to destroy */
386
0
  RelinquishSemaphoreInfo(&cache_semaphore);
387
0
}
388

389
/*
390
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
391
%                                                                             %
392
%                                                                             %
393
%                                                                             %
394
+   C l i p P i x e l C a c h e N e x u s                                     %
395
%                                                                             %
396
%                                                                             %
397
%                                                                             %
398
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
399
%
400
%  ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
401
%  mask.  The method returns MagickTrue if the pixel region is clipped,
402
%  otherwise MagickFalse.
403
%
404
%  The format of the ClipPixelCacheNexus() method is:
405
%
406
%      MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
407
%        ExceptionInfo *exception)
408
%
409
%  A description of each parameter follows:
410
%
411
%    o image: the image.
412
%
413
%    o nexus_info: the cache nexus to clip.
414
%
415
%    o exception: return any errors or warnings in this structure.
416
%
417
*/
418
static MagickBooleanType ClipPixelCacheNexus(Image *image,
419
  NexusInfo *nexus_info,ExceptionInfo *exception)
420
67.4k
{
421
67.4k
  CacheInfo
422
67.4k
    *magick_restrict cache_info;
423
424
67.4k
  Quantum
425
67.4k
    *magick_restrict p,
426
67.4k
    *magick_restrict q;
427
428
67.4k
  ssize_t
429
67.4k
    y;
430
431
  /*
432
    Apply clip mask.
433
  */
434
67.4k
  if (IsEventLogging() != MagickFalse)
435
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
436
67.4k
  if ((image->channels & WriteMaskChannel) == 0)
437
0
    return(MagickTrue);
438
67.4k
  if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
439
0
    return(MagickTrue);
440
67.4k
  cache_info=(CacheInfo *) image->cache;
441
67.4k
  if (cache_info == (CacheInfo *) NULL)
442
0
    return(MagickFalse);
443
67.4k
  p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
444
67.4k
    nexus_info->region.width,nexus_info->region.height,
445
67.4k
    nexus_info->virtual_nexus,exception);
446
67.4k
  q=nexus_info->pixels;
447
67.4k
  if ((p == (Quantum *) NULL) || (q == (Quantum *) NULL))
448
0
    return(MagickFalse);
449
134k
  for (y=0; y < (ssize_t) nexus_info->region.height; y++)
450
67.4k
  {
451
67.4k
    ssize_t
452
67.4k
      x;
453
454
1.14M
    for (x=0; x < (ssize_t) nexus_info->region.width; x++)
455
1.08M
    {
456
1.08M
      double
457
1.08M
        mask;
458
459
1.08M
      ssize_t
460
1.08M
        i;
461
462
1.08M
      mask=(double) GetPixelWriteMask(image,p);
463
1.08M
      if (fabs(mask) >= MagickEpsilon)
464
226k
        {
465
226k
          double
466
226k
            mask_alpha,
467
226k
            dst_alpha;
468
469
226k
          Quantum
470
226k
            src_alpha;
471
472
226k
          src_alpha=GetPixelAlpha(image,p);
473
226k
          mask_alpha=QuantumScale*mask*(double) src_alpha;
474
226k
          dst_alpha=(double) GetPixelAlpha(image,q);
475
824k
          for (i=0; i < (ssize_t) image->number_channels; i++)
476
598k
          {
477
598k
            PixelTrait
478
598k
              traits;
479
480
598k
            PixelChannel channel = GetPixelChannelChannel(image,i);
481
598k
            if (channel == AlphaPixelChannel)
482
19.3k
              continue;
483
579k
            traits=GetPixelChannelTraits(image,channel);
484
579k
            if ((traits & UpdatePixelTrait) == 0)
485
314k
              continue;
486
264k
            q[i]=ClampToQuantum(MagickOver_((double) p[i],mask_alpha,
487
264k
              (double) q[i],dst_alpha));
488
264k
          }
489
226k
          SetPixelAlpha(image,src_alpha,q);
490
226k
        }
491
1.08M
      p+=(ptrdiff_t) GetPixelChannels(image);
492
1.08M
      q+=(ptrdiff_t) GetPixelChannels(image);
493
1.08M
    }
494
67.4k
  }
495
67.4k
  return(MagickTrue);
496
67.4k
}
497

498
/*
499
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500
%                                                                             %
501
%                                                                             %
502
%                                                                             %
503
+   C l o n e P i x e l C a c h e                                             %
504
%                                                                             %
505
%                                                                             %
506
%                                                                             %
507
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508
%
509
%  ClonePixelCache() clones a pixel cache.
510
%
511
%  The format of the ClonePixelCache() method is:
512
%
513
%      Cache ClonePixelCache(const Cache cache)
514
%
515
%  A description of each parameter follows:
516
%
517
%    o cache: the pixel cache.
518
%
519
*/
520
MagickPrivate Cache ClonePixelCache(const Cache cache)
521
269k
{
522
269k
  CacheInfo
523
269k
    *magick_restrict clone_info;
524
525
269k
  const CacheInfo
526
269k
    *magick_restrict cache_info;
527
528
269k
  assert(cache != NULL);
529
269k
  cache_info=(const CacheInfo *) cache;
530
269k
  assert(cache_info->signature == MagickCoreSignature);
531
269k
  if (IsEventLogging() != MagickFalse)
532
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
533
0
      cache_info->filename);
534
269k
  clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
535
269k
  clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
536
269k
  return((Cache ) clone_info);
537
269k
}
538

539
/*
540
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541
%                                                                             %
542
%                                                                             %
543
%                                                                             %
544
+   C l o n e P i x e l C a c h e M e t h o d s                               %
545
%                                                                             %
546
%                                                                             %
547
%                                                                             %
548
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549
%
550
%  ClonePixelCacheMethods() clones the pixel cache methods from one cache to
551
%  another.
552
%
553
%  The format of the ClonePixelCacheMethods() method is:
554
%
555
%      void ClonePixelCacheMethods(Cache clone,const Cache cache)
556
%
557
%  A description of each parameter follows:
558
%
559
%    o clone: Specifies a pointer to a Cache structure.
560
%
561
%    o cache: the pixel cache.
562
%
563
*/
564
MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
565
74.3k
{
566
74.3k
  CacheInfo
567
74.3k
    *magick_restrict cache_info,
568
74.3k
    *magick_restrict source_info;
569
570
74.3k
  assert(clone != (Cache) NULL);
571
74.3k
  source_info=(CacheInfo *) clone;
572
74.3k
  assert(source_info->signature == MagickCoreSignature);
573
74.3k
  if (IsEventLogging() != MagickFalse)
574
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
575
0
      source_info->filename);
576
74.3k
  assert(cache != (Cache) NULL);
577
74.3k
  cache_info=(CacheInfo *) cache;
578
74.3k
  assert(cache_info->signature == MagickCoreSignature);
579
74.3k
  source_info->methods=cache_info->methods;
580
74.3k
}
581

582
/*
583
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584
%                                                                             %
585
%                                                                             %
586
%                                                                             %
587
+   C l o n e P i x e l C a c h e R e p o s i t o r y                         %
588
%                                                                             %
589
%                                                                             %
590
%                                                                             %
591
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592
%
593
%  ClonePixelCacheRepository() clones the source pixel cache to the destination
594
%  cache.
595
%
596
%  The format of the ClonePixelCacheRepository() method is:
597
%
598
%      MagickBooleanType ClonePixelCacheRepository(CacheInfo *clone_info,
599
%        CacheInfo *cache_info,ExceptionInfo *exception)
600
%
601
%  A description of each parameter follows:
602
%
603
%    o clone_info: the pixel cache.
604
%
605
%    o cache_info: the source pixel cache.
606
%
607
%    o exception: return any errors or warnings in this structure.
608
%
609
*/
610
611
static MagickBooleanType ClonePixelCacheOnDisk(
612
  CacheInfo *magick_restrict cache_info,CacheInfo *magick_restrict clone_info)
613
0
{
614
0
  MagickSizeType
615
0
    extent;
616
617
0
  size_t
618
0
    quantum;
619
620
0
  ssize_t
621
0
    count;
622
623
0
  struct stat
624
0
    file_stats;
625
626
0
  unsigned char
627
0
    *buffer;
628
629
  /*
630
    Clone pixel cache on disk with identical morphology.
631
  */
632
0
  if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
633
0
      (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
634
0
    return(MagickFalse);
635
0
  if ((lseek(cache_info->file,0,SEEK_SET) < 0) ||
636
0
      (lseek(clone_info->file,0,SEEK_SET) < 0))
637
0
    return(MagickFalse);
638
0
  quantum=(size_t) MagickMaxBufferExtent;
639
0
  if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0))
640
0
    {
641
0
#if defined(MAGICKCORE_HAVE_LINUX_SENDFILE)
642
0
      if (cache_info->length < 0x7ffff000)
643
0
        {
644
0
          do
645
0
          {
646
0
            count=sendfile(clone_info->file,cache_info->file,(off_t *) NULL,
647
0
              (size_t) cache_info->length);
648
0
          } while ((count < 0) && (errno == EINTR));
649
0
          if (count == (ssize_t) cache_info->length)
650
0
            return(MagickTrue);
651
0
          if (count < 0)
652
0
            return(MagickFalse);
653
0
          if ((lseek(cache_info->file,0,SEEK_SET) < 0) ||
654
0
              (lseek(clone_info->file,0,SEEK_SET) < 0))
655
0
            return(MagickFalse);
656
0
        }
657
0
#endif
658
0
      quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
659
0
    }
660
0
  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
661
0
  if (buffer == (unsigned char *) NULL)
662
0
    return(MagickFalse);
663
0
  extent=0;
664
0
  while (extent < cache_info->length)
665
0
  {
666
0
    size_t
667
0
      length;
668
669
0
    length=(size_t) MagickMin((MagickSizeType) quantum,cache_info->length-
670
0
      extent);
671
0
    count=MagickRead(cache_info->file,buffer,length);
672
0
    if (count <= 0)
673
0
      {
674
0
        buffer=(unsigned char *) RelinquishMagickMemory(buffer);
675
0
        return(MagickFalse);
676
0
      }
677
0
    {
678
0
      ssize_t
679
0
        number_bytes,
680
0
        offset = 0;
681
682
0
      while (offset < count)
683
0
      {
684
0
        number_bytes=MagickWrite(clone_info->file,buffer+offset,(size_t) (count-
685
0
          offset));
686
0
        if (number_bytes <= 0)
687
0
          {
688
0
            buffer=(unsigned char *) RelinquishMagickMemory(buffer);
689
0
            return(MagickFalse);
690
0
          }
691
0
        offset+=number_bytes;
692
0
      }
693
0
      extent+=(MagickSizeType) offset;
694
0
    }
695
0
  }
696
0
  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
697
0
  return(extent == cache_info->length ? MagickTrue : MagickFalse);
698
0
}
699
700
#if defined(MAGICKCORE_OPENMP_SUPPORT)
701
static inline int GetCacheNumberThreads(const CacheInfo *source,
702
  const CacheInfo *destination,const size_t chunk,const int factor)
703
{
704
  size_t
705
    max_threads = (size_t) GetMagickResourceLimit(ThreadResource),
706
    number_threads = 1UL,
707
    workload_factor = 64UL << factor;
708
  
709
  /*
710
    Determine number of threads based on workload.
711
  */
712
  number_threads=(chunk <= workload_factor) ? 1UL :
713
    (chunk >= (workload_factor << 6)) ? max_threads :
714
    1UL+(chunk-workload_factor)*(max_threads-1L)/(((workload_factor << 6))-1L);
715
  /*
716
    Limit threads for non-memory or non-map cache sources/destinations.
717
  */
718
  if (((source->type != MemoryCache) && (source->type != MapCache)) ||
719
      ((destination->type != MemoryCache) && (destination->type != MapCache)))
720
    number_threads=MagickMin(number_threads,4);
721
  return((int) number_threads);
722
}
723
#endif
724
725
static MagickBooleanType ClonePixelCacheRepository(
726
  CacheInfo *magick_restrict clone_info,CacheInfo *magick_restrict cache_info,
727
  ExceptionInfo *exception)
728
914k
{
729
914k
#define cache_number_threads(source,destination,chunk,factor) \
730
914k
  num_threads(GetCacheNumberThreads((source),(destination),(chunk),(factor)))
731
732
914k
  MagickBooleanType
733
914k
    optimize,
734
914k
    status;
735
736
914k
  NexusInfo
737
914k
    **magick_restrict cache_nexus,
738
914k
    **magick_restrict clone_nexus;
739
740
914k
  size_t
741
914k
    length;
742
743
914k
  ssize_t
744
914k
    y;
745
746
914k
  assert(cache_info != (CacheInfo *) NULL);
747
914k
  assert(clone_info != (CacheInfo *) NULL);
748
914k
  assert(exception != (ExceptionInfo *) NULL);
749
914k
  if (cache_info->type == PingCache)
750
185
    return(MagickTrue);
751
914k
  length=cache_info->number_channels*sizeof(*cache_info->channel_map);
752
914k
  if ((cache_info->storage_class == clone_info->storage_class) &&
753
821k
      (cache_info->colorspace == clone_info->colorspace) &&
754
580k
      (cache_info->alpha_trait == clone_info->alpha_trait) &&
755
325k
      (cache_info->channels == clone_info->channels) &&
756
228k
      (cache_info->columns == clone_info->columns) &&
757
222k
      (cache_info->rows == clone_info->rows) &&
758
220k
      (cache_info->number_channels == clone_info->number_channels) &&
759
213k
      (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
760
211k
      (cache_info->metacontent_extent == clone_info->metacontent_extent))
761
211k
    {
762
      /*
763
        Identical pixel cache morphology.
764
      */
765
211k
      if (((cache_info->type == MemoryCache) ||
766
852
           (cache_info->type == MapCache)) &&
767
210k
          ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)))
768
210k
        {
769
210k
          (void) memcpy(clone_info->pixels,cache_info->pixels,
770
210k
            cache_info->number_channels*cache_info->columns*cache_info->rows*
771
210k
            sizeof(*cache_info->pixels));
772
210k
          if ((cache_info->metacontent_extent != 0) &&
773
0
              (clone_info->metacontent_extent != 0))
774
0
            (void) memcpy(clone_info->metacontent,cache_info->metacontent,
775
0
              cache_info->columns*cache_info->rows*
776
0
              clone_info->metacontent_extent*sizeof(unsigned char));
777
210k
          return(MagickTrue);
778
210k
        }
779
852
      if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache))
780
0
        return(ClonePixelCacheOnDisk(cache_info,clone_info));
781
852
    }
782
  /*
783
    Mismatched pixel cache morphology.
784
  */
785
703k
  cache_nexus=AcquirePixelCacheNexus(cache_info->number_threads);
786
703k
  clone_nexus=AcquirePixelCacheNexus(clone_info->number_threads);
787
703k
  length=cache_info->number_channels*sizeof(*cache_info->channel_map);
788
703k
  optimize=(cache_info->number_channels == clone_info->number_channels) &&
789
20.4k
    (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
790
686k
    MagickTrue : MagickFalse;
791
703k
  length=(size_t) MagickMin(cache_info->number_channels*cache_info->columns,
792
703k
    clone_info->number_channels*clone_info->columns);
793
703k
  status=MagickTrue;
794
#if defined(MAGICKCORE_OPENMP_SUPPORT)
795
  #pragma omp parallel for schedule(static) shared(status) \
796
    cache_number_threads(cache_info,clone_info,cache_info->rows,3)
797
#endif
798
45.9M
  for (y=0; y < (ssize_t) cache_info->rows; y++)
799
45.2M
  {
800
45.2M
    const int
801
45.2M
      id = GetOpenMPThreadId();
802
803
45.2M
    Quantum
804
45.2M
      *pixels;
805
806
45.2M
    ssize_t
807
45.2M
      x;
808
809
45.2M
    if (status == MagickFalse)
810
0
      continue;
811
45.2M
    if (y >= (ssize_t) clone_info->rows)
812
966k
      continue;
813
44.3M
    pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,0,y,
814
44.3M
      cache_info->columns,1,MagickFalse,cache_nexus[id],exception);
815
44.3M
    if (pixels == (Quantum *) NULL)
816
82.3k
      continue;
817
44.2M
    status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
818
44.2M
    if (status == MagickFalse)
819
0
      continue;
820
44.2M
    pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,0,y,
821
44.2M
      clone_info->columns,1,MagickFalse,clone_nexus[id],exception);
822
44.2M
    if (pixels == (Quantum *) NULL)
823
0
      continue;
824
44.2M
    (void) memset(clone_nexus[id]->pixels,0,(size_t) clone_nexus[id]->length);
825
44.2M
    if (optimize != MagickFalse)
826
2.07M
      (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
827
2.07M
        sizeof(Quantum));
828
42.1M
    else
829
42.1M
      {
830
42.1M
        const Quantum
831
42.1M
          *magick_restrict p;
832
833
42.1M
        Quantum
834
42.1M
          *magick_restrict q;
835
836
        /*
837
          Mismatched pixel channel map.
838
        */
839
42.1M
        p=cache_nexus[id]->pixels;
840
42.1M
        q=clone_nexus[id]->pixels;
841
20.6G
        for (x=0; x < (ssize_t) cache_info->columns; x++)
842
20.6G
        {
843
20.6G
          ssize_t
844
20.6G
            i;
845
846
20.6G
          if (x == (ssize_t) clone_info->columns)
847
586
            break;
848
80.9G
          for (i=0; i < (ssize_t) clone_info->number_channels; i++)
849
60.3G
          {
850
60.3G
            PixelChannel
851
60.3G
              channel;
852
853
60.3G
            PixelTrait
854
60.3G
              traits;
855
856
60.3G
            channel=clone_info->channel_map[i].channel;
857
60.3G
            traits=cache_info->channel_map[channel].traits;
858
60.3G
            if (traits != UndefinedPixelTrait)
859
29.8G
              *q=*(p+cache_info->channel_map[channel].offset);
860
60.3G
            q++;
861
60.3G
          }
862
20.6G
          p+=(ptrdiff_t) cache_info->number_channels;
863
20.6G
        }
864
42.1M
      }
865
44.2M
    status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
866
44.2M
  }
867
703k
  if ((cache_info->metacontent_extent != 0) &&
868
0
      (clone_info->metacontent_extent != 0))
869
0
    {
870
      /*
871
        Clone metacontent.
872
      */
873
0
      length=(size_t) MagickMin(cache_info->metacontent_extent,
874
0
        clone_info->metacontent_extent);
875
#if defined(MAGICKCORE_OPENMP_SUPPORT)
876
      #pragma omp parallel for schedule(static) shared(status) \
877
        cache_number_threads(cache_info,clone_info,cache_info->rows,3)
878
#endif
879
0
      for (y=0; y < (ssize_t) cache_info->rows; y++)
880
0
      {
881
0
        const int
882
0
          id = GetOpenMPThreadId();
883
884
0
        Quantum
885
0
          *pixels;
886
887
0
        if (status == MagickFalse)
888
0
          continue;
889
0
        if (y >= (ssize_t) clone_info->rows)
890
0
          continue;
891
0
        pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,0,y,
892
0
          cache_info->columns,1,MagickFalse,cache_nexus[id],exception);
893
0
        if (pixels == (Quantum *) NULL)
894
0
          continue;
895
0
        status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
896
0
        if (status == MagickFalse)
897
0
          continue;
898
0
        pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,0,y,
899
0
          clone_info->columns,1,MagickFalse,clone_nexus[id],exception);
900
0
        if (pixels == (Quantum *) NULL)
901
0
          continue;
902
0
        if ((clone_nexus[id]->metacontent != (void *) NULL) &&
903
0
            (cache_nexus[id]->metacontent != (void *) NULL))
904
0
          (void) memcpy(clone_nexus[id]->metacontent,
905
0
            cache_nexus[id]->metacontent,length*sizeof(unsigned char));
906
0
        status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
907
0
      }
908
0
    }
909
703k
  clone_nexus=DestroyPixelCacheNexus(clone_nexus,clone_info->number_threads);
910
703k
  cache_nexus=DestroyPixelCacheNexus(cache_nexus,cache_info->number_threads);
911
703k
  if (cache_info->debug != MagickFalse)
912
0
    {
913
0
      char
914
0
        message[MagickPathExtent];
915
916
0
      (void) FormatLocaleString(message,MagickPathExtent,"%s => %s",
917
0
        CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
918
0
        CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
919
0
      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
920
0
    }
921
703k
  return(status);
922
914k
}
923

924
/*
925
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926
%                                                                             %
927
%                                                                             %
928
%                                                                             %
929
+   D e s t r o y I m a g e P i x e l C a c h e                               %
930
%                                                                             %
931
%                                                                             %
932
%                                                                             %
933
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
934
%
935
%  DestroyImagePixelCache() deallocates memory associated with the pixel cache.
936
%
937
%  The format of the DestroyImagePixelCache() method is:
938
%
939
%      void DestroyImagePixelCache(Image *image)
940
%
941
%  A description of each parameter follows:
942
%
943
%    o image: the image.
944
%
945
*/
946
static void DestroyImagePixelCache(Image *image)
947
0
{
948
0
  assert(image != (Image *) NULL);
949
0
  assert(image->signature == MagickCoreSignature);
950
0
  if (IsEventLogging() != MagickFalse)
951
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
952
0
  if (image->cache != (void *) NULL)
953
0
    image->cache=DestroyPixelCache(image->cache);
954
0
}
955

956
/*
957
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
958
%                                                                             %
959
%                                                                             %
960
%                                                                             %
961
+   D e s t r o y I m a g e P i x e l s                                       %
962
%                                                                             %
963
%                                                                             %
964
%                                                                             %
965
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966
%
967
%  DestroyImagePixels() deallocates memory associated with the pixel cache.
968
%
969
%  The format of the DestroyImagePixels() method is:
970
%
971
%      void DestroyImagePixels(Image *image)
972
%
973
%  A description of each parameter follows:
974
%
975
%    o image: the image.
976
%
977
*/
978
MagickExport void DestroyImagePixels(Image *image)
979
3.38M
{
980
3.38M
  CacheInfo
981
3.38M
    *magick_restrict cache_info;
982
983
3.38M
  assert(image != (const Image *) NULL);
984
3.38M
  assert(image->signature == MagickCoreSignature);
985
3.38M
  if (IsEventLogging() != MagickFalse)
986
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
987
3.38M
  assert(image->cache != (Cache) NULL);
988
3.38M
  cache_info=(CacheInfo *) image->cache;
989
3.38M
  assert(cache_info->signature == MagickCoreSignature);
990
3.38M
  if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
991
74.5k
    {
992
74.5k
      cache_info->methods.destroy_pixel_handler(image);
993
74.5k
      return;
994
74.5k
    }
995
3.30M
  image->cache=DestroyPixelCache(image->cache);
996
3.30M
}
997

998
/*
999
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1000
%                                                                             %
1001
%                                                                             %
1002
%                                                                             %
1003
+   D e s t r o y P i x e l C a c h e                                         %
1004
%                                                                             %
1005
%                                                                             %
1006
%                                                                             %
1007
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1008
%
1009
%  DestroyPixelCache() deallocates memory associated with the pixel cache.
1010
%
1011
%  The format of the DestroyPixelCache() method is:
1012
%
1013
%      Cache DestroyPixelCache(Cache cache)
1014
%
1015
%  A description of each parameter follows:
1016
%
1017
%    o cache: the pixel cache.
1018
%
1019
*/
1020
1021
static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
1022
721
{
1023
721
  int
1024
721
    status;
1025
1026
721
  status=(-1);
1027
721
  if (cache_info->file != -1)
1028
451
    {
1029
451
      status=close_utf8(cache_info->file);
1030
451
      cache_info->file=(-1);
1031
451
      RelinquishMagickResource(FileResource,1);
1032
451
    }
1033
721
  return(status == -1 ? MagickFalse : MagickTrue);
1034
721
}
1035
1036
static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1037
3.65M
{
1038
3.65M
  switch (cache_info->type)
1039
3.65M
  {
1040
1.60M
    case MemoryCache:
1041
1.60M
    {
1042
1.60M
      (void) ShredMagickMemory(cache_info->pixels,(size_t) cache_info->length);
1043
#if defined(MAGICKCORE_OPENCL_SUPPORT)
1044
      if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1045
        {
1046
          cache_info->opencl=RelinquishMagickCLCacheInfo(cache_info->opencl,
1047
            MagickTrue);
1048
          cache_info->pixels=(Quantum *) NULL;
1049
          break;
1050
        }
1051
#endif
1052
1.60M
      if (cache_info->mapped == MagickFalse)
1053
1.60M
        cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
1054
1.60M
          cache_info->pixels);
1055
0
      else
1056
0
        {
1057
0
          (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
1058
0
          cache_info->pixels=(Quantum *) NULL;
1059
0
        }
1060
1.60M
      RelinquishMagickResource(MemoryResource,cache_info->length);
1061
1.60M
      break;
1062
0
    }
1063
405
    case MapCache:
1064
405
    {
1065
405
      (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
1066
405
      cache_info->pixels=(Quantum *) NULL;
1067
405
      if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
1068
405
        (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1069
405
      *cache_info->cache_filename='\0';
1070
405
      RelinquishMagickResource(MapResource,cache_info->length);
1071
405
      magick_fallthrough;
1072
405
    }
1073
531
    case DiskCache:
1074
531
    {
1075
531
      if (cache_info->file != -1)
1076
47
        (void) ClosePixelCacheOnDisk(cache_info);
1077
531
      if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
1078
531
        (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1079
531
      *cache_info->cache_filename='\0';
1080
531
      RelinquishMagickResource(DiskResource,cache_info->length);
1081
531
      break;
1082
405
    }
1083
0
    case DistributedCache:
1084
0
    {
1085
0
      *cache_info->cache_filename='\0';
1086
0
      (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
1087
0
        cache_info->server_info);
1088
0
      break;
1089
405
    }
1090
2.05M
    default:
1091
2.05M
      break;
1092
3.65M
  }
1093
3.65M
  cache_info->type=UndefinedCache;
1094
3.65M
  cache_info->mapped=MagickFalse;
1095
3.65M
  cache_info->metacontent=(void *) NULL;
1096
3.65M
}
1097
1098
MagickPrivate Cache DestroyPixelCache(Cache cache)
1099
3.68M
{
1100
3.68M
  CacheInfo
1101
3.68M
    *magick_restrict cache_info;
1102
1103
3.68M
  assert(cache != (Cache) NULL);
1104
3.68M
  cache_info=(CacheInfo *) cache;
1105
3.68M
  assert(cache_info->signature == MagickCoreSignature);
1106
3.68M
  if (IsEventLogging() != MagickFalse)
1107
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1108
0
      cache_info->filename);
1109
3.68M
  LockSemaphoreInfo(cache_info->semaphore);
1110
3.68M
  cache_info->reference_count--;
1111
3.68M
  if (cache_info->reference_count != 0)
1112
738k
    {
1113
738k
      UnlockSemaphoreInfo(cache_info->semaphore);
1114
738k
      return((Cache) NULL);
1115
738k
    }
1116
2.95M
  UnlockSemaphoreInfo(cache_info->semaphore);
1117
2.95M
  if (cache_info->debug != MagickFalse)
1118
0
    {
1119
0
      char
1120
0
        message[MagickPathExtent];
1121
1122
0
      (void) FormatLocaleString(message,MagickPathExtent,"destroy %s",
1123
0
        cache_info->filename);
1124
0
      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1125
0
    }
1126
2.95M
  RelinquishPixelCachePixels(cache_info);
1127
2.95M
  if (cache_info->server_info != (DistributeCacheInfo *) NULL)
1128
0
    cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
1129
0
      cache_info->server_info);
1130
2.95M
  if (cache_info->nexus_info != (NexusInfo **) NULL)
1131
2.95M
    cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1132
2.95M
      cache_info->number_threads);
1133
2.95M
  if (cache_info->random_info != (RandomInfo *) NULL)
1134
0
    cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1135
2.95M
  if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
1136
2.95M
    RelinquishSemaphoreInfo(&cache_info->file_semaphore);
1137
2.95M
  if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1138
2.95M
    RelinquishSemaphoreInfo(&cache_info->semaphore);
1139
2.95M
  cache_info->signature=(~MagickCoreSignature);
1140
2.95M
  cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1141
2.95M
  cache=(Cache) NULL;
1142
2.95M
  return(cache);
1143
3.68M
}
1144

1145
/*
1146
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1147
%                                                                             %
1148
%                                                                             %
1149
%                                                                             %
1150
+   D e s t r o y P i x e l C a c h e N e x u s                               %
1151
%                                                                             %
1152
%                                                                             %
1153
%                                                                             %
1154
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1155
%
1156
%  DestroyPixelCacheNexus() destroys a pixel cache nexus.
1157
%
1158
%  The format of the DestroyPixelCacheNexus() method is:
1159
%
1160
%      NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1161
%        const size_t number_threads)
1162
%
1163
%  A description of each parameter follows:
1164
%
1165
%    o nexus_info: the nexus to destroy.
1166
%
1167
%    o number_threads: the number of nexus threads.
1168
%
1169
*/
1170
1171
static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1172
849k
{
1173
849k
  if (nexus_info->mapped == MagickFalse)
1174
849k
    (void) RelinquishAlignedMemory(nexus_info->cache);
1175
0
  else
1176
0
    (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1177
849k
  nexus_info->cache=(Quantum *) NULL;
1178
849k
  nexus_info->pixels=(Quantum *) NULL;
1179
849k
  nexus_info->metacontent=(void *) NULL;
1180
849k
  nexus_info->length=0;
1181
849k
  nexus_info->mapped=MagickFalse;
1182
849k
}
1183
1184
MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1185
  const size_t number_threads)
1186
7.83M
{
1187
7.83M
  ssize_t
1188
7.83M
    i;
1189
1190
7.83M
  assert(nexus_info != (NexusInfo **) NULL);
1191
23.5M
  for (i=0; i < (ssize_t) (2*number_threads); i++)
1192
15.6M
  {
1193
15.6M
    if (nexus_info[i]->cache != (Quantum *) NULL)
1194
845k
      RelinquishCacheNexusPixels(nexus_info[i]);
1195
15.6M
    nexus_info[i]->signature=(~MagickCoreSignature);
1196
15.6M
  }
1197
7.83M
  *nexus_info=(NexusInfo *) RelinquishMagickMemory(*nexus_info);
1198
7.83M
  nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1199
7.83M
  return(nexus_info);
1200
7.83M
}
1201
1202
1203
/*
1204
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205
%                                                                             %
1206
%                                                                             %
1207
%                                                                             %
1208
%   G e t A u t h e n t i c M e t a c o n t e n t                             %
1209
%                                                                             %
1210
%                                                                             %
1211
%                                                                             %
1212
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1213
%
1214
%  GetAuthenticMetacontent() returns the authentic metacontent corresponding
1215
%  with the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
1216
%  returned if the associated pixels are not available.
1217
%
1218
%  The format of the GetAuthenticMetacontent() method is:
1219
%
1220
%      void *GetAuthenticMetacontent(const Image *image)
1221
%
1222
%  A description of each parameter follows:
1223
%
1224
%    o image: the image.
1225
%
1226
*/
1227
MagickExport void *GetAuthenticMetacontent(const Image *image)
1228
0
{
1229
0
  CacheInfo
1230
0
    *magick_restrict cache_info;
1231
1232
0
  const int
1233
0
    id = GetOpenMPThreadId();
1234
1235
0
  assert(image != (const Image *) NULL);
1236
0
  assert(image->signature == MagickCoreSignature);
1237
0
  assert(image->cache != (Cache) NULL);
1238
0
  cache_info=(CacheInfo *) image->cache;
1239
0
  assert(cache_info->signature == MagickCoreSignature);
1240
0
  if (cache_info->methods.get_authentic_metacontent_from_handler !=
1241
0
      (GetAuthenticMetacontentFromHandler) NULL)
1242
0
    {
1243
0
      void
1244
0
        *metacontent;
1245
1246
0
      metacontent=cache_info->methods.
1247
0
        get_authentic_metacontent_from_handler(image);
1248
0
      return(metacontent);
1249
0
    }
1250
0
  assert(id < (int) cache_info->number_threads);
1251
0
  return(cache_info->nexus_info[id]->metacontent);
1252
0
}
1253

1254
/*
1255
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1256
%                                                                             %
1257
%                                                                             %
1258
%                                                                             %
1259
+   G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e           %
1260
%                                                                             %
1261
%                                                                             %
1262
%                                                                             %
1263
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264
%
1265
%  GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1266
%  with the last call to QueueAuthenticPixelsCache() or
1267
%  GetAuthenticPixelsCache().
1268
%
1269
%  The format of the GetAuthenticMetacontentFromCache() method is:
1270
%
1271
%      void *GetAuthenticMetacontentFromCache(const Image *image)
1272
%
1273
%  A description of each parameter follows:
1274
%
1275
%    o image: the image.
1276
%
1277
*/
1278
static void *GetAuthenticMetacontentFromCache(const Image *image)
1279
0
{
1280
0
  CacheInfo
1281
0
    *magick_restrict cache_info;
1282
1283
0
  const int
1284
0
    id = GetOpenMPThreadId();
1285
1286
0
  assert(image != (const Image *) NULL);
1287
0
  assert(image->signature == MagickCoreSignature);
1288
0
  assert(image->cache != (Cache) NULL);
1289
0
  cache_info=(CacheInfo *) image->cache;
1290
0
  assert(cache_info->signature == MagickCoreSignature);
1291
0
  assert(id < (int) cache_info->number_threads);
1292
0
  return(cache_info->nexus_info[id]->metacontent);
1293
0
}
1294
1295
#if defined(MAGICKCORE_OPENCL_SUPPORT)
1296
/*
1297
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1298
%                                                                             %
1299
%                                                                             %
1300
%                                                                             %
1301
+   G e t A u t h e n t i c O p e n C L B u f f e r                           %
1302
%                                                                             %
1303
%                                                                             %
1304
%                                                                             %
1305
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1306
%
1307
%  GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL
1308
%  operations.
1309
%
1310
%  The format of the GetAuthenticOpenCLBuffer() method is:
1311
%
1312
%      cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1313
%        MagickCLDevice device,ExceptionInfo *exception)
1314
%
1315
%  A description of each parameter follows:
1316
%
1317
%    o image: the image.
1318
%
1319
%    o device: the device to use.
1320
%
1321
%    o exception: return any errors or warnings in this structure.
1322
%
1323
*/
1324
MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1325
  MagickCLDevice device,ExceptionInfo *exception)
1326
{
1327
  CacheInfo
1328
    *magick_restrict cache_info;
1329
1330
  assert(image != (const Image *) NULL);
1331
  assert(device != (const MagickCLDevice) NULL);
1332
  cache_info=(CacheInfo *) image->cache;
1333
  if ((cache_info->type == UndefinedCache) || (cache_info->reference_count > 1))
1334
    {
1335
      (void) SyncImagePixelCache((Image *) image,exception);
1336
      cache_info=(CacheInfo *) image->cache;
1337
    }
1338
  if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1339
    return((cl_mem) NULL);
1340
  LockSemaphoreInfo(cache_info->semaphore);
1341
  if ((cache_info->opencl != (MagickCLCacheInfo) NULL) &&
1342
      (cache_info->opencl->device->context != device->context))
1343
    cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
1344
  if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1345
    {
1346
      assert(cache_info->pixels != (Quantum *) NULL);
1347
      cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels,
1348
        cache_info->length);
1349
    }
1350
  if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1351
    RetainOpenCLMemObject(cache_info->opencl->buffer);
1352
  UnlockSemaphoreInfo(cache_info->semaphore);
1353
  if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1354
    return((cl_mem) NULL);
1355
  assert(cache_info->opencl->pixels == cache_info->pixels);
1356
  return(cache_info->opencl->buffer);
1357
}
1358
#endif
1359

1360
/*
1361
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362
%                                                                             %
1363
%                                                                             %
1364
%                                                                             %
1365
+   G e t A u t h e n t i c P i x e l C a c h e N e x u s                     %
1366
%                                                                             %
1367
%                                                                             %
1368
%                                                                             %
1369
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370
%
1371
%  GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1372
%  disk pixel cache as defined by the geometry parameters.   A pointer to the
1373
%  pixels is returned if the pixels are transferred, otherwise a NULL is
1374
%  returned.
1375
%
1376
%  The format of the GetAuthenticPixelCacheNexus() method is:
1377
%
1378
%      Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1379
%        const ssize_t y,const size_t columns,const size_t rows,
1380
%        NexusInfo *nexus_info,ExceptionInfo *exception)
1381
%
1382
%  A description of each parameter follows:
1383
%
1384
%    o image: the image.
1385
%
1386
%    o x,y,columns,rows:  These values define the perimeter of a region of
1387
%      pixels.
1388
%
1389
%    o nexus_info: the cache nexus to return.
1390
%
1391
%    o exception: return any errors or warnings in this structure.
1392
%
1393
*/
1394
1395
MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1396
  const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1397
  ExceptionInfo *exception)
1398
220M
{
1399
220M
  CacheInfo
1400
220M
    *magick_restrict cache_info;
1401
1402
220M
  Quantum
1403
220M
    *magick_restrict pixels;
1404
1405
  /*
1406
    Transfer pixels from the cache.
1407
  */
1408
220M
  assert(image != (Image *) NULL);
1409
220M
  assert(image->signature == MagickCoreSignature);
1410
220M
  pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1411
220M
    nexus_info,exception);
1412
220M
  if (pixels == (Quantum *) NULL)
1413
92.0k
    return((Quantum *) NULL);
1414
219M
  cache_info=(CacheInfo *) image->cache;
1415
219M
  assert(cache_info->signature == MagickCoreSignature);
1416
219M
  if (nexus_info->authentic_pixel_cache != MagickFalse)
1417
209M
    return(pixels);
1418
10.2M
  if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1419
0
    return((Quantum *) NULL);
1420
10.2M
  if (cache_info->metacontent_extent != 0)
1421
0
    if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1422
0
      return((Quantum *) NULL);
1423
10.2M
  return(pixels);
1424
10.2M
}
1425

1426
/*
1427
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428
%                                                                             %
1429
%                                                                             %
1430
%                                                                             %
1431
+   G e t A u t h e n t i c P i x e l s F r o m C a c h e                     %
1432
%                                                                             %
1433
%                                                                             %
1434
%                                                                             %
1435
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1436
%
1437
%  GetAuthenticPixelsFromCache() returns the pixels associated with the last
1438
%  call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1439
%
1440
%  The format of the GetAuthenticPixelsFromCache() method is:
1441
%
1442
%      Quantum *GetAuthenticPixelsFromCache(const Image image)
1443
%
1444
%  A description of each parameter follows:
1445
%
1446
%    o image: the image.
1447
%
1448
*/
1449
static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1450
0
{
1451
0
  CacheInfo
1452
0
    *magick_restrict cache_info;
1453
1454
0
  const int
1455
0
    id = GetOpenMPThreadId();
1456
1457
0
  assert(image != (const Image *) NULL);
1458
0
  assert(image->signature == MagickCoreSignature);
1459
0
  assert(image->cache != (Cache) NULL);
1460
0
  cache_info=(CacheInfo *) image->cache;
1461
0
  assert(cache_info->signature == MagickCoreSignature);
1462
0
  assert(id < (int) cache_info->number_threads);
1463
0
  return(cache_info->nexus_info[id]->pixels);
1464
0
}
1465

1466
/*
1467
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468
%                                                                             %
1469
%                                                                             %
1470
%                                                                             %
1471
%   G e t A u t h e n t i c P i x e l Q u e u e                               %
1472
%                                                                             %
1473
%                                                                             %
1474
%                                                                             %
1475
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476
%
1477
%  GetAuthenticPixelQueue() returns the authentic pixels associated
1478
%  corresponding with the last call to QueueAuthenticPixels() or
1479
%  GetAuthenticPixels().
1480
%
1481
%  The format of the GetAuthenticPixelQueue() method is:
1482
%
1483
%      Quantum *GetAuthenticPixelQueue(const Image image)
1484
%
1485
%  A description of each parameter follows:
1486
%
1487
%    o image: the image.
1488
%
1489
*/
1490
MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1491
9.24M
{
1492
9.24M
  CacheInfo
1493
9.24M
    *magick_restrict cache_info;
1494
1495
9.24M
  const int
1496
9.24M
    id = GetOpenMPThreadId();
1497
1498
9.24M
  assert(image != (const Image *) NULL);
1499
9.24M
  assert(image->signature == MagickCoreSignature);
1500
9.24M
  assert(image->cache != (Cache) NULL);
1501
9.24M
  cache_info=(CacheInfo *) image->cache;
1502
9.24M
  assert(cache_info->signature == MagickCoreSignature);
1503
9.24M
  if (cache_info->methods.get_authentic_pixels_from_handler !=
1504
9.24M
       (GetAuthenticPixelsFromHandler) NULL)
1505
83.2k
    return(cache_info->methods.get_authentic_pixels_from_handler(image));
1506
9.24M
  assert(id < (int) cache_info->number_threads);
1507
9.16M
  return(cache_info->nexus_info[id]->pixels);
1508
9.16M
}
1509

1510
/*
1511
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512
%                                                                             %
1513
%                                                                             %
1514
%                                                                             %
1515
%   G e t A u t h e n t i c P i x e l s                                       %
1516
%                                                                             %
1517
%                                                                             %
1518
%                                                                             %
1519
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1520
%
1521
%  GetAuthenticPixels() obtains a pixel region for read/write access. If the
1522
%  region is successfully accessed, a pointer to a Quantum array
1523
%  representing the region is returned, otherwise NULL is returned.
1524
%
1525
%  The returned pointer may point to a temporary working copy of the pixels
1526
%  or it may point to the original pixels in memory. Performance is maximized
1527
%  if the selected region is part of one row, or one or more full rows, since
1528
%  then there is opportunity to access the pixels in-place (without a copy)
1529
%  if the image is in memory, or in a memory-mapped file. The returned pointer
1530
%  must *never* be deallocated by the user.
1531
%
1532
%  Pixels accessed via the returned pointer represent a simple array of type
1533
%  Quantum.  If the image has corresponding metacontent,call
1534
%  GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1535
%  meta-content corresponding to the region.  Once the Quantum array has
1536
%  been updated, the changes must be saved back to the underlying image using
1537
%  SyncAuthenticPixels() or they may be lost.
1538
%
1539
%  The format of the GetAuthenticPixels() method is:
1540
%
1541
%      Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1542
%        const ssize_t y,const size_t columns,const size_t rows,
1543
%        ExceptionInfo *exception)
1544
%
1545
%  A description of each parameter follows:
1546
%
1547
%    o image: the image.
1548
%
1549
%    o x,y,columns,rows:  These values define the perimeter of a region of
1550
%      pixels.
1551
%
1552
%    o exception: return any errors or warnings in this structure.
1553
%
1554
*/
1555
MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1556
  const ssize_t y,const size_t columns,const size_t rows,
1557
  ExceptionInfo *exception)
1558
35.2M
{
1559
35.2M
  CacheInfo
1560
35.2M
    *magick_restrict cache_info;
1561
1562
35.2M
  const int
1563
35.2M
    id = GetOpenMPThreadId();
1564
1565
35.2M
  Quantum
1566
35.2M
    *pixels;
1567
1568
35.2M
  assert(image != (Image *) NULL);
1569
35.2M
  assert(image->signature == MagickCoreSignature);
1570
35.2M
  assert(image->cache != (Cache) NULL);
1571
35.2M
  cache_info=(CacheInfo *) image->cache;
1572
35.2M
  assert(cache_info->signature == MagickCoreSignature);
1573
35.2M
  if (cache_info->methods.get_authentic_pixels_handler !=
1574
35.2M
      (GetAuthenticPixelsHandler) NULL)
1575
15.9k
    {
1576
15.9k
      pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1577
15.9k
        rows,exception);
1578
15.9k
      return(pixels);
1579
15.9k
    }
1580
35.2M
  assert(id < (int) cache_info->number_threads);
1581
35.2M
  pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1582
35.2M
    cache_info->nexus_info[id],exception);
1583
35.2M
  return(pixels);
1584
35.2M
}
1585

1586
/*
1587
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588
%                                                                             %
1589
%                                                                             %
1590
%                                                                             %
1591
+   G e t A u t h e n t i c P i x e l s C a c h e                             %
1592
%                                                                             %
1593
%                                                                             %
1594
%                                                                             %
1595
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596
%
1597
%  GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1598
%  as defined by the geometry parameters.   A pointer to the pixels is returned
1599
%  if the pixels are transferred, otherwise a NULL is returned.
1600
%
1601
%  The format of the GetAuthenticPixelsCache() method is:
1602
%
1603
%      Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1604
%        const ssize_t y,const size_t columns,const size_t rows,
1605
%        ExceptionInfo *exception)
1606
%
1607
%  A description of each parameter follows:
1608
%
1609
%    o image: the image.
1610
%
1611
%    o x,y,columns,rows:  These values define the perimeter of a region of
1612
%      pixels.
1613
%
1614
%    o exception: return any errors or warnings in this structure.
1615
%
1616
*/
1617
static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1618
  const ssize_t y,const size_t columns,const size_t rows,
1619
  ExceptionInfo *exception)
1620
0
{
1621
0
  CacheInfo
1622
0
    *magick_restrict cache_info;
1623
1624
0
  const int
1625
0
    id = GetOpenMPThreadId();
1626
1627
0
  Quantum
1628
0
    *magick_restrict pixels;
1629
1630
0
  assert(image != (const Image *) NULL);
1631
0
  assert(image->signature == MagickCoreSignature);
1632
0
  assert(image->cache != (Cache) NULL);
1633
0
  cache_info=(CacheInfo *) image->cache;
1634
0
  if (cache_info == (Cache) NULL)
1635
0
    return((Quantum *) NULL);
1636
0
  assert(cache_info->signature == MagickCoreSignature);
1637
0
  assert(id < (int) cache_info->number_threads);
1638
0
  pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1639
0
    cache_info->nexus_info[id],exception);
1640
0
  return(pixels);
1641
0
}
1642

1643
/*
1644
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1645
%                                                                             %
1646
%                                                                             %
1647
%                                                                             %
1648
+   G e t I m a g e E x t e n t                                               %
1649
%                                                                             %
1650
%                                                                             %
1651
%                                                                             %
1652
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1653
%
1654
%  GetImageExtent() returns the extent of the pixels associated corresponding
1655
%  with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1656
%
1657
%  The format of the GetImageExtent() method is:
1658
%
1659
%      MagickSizeType GetImageExtent(const Image *image)
1660
%
1661
%  A description of each parameter follows:
1662
%
1663
%    o image: the image.
1664
%
1665
*/
1666
MagickExport MagickSizeType GetImageExtent(const Image *image)
1667
11.3M
{
1668
11.3M
  CacheInfo
1669
11.3M
    *magick_restrict cache_info;
1670
1671
11.3M
  const int
1672
11.3M
    id = GetOpenMPThreadId();
1673
1674
11.3M
  assert(image != (Image *) NULL);
1675
11.3M
  assert(image->signature == MagickCoreSignature);
1676
11.3M
  if (IsEventLogging() != MagickFalse)
1677
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1678
11.3M
  assert(image->cache != (Cache) NULL);
1679
11.3M
  cache_info=(CacheInfo *) image->cache;
1680
11.3M
  assert(cache_info->signature == MagickCoreSignature);
1681
11.3M
  assert(id < (int) cache_info->number_threads);
1682
11.3M
  return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1683
11.3M
}
1684

1685
/*
1686
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1687
%                                                                             %
1688
%                                                                             %
1689
%                                                                             %
1690
+   G e t I m a g e P i x e l C a c h e                                       %
1691
%                                                                             %
1692
%                                                                             %
1693
%                                                                             %
1694
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1695
%
1696
%  GetImagePixelCache() ensures that there is only a single reference to the
1697
%  pixel cache to be modified, updating the provided cache pointer to point to
1698
%  a clone of the original pixel cache if necessary.
1699
%
1700
%  The format of the GetImagePixelCache method is:
1701
%
1702
%      Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1703
%        ExceptionInfo *exception)
1704
%
1705
%  A description of each parameter follows:
1706
%
1707
%    o image: the image.
1708
%
1709
%    o clone: any value other than MagickFalse clones the cache pixels.
1710
%
1711
%    o exception: return any errors or warnings in this structure.
1712
%
1713
*/
1714
1715
static MagickBooleanType GetDynamicThrottlePolicy(void)
1716
291M
{
1717
291M
  static MagickBooleanType
1718
291M
    check_policy = MagickTrue;
1719
1720
291M
  static MagickBooleanType
1721
291M
    dynamic_throttle = MagickFalse;
1722
1723
291M
  if (check_policy != MagickFalse)
1724
101
    {
1725
101
      char *value = GetPolicyValue("resource:dynamic-throttle");
1726
101
      if (value != (char *) NULL)
1727
0
        {
1728
0
          dynamic_throttle=IsStringTrue(value);
1729
0
          value=DestroyString(value);
1730
0
        }
1731
101
      check_policy=MagickFalse;
1732
101
    }
1733
291M
  return(dynamic_throttle);
1734
291M
}
1735
1736
static inline MagickBooleanType ValidatePixelCacheMorphology(
1737
  const Image *magick_restrict image)
1738
291M
{
1739
291M
  const CacheInfo
1740
291M
    *magick_restrict cache_info;
1741
1742
291M
  const PixelChannelMap
1743
291M
    *magick_restrict p,
1744
291M
    *magick_restrict q;
1745
1746
  /*
1747
    Does the image match the pixel cache morphology?
1748
  */
1749
291M
  cache_info=(CacheInfo *) image->cache;
1750
291M
  p=image->channel_map;
1751
291M
  q=cache_info->channel_map;
1752
291M
  if ((image->storage_class != cache_info->storage_class) ||
1753
290M
      (image->colorspace != cache_info->colorspace) ||
1754
290M
      (image->alpha_trait != cache_info->alpha_trait) ||
1755
290M
      (image->channels != cache_info->channels) ||
1756
290M
      (image->columns != cache_info->columns) ||
1757
290M
      (image->rows != cache_info->rows) ||
1758
290M
      (image->number_channels != cache_info->number_channels) ||
1759
290M
      (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1760
290M
      (image->metacontent_extent != cache_info->metacontent_extent) ||
1761
290M
      (cache_info->nexus_info == (NexusInfo **) NULL))
1762
1.45M
    return(MagickFalse);
1763
290M
  return(MagickTrue);
1764
291M
}
1765
1766
static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1767
  ExceptionInfo *exception)
1768
291M
{
1769
291M
  CacheInfo
1770
291M
    *magick_restrict cache_info;
1771
1772
291M
  MagickBooleanType
1773
291M
    destroy,
1774
291M
    status = MagickTrue;
1775
1776
291M
  static MagickSizeType
1777
291M
    cpu_throttle = MagickResourceInfinity,
1778
291M
    cycles = 0;
1779
1780
291M
  if (IsImageTTLExpired(image) != MagickFalse)
1781
0
    {
1782
0
#if defined(ESTALE)
1783
0
      errno=ESTALE;
1784
0
#endif
1785
0
      (void) ThrowMagickException(exception,GetMagickModule(),
1786
0
        ResourceLimitError,"TimeLimitExceeded","`%s'",image->filename);
1787
0
      return((Cache) NULL);
1788
0
    }
1789
291M
  if (cpu_throttle == MagickResourceInfinity)
1790
101
    cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1791
291M
  if ((GetDynamicThrottlePolicy() != MagickFalse) && ((cycles % 65536) == 0))
1792
0
    {
1793
0
      const double
1794
0
        max_delay = 50.0,
1795
0
        sensitivity = 0.3;
1796
1797
0
      double
1798
0
        load,
1799
0
        load_average = 0.0;
1800
1801
      /*
1802
        Dynamically throttle the CPU relative to the load average.
1803
      */
1804
0
#if defined(MAGICKCORE_HAVE_GETLOADAVG)
1805
0
      if (getloadavg(&load_average,1) != 1)
1806
0
        load_average=0.0;
1807
0
#endif
1808
0
      load=MagickMax(load_average-GetOpenMPMaximumThreads(),0.0);
1809
0
      cpu_throttle=(MagickSizeType) (max_delay*(1.0-exp(-sensitivity*load)));
1810
0
    }
1811
291M
  if ((cpu_throttle != 0) && ((cycles % 4096) == 0))
1812
0
    MagickDelay(cpu_throttle);
1813
291M
  cycles++;
1814
291M
  LockSemaphoreInfo(image->semaphore);
1815
291M
  assert(image->cache != (Cache) NULL);
1816
291M
  cache_info=(CacheInfo *) image->cache;
1817
#if defined(MAGICKCORE_OPENCL_SUPPORT)
1818
  CopyOpenCLBuffer(cache_info);
1819
#endif
1820
291M
  destroy=MagickFalse;
1821
291M
  if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1822
219k
    {
1823
219k
      LockSemaphoreInfo(cache_info->semaphore);
1824
219k
      if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1825
219k
        {
1826
219k
          CacheInfo
1827
219k
            *clone_info;
1828
1829
219k
          Image
1830
219k
            clone_image;
1831
1832
          /*
1833
            Clone pixel cache.
1834
          */
1835
219k
          clone_image=(*image);
1836
219k
          clone_image.semaphore=AcquireSemaphoreInfo();
1837
219k
          clone_image.reference_count=1;
1838
219k
          clone_image.cache=ClonePixelCache(cache_info);
1839
219k
          clone_info=(CacheInfo *) clone_image.cache;
1840
219k
          status=OpenPixelCache(&clone_image,IOMode,exception);
1841
219k
          if (status == MagickFalse)
1842
104
            clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
1843
219k
          else
1844
219k
            {
1845
219k
              if (clone != MagickFalse)
1846
210k
                status=ClonePixelCacheRepository(clone_info,cache_info,
1847
210k
                  exception);
1848
219k
              if (status == MagickFalse)
1849
0
                clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
1850
219k
              else
1851
219k
                {
1852
219k
                  destroy=MagickTrue;
1853
219k
                  image->cache=clone_info;
1854
219k
                }
1855
219k
            }
1856
219k
          RelinquishSemaphoreInfo(&clone_image.semaphore);
1857
219k
        }
1858
219k
      UnlockSemaphoreInfo(cache_info->semaphore);
1859
219k
    }
1860
291M
  if (destroy != MagickFalse)
1861
219k
    cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1862
291M
  if (status != MagickFalse)
1863
291M
    {
1864
      /*
1865
        Ensure the image matches the pixel cache morphology.
1866
      */
1867
291M
      if (ValidatePixelCacheMorphology(image) == MagickFalse)
1868
1.45M
        {
1869
1.45M
          image->type=UndefinedType;
1870
1.45M
          status=OpenPixelCache(image,IOMode,exception);
1871
1.45M
          cache_info=(CacheInfo *) image->cache;
1872
1.45M
          if (cache_info->file != -1)
1873
116
            (void) ClosePixelCacheOnDisk(cache_info);
1874
1.45M
        }
1875
291M
    }
1876
291M
  UnlockSemaphoreInfo(image->semaphore);
1877
291M
  if (status == MagickFalse)
1878
32.5k
    return((Cache) NULL);
1879
291M
  return(image->cache);
1880
291M
}
1881

1882
/*
1883
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1884
%                                                                             %
1885
%                                                                             %
1886
%                                                                             %
1887
+   G e t I m a g e P i x e l C a c h e T y p e                               %
1888
%                                                                             %
1889
%                                                                             %
1890
%                                                                             %
1891
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1892
%
1893
%  GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1894
%  DiskCache, MemoryCache, MapCache, or PingCache.
1895
%
1896
%  The format of the GetImagePixelCacheType() method is:
1897
%
1898
%      CacheType GetImagePixelCacheType(const Image *image)
1899
%
1900
%  A description of each parameter follows:
1901
%
1902
%    o image: the image.
1903
%
1904
*/
1905
MagickExport CacheType GetImagePixelCacheType(const Image *image)
1906
63.0k
{
1907
63.0k
  CacheInfo
1908
63.0k
    *magick_restrict cache_info;
1909
1910
63.0k
  assert(image != (Image *) NULL);
1911
63.0k
  assert(image->signature == MagickCoreSignature);
1912
63.0k
  assert(image->cache != (Cache) NULL);
1913
63.0k
  cache_info=(CacheInfo *) image->cache;
1914
63.0k
  assert(cache_info->signature == MagickCoreSignature);
1915
63.0k
  return(cache_info->type);
1916
63.0k
}
1917

1918
/*
1919
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1920
%                                                                             %
1921
%                                                                             %
1922
%                                                                             %
1923
%   G e t O n e A u t h e n t i c P i x e l                                   %
1924
%                                                                             %
1925
%                                                                             %
1926
%                                                                             %
1927
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1928
%
1929
%  GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1930
%  location.  The image background color is returned if an error occurs.
1931
%
1932
%  The format of the GetOneAuthenticPixel() method is:
1933
%
1934
%      MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1935
%        const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1936
%
1937
%  A description of each parameter follows:
1938
%
1939
%    o image: the image.
1940
%
1941
%    o x,y:  These values define the location of the pixel to return.
1942
%
1943
%    o pixel: return a pixel at the specified (x,y) location.
1944
%
1945
%    o exception: return any errors or warnings in this structure.
1946
%
1947
*/
1948
1949
static inline MagickBooleanType CopyPixel(const Image *image,
1950
  const Quantum *source,Quantum *destination)
1951
0
{
1952
0
  ssize_t
1953
0
    i;
1954
1955
0
  if (source == (const Quantum *) NULL)
1956
0
    {
1957
0
      destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1958
0
      destination[GreenPixelChannel]=ClampToQuantum(
1959
0
        image->background_color.green);
1960
0
      destination[BluePixelChannel]=ClampToQuantum(
1961
0
        image->background_color.blue);
1962
0
      destination[BlackPixelChannel]=ClampToQuantum(
1963
0
        image->background_color.black);
1964
0
      destination[AlphaPixelChannel]=ClampToQuantum(
1965
0
        image->background_color.alpha);
1966
0
      return(MagickFalse);
1967
0
    }
1968
0
  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1969
0
  {
1970
0
    PixelChannel channel = GetPixelChannelChannel(image,i);
1971
0
    destination[channel]=source[i];
1972
0
  }
1973
0
  return(MagickTrue);
1974
0
}
1975
1976
MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1977
  const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1978
0
{
1979
0
  CacheInfo
1980
0
    *magick_restrict cache_info;
1981
1982
0
  Quantum
1983
0
    *magick_restrict q;
1984
1985
0
  assert(image != (Image *) NULL);
1986
0
  assert(image->signature == MagickCoreSignature);
1987
0
  assert(image->cache != (Cache) NULL);
1988
0
  cache_info=(CacheInfo *) image->cache;
1989
0
  assert(cache_info->signature == MagickCoreSignature);
1990
0
  (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1991
0
  if (cache_info->methods.get_one_authentic_pixel_from_handler != (GetOneAuthenticPixelFromHandler) NULL)
1992
0
    return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,pixel,exception));
1993
0
  q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1994
0
  return(CopyPixel(image,q,pixel));
1995
0
}
1996

1997
/*
1998
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999
%                                                                             %
2000
%                                                                             %
2001
%                                                                             %
2002
+   G e t O n e A u t h e n t i c P i x e l F r o m C a c h e                 %
2003
%                                                                             %
2004
%                                                                             %
2005
%                                                                             %
2006
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007
%
2008
%  GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2009
%  location.  The image background color is returned if an error occurs.
2010
%
2011
%  The format of the GetOneAuthenticPixelFromCache() method is:
2012
%
2013
%      MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2014
%        const ssize_t x,const ssize_t y,Quantum *pixel,
2015
%        ExceptionInfo *exception)
2016
%
2017
%  A description of each parameter follows:
2018
%
2019
%    o image: the image.
2020
%
2021
%    o x,y:  These values define the location of the pixel to return.
2022
%
2023
%    o pixel: return a pixel at the specified (x,y) location.
2024
%
2025
%    o exception: return any errors or warnings in this structure.
2026
%
2027
*/
2028
static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2029
  const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2030
0
{
2031
0
  CacheInfo
2032
0
    *magick_restrict cache_info;
2033
2034
0
  const int
2035
0
    id = GetOpenMPThreadId();
2036
2037
0
  Quantum
2038
0
    *magick_restrict q;
2039
2040
0
  assert(image != (const Image *) NULL);
2041
0
  assert(image->signature == MagickCoreSignature);
2042
0
  assert(image->cache != (Cache) NULL);
2043
0
  cache_info=(CacheInfo *) image->cache;
2044
0
  assert(cache_info->signature == MagickCoreSignature);
2045
0
  assert(id < (int) cache_info->number_threads);
2046
0
  (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2047
0
  q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2048
0
    exception);
2049
0
  return(CopyPixel(image,q,pixel));
2050
0
}
2051

2052
/*
2053
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2054
%                                                                             %
2055
%                                                                             %
2056
%                                                                             %
2057
%   G e t O n e V i r t u a l P i x e l                                       %
2058
%                                                                             %
2059
%                                                                             %
2060
%                                                                             %
2061
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2062
%
2063
%  GetOneVirtualPixel() returns a single virtual pixel at the specified
2064
%  (x,y) location.  The image background color is returned if an error occurs.
2065
%  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2066
%
2067
%  The format of the GetOneVirtualPixel() method is:
2068
%
2069
%      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2070
%        const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2071
%
2072
%  A description of each parameter follows:
2073
%
2074
%    o image: the image.
2075
%
2076
%    o x,y:  These values define the location of the pixel to return.
2077
%
2078
%    o pixel: return a pixel at the specified (x,y) location.
2079
%
2080
%    o exception: return any errors or warnings in this structure.
2081
%
2082
*/
2083
MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2084
  const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2085
0
{
2086
0
  CacheInfo
2087
0
    *magick_restrict cache_info;
2088
2089
0
  const int
2090
0
    id = GetOpenMPThreadId();
2091
2092
0
  const Quantum
2093
0
    *p;
2094
2095
0
  assert(image != (const Image *) NULL);
2096
0
  assert(image->signature == MagickCoreSignature);
2097
0
  assert(image->cache != (Cache) NULL);
2098
0
  cache_info=(CacheInfo *) image->cache;
2099
0
  assert(cache_info->signature == MagickCoreSignature);
2100
0
  (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2101
0
  if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2102
0
       (GetOneVirtualPixelFromHandler) NULL)
2103
0
    return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2104
0
      GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2105
0
  assert(id < (int) cache_info->number_threads);
2106
0
  p=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2107
0
    1UL,1UL,cache_info->nexus_info[id],exception);
2108
0
  return(CopyPixel(image,p,pixel));
2109
0
}
2110

2111
/*
2112
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2113
%                                                                             %
2114
%                                                                             %
2115
%                                                                             %
2116
+   G e t O n e V i r t u a l P i x e l F r o m C a c h e                     %
2117
%                                                                             %
2118
%                                                                             %
2119
%                                                                             %
2120
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2121
%
2122
%  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2123
%  specified (x,y) location.  The image background color is returned if an
2124
%  error occurs.
2125
%
2126
%  The format of the GetOneVirtualPixelFromCache() method is:
2127
%
2128
%      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2129
%        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2130
%        Quantum *pixel,ExceptionInfo *exception)
2131
%
2132
%  A description of each parameter follows:
2133
%
2134
%    o image: the image.
2135
%
2136
%    o virtual_pixel_method: the virtual pixel method.
2137
%
2138
%    o x,y:  These values define the location of the pixel to return.
2139
%
2140
%    o pixel: return a pixel at the specified (x,y) location.
2141
%
2142
%    o exception: return any errors or warnings in this structure.
2143
%
2144
*/
2145
static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2146
  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2147
  Quantum *pixel,ExceptionInfo *exception)
2148
0
{
2149
0
  CacheInfo
2150
0
    *magick_restrict cache_info;
2151
2152
0
  const int
2153
0
    id = GetOpenMPThreadId();
2154
2155
0
  const Quantum
2156
0
    *p;
2157
2158
0
  assert(image != (const Image *) NULL);
2159
0
  assert(image->signature == MagickCoreSignature);
2160
0
  assert(image->cache != (Cache) NULL);
2161
0
  cache_info=(CacheInfo *) image->cache;
2162
0
  assert(cache_info->signature == MagickCoreSignature);
2163
0
  assert(id < (int) cache_info->number_threads);
2164
0
  (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2165
0
  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2166
0
    cache_info->nexus_info[id],exception);
2167
0
  return(CopyPixel(image,p,pixel));
2168
0
}
2169

2170
/*
2171
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2172
%                                                                             %
2173
%                                                                             %
2174
%                                                                             %
2175
%   G e t O n e V i r t u a l P i x e l I n f o                               %
2176
%                                                                             %
2177
%                                                                             %
2178
%                                                                             %
2179
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2180
%
2181
%  GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2182
%  location.  The image background color is returned if an error occurs.  If
2183
%  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2184
%
2185
%  The format of the GetOneVirtualPixelInfo() method is:
2186
%
2187
%      MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2188
%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2189
%        const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2190
%
2191
%  A description of each parameter follows:
2192
%
2193
%    o image: the image.
2194
%
2195
%    o virtual_pixel_method: the virtual pixel method.
2196
%
2197
%    o x,y:  these values define the location of the pixel to return.
2198
%
2199
%    o pixel: return a pixel at the specified (x,y) location.
2200
%
2201
%    o exception: return any errors or warnings in this structure.
2202
%
2203
*/
2204
MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2205
  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2206
  PixelInfo *pixel,ExceptionInfo *exception)
2207
3.33M
{
2208
3.33M
  CacheInfo
2209
3.33M
    *magick_restrict cache_info;
2210
2211
3.33M
  const int
2212
3.33M
    id = GetOpenMPThreadId();
2213
2214
3.33M
  const Quantum
2215
3.33M
    *magick_restrict p;
2216
2217
3.33M
  assert(image != (const Image *) NULL);
2218
3.33M
  assert(image->signature == MagickCoreSignature);
2219
3.33M
  assert(image->cache != (Cache) NULL);
2220
3.33M
  cache_info=(CacheInfo *) image->cache;
2221
3.33M
  assert(cache_info->signature == MagickCoreSignature);
2222
3.33M
  assert(id < (int) cache_info->number_threads);
2223
3.33M
  GetPixelInfo(image,pixel);
2224
3.33M
  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2225
3.33M
    cache_info->nexus_info[id],exception);
2226
3.33M
  if (p == (const Quantum *) NULL)
2227
647k
    return(MagickFalse);
2228
2.69M
  GetPixelInfoPixel(image,p,pixel);
2229
2.69M
  return(MagickTrue);
2230
3.33M
}
2231

2232
/*
2233
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2234
%                                                                             %
2235
%                                                                             %
2236
%                                                                             %
2237
+   G e t P i x e l C a c h e C o l o r s p a c e                             %
2238
%                                                                             %
2239
%                                                                             %
2240
%                                                                             %
2241
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242
%
2243
%  GetPixelCacheColorspace() returns the colorspace of the pixel cache.
2244
%
2245
%  The format of the GetPixelCacheColorspace() method is:
2246
%
2247
%      Colorspace GetPixelCacheColorspace(const Cache cache)
2248
%
2249
%  A description of each parameter follows:
2250
%
2251
%    o cache: the pixel cache.
2252
%
2253
*/
2254
MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2255
0
{
2256
0
  CacheInfo
2257
0
    *magick_restrict cache_info;
2258
2259
0
  assert(cache != (Cache) NULL);
2260
0
  cache_info=(CacheInfo *) cache;
2261
0
  assert(cache_info->signature == MagickCoreSignature);
2262
0
  if (IsEventLogging() != MagickFalse)
2263
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2264
0
      cache_info->filename);
2265
0
  return(cache_info->colorspace);
2266
0
}
2267

2268
/*
2269
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270
%                                                                             %
2271
%                                                                             %
2272
%                                                                             %
2273
+   G e t P i x e l C a c h e F i l e n a m e                                 %
2274
%                                                                             %
2275
%                                                                             %
2276
%                                                                             %
2277
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278
%
2279
%  GetPixelCacheFilename() returns the filename associated with the pixel
2280
%  cache.
2281
%
2282
%  The format of the GetPixelCacheFilename() method is:
2283
%
2284
%      const char *GetPixelCacheFilename(const Image *image)
2285
%
2286
%  A description of each parameter follows:
2287
%
2288
%    o image: the image.
2289
%
2290
*/
2291
MagickExport const char *GetPixelCacheFilename(const Image *image)
2292
0
{
2293
0
  CacheInfo
2294
0
    *magick_restrict cache_info;
2295
2296
0
  assert(image != (const Image *) NULL);
2297
0
  assert(image->signature == MagickCoreSignature);
2298
0
  assert(image->cache != (Cache) NULL);
2299
0
  cache_info=(CacheInfo *) image->cache;
2300
0
  assert(cache_info->signature == MagickCoreSignature);
2301
0
  return(cache_info->cache_filename);
2302
0
}
2303

2304
/*
2305
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2306
%                                                                             %
2307
%                                                                             %
2308
%                                                                             %
2309
+   G e t P i x e l C a c h e M e t h o d s                                   %
2310
%                                                                             %
2311
%                                                                             %
2312
%                                                                             %
2313
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2314
%
2315
%  GetPixelCacheMethods() initializes the CacheMethods structure.
2316
%
2317
%  The format of the GetPixelCacheMethods() method is:
2318
%
2319
%      void GetPixelCacheMethods(CacheMethods *cache_methods)
2320
%
2321
%  A description of each parameter follows:
2322
%
2323
%    o cache_methods: Specifies a pointer to a CacheMethods structure.
2324
%
2325
*/
2326
MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2327
39.9k
{
2328
39.9k
  assert(cache_methods != (CacheMethods *) NULL);
2329
39.9k
  (void) memset(cache_methods,0,sizeof(*cache_methods));
2330
39.9k
  cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2331
39.9k
  cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2332
39.9k
  cache_methods->get_virtual_metacontent_from_handler=
2333
39.9k
    GetVirtualMetacontentFromCache;
2334
39.9k
  cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2335
39.9k
  cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2336
39.9k
  cache_methods->get_authentic_metacontent_from_handler=
2337
39.9k
    GetAuthenticMetacontentFromCache;
2338
39.9k
  cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2339
39.9k
  cache_methods->get_one_authentic_pixel_from_handler=
2340
39.9k
    GetOneAuthenticPixelFromCache;
2341
39.9k
  cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2342
39.9k
  cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2343
39.9k
  cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2344
39.9k
}
2345

2346
/*
2347
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2348
%                                                                             %
2349
%                                                                             %
2350
%                                                                             %
2351
+   G e t P i x e l C a c h e N e x u s E x t e n t                           %
2352
%                                                                             %
2353
%                                                                             %
2354
%                                                                             %
2355
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2356
%
2357
%  GetPixelCacheNexusExtent() returns the extent of the pixels associated
2358
%  corresponding with the last call to SetPixelCacheNexusPixels() or
2359
%  GetPixelCacheNexusPixels().
2360
%
2361
%  The format of the GetPixelCacheNexusExtent() method is:
2362
%
2363
%      MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2364
%        NexusInfo *nexus_info)
2365
%
2366
%  A description of each parameter follows:
2367
%
2368
%    o nexus_info: the nexus info.
2369
%
2370
*/
2371
MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2372
  NexusInfo *magick_restrict nexus_info)
2373
11.3M
{
2374
11.3M
  CacheInfo
2375
11.3M
    *magick_restrict cache_info;
2376
2377
11.3M
  MagickSizeType
2378
11.3M
    extent;
2379
2380
11.3M
  assert(cache != NULL);
2381
11.3M
  cache_info=(CacheInfo *) cache;
2382
11.3M
  assert(cache_info->signature == MagickCoreSignature);
2383
11.3M
  extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2384
11.3M
  if (extent == 0)
2385
81.8k
    return((MagickSizeType) cache_info->columns*cache_info->rows);
2386
11.3M
  return(extent);
2387
11.3M
}
2388

2389
/*
2390
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2391
%                                                                             %
2392
%                                                                             %
2393
%                                                                             %
2394
+   G e t P i x e l C a c h e P i x e l s                                     %
2395
%                                                                             %
2396
%                                                                             %
2397
%                                                                             %
2398
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2399
%
2400
%  GetPixelCachePixels() returns the pixels associated with the specified image.
2401
%
2402
%  The format of the GetPixelCachePixels() method is:
2403
%
2404
%      void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2405
%        ExceptionInfo *exception)
2406
%
2407
%  A description of each parameter follows:
2408
%
2409
%    o image: the image.
2410
%
2411
%    o length: the pixel cache length.
2412
%
2413
%    o exception: return any errors or warnings in this structure.
2414
%
2415
*/
2416
MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2417
  ExceptionInfo *magick_unused(exception))
2418
0
{
2419
0
  CacheInfo
2420
0
    *magick_restrict cache_info;
2421
2422
0
  assert(image != (const Image *) NULL);
2423
0
  assert(image->signature == MagickCoreSignature);
2424
0
  assert(image->cache != (Cache) NULL);
2425
0
  assert(length != (MagickSizeType *) NULL);
2426
0
  magick_unreferenced(exception);
2427
0
  cache_info=(CacheInfo *) image->cache;
2428
0
  assert(cache_info->signature == MagickCoreSignature);
2429
0
  *length=cache_info->length;
2430
0
  if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2431
0
    return((void *) NULL);
2432
0
  return((void *) cache_info->pixels);
2433
0
}
2434

2435
/*
2436
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2437
%                                                                             %
2438
%                                                                             %
2439
%                                                                             %
2440
+   G e t P i x e l C a c h e S t o r a g e C l a s s                         %
2441
%                                                                             %
2442
%                                                                             %
2443
%                                                                             %
2444
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2445
%
2446
%  GetPixelCacheStorageClass() returns the class type of the pixel cache.
2447
%
2448
%  The format of the GetPixelCacheStorageClass() method is:
2449
%
2450
%      ClassType GetPixelCacheStorageClass(Cache cache)
2451
%
2452
%  A description of each parameter follows:
2453
%
2454
%    o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2455
%
2456
%    o cache: the pixel cache.
2457
%
2458
*/
2459
MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2460
0
{
2461
0
  CacheInfo
2462
0
    *magick_restrict cache_info;
2463
2464
0
  assert(cache != (Cache) NULL);
2465
0
  cache_info=(CacheInfo *) cache;
2466
0
  assert(cache_info->signature == MagickCoreSignature);
2467
0
  if (IsEventLogging() != MagickFalse)
2468
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2469
0
      cache_info->filename);
2470
0
  return(cache_info->storage_class);
2471
0
}
2472

2473
/*
2474
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2475
%                                                                             %
2476
%                                                                             %
2477
%                                                                             %
2478
+   G e t P i x e l C a c h e T i l e S i z e                                 %
2479
%                                                                             %
2480
%                                                                             %
2481
%                                                                             %
2482
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2483
%
2484
%  GetPixelCacheTileSize() returns the pixel cache tile size.
2485
%
2486
%  The format of the GetPixelCacheTileSize() method is:
2487
%
2488
%      void GetPixelCacheTileSize(const Image *image,size_t *width,
2489
%        size_t *height)
2490
%
2491
%  A description of each parameter follows:
2492
%
2493
%    o image: the image.
2494
%
2495
%    o width: the optimized cache tile width in pixels.
2496
%
2497
%    o height: the optimized cache tile height in pixels.
2498
%
2499
*/
2500
MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2501
  size_t *height)
2502
5.57k
{
2503
5.57k
  CacheInfo
2504
5.57k
    *magick_restrict cache_info;
2505
2506
5.57k
  assert(image != (Image *) NULL);
2507
5.57k
  assert(image->signature == MagickCoreSignature);
2508
5.57k
  if (IsEventLogging() != MagickFalse)
2509
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2510
5.57k
  cache_info=(CacheInfo *) image->cache;
2511
5.57k
  assert(cache_info->signature == MagickCoreSignature);
2512
5.57k
  *width=2048UL/(MagickMax(cache_info->number_channels,1)*sizeof(Quantum));
2513
5.57k
  if (GetImagePixelCacheType(image) == DiskCache)
2514
0
    *width=8192UL/(MagickMax(cache_info->number_channels,1)*sizeof(Quantum));
2515
5.57k
  *height=(*width);
2516
5.57k
}
2517

2518
/*
2519
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2520
%                                                                             %
2521
%                                                                             %
2522
%                                                                             %
2523
+   G e t P i x e l C a c h e V i r t u a l M e t h o d                       %
2524
%                                                                             %
2525
%                                                                             %
2526
%                                                                             %
2527
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2528
%
2529
%  GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2530
%  pixel cache.  A virtual pixel is any pixel access that is outside the
2531
%  boundaries of the image cache.
2532
%
2533
%  The format of the GetPixelCacheVirtualMethod() method is:
2534
%
2535
%      VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2536
%
2537
%  A description of each parameter follows:
2538
%
2539
%    o image: the image.
2540
%
2541
*/
2542
MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2543
21.2M
{
2544
21.2M
  CacheInfo
2545
21.2M
    *magick_restrict cache_info;
2546
2547
21.2M
  assert(image != (Image *) NULL);
2548
21.2M
  assert(image->signature == MagickCoreSignature);
2549
21.2M
  assert(image->cache != (Cache) NULL);
2550
21.2M
  cache_info=(CacheInfo *) image->cache;
2551
21.2M
  assert(cache_info->signature == MagickCoreSignature);
2552
21.2M
  return(cache_info->virtual_pixel_method);
2553
21.2M
}
2554

2555
/*
2556
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2557
%                                                                             %
2558
%                                                                             %
2559
%                                                                             %
2560
+   G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e               %
2561
%                                                                             %
2562
%                                                                             %
2563
%                                                                             %
2564
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2565
%
2566
%  GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2567
%  the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2568
%
2569
%  The format of the GetVirtualMetacontentFromCache() method is:
2570
%
2571
%      void *GetVirtualMetacontentFromCache(const Image *image)
2572
%
2573
%  A description of each parameter follows:
2574
%
2575
%    o image: the image.
2576
%
2577
*/
2578
static const void *GetVirtualMetacontentFromCache(const Image *image)
2579
0
{
2580
0
  CacheInfo
2581
0
    *magick_restrict cache_info;
2582
2583
0
  const int
2584
0
    id = GetOpenMPThreadId();
2585
2586
0
  const void
2587
0
    *magick_restrict metacontent;
2588
2589
0
  assert(image != (const Image *) NULL);
2590
0
  assert(image->signature == MagickCoreSignature);
2591
0
  assert(image->cache != (Cache) NULL);
2592
0
  cache_info=(CacheInfo *) image->cache;
2593
0
  assert(cache_info->signature == MagickCoreSignature);
2594
0
  assert(id < (int) cache_info->number_threads);
2595
0
  metacontent=GetVirtualMetacontentFromNexus(cache_info,
2596
0
    cache_info->nexus_info[id]);
2597
0
  return(metacontent);
2598
0
}
2599

2600
/*
2601
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2602
%                                                                             %
2603
%                                                                             %
2604
%                                                                             %
2605
+   G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s               %
2606
%                                                                             %
2607
%                                                                             %
2608
%                                                                             %
2609
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2610
%
2611
%  GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2612
%  cache nexus.
2613
%
2614
%  The format of the GetVirtualMetacontentFromNexus() method is:
2615
%
2616
%      const void *GetVirtualMetacontentFromNexus(const Cache cache,
2617
%        NexusInfo *nexus_info)
2618
%
2619
%  A description of each parameter follows:
2620
%
2621
%    o cache: the pixel cache.
2622
%
2623
%    o nexus_info: the cache nexus to return the meta-content.
2624
%
2625
*/
2626
MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2627
  NexusInfo *magick_restrict nexus_info)
2628
3.83M
{
2629
3.83M
  CacheInfo
2630
3.83M
    *magick_restrict cache_info;
2631
2632
3.83M
  assert(cache != (Cache) NULL);
2633
3.83M
  cache_info=(CacheInfo *) cache;
2634
3.83M
  assert(cache_info->signature == MagickCoreSignature);
2635
3.83M
  if (cache_info->storage_class == UndefinedClass)
2636
0
    return((void *) NULL);
2637
3.83M
  return(nexus_info->metacontent);
2638
3.83M
}
2639

2640
/*
2641
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2642
%                                                                             %
2643
%                                                                             %
2644
%                                                                             %
2645
%   G e t V i r t u a l M e t a c o n t e n t                                 %
2646
%                                                                             %
2647
%                                                                             %
2648
%                                                                             %
2649
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2650
%
2651
%  GetVirtualMetacontent() returns the virtual metacontent corresponding with
2652
%  the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
2653
%  returned if the meta-content are not available.
2654
%
2655
%  The format of the GetVirtualMetacontent() method is:
2656
%
2657
%      const void *GetVirtualMetacontent(const Image *image)
2658
%
2659
%  A description of each parameter follows:
2660
%
2661
%    o image: the image.
2662
%
2663
*/
2664
MagickExport const void *GetVirtualMetacontent(const Image *image)
2665
0
{
2666
0
  CacheInfo
2667
0
    *magick_restrict cache_info;
2668
2669
0
  const int
2670
0
    id = GetOpenMPThreadId();
2671
2672
0
  const void
2673
0
    *magick_restrict metacontent;
2674
2675
0
  assert(image != (const Image *) NULL);
2676
0
  assert(image->signature == MagickCoreSignature);
2677
0
  assert(image->cache != (Cache) NULL);
2678
0
  cache_info=(CacheInfo *) image->cache;
2679
0
  assert(cache_info->signature == MagickCoreSignature);
2680
0
  if (cache_info->methods.get_virtual_metacontent_from_handler != (GetVirtualMetacontentFromHandler) NULL)
2681
0
    {
2682
0
      metacontent=cache_info->methods.get_virtual_metacontent_from_handler(
2683
0
        image);
2684
0
      if (metacontent != (const void *) NULL)
2685
0
        return(metacontent);
2686
0
    }
2687
0
  assert(id < (int) cache_info->number_threads);
2688
0
  metacontent=GetVirtualMetacontentFromNexus(cache_info,
2689
0
    cache_info->nexus_info[id]);
2690
0
  return(metacontent);
2691
0
}
2692

2693
/*
2694
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2695
%                                                                             %
2696
%                                                                             %
2697
%                                                                             %
2698
+   G e t V i r t u a l P i x e l C a c h e N e x u s                         %
2699
%                                                                             %
2700
%                                                                             %
2701
%                                                                             %
2702
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2703
%
2704
%  GetVirtualPixelCacheNexus() gets virtual pixels from the in-memory or disk
2705
%  pixel cache as defined by the geometry parameters.   A pointer to the pixels
2706
%  is returned if the pixels are transferred, otherwise a NULL is returned.
2707
%
2708
%  The format of the GetVirtualPixelCacheNexus() method is:
2709
%
2710
%      Quantum *GetVirtualPixelCacheNexus(const Image *image,
2711
%        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2712
%        const size_t columns,const size_t rows,NexusInfo *nexus_info,
2713
%        ExceptionInfo *exception)
2714
%
2715
%  A description of each parameter follows:
2716
%
2717
%    o image: the image.
2718
%
2719
%    o virtual_pixel_method: the virtual pixel method.
2720
%
2721
%    o x,y,columns,rows:  These values define the perimeter of a region of
2722
%      pixels.
2723
%
2724
%    o nexus_info: the cache nexus to acquire.
2725
%
2726
%    o exception: return any errors or warnings in this structure.
2727
%
2728
*/
2729
2730
static ssize_t
2731
  DitherMatrix[64] =
2732
  {
2733
     0,  48,  12,  60,   3,  51,  15,  63,
2734
    32,  16,  44,  28,  35,  19,  47,  31,
2735
     8,  56,   4,  52,  11,  59,   7,  55,
2736
    40,  24,  36,  20,  43,  27,  39,  23,
2737
     2,  50,  14,  62,   1,  49,  13,  61,
2738
    34,  18,  46,  30,  33,  17,  45,  29,
2739
    10,  58,   6,  54,   9,  57,   5,  53,
2740
    42,  26,  38,  22,  41,  25,  37,  21
2741
  };
2742
2743
static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2744
0
{
2745
0
  ssize_t
2746
0
    index;
2747
2748
0
  index=x+DitherMatrix[x & 0x07]-32L;
2749
0
  if (index < 0L)
2750
0
    return(0L);
2751
0
  if (index >= (ssize_t) columns)
2752
0
    return((ssize_t) columns-1L);
2753
0
  return(index);
2754
0
}
2755
2756
static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2757
0
{
2758
0
  ssize_t
2759
0
    index;
2760
2761
0
  index=y+DitherMatrix[y & 0x07]-32L;
2762
0
  if (index < 0L)
2763
0
    return(0L);
2764
0
  if (index >= (ssize_t) rows)
2765
0
    return((ssize_t) rows-1L);
2766
0
  return(index);
2767
0
}
2768
2769
static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2770
309k
{
2771
309k
  if (x < 0L)
2772
5.04k
    return(0L);
2773
304k
  if (x >= (ssize_t) columns)
2774
304k
    return((ssize_t) (columns-1));
2775
0
  return(x);
2776
304k
}
2777
2778
static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2779
386k
{
2780
386k
  if (y < 0L)
2781
2.07k
    return(0L);
2782
384k
  if (y >= (ssize_t) rows)
2783
42.5k
    return((ssize_t) (rows-1));
2784
341k
  return(y);
2785
384k
}
2786
2787
static inline MagickBooleanType IsOffsetOverflow(const MagickOffsetType x,
2788
  const MagickOffsetType y)
2789
654M
{
2790
654M
  if (((y > 0) && (x > ((MagickOffsetType) MAGICK_SSIZE_MAX-y))) ||
2791
654M
      ((y < 0) && (x < ((MagickOffsetType) MAGICK_SSIZE_MIN-y))))
2792
56
    return(MagickFalse);
2793
654M
  return(MagickTrue);
2794
654M
}
2795
2796
static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2797
0
{
2798
0
  return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2799
0
}
2800
2801
static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2802
0
{
2803
0
  return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2804
0
}
2805
2806
static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2807
  const size_t extent)
2808
5.31M
{
2809
5.31M
  MagickModulo
2810
5.31M
    modulo;
2811
2812
5.31M
  modulo.quotient=offset;
2813
5.31M
  modulo.remainder=0;
2814
5.31M
  if (extent != 0)
2815
5.31M
    {
2816
5.31M
      modulo.quotient=offset/((ssize_t) extent);
2817
5.31M
      modulo.remainder=offset % ((ssize_t) extent);
2818
5.31M
    }
2819
5.31M
  if ((modulo.remainder != 0) && ((offset ^ ((ssize_t) extent)) < 0))
2820
671
    {
2821
671
      modulo.quotient-=1;
2822
671
      modulo.remainder+=((ssize_t) extent);
2823
671
    }
2824
5.31M
  return(modulo);
2825
5.31M
}
2826
2827
MagickPrivate const Quantum *GetVirtualPixelCacheNexus(const Image *image,
2828
  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2829
  const size_t columns,const size_t rows,NexusInfo *nexus_info,
2830
  ExceptionInfo *exception)
2831
77.4M
{
2832
77.4M
  CacheInfo
2833
77.4M
    *magick_restrict cache_info;
2834
2835
77.4M
  const Quantum
2836
77.4M
    *magick_restrict p;
2837
2838
77.4M
  const void
2839
77.4M
    *magick_restrict r;
2840
2841
77.4M
  MagickOffsetType
2842
77.4M
    offset;
2843
2844
77.4M
  MagickSizeType
2845
77.4M
    length,
2846
77.4M
    number_pixels;
2847
2848
77.4M
  NexusInfo
2849
77.4M
    *magick_restrict virtual_nexus;
2850
2851
77.4M
  Quantum
2852
77.4M
    *magick_restrict pixels,
2853
77.4M
    *magick_restrict q,
2854
77.4M
    virtual_pixel[MaxPixelChannels];
2855
2856
77.4M
  ssize_t
2857
77.4M
    i,
2858
77.4M
    u,
2859
77.4M
    v;
2860
2861
77.4M
  unsigned char
2862
77.4M
    *magick_restrict s;
2863
2864
77.4M
  void
2865
77.4M
    *magick_restrict virtual_metacontent;
2866
2867
  /*
2868
    Acquire pixels.
2869
  */
2870
77.4M
  assert(image != (const Image *) NULL);
2871
77.4M
  assert(image->signature == MagickCoreSignature);
2872
77.4M
  assert(image->cache != (Cache) NULL);
2873
77.4M
  cache_info=(CacheInfo *) image->cache;
2874
77.4M
  assert(cache_info->signature == MagickCoreSignature);
2875
77.4M
  if (cache_info->type == UndefinedCache)
2876
647k
    return((const Quantum *) NULL);
2877
#if defined(MAGICKCORE_OPENCL_SUPPORT)
2878
  CopyOpenCLBuffer(cache_info);
2879
#endif
2880
76.8M
  pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,x,y,columns,rows,
2881
76.8M
    ((image->channels & WriteMaskChannel) != 0) ||
2882
76.7M
    ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
2883
76.8M
    nexus_info,exception);
2884
76.8M
  if (pixels == (Quantum *) NULL)
2885
9.67k
    return((const Quantum *) NULL);
2886
76.8M
  if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
2887
647
    return((const Quantum *) NULL);
2888
76.8M
  offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns;
2889
76.8M
  if (IsOffsetOverflow(offset,(MagickOffsetType) nexus_info->region.x) == MagickFalse)
2890
56
    return((const Quantum *) NULL);
2891
76.8M
  offset+=nexus_info->region.x;
2892
76.8M
  length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2893
76.8M
    nexus_info->region.width-1L;
2894
76.8M
  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2895
76.8M
  if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2896
63.1M
    if ((x >= 0) && ((x+(ssize_t) columns-1) < (ssize_t) cache_info->columns) &&
2897
56.1M
        (y >= 0) && ((y+(ssize_t) rows-1) < (ssize_t) cache_info->rows))
2898
56.1M
      {
2899
56.1M
        MagickBooleanType
2900
56.1M
          status;
2901
2902
        /*
2903
          Pixel request is inside cache extents.
2904
        */
2905
56.1M
        if (nexus_info->authentic_pixel_cache != MagickFalse)
2906
51.6M
          return(pixels);
2907
4.45M
        status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2908
4.45M
        if (status == MagickFalse)
2909
0
          return((const Quantum *) NULL);
2910
4.45M
        if (cache_info->metacontent_extent != 0)
2911
0
          {
2912
0
            status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2913
0
            if (status == MagickFalse)
2914
0
              return((const Quantum *) NULL);
2915
0
          }
2916
4.45M
        return(pixels);
2917
4.45M
      }
2918
  /*
2919
    Pixel request is outside cache extents.
2920
  */
2921
20.6M
  virtual_nexus=nexus_info->virtual_nexus;
2922
20.6M
  q=pixels;
2923
20.6M
  s=(unsigned char *) nexus_info->metacontent;
2924
20.6M
  (void) memset(virtual_pixel,0,cache_info->number_channels*
2925
20.6M
    sizeof(*virtual_pixel));
2926
20.6M
  virtual_metacontent=(void *) NULL;
2927
20.6M
  switch (virtual_pixel_method)
2928
20.6M
  {
2929
17.9M
    case BackgroundVirtualPixelMethod:
2930
17.9M
    case BlackVirtualPixelMethod:
2931
17.9M
    case GrayVirtualPixelMethod:
2932
17.9M
    case TransparentVirtualPixelMethod:
2933
17.9M
    case MaskVirtualPixelMethod:
2934
17.9M
    case WhiteVirtualPixelMethod:
2935
17.9M
    case EdgeVirtualPixelMethod:
2936
17.9M
    case CheckerTileVirtualPixelMethod:
2937
17.9M
    case HorizontalTileVirtualPixelMethod:
2938
17.9M
    case VerticalTileVirtualPixelMethod:
2939
17.9M
    {
2940
17.9M
      if (cache_info->metacontent_extent != 0)
2941
0
        {
2942
          /*
2943
            Acquire a metacontent buffer.
2944
          */
2945
0
          virtual_metacontent=(void *) AcquireQuantumMemory(1,
2946
0
            cache_info->metacontent_extent);
2947
0
          if (virtual_metacontent == (void *) NULL)
2948
0
            {
2949
0
              (void) ThrowMagickException(exception,GetMagickModule(),
2950
0
                CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2951
0
              return((const Quantum *) NULL);
2952
0
            }
2953
0
          (void) memset(virtual_metacontent,0,cache_info->metacontent_extent);
2954
0
        }
2955
17.9M
      switch (virtual_pixel_method)
2956
17.9M
      {
2957
0
        case BlackVirtualPixelMethod:
2958
0
        {
2959
0
          for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2960
0
            SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2961
0
          SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2962
0
          break;
2963
0
        }
2964
0
        case GrayVirtualPixelMethod:
2965
0
        {
2966
0
          for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2967
0
            SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2968
0
              virtual_pixel);
2969
0
          SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2970
0
          break;
2971
0
        }
2972
0
        case TransparentVirtualPixelMethod:
2973
0
        {
2974
0
          for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2975
0
            SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2976
0
          SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2977
0
          break;
2978
0
        }
2979
0
        case MaskVirtualPixelMethod:
2980
0
        case WhiteVirtualPixelMethod:
2981
0
        {
2982
0
          for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2983
0
            SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2984
0
          SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2985
0
          break;
2986
0
        }
2987
17.9M
        default:
2988
17.9M
        {
2989
17.9M
          SetPixelRed(image,ClampToQuantum(image->background_color.red),
2990
17.9M
            virtual_pixel);
2991
17.9M
          SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2992
17.9M
            virtual_pixel);
2993
17.9M
          SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2994
17.9M
            virtual_pixel);
2995
17.9M
          SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2996
17.9M
            virtual_pixel);
2997
17.9M
          SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2998
17.9M
            virtual_pixel);
2999
17.9M
          break;
3000
0
        }
3001
17.9M
      }
3002
17.9M
      break;
3003
17.9M
    }
3004
17.9M
    default:
3005
2.70M
      break;
3006
20.6M
  }
3007
41.4M
  for (v=0; v < (ssize_t) rows; v++)
3008
20.7M
  {
3009
20.7M
    ssize_t
3010
20.7M
      y_offset;
3011
3012
20.7M
    y_offset=y+v;
3013
20.7M
    if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
3014
20.7M
        (virtual_pixel_method == UndefinedVirtualPixelMethod))
3015
76.5k
      y_offset=EdgeY(y_offset,cache_info->rows);
3016
48.4M
    for (u=0; u < (ssize_t) columns; u+=(ssize_t) length)
3017
27.6M
    {
3018
27.6M
      ssize_t
3019
27.6M
        x_offset;
3020
3021
27.6M
      x_offset=x+u;
3022
27.6M
      length=(MagickSizeType) MagickMin((ssize_t) cache_info->columns-
3023
27.6M
        x_offset,(ssize_t) columns-u);
3024
27.6M
      if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
3025
16.3M
          ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
3026
865k
          (length == 0))
3027
26.8M
        {
3028
26.8M
          MagickModulo
3029
26.8M
            x_modulo,
3030
26.8M
            y_modulo;
3031
3032
          /*
3033
            Transfer a single pixel.
3034
          */
3035
26.8M
          length=(MagickSizeType) 1;
3036
26.8M
          switch (virtual_pixel_method)
3037
26.8M
          {
3038
0
            case EdgeVirtualPixelMethod:
3039
309k
            default:
3040
309k
            {
3041
309k
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3042
309k
                EdgeX(x_offset,cache_info->columns),
3043
309k
                EdgeY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
3044
309k
                exception);
3045
309k
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3046
309k
              break;
3047
0
            }
3048
0
            case RandomVirtualPixelMethod:
3049
0
            {
3050
0
              if (cache_info->random_info == (RandomInfo *) NULL)
3051
0
                cache_info->random_info=AcquireRandomInfo();
3052
0
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3053
0
                RandomX(cache_info->random_info,cache_info->columns),
3054
0
                RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3055
0
                virtual_nexus,exception);
3056
0
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3057
0
              break;
3058
0
            }
3059
0
            case DitherVirtualPixelMethod:
3060
0
            {
3061
0
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3062
0
                DitherX(x_offset,cache_info->columns),
3063
0
                DitherY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
3064
0
                exception);
3065
0
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3066
0
              break;
3067
0
            }
3068
2.65M
            case TileVirtualPixelMethod:
3069
2.65M
            {
3070
2.65M
              x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3071
2.65M
              y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3072
2.65M
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3073
2.65M
                x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3074
2.65M
                exception);
3075
2.65M
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3076
2.65M
              break;
3077
0
            }
3078
0
            case MirrorVirtualPixelMethod:
3079
0
            {
3080
0
              x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3081
0
              if ((x_modulo.quotient & 0x01) == 1L)
3082
0
                x_modulo.remainder=(ssize_t) cache_info->columns-
3083
0
                  x_modulo.remainder-1L;
3084
0
              y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3085
0
              if ((y_modulo.quotient & 0x01) == 1L)
3086
0
                y_modulo.remainder=(ssize_t) cache_info->rows-
3087
0
                  y_modulo.remainder-1L;
3088
0
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3089
0
                x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3090
0
                exception);
3091
0
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3092
0
              break;
3093
0
            }
3094
0
            case HorizontalTileEdgeVirtualPixelMethod:
3095
0
            {
3096
0
              x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3097
0
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3098
0
                x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
3099
0
                virtual_nexus,exception);
3100
0
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3101
0
              break;
3102
0
            }
3103
0
            case VerticalTileEdgeVirtualPixelMethod:
3104
0
            {
3105
0
              y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3106
0
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3107
0
                EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
3108
0
                virtual_nexus,exception);
3109
0
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3110
0
              break;
3111
0
            }
3112
23.8M
            case BackgroundVirtualPixelMethod:
3113
23.8M
            case BlackVirtualPixelMethod:
3114
23.8M
            case GrayVirtualPixelMethod:
3115
23.8M
            case TransparentVirtualPixelMethod:
3116
23.8M
            case MaskVirtualPixelMethod:
3117
23.8M
            case WhiteVirtualPixelMethod:
3118
23.8M
            {
3119
23.8M
              p=virtual_pixel;
3120
23.8M
              r=virtual_metacontent;
3121
23.8M
              break;
3122
23.8M
            }
3123
0
            case CheckerTileVirtualPixelMethod:
3124
0
            {
3125
0
              x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3126
0
              y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3127
0
              if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3128
0
                {
3129
0
                  p=virtual_pixel;
3130
0
                  r=virtual_metacontent;
3131
0
                  break;
3132
0
                }
3133
0
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3134
0
                x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3135
0
                exception);
3136
0
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3137
0
              break;
3138
0
            }
3139
0
            case HorizontalTileVirtualPixelMethod:
3140
0
            {
3141
0
              if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
3142
0
                {
3143
0
                  p=virtual_pixel;
3144
0
                  r=virtual_metacontent;
3145
0
                  break;
3146
0
                }
3147
0
              x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3148
0
              y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3149
0
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3150
0
                x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3151
0
                exception);
3152
0
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3153
0
              break;
3154
0
            }
3155
0
            case VerticalTileVirtualPixelMethod:
3156
0
            {
3157
0
              if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
3158
0
                {
3159
0
                  p=virtual_pixel;
3160
0
                  r=virtual_metacontent;
3161
0
                  break;
3162
0
                }
3163
0
              x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3164
0
              y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3165
0
              p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3166
0
                x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3167
0
                exception);
3168
0
              r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3169
0
              break;
3170
0
            }
3171
26.8M
          }
3172
26.8M
          if (p == (const Quantum *) NULL)
3173
0
            break;
3174
26.8M
          (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3175
26.8M
            sizeof(*p)));
3176
26.8M
          q+=(ptrdiff_t) cache_info->number_channels;
3177
26.8M
          if ((s != (void *) NULL) && (r != (const void *) NULL))
3178
0
            {
3179
0
              (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3180
0
              s+=(ptrdiff_t) cache_info->metacontent_extent;
3181
0
            }
3182
26.8M
          continue;
3183
26.8M
        }
3184
      /*
3185
        Transfer a run of pixels.
3186
      */
3187
865k
      p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x_offset,y_offset,
3188
865k
        (size_t) length,1UL,virtual_nexus,exception);
3189
865k
      if (p == (const Quantum *) NULL)
3190
0
        break;
3191
865k
      r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3192
865k
      (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3193
865k
        sizeof(*p)));
3194
865k
      q+=(ptrdiff_t) cache_info->number_channels*length;
3195
865k
      if ((r != (void *) NULL) && (s != (const void *) NULL))
3196
0
        {
3197
0
          (void) memcpy(s,r,(size_t) length);
3198
0
          s+=(ptrdiff_t) length*cache_info->metacontent_extent;
3199
0
        }
3200
865k
    }
3201
20.7M
    if (u < (ssize_t) columns)
3202
0
      break;
3203
20.7M
  }
3204
  /*
3205
    Free resources.
3206
  */
3207
20.6M
  if (virtual_metacontent != (void *) NULL)
3208
0
    virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3209
20.6M
  if (v < (ssize_t) rows)
3210
0
    return((const Quantum *) NULL);
3211
20.6M
  return(pixels);
3212
20.6M
}
3213

3214
/*
3215
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3216
%                                                                             %
3217
%                                                                             %
3218
%                                                                             %
3219
+   G e t V i r t u a l P i x e l C a c h e                                   %
3220
%                                                                             %
3221
%                                                                             %
3222
%                                                                             %
3223
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3224
%
3225
%  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3226
%  cache as defined by the geometry parameters.   A pointer to the pixels
3227
%  is returned if the pixels are transferred, otherwise a NULL is returned.
3228
%
3229
%  The format of the GetVirtualPixelCache() method is:
3230
%
3231
%      const Quantum *GetVirtualPixelCache(const Image *image,
3232
%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3233
%        const ssize_t y,const size_t columns,const size_t rows,
3234
%        ExceptionInfo *exception)
3235
%
3236
%  A description of each parameter follows:
3237
%
3238
%    o image: the image.
3239
%
3240
%    o virtual_pixel_method: the virtual pixel method.
3241
%
3242
%    o x,y,columns,rows:  These values define the perimeter of a region of
3243
%      pixels.
3244
%
3245
%    o exception: return any errors or warnings in this structure.
3246
%
3247
*/
3248
static const Quantum *GetVirtualPixelCache(const Image *image,
3249
  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3250
  const size_t columns,const size_t rows,ExceptionInfo *exception)
3251
0
{
3252
0
  CacheInfo
3253
0
    *magick_restrict cache_info;
3254
3255
0
  const int
3256
0
    id = GetOpenMPThreadId();
3257
3258
0
  const Quantum
3259
0
    *magick_restrict p;
3260
3261
0
  assert(image != (const Image *) NULL);
3262
0
  assert(image->signature == MagickCoreSignature);
3263
0
  assert(image->cache != (Cache) NULL);
3264
0
  cache_info=(CacheInfo *) image->cache;
3265
0
  assert(cache_info->signature == MagickCoreSignature);
3266
0
  assert(id < (int) cache_info->number_threads);
3267
0
  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,columns,rows,
3268
0
    cache_info->nexus_info[id],exception);
3269
0
  return(p);
3270
0
}
3271

3272
/*
3273
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3274
%                                                                             %
3275
%                                                                             %
3276
%                                                                             %
3277
%   G e t V i r t u a l P i x e l Q u e u e                                   %
3278
%                                                                             %
3279
%                                                                             %
3280
%                                                                             %
3281
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3282
%
3283
%  GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3284
%  with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3285
%
3286
%  The format of the GetVirtualPixelQueue() method is:
3287
%
3288
%      const Quantum *GetVirtualPixelQueue(const Image image)
3289
%
3290
%  A description of each parameter follows:
3291
%
3292
%    o image: the image.
3293
%
3294
*/
3295
MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3296
2.57M
{
3297
2.57M
  CacheInfo
3298
2.57M
    *magick_restrict cache_info;
3299
3300
2.57M
  const int
3301
2.57M
    id = GetOpenMPThreadId();
3302
3303
2.57M
  assert(image != (const Image *) NULL);
3304
2.57M
  assert(image->signature == MagickCoreSignature);
3305
2.57M
  assert(image->cache != (Cache) NULL);
3306
2.57M
  cache_info=(CacheInfo *) image->cache;
3307
2.57M
  assert(cache_info->signature == MagickCoreSignature);
3308
2.57M
  if (cache_info->methods.get_virtual_pixels_handler != (GetVirtualPixelsHandler) NULL)
3309
0
    return(cache_info->methods.get_virtual_pixels_handler(image));
3310
2.57M
  assert(id < (int) cache_info->number_threads);
3311
2.57M
  return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3312
2.57M
}
3313

3314
/*
3315
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3316
%                                                                             %
3317
%                                                                             %
3318
%                                                                             %
3319
%   G e t V i r t u a l P i x e l s                                           %
3320
%                                                                             %
3321
%                                                                             %
3322
%                                                                             %
3323
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3324
%
3325
%  GetVirtualPixels() returns an immutable pixel region. If the
3326
%  region is successfully accessed, a pointer to it is returned, otherwise
3327
%  NULL is returned.  The returned pointer may point to a temporary working
3328
%  copy of the pixels or it may point to the original pixels in memory.
3329
%  Performance is maximized if the selected region is part of one row, or one
3330
%  or more full rows, since there is opportunity to access the pixels in-place
3331
%  (without a copy) if the image is in memory, or in a memory-mapped file.  The
3332
%  returned pointer must *never* be deallocated by the user.
3333
%
3334
%  Pixels accessed via the returned pointer represent a simple array of type
3335
%  Quantum.  If the image type is CMYK or the storage class is PseudoClass,
3336
%  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3337
%  access the meta-content (of type void) corresponding to the
3338
%  region.
3339
%
3340
%  If you plan to modify the pixels, use GetAuthenticPixels() instead.
3341
%
3342
%  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3343
%  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
3344
%  GetCacheViewAuthenticPixels() instead.
3345
%
3346
%  The format of the GetVirtualPixels() method is:
3347
%
3348
%      const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3349
%        const ssize_t y,const size_t columns,const size_t rows,
3350
%        ExceptionInfo *exception)
3351
%
3352
%  A description of each parameter follows:
3353
%
3354
%    o image: the image.
3355
%
3356
%    o x,y,columns,rows:  These values define the perimeter of a region of
3357
%      pixels.
3358
%
3359
%    o exception: return any errors or warnings in this structure.
3360
%
3361
*/
3362
MagickExport const Quantum *GetVirtualPixels(const Image *image,
3363
  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3364
  ExceptionInfo *exception)
3365
17.8M
{
3366
17.8M
  CacheInfo
3367
17.8M
    *magick_restrict cache_info;
3368
3369
17.8M
  const int
3370
17.8M
    id = GetOpenMPThreadId();
3371
3372
17.8M
  const Quantum
3373
17.8M
    *magick_restrict p;
3374
3375
17.8M
  assert(image != (const Image *) NULL);
3376
17.8M
  assert(image->signature == MagickCoreSignature);
3377
17.8M
  assert(image->cache != (Cache) NULL);
3378
17.8M
  cache_info=(CacheInfo *) image->cache;
3379
17.8M
  assert(cache_info->signature == MagickCoreSignature);
3380
17.8M
  if (cache_info->methods.get_virtual_pixel_handler !=
3381
17.8M
       (GetVirtualPixelHandler) NULL)
3382
0
    return(cache_info->methods.get_virtual_pixel_handler(image,
3383
0
      GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3384
17.8M
  assert(id < (int) cache_info->number_threads);
3385
17.8M
  p=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3386
17.8M
    columns,rows,cache_info->nexus_info[id],exception);
3387
17.8M
  return(p);
3388
17.8M
}
3389

3390
/*
3391
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3392
%                                                                             %
3393
%                                                                             %
3394
%                                                                             %
3395
+   G e t V i r t u a l P i x e l s F r o m C a c h e                         %
3396
%                                                                             %
3397
%                                                                             %
3398
%                                                                             %
3399
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3400
%
3401
%  GetVirtualPixelsCache() returns the pixels associated corresponding with the
3402
%  last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3403
%
3404
%  The format of the GetVirtualPixelsCache() method is:
3405
%
3406
%      Quantum *GetVirtualPixelsCache(const Image *image)
3407
%
3408
%  A description of each parameter follows:
3409
%
3410
%    o image: the image.
3411
%
3412
*/
3413
static const Quantum *GetVirtualPixelsCache(const Image *image)
3414
0
{
3415
0
  CacheInfo
3416
0
    *magick_restrict cache_info;
3417
3418
0
  const int
3419
0
    id = GetOpenMPThreadId();
3420
3421
0
  assert(image != (const Image *) NULL);
3422
0
  assert(image->signature == MagickCoreSignature);
3423
0
  assert(image->cache != (Cache) NULL);
3424
0
  cache_info=(CacheInfo *) image->cache;
3425
0
  assert(cache_info->signature == MagickCoreSignature);
3426
0
  assert(id < (int) cache_info->number_threads);
3427
0
  return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3428
0
}
3429

3430
/*
3431
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3432
%                                                                             %
3433
%                                                                             %
3434
%                                                                             %
3435
+   G e t V i r t u a l P i x e l s N e x u s                                 %
3436
%                                                                             %
3437
%                                                                             %
3438
%                                                                             %
3439
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3440
%
3441
%  GetVirtualPixelsNexus() returns the pixels associated with the specified
3442
%  cache nexus.
3443
%
3444
%  The format of the GetVirtualPixelsNexus() method is:
3445
%
3446
%      const Quantum *GetVirtualPixelsNexus(const Cache cache,
3447
%        NexusInfo *nexus_info)
3448
%
3449
%  A description of each parameter follows:
3450
%
3451
%    o cache: the pixel cache.
3452
%
3453
%    o nexus_info: the cache nexus to return the colormap pixels.
3454
%
3455
*/
3456
MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3457
  NexusInfo *magick_restrict nexus_info)
3458
2.57M
{
3459
2.57M
  CacheInfo
3460
2.57M
    *magick_restrict cache_info;
3461
3462
2.57M
  assert(cache != (Cache) NULL);
3463
2.57M
  cache_info=(CacheInfo *) cache;
3464
2.57M
  assert(cache_info->signature == MagickCoreSignature);
3465
2.57M
  if (cache_info->storage_class == UndefinedClass)
3466
0
    return((Quantum *) NULL);
3467
2.57M
  return((const Quantum *) nexus_info->pixels);
3468
2.57M
}
3469

3470
/*
3471
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3472
%                                                                             %
3473
%                                                                             %
3474
%                                                                             %
3475
+   M a s k P i x e l C a c h e N e x u s                                     %
3476
%                                                                             %
3477
%                                                                             %
3478
%                                                                             %
3479
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3480
%
3481
%  MaskPixelCacheNexus() masks the cache nexus as defined by the composite mask.
3482
%  The method returns MagickTrue if the pixel region is masked, otherwise
3483
%  MagickFalse.
3484
%
3485
%  The format of the MaskPixelCacheNexus() method is:
3486
%
3487
%      MagickBooleanType MaskPixelCacheNexus(Image *image,
3488
%        NexusInfo *nexus_info,ExceptionInfo *exception)
3489
%
3490
%  A description of each parameter follows:
3491
%
3492
%    o image: the image.
3493
%
3494
%    o nexus_info: the cache nexus to clip.
3495
%
3496
%    o exception: return any errors or warnings in this structure.
3497
%
3498
*/
3499
3500
static inline Quantum ApplyPixelCompositeMask(const Quantum p,
3501
  const MagickRealType alpha,const Quantum q,const MagickRealType beta)
3502
281M
{
3503
281M
  double
3504
281M
    gamma;
3505
3506
281M
  if (fabs((double) (alpha-(double) TransparentAlpha)) < MagickEpsilon)
3507
142M
    return(q);
3508
139M
  gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3509
139M
  gamma=MagickSafeReciprocal(gamma);
3510
139M
  return(ClampToQuantum(gamma*MagickOver_((double) p,alpha,(double) q,beta)));
3511
281M
}
3512
3513
static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3514
  ExceptionInfo *exception)
3515
3.96M
{
3516
3.96M
  CacheInfo
3517
3.96M
    *magick_restrict cache_info;
3518
3519
3.96M
  Quantum
3520
3.96M
    *magick_restrict p,
3521
3.96M
    *magick_restrict q;
3522
3523
3.96M
  ssize_t
3524
3.96M
    y;
3525
3526
  /*
3527
    Apply composite mask.
3528
  */
3529
3.96M
  if (IsEventLogging() != MagickFalse)
3530
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3531
3.96M
  if ((image->channels & CompositeMaskChannel) == 0)
3532
0
    return(MagickTrue);
3533
3.96M
  if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
3534
0
    return(MagickTrue);
3535
3.96M
  cache_info=(CacheInfo *) image->cache;
3536
3.96M
  if (cache_info == (Cache) NULL)
3537
0
    return(MagickFalse);
3538
3.96M
  p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3539
3.96M
    nexus_info->region.width,nexus_info->region.height,
3540
3.96M
    nexus_info->virtual_nexus,exception);
3541
3.96M
  q=nexus_info->pixels;
3542
3.96M
  if ((p == (Quantum *) NULL) || (q == (Quantum *) NULL))
3543
0
    return(MagickFalse);
3544
7.92M
  for (y=0; y < (ssize_t) nexus_info->region.height; y++)
3545
3.96M
  {
3546
3.96M
    ssize_t
3547
3.96M
      x;
3548
3549
279M
    for (x=0; x < (ssize_t) nexus_info->region.width; x++)
3550
275M
    {
3551
275M
      double
3552
275M
        alpha;
3553
3554
275M
      ssize_t
3555
275M
        i;
3556
3557
275M
      alpha=(double) GetPixelCompositeMask(image,p);
3558
834M
      for (i=0; i < (ssize_t) image->number_channels; i++)
3559
558M
      {
3560
558M
        PixelChannel channel = GetPixelChannelChannel(image,i);
3561
558M
        PixelTrait traits = GetPixelChannelTraits(image,channel);
3562
558M
        if ((traits & UpdatePixelTrait) == 0)
3563
277M
          continue;
3564
281M
        q[i]=ApplyPixelCompositeMask(q[i],alpha,p[i],GetPixelAlpha(image,p));
3565
281M
      }
3566
275M
      p+=(ptrdiff_t) GetPixelChannels(image);
3567
275M
      q+=(ptrdiff_t) GetPixelChannels(image);
3568
275M
    }
3569
3.96M
  }
3570
3.96M
  return(MagickTrue);
3571
3.96M
}
3572

3573
/*
3574
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3575
%                                                                             %
3576
%                                                                             %
3577
%                                                                             %
3578
+   O p e n P i x e l C a c h e                                               %
3579
%                                                                             %
3580
%                                                                             %
3581
%                                                                             %
3582
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3583
%
3584
%  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
3585
%  dimensions, allocating space for the image pixels and optionally the
3586
%  metacontent, and memory mapping the cache if it is disk based.  The cache
3587
%  nexus array is initialized as well.
3588
%
3589
%  The format of the OpenPixelCache() method is:
3590
%
3591
%      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3592
%        ExceptionInfo *exception)
3593
%
3594
%  A description of each parameter follows:
3595
%
3596
%    o image: the image.
3597
%
3598
%    o mode: ReadMode, WriteMode, or IOMode.
3599
%
3600
%    o exception: return any errors or warnings in this structure.
3601
%
3602
*/
3603
3604
static inline MagickBooleanType CacheOverflowSanityCheckGetSize(
3605
  const MagickSizeType count,const size_t quantum,MagickSizeType *const extent)
3606
285M
{
3607
285M
  MagickSizeType
3608
285M
    length;
3609
3610
285M
  if ((count == 0) || (quantum == 0))
3611
0
    return(MagickTrue);
3612
285M
  length=count*quantum;
3613
285M
  if (quantum != (length/count))
3614
0
    {
3615
0
      errno=ENOMEM;
3616
0
      return(MagickTrue);
3617
0
    }
3618
285M
  if (extent != NULL)
3619
285M
    *extent=length;
3620
285M
  return(MagickFalse);
3621
285M
}
3622
3623
static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3624
  const MapMode mode)
3625
125k
{
3626
125k
  int
3627
125k
    file;
3628
3629
  /*
3630
    Open pixel cache on disk.
3631
  */
3632
125k
  if ((cache_info->file != -1) && (cache_info->disk_mode == mode))
3633
124k
    return(MagickTrue);  /* cache already open and in the proper mode */
3634
1.30k
  if (*cache_info->cache_filename == '\0')
3635
414
    file=AcquireUniqueFileResource(cache_info->cache_filename);
3636
889
  else
3637
889
    switch (mode)
3638
889
    {
3639
852
      case ReadMode:
3640
852
      {
3641
852
        file=open_utf8(cache_info->cache_filename,O_RDONLY | O_CLOEXEC | O_BINARY,0);
3642
852
        break;
3643
0
      }
3644
0
      case WriteMode:
3645
0
      {
3646
0
        file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CLOEXEC | O_CREAT |
3647
0
          O_BINARY | O_EXCL,S_MODE);
3648
0
        if (file == -1)
3649
0
          file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CLOEXEC | O_BINARY,S_MODE);
3650
0
        break;
3651
0
      }
3652
37
      case IOMode:
3653
37
      default:
3654
37
      {
3655
37
        file=open_utf8(cache_info->cache_filename,O_RDWR | O_CLOEXEC | O_CREAT | O_BINARY |
3656
37
          O_EXCL,S_MODE);
3657
37
        if (file == -1)
3658
37
          file=open_utf8(cache_info->cache_filename,O_RDWR | O_CLOEXEC | O_BINARY,S_MODE);
3659
37
        break;
3660
37
      }
3661
889
    }
3662
1.30k
  if (file == -1)
3663
852
    return(MagickFalse);
3664
451
  (void) AcquireMagickResource(FileResource,1);
3665
451
  if (cache_info->file != -1)
3666
0
    (void) ClosePixelCacheOnDisk(cache_info);
3667
451
  cache_info->file=file;
3668
451
  cache_info->disk_mode=mode;
3669
451
  return(MagickTrue);
3670
1.30k
}
3671
3672
static inline MagickOffsetType WritePixelCacheRegion(
3673
  const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3674
  const MagickSizeType length,const unsigned char *magick_restrict buffer)
3675
124k
{
3676
124k
  MagickOffsetType
3677
124k
    i;
3678
3679
124k
  ssize_t
3680
124k
    count = 0;
3681
3682
124k
  if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3683
0
    return((MagickOffsetType) -1);
3684
249k
  for (i=0; i < (MagickOffsetType) length; i+=count)
3685
124k
  {
3686
124k
    count=MagickWrite(cache_info->file,buffer+i,(size_t) MagickMin(length-
3687
124k
      (MagickSizeType) i,MagickMaxBufferExtent));
3688
124k
    if (count <= 0)
3689
0
      break;
3690
124k
  }
3691
124k
  return(i);
3692
124k
}
3693
3694
static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3695
414
{
3696
414
  CacheInfo
3697
414
    *magick_restrict cache_info;
3698
3699
414
  MagickOffsetType
3700
414
    offset;
3701
3702
414
  cache_info=(CacheInfo *) image->cache;
3703
414
  if (cache_info->debug != MagickFalse)
3704
0
    {
3705
0
      char
3706
0
        format[MagickPathExtent],
3707
0
        message[MagickPathExtent];
3708
3709
0
      (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3710
0
      (void) FormatLocaleString(message,MagickPathExtent,
3711
0
        "extend %s (%s[%d], disk, %s)",cache_info->filename,
3712
0
        cache_info->cache_filename,cache_info->file,format);
3713
0
      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3714
0
    }
3715
414
  if (length != (MagickSizeType) ((MagickOffsetType) length))
3716
0
    return(MagickFalse);
3717
414
  offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3718
414
  if (offset < 0)
3719
0
    return(MagickFalse);
3720
414
  if ((MagickSizeType) offset < length)
3721
414
    {
3722
414
      MagickOffsetType
3723
414
        count,
3724
414
        extent;
3725
3726
414
      extent=(MagickOffsetType) length-1;
3727
414
      count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3728
414
        "");
3729
414
      if (count != 1)
3730
0
        return(MagickFalse);
3731
414
#if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3732
414
      if (cache_info->synchronize != MagickFalse)
3733
0
        if (posix_fallocate(cache_info->file,offset+1,extent-offset) != 0)
3734
0
          return(MagickFalse);
3735
414
#endif
3736
414
    }
3737
414
  offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3738
414
  if (offset < 0)
3739
0
    return(MagickFalse);
3740
414
  return(MagickTrue);
3741
414
}
3742
3743
static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3744
  ExceptionInfo *exception)
3745
1.67M
{
3746
1.67M
  CacheInfo
3747
1.67M
    *magick_restrict cache_info,
3748
1.67M
    source_info;
3749
3750
1.67M
  char
3751
1.67M
    format[MagickPathExtent],
3752
1.67M
    message[MagickPathExtent];
3753
3754
1.67M
  const char
3755
1.67M
    *hosts,
3756
1.67M
    *type;
3757
3758
1.67M
  MagickBooleanType
3759
1.67M
    status;
3760
3761
1.67M
  MagickSizeType
3762
1.67M
    length = 0,
3763
1.67M
    number_pixels;
3764
3765
1.67M
  size_t
3766
1.67M
    columns,
3767
1.67M
    packet_size;
3768
3769
1.67M
  assert(image != (const Image *) NULL);
3770
1.67M
  assert(image->signature == MagickCoreSignature);
3771
1.67M
  assert(image->cache != (Cache) NULL);
3772
1.67M
  if (IsEventLogging() != MagickFalse)
3773
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3774
1.67M
  if (cache_anonymous_memory < 0)
3775
0
    {
3776
0
      char
3777
0
        *value;
3778
3779
      /*
3780
        Does the security policy require anonymous mapping for pixel cache?
3781
      */
3782
0
      cache_anonymous_memory=0;
3783
0
      value=GetPolicyValue("pixel-cache-memory");
3784
0
      if (value == (char *) NULL)
3785
0
        value=GetPolicyValue("cache:memory-map");
3786
0
      if (LocaleCompare(value,"anonymous") == 0)
3787
0
        {
3788
0
#if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3789
0
          cache_anonymous_memory=1;
3790
#else
3791
          (void) ThrowMagickException(exception,GetMagickModule(),
3792
            MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3793
            "`%s' (policy requires anonymous memory mapping)",image->filename);
3794
#endif
3795
0
        }
3796
0
      value=DestroyString(value);
3797
0
    }
3798
1.67M
  if ((image->columns == 0) || (image->rows == 0))
3799
1.66M
    ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3800
1.66M
  cache_info=(CacheInfo *) image->cache;
3801
1.66M
  assert(cache_info->signature == MagickCoreSignature);
3802
1.66M
  if (((MagickSizeType) image->columns > cache_info->width_limit) ||
3803
1.65M
      ((MagickSizeType) image->rows > cache_info->height_limit))
3804
22.4k
    {
3805
22.4k
      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
3806
22.4k
        "WidthOrHeightExceedsLimit","`%s' (%.17gx%.17g) > (%.17gx%.17g)",
3807
22.4k
        image->filename, (double) image->columns, (double) image->rows,
3808
22.4k
        (double) cache_info->width_limit,(double) cache_info->height_limit);
3809
22.4k
      return(MagickFalse);
3810
22.4k
    }
3811
1.64M
  if (GetMagickResourceLimit(ListLengthResource) != MagickResourceInfinity)
3812
1.64M
    {
3813
1.64M
      length=GetImageListLength(image);
3814
1.64M
      if (AcquireMagickResource(ListLengthResource,length) == MagickFalse)
3815
8.49k
        ThrowBinaryException(ResourceLimitError,"ListLengthExceedsLimit",
3816
1.64M
          image->filename);
3817
1.63M
    }
3818
1.63M
  source_info=(*cache_info);
3819
1.63M
  source_info.file=(-1);
3820
1.63M
  (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.17g]",
3821
1.63M
    image->filename,(double) image->scene);
3822
1.63M
  cache_info->storage_class=image->storage_class;
3823
1.63M
  cache_info->colorspace=image->colorspace;
3824
1.63M
  cache_info->alpha_trait=image->alpha_trait;
3825
1.63M
  cache_info->channels=image->channels;
3826
1.63M
  cache_info->rows=image->rows;
3827
1.63M
  cache_info->columns=image->columns;
3828
1.63M
  status=ResetPixelChannelMap(image,exception);
3829
1.63M
  if (status == MagickFalse)
3830
123
    return(MagickFalse);
3831
1.63M
  cache_info->number_channels=GetPixelChannels(image);
3832
1.63M
  (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3833
1.63M
    sizeof(*image->channel_map));
3834
1.63M
  cache_info->metacontent_extent=image->metacontent_extent;
3835
1.63M
  cache_info->mode=mode;
3836
1.63M
  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3837
1.63M
  packet_size=MagickMax(cache_info->number_channels,1)*sizeof(Quantum);
3838
1.63M
  if (cache_info->metacontent_extent != 0)
3839
0
    {
3840
0
      if (HeapOverflowCheckAdd(packet_size,cache_info->metacontent_extent) != MagickFalse)
3841
0
        {
3842
0
          cache_info->storage_class=UndefinedClass;
3843
0
          cache_info->length=0;
3844
0
          ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3845
0
            image->filename);
3846
0
        }
3847
0
      packet_size+=cache_info->metacontent_extent;
3848
0
    }
3849
1.63M
  if (CacheOverflowSanityCheckGetSize(number_pixels,packet_size,&length) != MagickFalse)
3850
0
    {
3851
0
      cache_info->storage_class=UndefinedClass;
3852
0
      cache_info->length=0;
3853
0
      ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3854
0
        image->filename);
3855
0
    }
3856
1.63M
  columns=(size_t) (length/cache_info->rows/packet_size);
3857
1.63M
  if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3858
1.63M
      ((ssize_t) cache_info->rows < 0))
3859
0
    {
3860
0
      cache_info->storage_class=UndefinedClass;
3861
0
      cache_info->length=0;
3862
0
      ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3863
0
        image->filename);
3864
0
    }
3865
1.63M
  cache_info->length=length;
3866
1.63M
  if (image->ping != MagickFalse)
3867
32.9k
    {
3868
32.9k
      cache_info->type=PingCache;
3869
32.9k
      return(MagickTrue);
3870
32.9k
    }
3871
1.60M
  status=AcquireMagickResource(AreaResource,(MagickSizeType)
3872
1.60M
    cache_info->columns*cache_info->rows);
3873
1.60M
  if (cache_info->mode == PersistMode)
3874
0
    status=MagickFalse;
3875
1.60M
  length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3876
1.60M
    cache_info->metacontent_extent);
3877
1.60M
  if ((status != MagickFalse) &&
3878
1.60M
      (length == (MagickSizeType) ((size_t) length)) &&
3879
1.60M
      ((cache_info->type == UndefinedCache) ||
3880
704k
       (cache_info->type == MemoryCache)))
3881
1.60M
    {
3882
1.60M
      status=AcquireMagickResource(MemoryResource,cache_info->length);
3883
1.60M
      if (status != MagickFalse)
3884
1.60M
        {
3885
1.60M
          status=MagickTrue;
3886
1.60M
          if (cache_anonymous_memory <= 0)
3887
1.60M
            {
3888
1.60M
              cache_info->mapped=MagickFalse;
3889
1.60M
              cache_info->pixels=(Quantum *) MagickAssumeAligned(
3890
1.60M
                AcquireAlignedMemory(1,(size_t) cache_info->length));
3891
1.60M
            }
3892
0
          else
3893
0
            {
3894
0
              cache_info->mapped=MagickTrue;
3895
0
              cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3896
0
                cache_info->length);
3897
0
            }
3898
1.60M
          if (cache_info->pixels == (Quantum *) NULL)
3899
293
            {
3900
293
              RelinquishMagickResource(MemoryResource,cache_info->length);
3901
293
              cache_info->mapped=source_info.mapped;
3902
293
              cache_info->pixels=source_info.pixels;
3903
293
            }
3904
1.60M
          else
3905
1.60M
            {
3906
              /*
3907
                Create memory pixel cache.
3908
              */
3909
1.60M
              cache_info->type=MemoryCache;
3910
1.60M
              cache_info->metacontent=(void *) NULL;
3911
1.60M
              if (cache_info->metacontent_extent != 0)
3912
0
                cache_info->metacontent=(void *) (cache_info->pixels+
3913
0
                  cache_info->number_channels*number_pixels);
3914
1.60M
              if ((source_info.storage_class != UndefinedClass) &&
3915
703k
                  (mode != ReadMode))
3916
703k
                {
3917
703k
                  status=ClonePixelCacheRepository(cache_info,&source_info,
3918
703k
                    exception);
3919
703k
                  RelinquishPixelCachePixels(&source_info);
3920
703k
                }
3921
1.60M
              if (cache_info->debug != MagickFalse)
3922
0
                {
3923
0
                  (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3924
0
                    MagickPathExtent,format);
3925
0
                  type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3926
0
                    cache_info->type);
3927
0
                  (void) FormatLocaleString(message,MagickPathExtent,
3928
0
                    "open %s (%s %s, %.17gx%.17gx%.17g %s)",
3929
0
                    cache_info->filename,cache_info->mapped != MagickFalse ?
3930
0
                    "Anonymous" : "Heap",type,(double) cache_info->columns,
3931
0
                    (double) cache_info->rows,(double)
3932
0
                    cache_info->number_channels,format);
3933
0
                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3934
0
                    message);
3935
0
                }
3936
1.60M
              cache_info->storage_class=image->storage_class;
3937
1.60M
              if (status == 0)
3938
0
                {
3939
0
                  if ((source_info.storage_class != UndefinedClass) &&
3940
0
                      (mode != ReadMode))
3941
0
                    RelinquishPixelCachePixels(&source_info);
3942
0
                  cache_info->type=UndefinedCache;
3943
0
                  return(MagickFalse);
3944
0
                }
3945
1.60M
              return(MagickTrue);
3946
1.60M
            }
3947
1.60M
        }
3948
1.60M
    }
3949
1.26k
  status=AcquireMagickResource(DiskResource,cache_info->length);
3950
1.26k
  hosts=(const char *) GetImageRegistry(StringRegistryType,"cache:hosts",
3951
1.26k
    exception);
3952
1.26k
  if ((status == MagickFalse) && (hosts != (const char *) NULL))
3953
0
    {
3954
0
      DistributeCacheInfo
3955
0
        *server_info;
3956
3957
      /*
3958
        Distribute the pixel cache to a remote server.
3959
      */
3960
0
      server_info=AcquireDistributeCacheInfo(exception);
3961
0
      if (server_info != (DistributeCacheInfo *) NULL)
3962
0
        {
3963
0
          status=OpenDistributePixelCache(server_info,image);
3964
0
          if (status == MagickFalse)
3965
0
            {
3966
0
              ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3967
0
                GetDistributeCacheHostname(server_info));
3968
0
              server_info=DestroyDistributeCacheInfo(server_info);
3969
0
            }
3970
0
          else
3971
0
            {
3972
              /*
3973
                Create a distributed pixel cache.
3974
              */
3975
0
              status=MagickTrue;
3976
0
              cache_info->type=DistributedCache;
3977
0
              cache_info->server_info=server_info;
3978
0
              (void) FormatLocaleString(cache_info->cache_filename,
3979
0
                MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3980
0
                (DistributeCacheInfo *) cache_info->server_info),
3981
0
                GetDistributeCachePort((DistributeCacheInfo *)
3982
0
                cache_info->server_info));
3983
0
              if ((source_info.storage_class != UndefinedClass) &&
3984
0
                  (mode != ReadMode))
3985
0
                {
3986
0
                  status=ClonePixelCacheRepository(cache_info,&source_info,
3987
0
                    exception);
3988
0
                  RelinquishPixelCachePixels(&source_info);
3989
0
                }
3990
0
              if (cache_info->debug != MagickFalse)
3991
0
                {
3992
0
                  (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3993
0
                    MagickPathExtent,format);
3994
0
                  type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3995
0
                    cache_info->type);
3996
0
                  (void) FormatLocaleString(message,MagickPathExtent,
3997
0
                    "open %s (%s[%d], %s, %.17gx%.17gx%.17g %s)",
3998
0
                    cache_info->filename,cache_info->cache_filename,
3999
0
                    GetDistributeCacheFile((DistributeCacheInfo *)
4000
0
                    cache_info->server_info),type,(double) cache_info->columns,
4001
0
                    (double) cache_info->rows,(double)
4002
0
                    cache_info->number_channels,format);
4003
0
                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4004
0
                    message);
4005
0
                }
4006
0
              if (status == 0)
4007
0
                {
4008
0
                  if ((source_info.storage_class != UndefinedClass) &&
4009
0
                      (mode != ReadMode))
4010
0
                    RelinquishPixelCachePixels(&source_info);
4011
0
                  cache_info->type=UndefinedCache;
4012
0
                  return(MagickFalse);
4013
0
                }
4014
0
              return(MagickTrue);
4015
0
            }
4016
0
        }
4017
0
      if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4018
0
        RelinquishPixelCachePixels(&source_info);
4019
0
      cache_info->type=UndefinedCache;
4020
0
      (void) memset(image->channel_map,0,MaxPixelChannels*
4021
0
        sizeof(*image->channel_map));
4022
0
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4023
0
        "CacheResourcesExhausted","`%s'",image->filename);
4024
0
      return(MagickFalse);
4025
0
    }
4026
  /*
4027
    Create pixel cache on disk.
4028
  */
4029
1.26k
  if (status == MagickFalse)
4030
0
    {
4031
0
      if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4032
0
        RelinquishPixelCachePixels(&source_info);
4033
0
      cache_info->type=UndefinedCache;
4034
0
      (void) memset(image->channel_map,0,MaxPixelChannels*
4035
0
        sizeof(*image->channel_map));
4036
0
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4037
0
        "CacheResourcesExhausted","`%s'",image->filename);
4038
0
      return(MagickFalse);
4039
0
    }
4040
1.26k
  if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
4041
270
      (cache_info->mode != PersistMode))
4042
270
    {
4043
270
      (void) ClosePixelCacheOnDisk(cache_info);
4044
270
      *cache_info->cache_filename='\0';
4045
270
    }
4046
1.26k
  if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4047
852
    {
4048
852
      if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4049
0
        RelinquishPixelCachePixels(&source_info);
4050
852
      cache_info->type=UndefinedCache;
4051
852
      ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4052
852
        image->filename);
4053
852
      return(MagickFalse);
4054
852
    }
4055
414
  status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
4056
414
    cache_info->length);
4057
414
  if (status == MagickFalse)
4058
0
    {
4059
0
      if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4060
0
        RelinquishPixelCachePixels(&source_info);
4061
0
      cache_info->type=UndefinedCache;
4062
0
      ThrowFileException(exception,CacheError,"UnableToExtendCache",
4063
0
        image->filename);
4064
0
      return(MagickFalse);
4065
0
    }
4066
414
  cache_info->type=DiskCache;
4067
414
  length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4068
414
    cache_info->metacontent_extent);
4069
414
  if (length == (MagickSizeType) ((size_t) length))
4070
414
    {
4071
414
      status=AcquireMagickResource(MapResource,cache_info->length);
4072
414
      if (status != MagickFalse)
4073
288
        {
4074
288
          cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4075
288
            cache_info->offset,(size_t) cache_info->length);
4076
288
          if (cache_info->pixels == (Quantum *) NULL)
4077
0
            {
4078
0
              cache_info->mapped=source_info.mapped;
4079
0
              cache_info->pixels=source_info.pixels;
4080
0
              RelinquishMagickResource(MapResource,cache_info->length);
4081
0
            }
4082
288
          else
4083
288
            {
4084
              /*
4085
                Create file-backed memory-mapped pixel cache.
4086
              */
4087
288
              (void) ClosePixelCacheOnDisk(cache_info);
4088
288
              cache_info->type=MapCache;
4089
288
              cache_info->mapped=MagickTrue;
4090
288
              cache_info->metacontent=(void *) NULL;
4091
288
              if (cache_info->metacontent_extent != 0)
4092
0
                cache_info->metacontent=(void *) (cache_info->pixels+
4093
0
                  cache_info->number_channels*number_pixels);
4094
288
              if ((source_info.storage_class != UndefinedClass) &&
4095
229
                  (mode != ReadMode))
4096
229
                {
4097
229
                  status=ClonePixelCacheRepository(cache_info,&source_info,
4098
229
                    exception);
4099
229
                  RelinquishPixelCachePixels(&source_info);
4100
229
                }
4101
288
              if (cache_info->debug != MagickFalse)
4102
0
                {
4103
0
                  (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
4104
0
                    MagickPathExtent,format);
4105
0
                  type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4106
0
                    cache_info->type);
4107
0
                  (void) FormatLocaleString(message,MagickPathExtent,
4108
0
                    "open %s (%s[%d], %s, %.17gx%.17gx%.17g %s)",
4109
0
                    cache_info->filename,cache_info->cache_filename,
4110
0
                    cache_info->file,type,(double) cache_info->columns,
4111
0
                    (double) cache_info->rows,(double)
4112
0
                    cache_info->number_channels,format);
4113
0
                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4114
0
                    message);
4115
0
                }
4116
288
              if (status == 0)
4117
0
                {
4118
0
                  if ((source_info.storage_class != UndefinedClass) &&
4119
0
                      (mode != ReadMode))
4120
0
                    RelinquishPixelCachePixels(&source_info);
4121
0
                  cache_info->type=UndefinedCache;
4122
0
                  return(MagickFalse);
4123
0
                }
4124
288
              return(MagickTrue);
4125
288
            }
4126
288
        }
4127
414
    }
4128
126
  status=MagickTrue;
4129
126
  if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4130
41
    {
4131
41
      status=ClonePixelCacheRepository(cache_info,&source_info,exception);
4132
41
      RelinquishPixelCachePixels(&source_info);
4133
41
    }
4134
126
  if (cache_info->debug != MagickFalse)
4135
0
    {
4136
0
      (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
4137
0
        MagickPathExtent,format);
4138
0
      type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4139
0
        cache_info->type);
4140
0
      (void) FormatLocaleString(message,MagickPathExtent,
4141
0
        "open %s (%s[%d], %s, %.17gx%.17gx%.17g %s)",cache_info->filename,
4142
0
        cache_info->cache_filename,cache_info->file,type,(double)
4143
0
        cache_info->columns,(double) cache_info->rows,(double)
4144
0
        cache_info->number_channels,format);
4145
0
      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4146
0
    }
4147
126
  if (status == 0)
4148
0
    {
4149
0
      cache_info->type=UndefinedCache;
4150
0
      return(MagickFalse);
4151
0
    }
4152
126
  return(MagickTrue);
4153
126
}
4154

4155
/*
4156
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4157
%                                                                             %
4158
%                                                                             %
4159
%                                                                             %
4160
+   P e r s i s t P i x e l C a c h e                                         %
4161
%                                                                             %
4162
%                                                                             %
4163
%                                                                             %
4164
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4165
%
4166
%  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
4167
%  persistent pixel cache is one that resides on disk and is not destroyed
4168
%  when the program exits.
4169
%
4170
%  The format of the PersistPixelCache() method is:
4171
%
4172
%      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4173
%        const MagickBooleanType attach,MagickOffsetType *offset,
4174
%        ExceptionInfo *exception)
4175
%
4176
%  A description of each parameter follows:
4177
%
4178
%    o image: the image.
4179
%
4180
%    o filename: the persistent pixel cache filename.
4181
%
4182
%    o attach: A value other than zero initializes the persistent pixel cache.
4183
%
4184
%    o initialize: A value other than zero initializes the persistent pixel
4185
%      cache.
4186
%
4187
%    o offset: the offset in the persistent cache to store pixels.
4188
%
4189
%    o exception: return any errors or warnings in this structure.
4190
%
4191
*/
4192
MagickExport MagickBooleanType PersistPixelCache(Image *image,
4193
  const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4194
  ExceptionInfo *exception)
4195
969
{
4196
969
  CacheInfo
4197
969
    *magick_restrict cache_info,
4198
969
    *magick_restrict clone_info;
4199
4200
969
  MagickBooleanType
4201
969
    status;
4202
4203
969
  ssize_t
4204
969
    page_size;
4205
4206
969
  assert(image != (Image *) NULL);
4207
969
  assert(image->signature == MagickCoreSignature);
4208
969
  if (IsEventLogging() != MagickFalse)
4209
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4210
969
  assert(image->cache != (void *) NULL);
4211
969
  assert(filename != (const char *) NULL);
4212
969
  assert(offset != (MagickOffsetType *) NULL);
4213
969
  page_size=GetMagickPageSize();
4214
969
  cache_info=(CacheInfo *) image->cache;
4215
969
  assert(cache_info->signature == MagickCoreSignature);
4216
#if defined(MAGICKCORE_OPENCL_SUPPORT)
4217
  CopyOpenCLBuffer(cache_info);
4218
#endif
4219
969
  if (attach != MagickFalse)
4220
969
    {
4221
      /*
4222
        Attach existing persistent pixel cache.
4223
      */
4224
969
      if (cache_info->debug != MagickFalse)
4225
0
        (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4226
0
          "attach persistent cache");
4227
969
      (void) CopyMagickString(cache_info->cache_filename,filename,
4228
969
        MagickPathExtent);
4229
969
      cache_info->type=MapCache;
4230
969
      cache_info->offset=(*offset);
4231
969
      if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4232
969
        return(MagickFalse);
4233
0
      *offset=(*offset+(MagickOffsetType) cache_info->length+page_size-
4234
0
        ((MagickOffsetType) cache_info->length % page_size));
4235
0
      return(MagickTrue);
4236
969
    }
4237
  /*
4238
    Clone persistent pixel cache.
4239
  */
4240
0
  status=AcquireMagickResource(DiskResource,cache_info->length);
4241
0
  if (status == MagickFalse)
4242
0
    {
4243
0
      cache_info->type=UndefinedCache;
4244
0
      (void) memset(image->channel_map,0,MaxPixelChannels*
4245
0
        sizeof(*image->channel_map));
4246
0
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4247
0
        "CacheResourcesExhausted","`%s'",image->filename);
4248
0
      return(MagickFalse);
4249
0
    }
4250
0
  clone_info=(CacheInfo *) ClonePixelCache(cache_info);
4251
0
  clone_info->type=DiskCache;
4252
0
  (void) CopyMagickString(clone_info->cache_filename,filename,MagickPathExtent);
4253
0
  clone_info->file=(-1);
4254
0
  clone_info->storage_class=cache_info->storage_class;
4255
0
  clone_info->colorspace=cache_info->colorspace;
4256
0
  clone_info->alpha_trait=cache_info->alpha_trait;
4257
0
  clone_info->channels=cache_info->channels;
4258
0
  clone_info->columns=cache_info->columns;
4259
0
  clone_info->rows=cache_info->rows;
4260
0
  clone_info->number_channels=cache_info->number_channels;
4261
0
  clone_info->metacontent_extent=cache_info->metacontent_extent;
4262
0
  clone_info->mode=PersistMode;
4263
0
  clone_info->length=cache_info->length;
4264
0
  (void) memcpy(clone_info->channel_map,cache_info->channel_map,
4265
0
    MaxPixelChannels*sizeof(*cache_info->channel_map));
4266
0
  clone_info->offset=(*offset);
4267
0
  status=OpenPixelCacheOnDisk(clone_info,WriteMode);
4268
0
  if (status != MagickFalse)
4269
0
    status=ClonePixelCacheRepository(clone_info,cache_info,exception);
4270
0
  *offset=(*offset+(MagickOffsetType) cache_info->length+page_size-
4271
0
    ((MagickOffsetType) cache_info->length % page_size));
4272
0
  clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4273
0
  return(status);
4274
0
}
4275

4276
/*
4277
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4278
%                                                                             %
4279
%                                                                             %
4280
%                                                                             %
4281
+   Q u e u e A u t h e n t i c P i x e l C a c h e N e x u s                 %
4282
%                                                                             %
4283
%                                                                             %
4284
%                                                                             %
4285
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4286
%
4287
%  QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4288
%  defined by the region rectangle and returns a pointer to the region.  This
4289
%  region is subsequently transferred from the pixel cache with
4290
%  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4291
%  pixels are transferred, otherwise a NULL is returned.
4292
%
4293
%  The format of the QueueAuthenticPixelCacheNexus() method is:
4294
%
4295
%      Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4296
%        const ssize_t y,const size_t columns,const size_t rows,
4297
%        const MagickBooleanType clone,NexusInfo *nexus_info,
4298
%        ExceptionInfo *exception)
4299
%
4300
%  A description of each parameter follows:
4301
%
4302
%    o image: the image.
4303
%
4304
%    o x,y,columns,rows:  These values define the perimeter of a region of
4305
%      pixels.
4306
%
4307
%    o nexus_info: the cache nexus to set.
4308
%
4309
%    o clone: clone the pixel cache.
4310
%
4311
%    o exception: return any errors or warnings in this structure.
4312
%
4313
*/
4314
MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4315
  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4316
  const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4317
289M
{
4318
289M
  CacheInfo
4319
289M
    *magick_restrict cache_info;
4320
4321
289M
  MagickOffsetType
4322
289M
    offset;
4323
4324
289M
  MagickSizeType
4325
289M
    number_pixels;
4326
4327
289M
  Quantum
4328
289M
    *magick_restrict pixels;
4329
4330
  /*
4331
    Validate pixel cache geometry.
4332
  */
4333
289M
  assert(image != (const Image *) NULL);
4334
289M
  assert(image->signature == MagickCoreSignature);
4335
289M
  assert(image->cache != (Cache) NULL);
4336
289M
  cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4337
289M
  if (cache_info == (Cache) NULL)
4338
7.20k
    return((Quantum *) NULL);
4339
289M
  assert(cache_info->signature == MagickCoreSignature);
4340
289M
  if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
4341
289M
      (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4342
289M
      (y >= (ssize_t) cache_info->rows))
4343
80.7k
    {
4344
80.7k
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4345
80.7k
        "PixelsAreNotAuthentic","`%s'",image->filename);
4346
80.7k
      return((Quantum *) NULL);
4347
80.7k
    }
4348
288M
  if (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
4349
0
    return((Quantum *) NULL);
4350
288M
  offset=y*(MagickOffsetType) cache_info->columns;
4351
288M
  if (IsOffsetOverflow(offset,(MagickOffsetType) x) == MagickFalse)
4352
0
    return((Quantum *) NULL);
4353
288M
  offset+=x;
4354
288M
  if (offset < 0)
4355
0
    return((Quantum *) NULL);
4356
288M
  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4357
288M
  offset+=((MagickOffsetType) rows-1)*(MagickOffsetType) cache_info->columns;
4358
288M
  if (IsOffsetOverflow(offset,(MagickOffsetType) columns-1) == MagickFalse)
4359
0
    return((Quantum *) NULL);
4360
288M
  offset+=(MagickOffsetType) columns-1;
4361
288M
  if ((MagickSizeType) offset >= number_pixels)
4362
380
    return((Quantum *) NULL);
4363
  /*
4364
    Return pixel cache.
4365
  */
4366
288M
  pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
4367
288M
    ((image->channels & WriteMaskChannel) != 0) ||
4368
288M
    ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
4369
288M
    nexus_info,exception);
4370
288M
  return(pixels);
4371
288M
}
4372

4373
/*
4374
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4375
%                                                                             %
4376
%                                                                             %
4377
%                                                                             %
4378
+   Q u e u e A u t h e n t i c P i x e l s C a c h e                         %
4379
%                                                                             %
4380
%                                                                             %
4381
%                                                                             %
4382
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4383
%
4384
%  QueueAuthenticPixelsCache() allocates an region to store image pixels as
4385
%  defined by the region rectangle and returns a pointer to the region.  This
4386
%  region is subsequently transferred from the pixel cache with
4387
%  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4388
%  pixels are transferred, otherwise a NULL is returned.
4389
%
4390
%  The format of the QueueAuthenticPixelsCache() method is:
4391
%
4392
%      Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4393
%        const ssize_t y,const size_t columns,const size_t rows,
4394
%        ExceptionInfo *exception)
4395
%
4396
%  A description of each parameter follows:
4397
%
4398
%    o image: the image.
4399
%
4400
%    o x,y,columns,rows:  These values define the perimeter of a region of
4401
%      pixels.
4402
%
4403
%    o exception: return any errors or warnings in this structure.
4404
%
4405
*/
4406
static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4407
  const ssize_t y,const size_t columns,const size_t rows,
4408
  ExceptionInfo *exception)
4409
0
{
4410
0
  CacheInfo
4411
0
    *magick_restrict cache_info;
4412
4413
0
  const int
4414
0
    id = GetOpenMPThreadId();
4415
4416
0
  Quantum
4417
0
    *magick_restrict pixels;
4418
4419
0
  assert(image != (const Image *) NULL);
4420
0
  assert(image->signature == MagickCoreSignature);
4421
0
  assert(image->cache != (Cache) NULL);
4422
0
  cache_info=(CacheInfo *) image->cache;
4423
0
  assert(cache_info->signature == MagickCoreSignature);
4424
0
  assert(id < (int) cache_info->number_threads);
4425
0
  pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4426
0
    cache_info->nexus_info[id],exception);
4427
0
  return(pixels);
4428
0
}
4429

4430
/*
4431
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4432
%                                                                             %
4433
%                                                                             %
4434
%                                                                             %
4435
%   Q u e u e A u t h e n t i c P i x e l s                                   %
4436
%                                                                             %
4437
%                                                                             %
4438
%                                                                             %
4439
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4440
%
4441
%  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
4442
%  successfully initialized a pointer to a Quantum array representing the
4443
%  region is returned, otherwise NULL is returned.  The returned pointer may
4444
%  point to a temporary working buffer for the pixels or it may point to the
4445
%  final location of the pixels in memory.
4446
%
4447
%  Write-only access means that any existing pixel values corresponding to
4448
%  the region are ignored.  This is useful if the initial image is being
4449
%  created from scratch, or if the existing pixel values are to be
4450
%  completely replaced without need to refer to their preexisting values.
4451
%  The application is free to read and write the pixel buffer returned by
4452
%  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4453
%  initialize the pixel array values. Initializing pixel array values is the
4454
%  application's responsibility.
4455
%
4456
%  Performance is maximized if the selected region is part of one row, or
4457
%  one or more full rows, since then there is opportunity to access the
4458
%  pixels in-place (without a copy) if the image is in memory, or in a
4459
%  memory-mapped file. The returned pointer must *never* be deallocated
4460
%  by the user.
4461
%
4462
%  Pixels accessed via the returned pointer represent a simple array of type
4463
%  Quantum. If the image type is CMYK or the storage class is PseudoClass,
4464
%  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4465
%  obtain the meta-content (of type void) corresponding to the region.
4466
%  Once the Quantum (and/or Quantum) array has been updated, the
4467
%  changes must be saved back to the underlying image using
4468
%  SyncAuthenticPixels() or they may be lost.
4469
%
4470
%  The format of the QueueAuthenticPixels() method is:
4471
%
4472
%      Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4473
%        const ssize_t y,const size_t columns,const size_t rows,
4474
%        ExceptionInfo *exception)
4475
%
4476
%  A description of each parameter follows:
4477
%
4478
%    o image: the image.
4479
%
4480
%    o x,y,columns,rows:  These values define the perimeter of a region of
4481
%      pixels.
4482
%
4483
%    o exception: return any errors or warnings in this structure.
4484
%
4485
*/
4486
MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4487
  const ssize_t y,const size_t columns,const size_t rows,
4488
  ExceptionInfo *exception)
4489
46.7M
{
4490
46.7M
  CacheInfo
4491
46.7M
    *magick_restrict cache_info;
4492
4493
46.7M
  const int
4494
46.7M
    id = GetOpenMPThreadId();
4495
4496
46.7M
  Quantum
4497
46.7M
    *magick_restrict pixels;
4498
4499
46.7M
  assert(image != (Image *) NULL);
4500
46.7M
  assert(image->signature == MagickCoreSignature);
4501
46.7M
  assert(image->cache != (Cache) NULL);
4502
46.7M
  cache_info=(CacheInfo *) image->cache;
4503
46.7M
  assert(cache_info->signature == MagickCoreSignature);
4504
46.7M
  if (cache_info->methods.queue_authentic_pixels_handler !=
4505
46.7M
      (QueueAuthenticPixelsHandler) NULL)
4506
3.03M
    {
4507
3.03M
      pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4508
3.03M
        columns,rows,exception);
4509
3.03M
      return(pixels);
4510
3.03M
    }
4511
46.7M
  assert(id < (int) cache_info->number_threads);
4512
43.7M
  pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4513
43.7M
    cache_info->nexus_info[id],exception);
4514
43.7M
  return(pixels);
4515
43.7M
}
4516

4517
/*
4518
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4519
%                                                                             %
4520
%                                                                             %
4521
%                                                                             %
4522
+   R e a d P i x e l C a c h e M e t a c o n t e n t                         %
4523
%                                                                             %
4524
%                                                                             %
4525
%                                                                             %
4526
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4527
%
4528
%  ReadPixelCacheMetacontent() reads metacontent from the specified region of
4529
%  the pixel cache.
4530
%
4531
%  The format of the ReadPixelCacheMetacontent() method is:
4532
%
4533
%      MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4534
%        NexusInfo *nexus_info,ExceptionInfo *exception)
4535
%
4536
%  A description of each parameter follows:
4537
%
4538
%    o cache_info: the pixel cache.
4539
%
4540
%    o nexus_info: the cache nexus to read the metacontent.
4541
%
4542
%    o exception: return any errors or warnings in this structure.
4543
%
4544
*/
4545
4546
static inline MagickOffsetType ReadPixelCacheRegion(
4547
  const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4548
  const MagickSizeType length,unsigned char *magick_restrict buffer)
4549
8
{
4550
8
  MagickOffsetType
4551
8
    i;
4552
4553
8
  ssize_t
4554
8
    count = 0;
4555
4556
8
  if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4557
0
    return((MagickOffsetType) -1);
4558
16
  for (i=0; i < (MagickOffsetType) length; i+=count)
4559
8
  {
4560
8
    count=MagickRead(cache_info->file,buffer+i,(size_t) MagickMin(length-
4561
8
      (MagickSizeType) i,(size_t) MagickMaxBufferExtent));
4562
8
    if (count <= 0)
4563
0
      break;
4564
8
  }
4565
8
  return(i);
4566
8
}
4567
4568
static MagickBooleanType ReadPixelCacheMetacontent(
4569
  CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4570
  ExceptionInfo *exception)
4571
0
{
4572
0
  MagickOffsetType
4573
0
    count,
4574
0
    offset;
4575
4576
0
  MagickSizeType
4577
0
    extent,
4578
0
    length;
4579
4580
0
  ssize_t
4581
0
    y;
4582
4583
0
  unsigned char
4584
0
    *magick_restrict q;
4585
4586
0
  size_t
4587
0
    rows;
4588
4589
0
  if (cache_info->metacontent_extent == 0)
4590
0
    return(MagickFalse);
4591
0
  if (nexus_info->authentic_pixel_cache != MagickFalse)
4592
0
    return(MagickTrue);
4593
0
  if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4594
0
    return(MagickFalse);
4595
0
  offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
4596
0
    nexus_info->region.x;
4597
0
  length=(MagickSizeType) nexus_info->region.width*
4598
0
    cache_info->metacontent_extent;
4599
0
  extent=length*nexus_info->region.height;
4600
0
  rows=nexus_info->region.height;
4601
0
  y=0;
4602
0
  q=(unsigned char *) nexus_info->metacontent;
4603
0
  switch (cache_info->type)
4604
0
  {
4605
0
    case MemoryCache:
4606
0
    case MapCache:
4607
0
    {
4608
0
      unsigned char
4609
0
        *magick_restrict p;
4610
4611
      /*
4612
        Read meta-content from memory.
4613
      */
4614
0
      if ((cache_info->columns == nexus_info->region.width) &&
4615
0
          (extent == (MagickSizeType) ((size_t) extent)))
4616
0
        {
4617
0
          length=extent;
4618
0
          rows=1UL;
4619
0
        }
4620
0
      p=(unsigned char *) cache_info->metacontent+offset*(MagickOffsetType)
4621
0
        cache_info->metacontent_extent;
4622
0
      for (y=0; y < (ssize_t) rows; y++)
4623
0
      {
4624
0
        (void) memcpy(q,p,(size_t) length);
4625
0
        p+=(ptrdiff_t) cache_info->metacontent_extent*cache_info->columns;
4626
0
        q+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
4627
0
      }
4628
0
      break;
4629
0
    }
4630
0
    case DiskCache:
4631
0
    {
4632
      /*
4633
        Read meta content from disk.
4634
      */
4635
0
      LockSemaphoreInfo(cache_info->file_semaphore);
4636
0
      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4637
0
        {
4638
0
          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4639
0
            cache_info->cache_filename);
4640
0
          UnlockSemaphoreInfo(cache_info->file_semaphore);
4641
0
          return(MagickFalse);
4642
0
        }
4643
0
      if ((cache_info->columns == nexus_info->region.width) &&
4644
0
          (extent <= MagickMaxBufferExtent))
4645
0
        {
4646
0
          length=extent;
4647
0
          rows=1UL;
4648
0
        }
4649
0
      extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4650
0
      for (y=0; y < (ssize_t) rows; y++)
4651
0
      {
4652
0
        count=ReadPixelCacheRegion(cache_info,cache_info->offset+
4653
0
          (MagickOffsetType) extent*(MagickOffsetType)
4654
0
          cache_info->number_channels*(MagickOffsetType) sizeof(Quantum)+offset*
4655
0
          (MagickOffsetType) cache_info->metacontent_extent,length,
4656
0
          (unsigned char *) q);
4657
0
        if (count != (MagickOffsetType) length)
4658
0
          break;
4659
0
        offset+=(MagickOffsetType) cache_info->columns;
4660
0
        q+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
4661
0
      }
4662
0
      if (IsFileDescriptorLimitExceeded() != MagickFalse)
4663
0
        (void) ClosePixelCacheOnDisk(cache_info);
4664
0
      UnlockSemaphoreInfo(cache_info->file_semaphore);
4665
0
      break;
4666
0
    }
4667
0
    case DistributedCache:
4668
0
    {
4669
0
      RectangleInfo
4670
0
        region;
4671
4672
      /*
4673
        Read metacontent from distributed cache.
4674
      */
4675
0
      LockSemaphoreInfo(cache_info->file_semaphore);
4676
0
      region=nexus_info->region;
4677
0
      if ((cache_info->columns != nexus_info->region.width) ||
4678
0
          (extent > MagickMaxBufferExtent))
4679
0
        region.height=1UL;
4680
0
      else
4681
0
        {
4682
0
          length=extent;
4683
0
          rows=1UL;
4684
0
        }
4685
0
      for (y=0; y < (ssize_t) rows; y++)
4686
0
      {
4687
0
        count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4688
0
          cache_info->server_info,&region,length,(unsigned char *) q);
4689
0
        if (count != (MagickOffsetType) length)
4690
0
          break;
4691
0
        q+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
4692
0
        region.y++;
4693
0
      }
4694
0
      UnlockSemaphoreInfo(cache_info->file_semaphore);
4695
0
      break;
4696
0
    }
4697
0
    default:
4698
0
      break;
4699
0
  }
4700
0
  if (y < (ssize_t) rows)
4701
0
    {
4702
0
      ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4703
0
        cache_info->cache_filename);
4704
0
      return(MagickFalse);
4705
0
    }
4706
0
  if ((cache_info->debug != MagickFalse) &&
4707
0
      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4708
0
    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4709
0
      "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
4710
0
      nexus_info->region.width,(double) nexus_info->region.height,(double)
4711
0
      nexus_info->region.x,(double) nexus_info->region.y);
4712
0
  return(MagickTrue);
4713
0
}
4714

4715
/*
4716
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4717
%                                                                             %
4718
%                                                                             %
4719
%                                                                             %
4720
+   R e a d P i x e l C a c h e P i x e l s                                   %
4721
%                                                                             %
4722
%                                                                             %
4723
%                                                                             %
4724
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4725
%
4726
%  ReadPixelCachePixels() reads pixels from the specified region of the pixel
4727
%  cache.
4728
%
4729
%  The format of the ReadPixelCachePixels() method is:
4730
%
4731
%      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4732
%        NexusInfo *nexus_info,ExceptionInfo *exception)
4733
%
4734
%  A description of each parameter follows:
4735
%
4736
%    o cache_info: the pixel cache.
4737
%
4738
%    o nexus_info: the cache nexus to read the pixels.
4739
%
4740
%    o exception: return any errors or warnings in this structure.
4741
%
4742
*/
4743
static MagickBooleanType ReadPixelCachePixels(
4744
  CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4745
  ExceptionInfo *exception)
4746
58.9M
{
4747
58.9M
  MagickOffsetType
4748
58.9M
    count,
4749
58.9M
    offset;
4750
4751
58.9M
  MagickSizeType
4752
58.9M
    extent,
4753
58.9M
    length;
4754
4755
58.9M
  Quantum
4756
58.9M
    *magick_restrict q;
4757
4758
58.9M
  size_t
4759
58.9M
    number_channels,
4760
58.9M
    rows;
4761
4762
58.9M
  ssize_t
4763
58.9M
    y;
4764
4765
58.9M
  if (nexus_info->authentic_pixel_cache != MagickFalse)
4766
44.2M
    return(MagickTrue);
4767
14.7M
  if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4768
0
    return(MagickFalse);
4769
14.7M
  offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns;
4770
14.7M
  if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4771
0
    return(MagickFalse);
4772
14.7M
  offset+=nexus_info->region.x;
4773
14.7M
  number_channels=cache_info->number_channels;
4774
14.7M
  length=(MagickSizeType) number_channels*nexus_info->region.width*
4775
14.7M
    sizeof(Quantum);
4776
14.7M
  if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4777
0
    return(MagickFalse);
4778
14.7M
  rows=nexus_info->region.height;
4779
14.7M
  extent=length*rows;
4780
14.7M
  if ((extent == 0) || ((extent/length) != rows))
4781
0
    return(MagickFalse);
4782
14.7M
  y=0;
4783
14.7M
  q=nexus_info->pixels;
4784
14.7M
  switch (cache_info->type)
4785
14.7M
  {
4786
14.7M
    case MemoryCache:
4787
14.7M
    case MapCache:
4788
14.7M
    {
4789
14.7M
      Quantum
4790
14.7M
        *magick_restrict p;
4791
4792
      /*
4793
        Read pixels from memory.
4794
      */
4795
14.7M
      if ((cache_info->columns == nexus_info->region.width) &&
4796
13.9M
          (extent == (MagickSizeType) ((size_t) extent)))
4797
13.9M
        {
4798
13.9M
          length=extent;
4799
13.9M
          rows=1UL;
4800
13.9M
        }
4801
14.7M
      p=cache_info->pixels+(MagickOffsetType) cache_info->number_channels*
4802
14.7M
        offset;
4803
332M
      for (y=0; y < (ssize_t) rows; y++)
4804
317M
      {
4805
317M
        (void) memcpy(q,p,(size_t) length);
4806
317M
        p+=(ptrdiff_t) cache_info->number_channels*cache_info->columns;
4807
317M
        q+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
4808
317M
      }
4809
14.7M
      break;
4810
14.7M
    }
4811
8
    case DiskCache:
4812
8
    {
4813
      /*
4814
        Read pixels from disk.
4815
      */
4816
8
      LockSemaphoreInfo(cache_info->file_semaphore);
4817
8
      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4818
0
        {
4819
0
          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4820
0
            cache_info->cache_filename);
4821
0
          UnlockSemaphoreInfo(cache_info->file_semaphore);
4822
0
          return(MagickFalse);
4823
0
        }
4824
8
      if ((cache_info->columns == nexus_info->region.width) &&
4825
8
          (extent <= MagickMaxBufferExtent))
4826
8
        {
4827
8
          length=extent;
4828
8
          rows=1UL;
4829
8
        }
4830
16
      for (y=0; y < (ssize_t) rows; y++)
4831
8
      {
4832
8
        count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4833
8
          (MagickOffsetType) cache_info->number_channels*(MagickOffsetType)
4834
8
          sizeof(*q),length,(unsigned char *) q);
4835
8
        if (count != (MagickOffsetType) length)
4836
0
          break;
4837
8
        offset+=(MagickOffsetType) cache_info->columns;
4838
8
        q+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
4839
8
      }
4840
8
      if (IsFileDescriptorLimitExceeded() != MagickFalse)
4841
0
        (void) ClosePixelCacheOnDisk(cache_info);
4842
8
      UnlockSemaphoreInfo(cache_info->file_semaphore);
4843
8
      break;
4844
8
    }
4845
0
    case DistributedCache:
4846
0
    {
4847
0
      RectangleInfo
4848
0
        region;
4849
4850
      /*
4851
        Read pixels from distributed cache.
4852
      */
4853
0
      LockSemaphoreInfo(cache_info->file_semaphore);
4854
0
      region=nexus_info->region;
4855
0
      if ((cache_info->columns != nexus_info->region.width) ||
4856
0
          (extent > MagickMaxBufferExtent))
4857
0
        region.height=1UL;
4858
0
      else
4859
0
        {
4860
0
          length=extent;
4861
0
          rows=1UL;
4862
0
        }
4863
0
      for (y=0; y < (ssize_t) rows; y++)
4864
0
      {
4865
0
        count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4866
0
          cache_info->server_info,&region,length,(unsigned char *) q);
4867
0
        if (count != (MagickOffsetType) length)
4868
0
          break;
4869
0
        q+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
4870
0
        region.y++;
4871
0
      }
4872
0
      UnlockSemaphoreInfo(cache_info->file_semaphore);
4873
0
      break;
4874
8
    }
4875
0
    default:
4876
0
      break;
4877
14.7M
  }
4878
14.7M
  if (y < (ssize_t) rows)
4879
0
    {
4880
0
      ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4881
0
        cache_info->cache_filename);
4882
0
      return(MagickFalse);
4883
0
    }
4884
14.7M
  if ((cache_info->debug != MagickFalse) &&
4885
0
      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4886
0
    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4887
0
      "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
4888
0
      nexus_info->region.width,(double) nexus_info->region.height,(double)
4889
0
      nexus_info->region.x,(double) nexus_info->region.y);
4890
14.7M
  return(MagickTrue);
4891
14.7M
}
4892

4893
/*
4894
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4895
%                                                                             %
4896
%                                                                             %
4897
%                                                                             %
4898
+   R e f e r e n c e P i x e l C a c h e                                     %
4899
%                                                                             %
4900
%                                                                             %
4901
%                                                                             %
4902
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4903
%
4904
%  ReferencePixelCache() increments the reference count associated with the
4905
%  pixel cache returning a pointer to the cache.
4906
%
4907
%  The format of the ReferencePixelCache method is:
4908
%
4909
%      Cache ReferencePixelCache(Cache cache_info)
4910
%
4911
%  A description of each parameter follows:
4912
%
4913
%    o cache_info: the pixel cache.
4914
%
4915
*/
4916
MagickPrivate Cache ReferencePixelCache(Cache cache)
4917
738k
{
4918
738k
  CacheInfo
4919
738k
    *magick_restrict cache_info;
4920
4921
738k
  assert(cache != (Cache *) NULL);
4922
738k
  cache_info=(CacheInfo *) cache;
4923
738k
  assert(cache_info->signature == MagickCoreSignature);
4924
738k
  LockSemaphoreInfo(cache_info->semaphore);
4925
738k
  cache_info->reference_count++;
4926
738k
  UnlockSemaphoreInfo(cache_info->semaphore);
4927
738k
  return(cache_info);
4928
738k
}
4929

4930
/*
4931
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4932
%                                                                             %
4933
%                                                                             %
4934
%                                                                             %
4935
+   R e s e t P i x e l C a c h e C h a n n e l s                             %
4936
%                                                                             %
4937
%                                                                             %
4938
%                                                                             %
4939
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4940
%
4941
%  ResetPixelCacheChannels() resets the pixel cache channels.
4942
%
4943
%  The format of the ResetPixelCacheChannels method is:
4944
%
4945
%      void ResetPixelCacheChannels(Image *)
4946
%
4947
%  A description of each parameter follows:
4948
%
4949
%    o image: the image.
4950
%
4951
*/
4952
MagickPrivate void ResetPixelCacheChannels(Image *image)
4953
3.04M
{
4954
3.04M
  CacheInfo
4955
3.04M
    *magick_restrict cache_info;
4956
4957
3.04M
  assert(image != (const Image *) NULL);
4958
3.04M
  assert(image->signature == MagickCoreSignature);
4959
3.04M
  assert(image->cache != (Cache) NULL);
4960
3.04M
  cache_info=(CacheInfo *) image->cache;
4961
3.04M
  assert(cache_info->signature == MagickCoreSignature);
4962
3.04M
  cache_info->number_channels=GetPixelChannels(image);
4963
3.04M
}
4964

4965
/*
4966
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4967
%                                                                             %
4968
%                                                                             %
4969
%                                                                             %
4970
+   R e s e t C a c h e A n o n y m o u s M e m o r y                         %
4971
%                                                                             %
4972
%                                                                             %
4973
%                                                                             %
4974
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4975
%
4976
%  ResetCacheAnonymousMemory() resets the anonymous_memory value.
4977
%
4978
%  The format of the ResetCacheAnonymousMemory method is:
4979
%
4980
%      void ResetCacheAnonymousMemory(void)
4981
%
4982
*/
4983
MagickPrivate void ResetCacheAnonymousMemory(void)
4984
294
{
4985
294
  cache_anonymous_memory=0;
4986
294
}
4987

4988
/*
4989
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4990
%                                                                             %
4991
%                                                                             %
4992
%                                                                             %
4993
%   R e s h a p e P i x e l C a c h e                                         %
4994
%                                                                             %
4995
%                                                                             %
4996
%                                                                             %
4997
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4998
%
4999
%  ReshapePixelCache() reshapes an existing pixel cache.
5000
%
5001
%  The format of the ReshapePixelCache() method is:
5002
%
5003
%      MagickBooleanType ReshapePixelCache(Image *image,const size_t columns,
5004
%        const size_t rows,ExceptionInfo *exception)
5005
%
5006
%  A description of each parameter follows:
5007
%
5008
%    o image: the image.
5009
%
5010
%    o columns: the number of columns in the reshaped pixel cache.
5011
%
5012
%    o rows: number of rows in the reshaped pixel cache.
5013
%
5014
%    o exception: return any errors or warnings in this structure.
5015
%
5016
*/
5017
MagickExport MagickBooleanType ReshapePixelCache(Image *image,
5018
  const size_t columns,const size_t rows,ExceptionInfo *exception)
5019
0
{
5020
0
  CacheInfo
5021
0
    *cache_info;
5022
5023
0
  MagickSizeType
5024
0
    extent;
5025
5026
0
  assert(image != (Image *) NULL);
5027
0
  assert(image->signature == MagickCoreSignature);
5028
0
  if (IsEventLogging() != MagickFalse)
5029
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5030
0
  assert(image->cache != (void *) NULL);
5031
0
  extent=(MagickSizeType) columns*rows;
5032
0
  if (extent > ((MagickSizeType) image->columns*image->rows))
5033
0
    ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
5034
0
      image->filename);
5035
0
  image->columns=columns;
5036
0
  image->rows=rows;
5037
0
  cache_info=(CacheInfo *) image->cache;
5038
0
  cache_info->columns=columns;
5039
0
  cache_info->rows=rows;
5040
0
  return(SyncImagePixelCache(image,exception));
5041
0
}
5042

5043
/*
5044
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5045
%                                                                             %
5046
%                                                                             %
5047
%                                                                             %
5048
+   S e t P i x e l C a c h e M e t h o d s                                   %
5049
%                                                                             %
5050
%                                                                             %
5051
%                                                                             %
5052
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5053
%
5054
%  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
5055
%
5056
%  The format of the SetPixelCacheMethods() method is:
5057
%
5058
%      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
5059
%
5060
%  A description of each parameter follows:
5061
%
5062
%    o cache: the pixel cache.
5063
%
5064
%    o cache_methods: Specifies a pointer to a CacheMethods structure.
5065
%
5066
*/
5067
MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
5068
39.9k
{
5069
39.9k
  CacheInfo
5070
39.9k
    *magick_restrict cache_info;
5071
5072
39.9k
  GetOneAuthenticPixelFromHandler
5073
39.9k
    get_one_authentic_pixel_from_handler;
5074
5075
39.9k
  GetOneVirtualPixelFromHandler
5076
39.9k
    get_one_virtual_pixel_from_handler;
5077
5078
  /*
5079
    Set cache pixel methods.
5080
  */
5081
39.9k
  assert(cache != (Cache) NULL);
5082
39.9k
  assert(cache_methods != (CacheMethods *) NULL);
5083
39.9k
  cache_info=(CacheInfo *) cache;
5084
39.9k
  assert(cache_info->signature == MagickCoreSignature);
5085
39.9k
  if (IsEventLogging() != MagickFalse)
5086
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5087
0
      cache_info->filename);
5088
39.9k
  if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
5089
39.9k
    cache_info->methods.get_virtual_pixel_handler=
5090
39.9k
      cache_methods->get_virtual_pixel_handler;
5091
39.9k
  if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
5092
39.9k
    cache_info->methods.destroy_pixel_handler=
5093
39.9k
      cache_methods->destroy_pixel_handler;
5094
39.9k
  if (cache_methods->get_virtual_metacontent_from_handler !=
5095
39.9k
      (GetVirtualMetacontentFromHandler) NULL)
5096
39.9k
    cache_info->methods.get_virtual_metacontent_from_handler=
5097
39.9k
      cache_methods->get_virtual_metacontent_from_handler;
5098
39.9k
  if (cache_methods->get_authentic_pixels_handler !=
5099
39.9k
      (GetAuthenticPixelsHandler) NULL)
5100
39.9k
    cache_info->methods.get_authentic_pixels_handler=
5101
39.9k
      cache_methods->get_authentic_pixels_handler;
5102
39.9k
  if (cache_methods->queue_authentic_pixels_handler !=
5103
39.9k
      (QueueAuthenticPixelsHandler) NULL)
5104
39.9k
    cache_info->methods.queue_authentic_pixels_handler=
5105
39.9k
      cache_methods->queue_authentic_pixels_handler;
5106
39.9k
  if (cache_methods->sync_authentic_pixels_handler !=
5107
39.9k
      (SyncAuthenticPixelsHandler) NULL)
5108
39.9k
    cache_info->methods.sync_authentic_pixels_handler=
5109
39.9k
      cache_methods->sync_authentic_pixels_handler;
5110
39.9k
  if (cache_methods->get_authentic_pixels_from_handler !=
5111
39.9k
      (GetAuthenticPixelsFromHandler) NULL)
5112
39.9k
    cache_info->methods.get_authentic_pixels_from_handler=
5113
39.9k
      cache_methods->get_authentic_pixels_from_handler;
5114
39.9k
  if (cache_methods->get_authentic_metacontent_from_handler !=
5115
39.9k
      (GetAuthenticMetacontentFromHandler) NULL)
5116
39.9k
    cache_info->methods.get_authentic_metacontent_from_handler=
5117
39.9k
      cache_methods->get_authentic_metacontent_from_handler;
5118
39.9k
  get_one_virtual_pixel_from_handler=
5119
39.9k
    cache_info->methods.get_one_virtual_pixel_from_handler;
5120
39.9k
  if (get_one_virtual_pixel_from_handler !=
5121
39.9k
      (GetOneVirtualPixelFromHandler) NULL)
5122
0
    cache_info->methods.get_one_virtual_pixel_from_handler=
5123
0
      cache_methods->get_one_virtual_pixel_from_handler;
5124
39.9k
  get_one_authentic_pixel_from_handler=
5125
39.9k
    cache_methods->get_one_authentic_pixel_from_handler;
5126
39.9k
  if (get_one_authentic_pixel_from_handler !=
5127
39.9k
      (GetOneAuthenticPixelFromHandler) NULL)
5128
39.9k
    cache_info->methods.get_one_authentic_pixel_from_handler=
5129
39.9k
      cache_methods->get_one_authentic_pixel_from_handler;
5130
39.9k
}
5131

5132
/*
5133
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5134
%                                                                             %
5135
%                                                                             %
5136
%                                                                             %
5137
+   S e t P i x e l C a c h e N e x u s P i x e l s                           %
5138
%                                                                             %
5139
%                                                                             %
5140
%                                                                             %
5141
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5142
%
5143
%  SetPixelCacheNexusPixels() defines the region of the cache for the
5144
%  specified cache nexus.
5145
%
5146
%  The format of the SetPixelCacheNexusPixels() method is:
5147
%
5148
%      Quantum SetPixelCacheNexusPixels(
5149
%        const CacheInfo *magick_restrict cache_info,const MapMode mode,
5150
%        const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5151
%        const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5152
%        ExceptionInfo *exception)
5153
%
5154
%  A description of each parameter follows:
5155
%
5156
%    o cache_info: the pixel cache.
5157
%
5158
%    o mode: ReadMode, WriteMode, or IOMode.
5159
%
5160
%    o x,y,width,height: define the region of this particular cache nexus.
5161
%
5162
%    o buffered: if true, nexus pixels are buffered.
5163
%
5164
%    o nexus_info: the cache nexus to set.
5165
%
5166
%    o exception: return any errors or warnings in this structure.
5167
%
5168
*/
5169
5170
static inline MagickBooleanType AcquireCacheNexusPixels(
5171
  const CacheInfo *magick_restrict cache_info,const MagickSizeType length,
5172
  NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5173
849k
{
5174
849k
  if (length != (MagickSizeType) ((size_t) length))
5175
0
    {
5176
0
      (void) ThrowMagickException(exception,GetMagickModule(),
5177
0
        ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5178
0
        cache_info->filename);
5179
0
      return(MagickFalse);
5180
0
    }
5181
849k
  nexus_info->length=0;
5182
849k
  nexus_info->mapped=MagickFalse;
5183
849k
  if (cache_anonymous_memory <= 0)
5184
849k
    {
5185
849k
      nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
5186
849k
        (size_t) length));
5187
849k
      if (nexus_info->cache != (Quantum *) NULL)
5188
849k
        (void) memset(nexus_info->cache,0,(size_t) length);
5189
849k
    }
5190
0
  else
5191
0
    {
5192
0
      nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t) length);
5193
0
      if (nexus_info->cache != (Quantum *) NULL)
5194
0
        nexus_info->mapped=MagickTrue;
5195
0
    }
5196
849k
  if (nexus_info->cache == (Quantum *) NULL)
5197
0
    {
5198
0
      (void) ThrowMagickException(exception,GetMagickModule(),
5199
0
        ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5200
0
        cache_info->filename);
5201
0
      return(MagickFalse);
5202
0
    }
5203
849k
  nexus_info->length=length;
5204
849k
  return(MagickTrue);
5205
849k
}
5206
5207
static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
5208
  const MapMode mode)
5209
454M
{
5210
454M
  if (nexus_info->length < CACHE_LINE_SIZE)
5211
352M
    return;
5212
101M
  if (mode == ReadMode)
5213
32.4M
    {
5214
32.4M
      MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,
5215
32.4M
        0,1);
5216
32.4M
      return;
5217
32.4M
    }
5218
69.4M
  MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,1,1);
5219
69.4M
}
5220
5221
static Quantum *SetPixelCacheNexusPixels(
5222
  const CacheInfo *magick_restrict cache_info,const MapMode mode,
5223
  const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5224
  const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5225
  ExceptionInfo *exception)
5226
454M
{
5227
454M
  MagickBooleanType
5228
454M
    status;
5229
5230
454M
  MagickSizeType
5231
454M
    length,
5232
454M
    number_pixels;
5233
5234
454M
  assert(cache_info != (const CacheInfo *) NULL);
5235
454M
  assert(cache_info->signature == MagickCoreSignature);
5236
454M
  if (cache_info->type == UndefinedCache)
5237
68.6k
    return((Quantum *) NULL);
5238
454M
  assert(nexus_info->signature == MagickCoreSignature);
5239
454M
  (void) memset(&nexus_info->region,0,sizeof(nexus_info->region));
5240
454M
  if ((width == 0) || (height == 0))
5241
71.4k
    {
5242
71.4k
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
5243
71.4k
        "NoPixelsDefinedInCache","`%s'",cache_info->filename);
5244
71.4k
      return((Quantum *) NULL);
5245
71.4k
    }
5246
454M
  if (((MagickSizeType) width > cache_info->width_limit) ||
5247
454M
      ((MagickSizeType) height > cache_info->height_limit))
5248
6.41k
    {
5249
6.41k
      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5250
6.41k
        "WidthOrHeightExceedsLimit","`%s'",cache_info->filename);
5251
6.41k
      return((Quantum *) NULL);
5252
6.41k
    }
5253
454M
  if ((IsValidPixelOffset(x,width) == MagickFalse) ||
5254
454M
      (IsValidPixelOffset(y,height) == MagickFalse))
5255
8.88k
    {
5256
8.88k
      (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
5257
8.88k
        "InvalidPixel","`%s'",cache_info->filename);
5258
8.88k
      return((Quantum *) NULL);
5259
8.88k
    }
5260
454M
  if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
5261
397M
      (buffered == MagickFalse))
5262
381M
    {
5263
381M
      if (((x >= 0) && (y >= 0) &&
5264
372M
          (((ssize_t) height+y-1) < (ssize_t) cache_info->rows)) &&
5265
366M
          (((x == 0) && (width == cache_info->columns)) || ((height == 1) &&
5266
156M
          (((ssize_t) width+x-1) < (ssize_t) cache_info->columns))))
5267
359M
        {
5268
359M
          MagickOffsetType
5269
359M
            offset;
5270
5271
          /*
5272
            Pixels are accessed directly from memory.
5273
          */
5274
359M
          if (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
5275
0
            return((Quantum *) NULL);
5276
359M
          offset=y*(MagickOffsetType) cache_info->columns+x;
5277
359M
          nexus_info->pixels=cache_info->pixels+(MagickOffsetType)
5278
359M
            cache_info->number_channels*offset;
5279
359M
          nexus_info->metacontent=(void *) NULL;
5280
359M
          if (cache_info->metacontent_extent != 0)
5281
0
            nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5282
0
              offset*(MagickOffsetType) cache_info->metacontent_extent;
5283
359M
          nexus_info->region.width=width;
5284
359M
          nexus_info->region.height=height;
5285
359M
          nexus_info->region.x=x;
5286
359M
          nexus_info->region.y=y;
5287
359M
          nexus_info->authentic_pixel_cache=MagickTrue;
5288
359M
          PrefetchPixelCacheNexusPixels(nexus_info,mode);
5289
359M
          return(nexus_info->pixels);
5290
359M
        }
5291
381M
    }
5292
  /*
5293
    Pixels are stored in a staging region until they are synced to the cache.
5294
  */
5295
94.6M
  if (CacheOverflowSanityCheckGetSize(width,height,&number_pixels) != MagickFalse)
5296
0
    {
5297
0
      (void) ThrowMagickException(exception,GetMagickModule(),
5298
0
        ResourceLimitError,"MemoryAllocationFailed","`%s'",
5299
0
        cache_info->filename);
5300
0
      return((Quantum *) NULL);
5301
0
    }
5302
94.6M
  {
5303
94.6M
    MagickSizeType
5304
94.6M
      extent,
5305
94.6M
      packets;
5306
5307
94.6M
    packets=MagickMax(number_pixels,MagickMax(cache_info->columns,
5308
94.6M
      cache_info->rows));
5309
94.6M
    if ((CacheOverflowSanityCheckGetSize(packets,cache_info->number_channels,&length) != MagickFalse) ||
5310
94.6M
        (CacheOverflowSanityCheckGetSize(length,sizeof(*nexus_info->pixels),&length) != MagickFalse))
5311
0
      {
5312
0
        (void) ThrowMagickException(exception,GetMagickModule(),
5313
0
          ResourceLimitError,"MemoryAllocationFailed","`%s'",
5314
0
          cache_info->filename);
5315
0
        return((Quantum *) NULL);
5316
0
      }
5317
94.6M
    if (cache_info->metacontent_extent != 0)
5318
0
      {
5319
0
        if ((CacheOverflowSanityCheckGetSize(number_pixels,cache_info->metacontent_extent,&extent) != MagickFalse) ||
5320
0
            (extent > (MagickSizeType) (~((MagickSizeType) 0))-length))
5321
0
          {
5322
0
            (void) ThrowMagickException(exception,GetMagickModule(),
5323
0
              ResourceLimitError,"MemoryAllocationFailed","`%s'",
5324
0
              cache_info->filename);
5325
0
            return((Quantum *) NULL);
5326
0
          }
5327
0
        length+=extent;
5328
0
      }
5329
94.6M
   }
5330
94.6M
  status=MagickTrue;
5331
94.6M
  if (nexus_info->cache == (Quantum *) NULL)
5332
845k
    status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5333
93.7M
  else
5334
93.7M
    if (nexus_info->length < length)
5335
3.84k
      {
5336
3.84k
        RelinquishCacheNexusPixels(nexus_info);
5337
3.84k
        status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5338
3.84k
      }
5339
94.6M
  if (status == MagickFalse)
5340
0
    return((Quantum *) NULL);
5341
94.6M
  nexus_info->pixels=nexus_info->cache;
5342
94.6M
  nexus_info->metacontent=(void *) NULL;
5343
94.6M
  if (cache_info->metacontent_extent != 0)
5344
0
    nexus_info->metacontent=(void *) (nexus_info->pixels+
5345
0
      cache_info->number_channels*number_pixels);
5346
94.6M
  nexus_info->region.width=width;
5347
94.6M
  nexus_info->region.height=height;
5348
94.6M
  nexus_info->region.x=x;
5349
94.6M
  nexus_info->region.y=y;
5350
94.6M
  nexus_info->authentic_pixel_cache=cache_info->type == PingCache ?
5351
56.3M
    MagickTrue : MagickFalse;
5352
94.6M
  PrefetchPixelCacheNexusPixels(nexus_info,mode);
5353
94.6M
  return(nexus_info->pixels);
5354
94.6M
}
5355

5356
/*
5357
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5358
%                                                                             %
5359
%                                                                             %
5360
%                                                                             %
5361
%   S e t P i x e l C a c h e V i r t u a l M e t h o d                       %
5362
%                                                                             %
5363
%                                                                             %
5364
%                                                                             %
5365
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5366
%
5367
%  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5368
%  pixel cache and returns the previous setting.  A virtual pixel is any pixel
5369
%  access that is outside the boundaries of the image cache.
5370
%
5371
%  The format of the SetPixelCacheVirtualMethod() method is:
5372
%
5373
%      VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5374
%        const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5375
%
5376
%  A description of each parameter follows:
5377
%
5378
%    o image: the image.
5379
%
5380
%    o virtual_pixel_method: choose the type of virtual pixel.
5381
%
5382
%    o exception: return any errors or warnings in this structure.
5383
%
5384
*/
5385
5386
static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
5387
  ExceptionInfo *exception)
5388
0
{
5389
0
  CacheView
5390
0
    *magick_restrict image_view;
5391
5392
0
  MagickBooleanType
5393
0
    status;
5394
5395
0
  ssize_t
5396
0
    y;
5397
5398
0
  assert(image != (Image *) NULL);
5399
0
  assert(image->signature == MagickCoreSignature);
5400
0
  if (IsEventLogging() != MagickFalse)
5401
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5402
0
  assert(image->cache != (Cache) NULL);
5403
0
  image->alpha_trait=BlendPixelTrait;
5404
0
  status=MagickTrue;
5405
0
  image_view=AcquireVirtualCacheView(image,exception);  /* must be virtual */
5406
#if defined(MAGICKCORE_OPENMP_SUPPORT)
5407
  #pragma omp parallel for schedule(static) shared(status) \
5408
    magick_number_threads(image,image,image->rows,2)
5409
#endif
5410
0
  for (y=0; y < (ssize_t) image->rows; y++)
5411
0
  {
5412
0
    Quantum
5413
0
      *magick_restrict q;
5414
5415
0
    ssize_t
5416
0
      x;
5417
5418
0
    if (status == MagickFalse)
5419
0
      continue;
5420
0
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5421
0
    if (q == (Quantum *) NULL)
5422
0
      {
5423
0
        status=MagickFalse;
5424
0
        continue;
5425
0
      }
5426
0
    for (x=0; x < (ssize_t) image->columns; x++)
5427
0
    {
5428
0
      SetPixelAlpha(image,alpha,q);
5429
0
      q+=(ptrdiff_t) GetPixelChannels(image);
5430
0
    }
5431
0
    status=SyncCacheViewAuthenticPixels(image_view,exception);
5432
0
  }
5433
0
  image_view=DestroyCacheView(image_view);
5434
0
  return(status);
5435
0
}
5436
5437
MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5438
  const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5439
1.90k
{
5440
1.90k
  CacheInfo
5441
1.90k
    *magick_restrict cache_info;
5442
5443
1.90k
  VirtualPixelMethod
5444
1.90k
    method;
5445
5446
1.90k
  assert(image != (Image *) NULL);
5447
1.90k
  assert(image->signature == MagickCoreSignature);
5448
1.90k
  if (IsEventLogging() != MagickFalse)
5449
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5450
1.90k
  assert(image->cache != (Cache) NULL);
5451
1.90k
  cache_info=(CacheInfo *) image->cache;
5452
1.90k
  assert(cache_info->signature == MagickCoreSignature);
5453
1.90k
  method=cache_info->virtual_pixel_method;
5454
1.90k
  cache_info->virtual_pixel_method=virtual_pixel_method;
5455
1.90k
  if ((image->columns != 0) && (image->rows != 0))
5456
1.90k
    switch (virtual_pixel_method)
5457
1.90k
    {
5458
1.90k
      case BackgroundVirtualPixelMethod:
5459
1.90k
      {
5460
1.90k
        if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
5461
0
            ((image->alpha_trait & BlendPixelTrait) == 0))
5462
0
          (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5463
1.90k
        if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5464
0
            (IsGrayColorspace(image->colorspace) != MagickFalse))
5465
0
          (void) SetImageColorspace(image,sRGBColorspace,exception);
5466
1.90k
        break;
5467
0
      }
5468
0
      case TransparentVirtualPixelMethod:
5469
0
      {
5470
0
        if ((image->alpha_trait & BlendPixelTrait) == 0)
5471
0
          (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5472
0
        break;
5473
0
      }
5474
0
      default:
5475
0
        break;
5476
1.90k
    }
5477
1.90k
  return(method);
5478
1.90k
}
5479
5480
#if defined(MAGICKCORE_OPENCL_SUPPORT)
5481
/*
5482
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5483
%                                                                             %
5484
%                                                                             %
5485
%                                                                             %
5486
+   S y n c A u t h e n t i c O p e n C L B u f f e r                         %
5487
%                                                                             %
5488
%                                                                             %
5489
%                                                                             %
5490
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5491
%
5492
%  SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5493
%  been completed and updates the host memory.
5494
%
5495
%  The format of the SyncAuthenticOpenCLBuffer() method is:
5496
%
5497
%      void SyncAuthenticOpenCLBuffer(const Image *image)
5498
%
5499
%  A description of each parameter follows:
5500
%
5501
%    o image: the image.
5502
%
5503
*/
5504
5505
static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5506
{
5507
  assert(cache_info != (CacheInfo *) NULL);
5508
  assert(cache_info->signature == MagickCoreSignature);
5509
  if ((cache_info->type != MemoryCache) ||
5510
      (cache_info->opencl == (MagickCLCacheInfo) NULL))
5511
    return;
5512
  /*
5513
    Ensure single threaded access to OpenCL environment.
5514
  */
5515
  LockSemaphoreInfo(cache_info->semaphore);
5516
  cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
5517
  UnlockSemaphoreInfo(cache_info->semaphore);
5518
}
5519
5520
MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5521
{
5522
  CacheInfo
5523
    *magick_restrict cache_info;
5524
5525
  assert(image != (const Image *) NULL);
5526
  cache_info=(CacheInfo *) image->cache;
5527
  CopyOpenCLBuffer(cache_info);
5528
}
5529
#endif
5530

5531
/*
5532
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5533
%                                                                             %
5534
%                                                                             %
5535
%                                                                             %
5536
+   S y n c A u t h e n t i c P i x e l C a c h e N e x u s                   %
5537
%                                                                             %
5538
%                                                                             %
5539
%                                                                             %
5540
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5541
%
5542
%  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5543
%  in-memory or disk cache.  The method returns MagickTrue if the pixel region
5544
%  is synced, otherwise MagickFalse.
5545
%
5546
%  The format of the SyncAuthenticPixelCacheNexus() method is:
5547
%
5548
%      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5549
%        NexusInfo *nexus_info,ExceptionInfo *exception)
5550
%
5551
%  A description of each parameter follows:
5552
%
5553
%    o image: the image.
5554
%
5555
%    o nexus_info: the cache nexus to sync.
5556
%
5557
%    o exception: return any errors or warnings in this structure.
5558
%
5559
*/
5560
MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5561
  NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5562
286M
{
5563
286M
  CacheInfo
5564
286M
    *magick_restrict cache_info;
5565
5566
286M
  MagickBooleanType
5567
286M
    status;
5568
5569
  /*
5570
    Transfer pixels to the cache.
5571
  */
5572
286M
  assert(image != (Image *) NULL);
5573
286M
  assert(image->signature == MagickCoreSignature);
5574
286M
  if (image->cache == (Cache) NULL)
5575
286M
    ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5576
286M
  cache_info=(CacheInfo *) image->cache;
5577
286M
  assert(cache_info->signature == MagickCoreSignature);
5578
286M
  if (cache_info->type == UndefinedCache)
5579
0
    return(MagickFalse);
5580
286M
  if ((image->mask_trait & UpdatePixelTrait) != 0)
5581
4.01M
    {
5582
4.01M
      if (((image->channels & WriteMaskChannel) != 0) &&
5583
67.4k
          (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5584
0
        return(MagickFalse);
5585
4.01M
      if (((image->channels & CompositeMaskChannel) != 0) &&
5586
3.96M
          (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5587
0
        return(MagickFalse);
5588
4.01M
    }
5589
286M
  if (nexus_info->authentic_pixel_cache != MagickFalse)
5590
274M
    {
5591
274M
      if (image->taint == MagickFalse)
5592
596k
        image->taint=MagickTrue;
5593
274M
      return(MagickTrue);
5594
274M
    }
5595
286M
  assert(cache_info->signature == MagickCoreSignature);
5596
11.7M
  status=WritePixelCachePixels(cache_info,nexus_info,exception);
5597
11.7M
  if ((cache_info->metacontent_extent != 0) &&
5598
0
      (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5599
0
    return(MagickFalse);
5600
11.7M
  if ((status != MagickFalse) && (image->taint == MagickFalse))
5601
4.69k
    image->taint=MagickTrue;
5602
11.7M
  return(status);
5603
11.7M
}
5604

5605
/*
5606
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5607
%                                                                             %
5608
%                                                                             %
5609
%                                                                             %
5610
+   S y n c A u t h e n t i c P i x e l C a c h e                             %
5611
%                                                                             %
5612
%                                                                             %
5613
%                                                                             %
5614
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5615
%
5616
%  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5617
%  or disk cache.  The method returns MagickTrue if the pixel region is synced,
5618
%  otherwise MagickFalse.
5619
%
5620
%  The format of the SyncAuthenticPixelsCache() method is:
5621
%
5622
%      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5623
%        ExceptionInfo *exception)
5624
%
5625
%  A description of each parameter follows:
5626
%
5627
%    o image: the image.
5628
%
5629
%    o exception: return any errors or warnings in this structure.
5630
%
5631
*/
5632
static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5633
  ExceptionInfo *exception)
5634
0
{
5635
0
  CacheInfo
5636
0
    *magick_restrict cache_info;
5637
5638
0
  const int
5639
0
    id = GetOpenMPThreadId();
5640
5641
0
  MagickBooleanType
5642
0
    status;
5643
5644
0
  assert(image != (Image *) NULL);
5645
0
  assert(image->signature == MagickCoreSignature);
5646
0
  assert(image->cache != (Cache) NULL);
5647
0
  cache_info=(CacheInfo *) image->cache;
5648
0
  assert(cache_info->signature == MagickCoreSignature);
5649
0
  assert(id < (int) cache_info->number_threads);
5650
0
  status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5651
0
    exception);
5652
0
  return(status);
5653
0
}
5654

5655
/*
5656
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5657
%                                                                             %
5658
%                                                                             %
5659
%                                                                             %
5660
%   S y n c A u t h e n t i c P i x e l s                                     %
5661
%                                                                             %
5662
%                                                                             %
5663
%                                                                             %
5664
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5665
%
5666
%  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5667
%  The method returns MagickTrue if the pixel region is flushed, otherwise
5668
%  MagickFalse.
5669
%
5670
%  The format of the SyncAuthenticPixels() method is:
5671
%
5672
%      MagickBooleanType SyncAuthenticPixels(Image *image,
5673
%        ExceptionInfo *exception)
5674
%
5675
%  A description of each parameter follows:
5676
%
5677
%    o image: the image.
5678
%
5679
%    o exception: return any errors or warnings in this structure.
5680
%
5681
*/
5682
MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5683
  ExceptionInfo *exception)
5684
80.5M
{
5685
80.5M
  CacheInfo
5686
80.5M
    *magick_restrict cache_info;
5687
5688
80.5M
  const int
5689
80.5M
    id = GetOpenMPThreadId();
5690
5691
80.5M
  MagickBooleanType
5692
80.5M
    status;
5693
5694
80.5M
  assert(image != (Image *) NULL);
5695
80.5M
  assert(image->signature == MagickCoreSignature);
5696
80.5M
  assert(image->cache != (Cache) NULL);
5697
80.5M
  cache_info=(CacheInfo *) image->cache;
5698
80.5M
  assert(cache_info->signature == MagickCoreSignature);
5699
80.5M
  if (cache_info->methods.sync_authentic_pixels_handler != (SyncAuthenticPixelsHandler) NULL)
5700
3.04M
    {
5701
3.04M
      status=cache_info->methods.sync_authentic_pixels_handler(image,
5702
3.04M
        exception);
5703
3.04M
      return(status);
5704
3.04M
    }
5705
80.5M
  assert(id < (int) cache_info->number_threads);
5706
77.5M
  status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5707
77.5M
    exception);
5708
77.5M
  return(status);
5709
77.5M
}
5710

5711
/*
5712
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5713
%                                                                             %
5714
%                                                                             %
5715
%                                                                             %
5716
+   S y n c I m a g e P i x e l C a c h e                                     %
5717
%                                                                             %
5718
%                                                                             %
5719
%                                                                             %
5720
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5721
%
5722
%  SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5723
%  The method returns MagickTrue if the pixel region is flushed, otherwise
5724
%  MagickFalse.
5725
%
5726
%  The format of the SyncImagePixelCache() method is:
5727
%
5728
%      MagickBooleanType SyncImagePixelCache(Image *image,
5729
%        ExceptionInfo *exception)
5730
%
5731
%  A description of each parameter follows:
5732
%
5733
%    o image: the image.
5734
%
5735
%    o exception: return any errors or warnings in this structure.
5736
%
5737
*/
5738
MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5739
  ExceptionInfo *exception)
5740
2.61M
{
5741
2.61M
  CacheInfo
5742
2.61M
    *magick_restrict cache_info;
5743
5744
2.61M
  assert(image != (Image *) NULL);
5745
2.61M
  assert(exception != (ExceptionInfo *) NULL);
5746
2.61M
  cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5747
2.61M
  return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5748
2.61M
}
5749

5750
/*
5751
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5752
%                                                                             %
5753
%                                                                             %
5754
%                                                                             %
5755
+   W r i t e P i x e l C a c h e M e t a c o n t e n t                       %
5756
%                                                                             %
5757
%                                                                             %
5758
%                                                                             %
5759
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5760
%
5761
%  WritePixelCacheMetacontent() writes the meta-content to the specified region
5762
%  of the pixel cache.
5763
%
5764
%  The format of the WritePixelCacheMetacontent() method is:
5765
%
5766
%      MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5767
%        NexusInfo *nexus_info,ExceptionInfo *exception)
5768
%
5769
%  A description of each parameter follows:
5770
%
5771
%    o cache_info: the pixel cache.
5772
%
5773
%    o nexus_info: the cache nexus to write the meta-content.
5774
%
5775
%    o exception: return any errors or warnings in this structure.
5776
%
5777
*/
5778
static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5779
  NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5780
0
{
5781
0
  MagickOffsetType
5782
0
    count,
5783
0
    offset;
5784
5785
0
  MagickSizeType
5786
0
    extent,
5787
0
    length;
5788
5789
0
  const unsigned char
5790
0
    *magick_restrict p;
5791
5792
0
  ssize_t
5793
0
    y;
5794
5795
0
  size_t
5796
0
    rows;
5797
5798
0
  if (cache_info->metacontent_extent == 0)
5799
0
    return(MagickFalse);
5800
0
  if (nexus_info->authentic_pixel_cache != MagickFalse)
5801
0
    return(MagickTrue);
5802
0
  if (nexus_info->metacontent == (unsigned char *) NULL)
5803
0
    return(MagickFalse);
5804
0
  if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
5805
0
    return(MagickFalse);
5806
0
  offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
5807
0
    nexus_info->region.x;
5808
0
  length=(MagickSizeType) nexus_info->region.width*
5809
0
    cache_info->metacontent_extent;
5810
0
  extent=(MagickSizeType) length*nexus_info->region.height;
5811
0
  rows=nexus_info->region.height;
5812
0
  y=0;
5813
0
  p=(unsigned char *) nexus_info->metacontent;
5814
0
  switch (cache_info->type)
5815
0
  {
5816
0
    case MemoryCache:
5817
0
    case MapCache:
5818
0
    {
5819
0
      unsigned char
5820
0
        *magick_restrict q;
5821
5822
      /*
5823
        Write associated pixels to memory.
5824
      */
5825
0
      if ((cache_info->columns == nexus_info->region.width) &&
5826
0
          (extent == (MagickSizeType) ((size_t) extent)))
5827
0
        {
5828
0
          length=extent;
5829
0
          rows=1UL;
5830
0
        }
5831
0
      q=(unsigned char *) cache_info->metacontent+offset*
5832
0
        (MagickOffsetType) cache_info->metacontent_extent;
5833
0
      for (y=0; y < (ssize_t) rows; y++)
5834
0
      {
5835
0
        (void) memcpy(q,p,(size_t) length);
5836
0
        p+=(ptrdiff_t) nexus_info->region.width*cache_info->metacontent_extent;
5837
0
        q+=(ptrdiff_t) cache_info->columns*cache_info->metacontent_extent;
5838
0
      }
5839
0
      break;
5840
0
    }
5841
0
    case DiskCache:
5842
0
    {
5843
      /*
5844
        Write associated pixels to disk.
5845
      */
5846
0
      LockSemaphoreInfo(cache_info->file_semaphore);
5847
0
      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5848
0
        {
5849
0
          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5850
0
            cache_info->cache_filename);
5851
0
          UnlockSemaphoreInfo(cache_info->file_semaphore);
5852
0
          return(MagickFalse);
5853
0
        }
5854
0
      if ((cache_info->columns == nexus_info->region.width) &&
5855
0
          (extent <= MagickMaxBufferExtent))
5856
0
        {
5857
0
          length=extent;
5858
0
          rows=1UL;
5859
0
        }
5860
0
      extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5861
0
      for (y=0; y < (ssize_t) rows; y++)
5862
0
      {
5863
0
        count=WritePixelCacheRegion(cache_info,cache_info->offset+
5864
0
          (MagickOffsetType) extent*(MagickOffsetType)
5865
0
          cache_info->number_channels*(MagickOffsetType) sizeof(Quantum)+offset*
5866
0
          (MagickOffsetType) cache_info->metacontent_extent,length,
5867
0
          (const unsigned char *) p);
5868
0
        if (count != (MagickOffsetType) length)
5869
0
          break;
5870
0
        p+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
5871
0
        offset+=(MagickOffsetType) cache_info->columns;
5872
0
      }
5873
0
      if (IsFileDescriptorLimitExceeded() != MagickFalse)
5874
0
        (void) ClosePixelCacheOnDisk(cache_info);
5875
0
      UnlockSemaphoreInfo(cache_info->file_semaphore);
5876
0
      break;
5877
0
    }
5878
0
    case DistributedCache:
5879
0
    {
5880
0
      RectangleInfo
5881
0
        region;
5882
5883
      /*
5884
        Write metacontent to distributed cache.
5885
      */
5886
0
      LockSemaphoreInfo(cache_info->file_semaphore);
5887
0
      region=nexus_info->region;
5888
0
      if ((cache_info->columns != nexus_info->region.width) ||
5889
0
          (extent > MagickMaxBufferExtent))
5890
0
        region.height=1UL;
5891
0
      else
5892
0
        {
5893
0
          length=extent;
5894
0
          rows=1UL;
5895
0
        }
5896
0
      for (y=0; y < (ssize_t) rows; y++)
5897
0
      {
5898
0
        count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5899
0
          cache_info->server_info,&region,length,(const unsigned char *) p);
5900
0
        if (count != (MagickOffsetType) length)
5901
0
          break;
5902
0
        p+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
5903
0
        region.y++;
5904
0
      }
5905
0
      UnlockSemaphoreInfo(cache_info->file_semaphore);
5906
0
      break;
5907
0
    }
5908
0
    default:
5909
0
      break;
5910
0
  }
5911
0
  if (y < (ssize_t) rows)
5912
0
    {
5913
0
      ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5914
0
        cache_info->cache_filename);
5915
0
      return(MagickFalse);
5916
0
    }
5917
0
  if ((cache_info->debug != MagickFalse) &&
5918
0
      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5919
0
    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5920
0
      "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
5921
0
      nexus_info->region.width,(double) nexus_info->region.height,(double)
5922
0
      nexus_info->region.x,(double) nexus_info->region.y);
5923
0
  return(MagickTrue);
5924
0
}
5925

5926
/*
5927
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5928
%                                                                             %
5929
%                                                                             %
5930
%                                                                             %
5931
+   W r i t e C a c h e P i x e l s                                           %
5932
%                                                                             %
5933
%                                                                             %
5934
%                                                                             %
5935
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5936
%
5937
%  WritePixelCachePixels() writes image pixels to the specified region of the
5938
%  pixel cache.
5939
%
5940
%  The format of the WritePixelCachePixels() method is:
5941
%
5942
%      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5943
%        NexusInfo *nexus_info,ExceptionInfo *exception)
5944
%
5945
%  A description of each parameter follows:
5946
%
5947
%    o cache_info: the pixel cache.
5948
%
5949
%    o nexus_info: the cache nexus to write the pixels.
5950
%
5951
%    o exception: return any errors or warnings in this structure.
5952
%
5953
*/
5954
static MagickBooleanType WritePixelCachePixels(
5955
  CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5956
  ExceptionInfo *exception)
5957
56.0M
{
5958
56.0M
  MagickOffsetType
5959
56.0M
    count,
5960
56.0M
    offset;
5961
5962
56.0M
  MagickSizeType
5963
56.0M
    extent,
5964
56.0M
    length;
5965
5966
56.0M
  const Quantum
5967
56.0M
    *magick_restrict p;
5968
5969
56.0M
  ssize_t
5970
56.0M
    y;
5971
5972
56.0M
  size_t
5973
56.0M
    rows;
5974
5975
56.0M
  if (nexus_info->authentic_pixel_cache != MagickFalse)
5976
44.1M
    return(MagickTrue);
5977
11.8M
  if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
5978
0
    return(MagickFalse);
5979
11.8M
  offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
5980
11.8M
    nexus_info->region.x;
5981
11.8M
  length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5982
11.8M
    sizeof(Quantum);
5983
11.8M
  extent=length*nexus_info->region.height;
5984
11.8M
  rows=nexus_info->region.height;
5985
11.8M
  y=0;
5986
11.8M
  p=nexus_info->pixels;
5987
11.8M
  switch (cache_info->type)
5988
11.8M
  {
5989
10.1M
    case MemoryCache:
5990
10.1M
    case MapCache:
5991
10.1M
    {
5992
10.1M
      Quantum
5993
10.1M
        *magick_restrict q;
5994
5995
      /*
5996
        Write pixels to memory.
5997
      */
5998
10.1M
      if ((cache_info->columns == nexus_info->region.width) &&
5999
8.10M
          (extent == (MagickSizeType) ((size_t) extent)))
6000
8.10M
        {
6001
8.10M
          length=extent;
6002
8.10M
          rows=1UL;
6003
8.10M
        }
6004
10.1M
      q=cache_info->pixels+(MagickOffsetType) cache_info->number_channels*
6005
10.1M
        offset;
6006
541M
      for (y=0; y < (ssize_t) rows; y++)
6007
531M
      {
6008
531M
        (void) memcpy(q,p,(size_t) length);
6009
531M
        p+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
6010
531M
        q+=(ptrdiff_t) cache_info->number_channels*cache_info->columns;
6011
531M
      }
6012
10.1M
      break;
6013
10.1M
    }
6014
124k
    case DiskCache:
6015
124k
    {
6016
      /*
6017
        Write pixels to disk.
6018
      */
6019
124k
      LockSemaphoreInfo(cache_info->file_semaphore);
6020
124k
      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
6021
0
        {
6022
0
          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
6023
0
            cache_info->cache_filename);
6024
0
          UnlockSemaphoreInfo(cache_info->file_semaphore);
6025
0
          return(MagickFalse);
6026
0
        }
6027
124k
      if ((cache_info->columns == nexus_info->region.width) &&
6028
124k
          (extent <= MagickMaxBufferExtent))
6029
124k
        {
6030
124k
          length=extent;
6031
124k
          rows=1UL;
6032
124k
        }
6033
249k
      for (y=0; y < (ssize_t) rows; y++)
6034
124k
      {
6035
124k
        count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
6036
124k
          (MagickOffsetType) cache_info->number_channels*(MagickOffsetType)
6037
124k
          sizeof(*p),length,(const unsigned char *) p);
6038
124k
        if (count != (MagickOffsetType) length)
6039
0
          break;
6040
124k
        p+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
6041
124k
        offset+=(MagickOffsetType) cache_info->columns;
6042
124k
      }
6043
124k
      if (IsFileDescriptorLimitExceeded() != MagickFalse)
6044
0
        (void) ClosePixelCacheOnDisk(cache_info);
6045
124k
      UnlockSemaphoreInfo(cache_info->file_semaphore);
6046
124k
      break;
6047
124k
    }
6048
0
    case DistributedCache:
6049
0
    {
6050
0
      RectangleInfo
6051
0
        region;
6052
6053
      /*
6054
        Write pixels to distributed cache.
6055
      */
6056
0
      LockSemaphoreInfo(cache_info->file_semaphore);
6057
0
      region=nexus_info->region;
6058
0
      if ((cache_info->columns != nexus_info->region.width) ||
6059
0
          (extent > MagickMaxBufferExtent))
6060
0
        region.height=1UL;
6061
0
      else
6062
0
        {
6063
0
          length=extent;
6064
0
          rows=1UL;
6065
0
        }
6066
0
      for (y=0; y < (ssize_t) rows; y++)
6067
0
      {
6068
0
        count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
6069
0
          cache_info->server_info,&region,length,(const unsigned char *) p);
6070
0
        if (count != (MagickOffsetType) length)
6071
0
          break;
6072
0
        p+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
6073
0
        region.y++;
6074
0
      }
6075
0
      UnlockSemaphoreInfo(cache_info->file_semaphore);
6076
0
      break;
6077
124k
    }
6078
1.51M
    default:
6079
1.51M
      break;
6080
11.8M
  }
6081
11.8M
  if (y < (ssize_t) rows)
6082
0
    {
6083
0
      ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
6084
0
        cache_info->cache_filename);
6085
0
      return(MagickFalse);
6086
0
    }
6087
11.8M
  if ((cache_info->debug != MagickFalse) &&
6088
0
      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
6089
0
    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
6090
0
      "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
6091
0
      nexus_info->region.width,(double) nexus_info->region.height,(double)
6092
0
      nexus_info->region.x,(double) nexus_info->region.y);
6093
11.8M
  return(MagickTrue);
6094
11.8M
}