Coverage Report

Created: 2026-11-12 07:35

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