MagickCore  6.9.13-19
Convert, Edit, Or Compose Bitmap Images
matrix.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % M M AAA TTTTT RRRR IIIII X X %
7 % MM MM A A T R R I X X %
8 % M M M AAAAA T RRRR I X %
9 % M M A A T R R I X X %
10 % M M A A T R R IIIII X X %
11 % %
12 % %
13 % MagickCore Matrix Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % August 2007 %
18 % %
19 % %
20 % Copyright 1999 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 ␌
39 /*
40  Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/blob-private.h"
45 #include "magick/exception.h"
46 #include "magick/exception-private.h"
47 #include "magick/image-private.h"
48 #include "magick/matrix.h"
49 #include "magick/memory_.h"
50 #include "magick/pixel-private.h"
51 #include "magick/resource_.h"
52 #include "magick/semaphore.h"
53 #include "magick/thread-private.h"
54 #include "magick/utility.h"
55 ␌
56 /*
57  Typedef declaration.
58 */
60 {
61  CacheType
62  type;
63 
64  size_t
65  columns,
66  rows,
67  stride;
68 
69  MagickSizeType
70  length;
71 
72  MagickBooleanType
73  mapped,
74  synchronize;
75 
76  char
77  path[MaxTextExtent];
78 
79  int
80  file;
81 
82  void
83  *elements;
84 
86  *semaphore;
87 
88  size_t
89  signature;
90 };
91 ␌
92 /*
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 % %
95 % %
96 % %
97 % A c q u i r e M a t r i x I n f o %
98 % %
99 % %
100 % %
101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102 %
103 % AcquireMatrixInfo() allocates the ImageInfo structure.
104 %
105 % The format of the AcquireMatrixInfo method is:
106 %
107 % MatrixInfo *AcquireMatrixInfo(const size_t columns,const size_t rows,
108 % const size_t stride,ExceptionInfo *exception)
109 %
110 % A description of each parameter follows:
111 %
112 % o columns: the matrix columns.
113 %
114 % o rows: the matrix rows.
115 %
116 % o stride: the matrix stride.
117 %
118 % o exception: return any errors or warnings in this structure.
119 %
120 */
121 
122 #if defined(SIGBUS)
123 static void MatrixSignalHandler(int magick_unused(status))
124 {
125  magick_unreferenced(status);
126  ThrowFatalException(CacheFatalError,"UnableToExtendMatrixCache");
127 }
128 #endif
129 
130 static inline MagickOffsetType WriteMatrixElements(
131  const MatrixInfo *magick_restrict matrix_info,const MagickOffsetType offset,
132  const MagickSizeType length,const unsigned char *magick_restrict buffer)
133 {
134  MagickOffsetType
135  i;
136 
137  ssize_t
138  count;
139 
140 #if !defined(MAGICKCORE_HAVE_PWRITE)
141  LockSemaphoreInfo(matrix_info->semaphore);
142  if (lseek(matrix_info->file,offset,SEEK_SET) < 0)
143  {
144  UnlockSemaphoreInfo(matrix_info->semaphore);
145  return((MagickOffsetType) -1);
146  }
147 #endif
148  count=0;
149  for (i=0; i < (MagickOffsetType) length; i+=count)
150  {
151 #if !defined(MAGICKCORE_HAVE_PWRITE)
152  count=write(matrix_info->file,buffer+i,(size_t) MagickMin(length-i,
153  (MagickSizeType) MagickMaxBufferExtent));
154 #else
155  count=pwrite(matrix_info->file,buffer+i,(size_t) MagickMin(length-i,
156  (MagickSizeType) MagickMaxBufferExtent),(off_t) (offset+i));
157 #endif
158  if (count <= 0)
159  {
160  count=0;
161  if (errno != EINTR)
162  break;
163  }
164  }
165 #if !defined(MAGICKCORE_HAVE_PWRITE)
166  UnlockSemaphoreInfo(matrix_info->semaphore);
167 #endif
168  return(i);
169 }
170 
171 static MagickBooleanType SetMatrixExtent(
172  MatrixInfo *magick_restrict matrix_info,MagickSizeType length)
173 {
174  MagickOffsetType
175  count,
176  extent,
177  offset;
178 
179  if (length != (MagickSizeType) ((MagickOffsetType) length))
180  return(MagickFalse);
181  offset=(MagickOffsetType) lseek(matrix_info->file,0,SEEK_END);
182  if (offset < 0)
183  return(MagickFalse);
184  if ((MagickSizeType) offset >= length)
185  return(MagickTrue);
186  extent=(MagickOffsetType) length-1;
187  count=WriteMatrixElements(matrix_info,extent,1,(const unsigned char *) "");
188 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
189  if (matrix_info->synchronize != MagickFalse)
190  (void) posix_fallocate(matrix_info->file,offset+1,extent-offset);
191 #endif
192 #if defined(SIGBUS)
193  (void) signal(SIGBUS,MatrixSignalHandler);
194 #endif
195  return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
196 }
197 
198 MagickExport MatrixInfo *AcquireMatrixInfo(const size_t columns,
199  const size_t rows,const size_t stride,ExceptionInfo *exception)
200 {
201  char
202  *synchronize;
203 
204  MagickBooleanType
205  status;
206 
207  MatrixInfo
208  *matrix_info;
209 
210  matrix_info=(MatrixInfo *) AcquireMagickMemory(sizeof(*matrix_info));
211  if (matrix_info == (MatrixInfo *) NULL)
212  return((MatrixInfo *) NULL);
213  (void) memset(matrix_info,0,sizeof(*matrix_info));
214  matrix_info->signature=MagickCoreSignature;
215  matrix_info->columns=columns;
216  matrix_info->rows=rows;
217  matrix_info->stride=stride;
218  matrix_info->semaphore=AllocateSemaphoreInfo();
219  synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
220  if (synchronize != (const char *) NULL)
221  {
222  matrix_info->synchronize=IsStringTrue(synchronize);
223  synchronize=DestroyString(synchronize);
224  }
225  matrix_info->length=(MagickSizeType) columns*rows*stride;
226  if (matrix_info->columns != (size_t) (matrix_info->length/rows/stride))
227  {
228  (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
229  "CacheResourcesExhausted","`%s'","matrix cache");
230  return(DestroyMatrixInfo(matrix_info));
231  }
232  matrix_info->type=MemoryCache;
233  status=AcquireMagickResource(AreaResource,matrix_info->length);
234  if ((status != MagickFalse) &&
235  (matrix_info->length == (MagickSizeType) ((size_t) matrix_info->length)))
236  {
237  status=AcquireMagickResource(MemoryResource,matrix_info->length);
238  if (status != MagickFalse)
239  {
240  matrix_info->mapped=MagickFalse;
241  matrix_info->elements=AcquireMagickMemory((size_t)
242  matrix_info->length);
243  if (matrix_info->elements == NULL)
244  {
245  matrix_info->mapped=MagickTrue;
246  matrix_info->elements=MapBlob(-1,IOMode,0,(size_t)
247  matrix_info->length);
248  }
249  if (matrix_info->elements == (unsigned short *) NULL)
250  RelinquishMagickResource(MemoryResource,matrix_info->length);
251  }
252  }
253  matrix_info->file=(-1);
254  if (matrix_info->elements == (unsigned short *) NULL)
255  {
256  status=AcquireMagickResource(DiskResource,matrix_info->length);
257  if (status == MagickFalse)
258  {
259  (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
260  "CacheResourcesExhausted","`%s'","matrix cache");
261  return(DestroyMatrixInfo(matrix_info));
262  }
263  matrix_info->type=DiskCache;
264  matrix_info->file=AcquireUniqueFileResource(matrix_info->path);
265  if (matrix_info->file == -1)
266  return(DestroyMatrixInfo(matrix_info));
267  status=AcquireMagickResource(MapResource,matrix_info->length);
268  if (status != MagickFalse)
269  {
270  status=SetMatrixExtent(matrix_info,matrix_info->length);
271  if (status != MagickFalse)
272  matrix_info->elements=(void *) MapBlob(matrix_info->file,IOMode,0,
273  (size_t) matrix_info->length);
274  if (matrix_info->elements != NULL)
275  matrix_info->type=MapCache;
276  else
277  RelinquishMagickResource(MapResource,matrix_info->length);
278  }
279  }
280  return(matrix_info);
281 }
282 ␌
283 /*
284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
285 % %
286 % %
287 % %
288 % A c q u i r e M a g i c k M a t r i x %
289 % %
290 % %
291 % %
292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
293 %
294 % AcquireMagickMatrix() allocates and returns a matrix in the form of an
295 % array of pointers to an array of doubles, with all values pre-set to zero.
296 %
297 % This used to generate the two dimensional matrix, and vectors required
298 % for the GaussJordanElimination() method below, solving some system of
299 % simultaneous equations.
300 %
301 % The format of the AcquireMagickMatrix method is:
302 %
303 % double **AcquireMagickMatrix(const size_t number_rows,
304 % const size_t size)
305 %
306 % A description of each parameter follows:
307 %
308 % o number_rows: the number pointers for the array of pointers
309 % (first dimension).
310 %
311 % o size: the size of the array of doubles each pointer points to
312 % (second dimension).
313 %
314 */
315 MagickExport double **AcquireMagickMatrix(const size_t number_rows,
316  const size_t size)
317 {
318  double
319  **matrix;
320 
321  ssize_t
322  i,
323  j;
324 
325  matrix=(double **) AcquireQuantumMemory(number_rows,sizeof(*matrix));
326  if (matrix == (double **) NULL)
327  return((double **) NULL);
328  for (i=0; i < (ssize_t) number_rows; i++)
329  {
330  matrix[i]=(double *) AcquireQuantumMemory(size,sizeof(*matrix[i]));
331  if (matrix[i] == (double *) NULL)
332  {
333  for (j=0; j < i; j++)
334  matrix[j]=(double *) RelinquishMagickMemory(matrix[j]);
335  matrix=(double **) RelinquishMagickMemory(matrix);
336  return((double **) NULL);
337  }
338  for (j=0; j < (ssize_t) size; j++)
339  matrix[i][j]=0.0;
340  }
341  return(matrix);
342 }
343 ␌
344 /*
345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 % %
347 % %
348 % %
349 % D e s t r o y M a t r i x I n f o %
350 % %
351 % %
352 % %
353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354 %
355 % DestroyMatrixInfo() dereferences a matrix, deallocating memory associated
356 % with the matrix.
357 %
358 % The format of the DestroyImage method is:
359 %
360 % MatrixInfo *DestroyMatrixInfo(MatrixInfo *matrix_info)
361 %
362 % A description of each parameter follows:
363 %
364 % o matrix_info: the matrix.
365 %
366 */
367 MagickExport MatrixInfo *DestroyMatrixInfo(MatrixInfo *matrix_info)
368 {
369  assert(matrix_info != (MatrixInfo *) NULL);
370  assert(matrix_info->signature == MagickCoreSignature);
371  LockSemaphoreInfo(matrix_info->semaphore);
372  switch (matrix_info->type)
373  {
374  case MemoryCache:
375  {
376  if (matrix_info->mapped == MagickFalse)
377  matrix_info->elements=RelinquishMagickMemory(matrix_info->elements);
378  else
379  {
380  (void) UnmapBlob(matrix_info->elements,(size_t) matrix_info->length);
381  matrix_info->elements=(unsigned short *) NULL;
382  }
383  RelinquishMagickResource(MemoryResource,matrix_info->length);
384  break;
385  }
386  case MapCache:
387  {
388  (void) UnmapBlob(matrix_info->elements,(size_t) matrix_info->length);
389  matrix_info->elements=NULL;
390  RelinquishMagickResource(MapResource,matrix_info->length);
391  magick_fallthrough;
392  }
393  case DiskCache:
394  {
395  if (matrix_info->file != -1)
396  (void) close(matrix_info->file);
397  (void) RelinquishUniqueFileResource(matrix_info->path);
398  RelinquishMagickResource(DiskResource,matrix_info->length);
399  break;
400  }
401  default:
402  break;
403  }
404  UnlockSemaphoreInfo(matrix_info->semaphore);
405  DestroySemaphoreInfo(&matrix_info->semaphore);
406  return((MatrixInfo *) RelinquishMagickMemory(matrix_info));
407 }
408 ␌
409 /*
410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 % %
412 % %
413 % %
414 % G a u s s J o r d a n E l i m i n a t i o n %
415 % %
416 % %
417 % %
418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419 %
420 % GaussJordanElimination() returns a matrix in reduced row echelon form,
421 % while simultaneously reducing and thus solving the augmented results
422 % matrix.
423 %
424 % See also http://en.wikipedia.org/wiki/Gauss-Jordan_elimination
425 %
426 % The format of the GaussJordanElimination method is:
427 %
428 % MagickBooleanType GaussJordanElimination(double **matrix,
429 % double **vectors,const size_t rank,const size_t number_vectors)
430 %
431 % A description of each parameter follows:
432 %
433 % o matrix: the matrix to be reduced, as an 'array of row pointers'.
434 %
435 % o vectors: the additional matrix argumenting the matrix for row reduction.
436 % Producing an 'array of column vectors'.
437 %
438 % o rank: The size of the matrix (both rows and columns). Also represents
439 % the number terms that need to be solved.
440 %
441 % o number_vectors: Number of vectors columns, argumenting the above matrix.
442 % Usually 1, but can be more for more complex equation solving.
443 %
444 % Note that the 'matrix' is given as a 'array of row pointers' of rank size.
445 % That is values can be assigned as matrix[row][column] where 'row' is
446 % typically the equation, and 'column' is the term of the equation.
447 % That is the matrix is in the form of a 'row first array'.
448 %
449 % However 'vectors' is a 'array of column pointers' which can have any number
450 % of columns, with each column array the same 'rank' size as 'matrix'.
451 %
452 % This allows for simpler handling of the results, especially is only one
453 % column 'vector' is all that is required to produce the desired solution.
454 %
455 % For example, the 'vectors' can consist of a pointer to a simple array of
456 % doubles. when only one set of simultaneous equations is to be solved from
457 % the given set of coefficient weighted terms.
458 %
459 % double **matrix = AcquireMagickMatrix(8UL,8UL);
460 % double coefficents[8];
461 % ...
462 % GaussJordanElimination(matrix, &coefficents, 8UL, 1UL);
463 %
464 % However by specifing more 'columns' (as an 'array of vector columns', you
465 % can use this function to solve a set of 'separable' equations.
466 %
467 % For example a distortion function where u = U(x,y) v = V(x,y)
468 % And the functions U() and V() have separate coefficents, but are being
469 % generated from a common x,y->u,v data set.
470 %
471 % Another example is generation of a color gradient from a set of colors at
472 % specific coordinates, such as a list x,y -> r,g,b,a.
473 %
474 % You can also use the 'vectors' to generate an inverse of the given 'matrix'
475 % though as a 'column first array' rather than a 'row first array'. For
476 % details see http://en.wikipedia.org/wiki/Gauss-Jordan_elimination
477 %
478 */
479 MagickExport MagickBooleanType GaussJordanElimination(double **matrix,
480  double **vectors,const size_t rank,const size_t number_vectors)
481 {
482 #define GaussJordanSwap(x,y) \
483 { \
484  if ((x) != (y)) \
485  { \
486  (x)+=(y); \
487  (y)=(x)-(y); \
488  (x)=(x)-(y); \
489  } \
490 }
491 
492  double
493  max,
494  scale;
495 
496  ssize_t
497  i,
498  j,
499  k;
500 
501  ssize_t
502  column,
503  *columns,
504  *pivots,
505  row,
506  *rows;
507 
508  columns=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*columns));
509  rows=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*rows));
510  pivots=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*pivots));
511  if ((rows == (ssize_t *) NULL) || (columns == (ssize_t *) NULL) ||
512  (pivots == (ssize_t *) NULL))
513  {
514  if (pivots != (ssize_t *) NULL)
515  pivots=(ssize_t *) RelinquishMagickMemory(pivots);
516  if (columns != (ssize_t *) NULL)
517  columns=(ssize_t *) RelinquishMagickMemory(columns);
518  if (rows != (ssize_t *) NULL)
519  rows=(ssize_t *) RelinquishMagickMemory(rows);
520  return(MagickFalse);
521  }
522  (void) memset(columns,0,rank*sizeof(*columns));
523  (void) memset(rows,0,rank*sizeof(*rows));
524  (void) memset(pivots,0,rank*sizeof(*pivots));
525  column=0;
526  row=0;
527  for (i=0; i < (ssize_t) rank; i++)
528  {
529  max=0.0;
530  for (j=0; j < (ssize_t) rank; j++)
531  if (pivots[j] != 1)
532  {
533  for (k=0; k < (ssize_t) rank; k++)
534  if (pivots[k] != 0)
535  {
536  if (pivots[k] > 1)
537  return(MagickFalse);
538  }
539  else
540  if (fabs(matrix[j][k]) >= max)
541  {
542  max=fabs(matrix[j][k]);
543  row=j;
544  column=k;
545  }
546  }
547  pivots[column]++;
548  if (row != column)
549  {
550  for (k=0; k < (ssize_t) rank; k++)
551  GaussJordanSwap(matrix[row][k],matrix[column][k]);
552  for (k=0; k < (ssize_t) number_vectors; k++)
553  GaussJordanSwap(vectors[k][row],vectors[k][column]);
554  }
555  rows[i]=row;
556  columns[i]=column;
557  if (matrix[column][column] == 0.0)
558  return(MagickFalse); /* singularity */
559  scale=PerceptibleReciprocal(matrix[column][column]);
560  matrix[column][column]=1.0;
561  for (j=0; j < (ssize_t) rank; j++)
562  matrix[column][j]*=scale;
563  for (j=0; j < (ssize_t) number_vectors; j++)
564  vectors[j][column]*=scale;
565  for (j=0; j < (ssize_t) rank; j++)
566  if (j != column)
567  {
568  scale=matrix[j][column];
569  matrix[j][column]=0.0;
570  for (k=0; k < (ssize_t) rank; k++)
571  matrix[j][k]-=scale*matrix[column][k];
572  for (k=0; k < (ssize_t) number_vectors; k++)
573  vectors[k][j]-=scale*vectors[k][column];
574  }
575  }
576  for (j=(ssize_t) rank-1; j >= 0; j--)
577  if (columns[j] != rows[j])
578  for (i=0; i < (ssize_t) rank; i++)
579  GaussJordanSwap(matrix[i][rows[j]],matrix[i][columns[j]]);
580  pivots=(ssize_t *) RelinquishMagickMemory(pivots);
581  rows=(ssize_t *) RelinquishMagickMemory(rows);
582  columns=(ssize_t *) RelinquishMagickMemory(columns);
583  return(MagickTrue);
584 }
585 ␌
586 /*
587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
588 % %
589 % %
590 % %
591 % G e t M a t r i x C o l u m n s %
592 % %
593 % %
594 % %
595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
596 %
597 % GetMatrixColumns() returns the number of columns in the matrix.
598 %
599 % The format of the GetMatrixColumns method is:
600 %
601 % size_t GetMatrixColumns(const MatrixInfo *matrix_info)
602 %
603 % A description of each parameter follows:
604 %
605 % o matrix_info: the matrix.
606 %
607 */
608 MagickExport size_t GetMatrixColumns(const MatrixInfo *matrix_info)
609 {
610  assert(matrix_info != (MatrixInfo *) NULL);
611  assert(matrix_info->signature == MagickCoreSignature);
612  return(matrix_info->columns);
613 }
614 ␌
615 /*
616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
617 % %
618 % %
619 % %
620 % G e t M a t r i x E l e m e n t %
621 % %
622 % %
623 % %
624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625 %
626 % GetMatrixElement() returns the specified element in the matrix.
627 %
628 % The format of the GetMatrixElement method is:
629 %
630 % MagickBooleanType GetMatrixElement(const MatrixInfo *matrix_info,
631 % const ssize_t x,const ssize_t y,void *value)
632 %
633 % A description of each parameter follows:
634 %
635 % o matrix_info: the matrix columns.
636 %
637 % o x: the matrix x-offset.
638 %
639 % o y: the matrix y-offset.
640 %
641 % o value: return the matrix element in this buffer.
642 %
643 */
644 
645 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
646 {
647  if (x < 0L)
648  return(0L);
649  if (x >= (ssize_t) columns)
650  return((ssize_t) (columns-1));
651  return(x);
652 }
653 
654 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
655 {
656  if (y < 0L)
657  return(0L);
658  if (y >= (ssize_t) rows)
659  return((ssize_t) (rows-1));
660  return(y);
661 }
662 
663 static inline MagickOffsetType ReadMatrixElements(
664  const MatrixInfo *magick_restrict matrix_info,const MagickOffsetType offset,
665  const MagickSizeType length,unsigned char *magick_restrict buffer)
666 {
667  MagickOffsetType
668  i;
669 
670  ssize_t
671  count;
672 
673 #if !defined(MAGICKCORE_HAVE_PREAD)
674  LockSemaphoreInfo(matrix_info->semaphore);
675  if (lseek(matrix_info->file,offset,SEEK_SET) < 0)
676  {
677  UnlockSemaphoreInfo(matrix_info->semaphore);
678  return((MagickOffsetType) -1);
679  }
680 #endif
681  count=0;
682  for (i=0; i < (MagickOffsetType) length; i+=count)
683  {
684 #if !defined(MAGICKCORE_HAVE_PREAD)
685  count=read(matrix_info->file,buffer+i,(size_t) MagickMin(length-i,
686  (MagickSizeType) MagickMaxBufferExtent));
687 #else
688  count=pread(matrix_info->file,buffer+i,(size_t) MagickMin(length-i,
689  (MagickSizeType) MagickMaxBufferExtent),(off_t) (offset+i));
690 #endif
691  if (count <= 0)
692  {
693  count=0;
694  if (errno != EINTR)
695  break;
696  }
697  }
698 #if !defined(MAGICKCORE_HAVE_PREAD)
699  UnlockSemaphoreInfo(matrix_info->semaphore);
700 #endif
701  return(i);
702 }
703 
704 MagickExport MagickBooleanType GetMatrixElement(const MatrixInfo *matrix_info,
705  const ssize_t x,const ssize_t y,void *value)
706 {
707  MagickOffsetType
708  count,
709  i;
710 
711  assert(matrix_info != (const MatrixInfo *) NULL);
712  assert(matrix_info->signature == MagickCoreSignature);
713  i=(MagickOffsetType) EdgeY(y,matrix_info->rows)*matrix_info->columns+
714  EdgeX(x,matrix_info->columns);
715  if (matrix_info->type != DiskCache)
716  {
717  (void) memcpy(value,(unsigned char *) matrix_info->elements+i*
718  matrix_info->stride,matrix_info->stride);
719  return(MagickTrue);
720  }
721  count=ReadMatrixElements(matrix_info,i*matrix_info->stride,
722  matrix_info->stride,(unsigned char *) value);
723  if (count != (MagickOffsetType) matrix_info->stride)
724  return(MagickFalse);
725  return(MagickTrue);
726 }
727 ␌
728 /*
729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
730 % %
731 % %
732 % %
733 % G e t M a t r i x R o w s %
734 % %
735 % %
736 % %
737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738 %
739 % GetMatrixRows() returns the number of rows in the matrix.
740 %
741 % The format of the GetMatrixRows method is:
742 %
743 % size_t GetMatrixRows(const MatrixInfo *matrix_info)
744 %
745 % A description of each parameter follows:
746 %
747 % o matrix_info: the matrix.
748 %
749 */
750 MagickExport size_t GetMatrixRows(const MatrixInfo *matrix_info)
751 {
752  assert(matrix_info != (const MatrixInfo *) NULL);
753  assert(matrix_info->signature == MagickCoreSignature);
754  return(matrix_info->rows);
755 }
756 ␌
757 /*
758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
759 % %
760 % %
761 % %
762 % L e a s t S q u a r e s A d d T e r m s %
763 % %
764 % %
765 % %
766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
767 %
768 % LeastSquaresAddTerms() adds one set of terms and associate results to the
769 % given matrix and vectors for solving using least-squares function fitting.
770 %
771 % The format of the AcquireMagickMatrix method is:
772 %
773 % void LeastSquaresAddTerms(double **matrix,double **vectors,
774 % const double *terms,const double *results,const size_t rank,
775 % const size_t number_vectors);
776 %
777 % A description of each parameter follows:
778 %
779 % o matrix: the square matrix to add given terms/results to.
780 %
781 % o vectors: the result vectors to add terms/results to.
782 %
783 % o terms: the pre-calculated terms (without the unknown coefficient
784 % weights) that forms the equation being added.
785 %
786 % o results: the result(s) that should be generated from the given terms
787 % weighted by the yet-to-be-solved coefficients.
788 %
789 % o rank: the rank or size of the dimensions of the square matrix.
790 % Also the length of vectors, and number of terms being added.
791 %
792 % o number_vectors: Number of result vectors, and number or results being
793 % added. Also represents the number of separable systems of equations
794 % that is being solved.
795 %
796 % Example of use...
797 %
798 % 2 dimensional Affine Equations (which are separable)
799 % c0*x + c2*y + c4*1 => u
800 % c1*x + c3*y + c5*1 => v
801 %
802 % double **matrix = AcquireMagickMatrix(3UL,3UL);
803 % double **vectors = AcquireMagickMatrix(2UL,3UL);
804 % double terms[3], results[2];
805 % ...
806 % for each given x,y -> u,v
807 % terms[0] = x;
808 % terms[1] = y;
809 % terms[2] = 1;
810 % results[0] = u;
811 % results[1] = v;
812 % LeastSquaresAddTerms(matrix,vectors,terms,results,3UL,2UL);
813 % ...
814 % if ( GaussJordanElimination(matrix,vectors,3UL,2UL) ) {
815 % c0 = vectors[0][0];
816 % c2 = vectors[0][1];
817 % c4 = vectors[0][2];
818 % c1 = vectors[1][0];
819 % c3 = vectors[1][1];
820 % c5 = vectors[1][2];
821 % }
822 % else
823 % printf("Matrix unsolvable\n);
824 % RelinquishMagickMatrix(matrix,3UL);
825 % RelinquishMagickMatrix(vectors,2UL);
826 %
827 */
828 MagickExport void LeastSquaresAddTerms(double **matrix,double **vectors,
829  const double *terms,const double *results,const size_t rank,
830  const size_t number_vectors)
831 {
832  ssize_t
833  i,
834  j;
835 
836  for (j=0; j < (ssize_t) rank; j++)
837  {
838  for (i=0; i < (ssize_t) rank; i++)
839  matrix[i][j]+=terms[i]*terms[j];
840  for (i=0; i < (ssize_t) number_vectors; i++)
841  vectors[i][j]+=results[i]*terms[j];
842  }
843 }
844 ␌
845 /*
846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
847 % %
848 % %
849 % %
850 % M a t r i x T o I m a g e %
851 % %
852 % %
853 % %
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
855 %
856 % MatrixToImage() returns a matrix as an image. The matrix elements must be
857 % of type double otherwise nonsense is returned.
858 %
859 % The format of the MatrixToImage method is:
860 %
861 % Image *MatrixToImage(const MatrixInfo *matrix_info,
862 % ExceptionInfo *exception)
863 %
864 % A description of each parameter follows:
865 %
866 % o matrix_info: the matrix.
867 %
868 % o exception: return any errors or warnings in this structure.
869 %
870 */
871 MagickExport Image *MatrixToImage(const MatrixInfo *matrix_info,
872  ExceptionInfo *exception)
873 {
874  CacheView
875  *image_view;
876 
877  double
878  max_value,
879  min_value,
880  scale_factor,
881  value;
882 
883  Image
884  *image;
885 
886  MagickBooleanType
887  status;
888 
889  ssize_t
890  y;
891 
892  assert(matrix_info != (const MatrixInfo *) NULL);
893  assert(matrix_info->signature == MagickCoreSignature);
894  assert(exception != (ExceptionInfo *) NULL);
895  assert(exception->signature == MagickCoreSignature);
896  if (matrix_info->stride < sizeof(double))
897  return((Image *) NULL);
898  /*
899  Determine range of matrix.
900  */
901  (void) GetMatrixElement(matrix_info,0,0,&value);
902  min_value=value;
903  max_value=value;
904  for (y=0; y < (ssize_t) matrix_info->rows; y++)
905  {
906  ssize_t
907  x;
908 
909  for (x=0; x < (ssize_t) matrix_info->columns; x++)
910  {
911  if (GetMatrixElement(matrix_info,x,y,&value) == MagickFalse)
912  continue;
913  if (value < min_value)
914  min_value=value;
915  else
916  if (value > max_value)
917  max_value=value;
918  }
919  }
920  if ((min_value == 0.0) && (max_value == 0.0))
921  scale_factor=0;
922  else
923  if (min_value == max_value)
924  {
925  scale_factor=(double) QuantumRange/min_value;
926  min_value=0;
927  }
928  else
929  scale_factor=(double) QuantumRange/(max_value-min_value);
930  /*
931  Convert matrix to image.
932  */
933  image=AcquireImage((ImageInfo *) NULL);
934  image->columns=matrix_info->columns;
935  image->rows=matrix_info->rows;
936  image->colorspace=GRAYColorspace;
937  status=MagickTrue;
938  image_view=AcquireAuthenticCacheView(image,exception);
939 #if defined(MAGICKCORE_OPENMP_SUPPORT)
940  #pragma omp parallel for schedule(static) shared(status) \
941  magick_number_threads(image,image,image->rows,2)
942 #endif
943  for (y=0; y < (ssize_t) image->rows; y++)
944  {
945  double
946  value;
947 
949  *q;
950 
951  ssize_t
952  x;
953 
954  if (status == MagickFalse)
955  continue;
956  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
957  if (q == (PixelPacket *) NULL)
958  {
959  status=MagickFalse;
960  continue;
961  }
962  for (x=0; x < (ssize_t) image->columns; x++)
963  {
964  if (GetMatrixElement(matrix_info,x,y,&value) == MagickFalse)
965  continue;
966  value=scale_factor*(value-min_value);
967  q->red=ClampToQuantum(value);
968  q->green=q->red;
969  q->blue=q->red;
970  q++;
971  }
972  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
973  status=MagickFalse;
974  }
975  image_view=DestroyCacheView(image_view);
976  if (status == MagickFalse)
977  image=DestroyImage(image);
978  return(image);
979 }
980 ␌
981 /*
982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
983 % %
984 % %
985 % %
986 % N u l l M a t r i x %
987 % %
988 % %
989 % %
990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
991 %
992 % NullMatrix() sets all elements of the matrix to zero.
993 %
994 % The format of the memset method is:
995 %
996 % MagickBooleanType *NullMatrix(MatrixInfo *matrix_info)
997 %
998 % A description of each parameter follows:
999 %
1000 % o matrix_info: the matrix.
1001 %
1002 */
1003 MagickExport MagickBooleanType NullMatrix(MatrixInfo *matrix_info)
1004 {
1005  ssize_t
1006  x;
1007 
1008  ssize_t
1009  count,
1010  y;
1011 
1012  unsigned char
1013  value;
1014 
1015  assert(matrix_info != (const MatrixInfo *) NULL);
1016  assert(matrix_info->signature == MagickCoreSignature);
1017  if (matrix_info->type != DiskCache)
1018  {
1019  (void) memset(matrix_info->elements,0,(size_t)
1020  matrix_info->length);
1021  return(MagickTrue);
1022  }
1023  value=0;
1024  (void) lseek(matrix_info->file,0,SEEK_SET);
1025  for (y=0; y < (ssize_t) matrix_info->rows; y++)
1026  {
1027  for (x=0; x < (ssize_t) matrix_info->length; x++)
1028  {
1029  count=write(matrix_info->file,&value,sizeof(value));
1030  if (count != (ssize_t) sizeof(value))
1031  break;
1032  }
1033  if (x < (ssize_t) matrix_info->length)
1034  break;
1035  }
1036  return(y < (ssize_t) matrix_info->rows ? MagickFalse : MagickTrue);
1037 }
1038 ␌
1039 /*
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 % %
1042 % %
1043 % %
1044 % R e l i n q u i s h M a g i c k M a t r i x %
1045 % %
1046 % %
1047 % %
1048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049 %
1050 % RelinquishMagickMatrix() frees the previously acquired matrix (array of
1051 % pointers to arrays of doubles).
1052 %
1053 % The format of the RelinquishMagickMatrix method is:
1054 %
1055 % double **RelinquishMagickMatrix(double **matrix,
1056 % const size_t number_rows)
1057 %
1058 % A description of each parameter follows:
1059 %
1060 % o matrix: the matrix to relinquish
1061 %
1062 % o number_rows: the first dimension of the acquired matrix (number of
1063 % pointers)
1064 %
1065 */
1066 MagickExport double **RelinquishMagickMatrix(double **matrix,
1067  const size_t number_rows)
1068 {
1069  ssize_t
1070  i;
1071 
1072  if (matrix == (double **) NULL )
1073  return(matrix);
1074  for (i=0; i < (ssize_t) number_rows; i++)
1075  matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
1076  matrix=(double **) RelinquishMagickMemory(matrix);
1077  return(matrix);
1078 }
1079 ␌
1080 /*
1081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1082 % %
1083 % %
1084 % %
1085 % S e t M a t r i x E l e m e n t %
1086 % %
1087 % %
1088 % %
1089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090 %
1091 % SetMatrixElement() sets the specified element in the matrix.
1092 %
1093 % The format of the SetMatrixElement method is:
1094 %
1095 % MagickBooleanType SetMatrixElement(const MatrixInfo *matrix_info,
1096 % const ssize_t x,const ssize_t y,void *value)
1097 %
1098 % A description of each parameter follows:
1099 %
1100 % o matrix_info: the matrix columns.
1101 %
1102 % o x: the matrix x-offset.
1103 %
1104 % o y: the matrix y-offset.
1105 %
1106 % o value: set the matrix element to this value.
1107 %
1108 */
1109 
1110 MagickExport MagickBooleanType SetMatrixElement(const MatrixInfo *matrix_info,
1111  const ssize_t x,const ssize_t y,const void *value)
1112 {
1113  MagickOffsetType
1114  count,
1115  i;
1116 
1117  assert(matrix_info != (const MatrixInfo *) NULL);
1118  assert(matrix_info->signature == MagickCoreSignature);
1119  i=(MagickOffsetType) y*matrix_info->columns+x;
1120  if ((i < 0) ||
1121  ((MagickSizeType) (i*matrix_info->stride) >= matrix_info->length))
1122  return(MagickFalse);
1123  if (matrix_info->type != DiskCache)
1124  {
1125  (void) memcpy((unsigned char *) matrix_info->elements+i*
1126  matrix_info->stride,value,matrix_info->stride);
1127  return(MagickTrue);
1128  }
1129  count=WriteMatrixElements(matrix_info,i*matrix_info->stride,
1130  matrix_info->stride,(unsigned char *) value);
1131  if (count != (MagickOffsetType) matrix_info->stride)
1132  return(MagickFalse);
1133  return(MagickTrue);
1134 }
Definition: image.h:134