Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/dds.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            DDDD   DDDD   SSSSS                              %
7
%                            D   D  D   D  SS                                 %
8
%                            D   D  D   D   SSS                               %
9
%                            D   D  D   D     SS                              %
10
%                            DDDD   DDDD   SSSSS                              %
11
%                                                                             %
12
%                                                                             %
13
%           Read/Write Microsoft Direct Draw Surface Image Format             %
14
%                                                                             %
15
%                              Software Design                                %
16
%                             Bianca van Schaik                               %
17
%                                March 2008                                   %
18
%                               Dirk Lemstra                                  %
19
%                              September 2013                                 %
20
%                                                                             %
21
%                                                                             %
22
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
23
%  dedicated to making software imaging solutions freely available.           %
24
%                                                                             %
25
%  You may not use this file except in compliance with the License.  You may  %
26
%  obtain a copy of the License at                                            %
27
%                                                                             %
28
%    https://imagemagick.org/license/                                         %
29
%                                                                             %
30
%  Unless required by applicable law or agreed to in writing, software        %
31
%  distributed under the License is distributed on an "AS IS" BASIS,          %
32
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
33
%  See the License for the specific language governing permissions and        %
34
%  limitations under the License.                                             %
35
%                                                                             %
36
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37
%
38
%
39
*/
40

41
/*
42
  Include declarations.
43
*/
44
#include "MagickCore/studio.h"
45
#include "MagickCore/attribute.h"
46
#include "MagickCore/blob.h"
47
#include "MagickCore/blob-private.h"
48
#include "MagickCore/cache.h"
49
#include "MagickCore/colorspace.h"
50
#include "MagickCore/colorspace-private.h"
51
#include "MagickCore/exception.h"
52
#include "MagickCore/exception-private.h"
53
#include "MagickCore/image.h"
54
#include "MagickCore/image-private.h"
55
#include "MagickCore/list.h"
56
#include "MagickCore/log.h"
57
#include "MagickCore/magick.h"
58
#include "MagickCore/memory_.h"
59
#include "MagickCore/monitor.h"
60
#include "MagickCore/monitor-private.h"
61
#include "MagickCore/option.h"
62
#include "MagickCore/pixel-accessor.h"
63
#include "MagickCore/profile.h"
64
#include "MagickCore/quantum.h"
65
#include "MagickCore/quantum-private.h"
66
#include "MagickCore/resource_.h"
67
#include "MagickCore/static.h"
68
#include "MagickCore/string_.h"
69
#include "MagickCore/string-private.h"
70
#include "MagickCore/module.h"
71
#include "MagickCore/transform.h"
72

73
/*
74
  Definitions
75
*/
76
11.8k
#define DDSD_CAPS         0x00000001
77
11.8k
#define DDSD_HEIGHT       0x00000002
78
11.8k
#define DDSD_WIDTH        0x00000004
79
0
#define DDSD_PITCH        0x00000008
80
11.8k
#define DDSD_PIXELFORMAT  0x00001000
81
1.12k
#define DDSD_MIPMAPCOUNT  0x00020000
82
2.58k
#define DDSD_LINEARSIZE   0x00080000
83
#define DDSD_DEPTH        0x00800000
84
85
4.77k
#define DDPF_ALPHAPIXELS  0x00000001
86
5.63k
#define DDPF_ALPHA        0x00000002
87
37.3k
#define DDPF_FOURCC       0x00000004
88
9.09k
#define DDPF_RGB          0x00000040
89
4.94k
#define DDPF_LUMINANCE    0x00020000
90
91
327
#define FOURCC_ATI2       0x32495441
92
348
#define FOURCC_BC5U       0x55354342
93
5.21k
#define FOURCC_DXT1       0x31545844
94
195
#define FOURCC_DXT3       0x33545844
95
1.92M
#define FOURCC_DXT5       0x35545844
96
8.09k
#define FOURCC_DX10       0x30315844
97
98
1.12k
#define DDSCAPS_COMPLEX   0x00000008
99
10.5k
#define DDSCAPS_TEXTURE   0x00001000
100
16.6k
#define DDSCAPS_MIPMAP    0x00400000
101
102
11.0k
#define DDSCAPS2_CUBEMAP  0x00000200
103
2.41k
#define DDSCAPS2_CUBEMAP_POSITIVEX  0x00000400
104
2.41k
#define DDSCAPS2_CUBEMAP_NEGATIVEX  0x00000800
105
2.41k
#define DDSCAPS2_CUBEMAP_POSITIVEY  0x00001000
106
2.41k
#define DDSCAPS2_CUBEMAP_NEGATIVEY  0x00002000
107
2.41k
#define DDSCAPS2_CUBEMAP_POSITIVEZ  0x00004000
108
2.41k
#define DDSCAPS2_CUBEMAP_NEGATIVEZ  0x00008000
109
18.1k
#define DDSCAPS2_VOLUME   0x00200000
110
111
736
#define DDSEXT_DIMENSION_TEX2D      0x00000003
112
637
#define DDSEXTFLAGS_CUBEMAP         0x00000004
113
114
typedef enum DXGI_FORMAT 
115
{
116
  DXGI_FORMAT_UNKNOWN,
117
  DXGI_FORMAT_R32G32B32A32_TYPELESS,
118
  DXGI_FORMAT_R32G32B32A32_FLOAT,
119
  DXGI_FORMAT_R32G32B32A32_UINT,
120
  DXGI_FORMAT_R32G32B32A32_SINT,
121
  DXGI_FORMAT_R32G32B32_TYPELESS,
122
  DXGI_FORMAT_R32G32B32_FLOAT,
123
  DXGI_FORMAT_R32G32B32_UINT,
124
  DXGI_FORMAT_R32G32B32_SINT,
125
  DXGI_FORMAT_R16G16B16A16_TYPELESS,
126
  DXGI_FORMAT_R16G16B16A16_FLOAT,
127
  DXGI_FORMAT_R16G16B16A16_UNORM,
128
  DXGI_FORMAT_R16G16B16A16_UINT,
129
  DXGI_FORMAT_R16G16B16A16_SNORM,
130
  DXGI_FORMAT_R16G16B16A16_SINT,
131
  DXGI_FORMAT_R32G32_TYPELESS,
132
  DXGI_FORMAT_R32G32_FLOAT,
133
  DXGI_FORMAT_R32G32_UINT,
134
  DXGI_FORMAT_R32G32_SINT,
135
  DXGI_FORMAT_R32G8X24_TYPELESS,
136
  DXGI_FORMAT_D32_FLOAT_S8X24_UINT,
137
  DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS,
138
  DXGI_FORMAT_X32_TYPELESS_G8X24_UINT,
139
  DXGI_FORMAT_R10G10B10A2_TYPELESS,
140
  DXGI_FORMAT_R10G10B10A2_UNORM,
141
  DXGI_FORMAT_R10G10B10A2_UINT,
142
  DXGI_FORMAT_R11G11B10_FLOAT,
143
  DXGI_FORMAT_R8G8B8A8_TYPELESS,
144
  DXGI_FORMAT_R8G8B8A8_UNORM,
145
  DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
146
  DXGI_FORMAT_R8G8B8A8_UINT,
147
  DXGI_FORMAT_R8G8B8A8_SNORM,
148
  DXGI_FORMAT_R8G8B8A8_SINT,
149
  DXGI_FORMAT_R16G16_TYPELESS,
150
  DXGI_FORMAT_R16G16_FLOAT,
151
  DXGI_FORMAT_R16G16_UNORM,
152
  DXGI_FORMAT_R16G16_UINT,
153
  DXGI_FORMAT_R16G16_SNORM,
154
  DXGI_FORMAT_R16G16_SINT,
155
  DXGI_FORMAT_R32_TYPELESS,
156
  DXGI_FORMAT_D32_FLOAT,
157
  DXGI_FORMAT_R32_FLOAT,
158
  DXGI_FORMAT_R32_UINT,
159
  DXGI_FORMAT_R32_SINT,
160
  DXGI_FORMAT_R24G8_TYPELESS,
161
  DXGI_FORMAT_D24_UNORM_S8_UINT,
162
  DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
163
  DXGI_FORMAT_X24_TYPELESS_G8_UINT,
164
  DXGI_FORMAT_R8G8_TYPELESS,
165
  DXGI_FORMAT_R8G8_UNORM,
166
  DXGI_FORMAT_R8G8_UINT,
167
  DXGI_FORMAT_R8G8_SNORM,
168
  DXGI_FORMAT_R8G8_SINT,
169
  DXGI_FORMAT_R16_TYPELESS,
170
  DXGI_FORMAT_R16_FLOAT,
171
  DXGI_FORMAT_D16_UNORM,
172
  DXGI_FORMAT_R16_UNORM,
173
  DXGI_FORMAT_R16_UINT,
174
  DXGI_FORMAT_R16_SNORM,
175
  DXGI_FORMAT_R16_SINT,
176
  DXGI_FORMAT_R8_TYPELESS,
177
  DXGI_FORMAT_R8_UNORM,
178
  DXGI_FORMAT_R8_UINT,
179
  DXGI_FORMAT_R8_SNORM,
180
  DXGI_FORMAT_R8_SINT,
181
  DXGI_FORMAT_A8_UNORM,
182
  DXGI_FORMAT_R1_UNORM,
183
  DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
184
  DXGI_FORMAT_R8G8_B8G8_UNORM,
185
  DXGI_FORMAT_G8R8_G8B8_UNORM,
186
  DXGI_FORMAT_BC1_TYPELESS,
187
  DXGI_FORMAT_BC1_UNORM,
188
  DXGI_FORMAT_BC1_UNORM_SRGB,
189
  DXGI_FORMAT_BC2_TYPELESS,
190
  DXGI_FORMAT_BC2_UNORM,
191
  DXGI_FORMAT_BC2_UNORM_SRGB,
192
  DXGI_FORMAT_BC3_TYPELESS,
193
  DXGI_FORMAT_BC3_UNORM,
194
  DXGI_FORMAT_BC3_UNORM_SRGB,
195
  DXGI_FORMAT_BC4_TYPELESS,
196
  DXGI_FORMAT_BC4_UNORM,
197
  DXGI_FORMAT_BC4_SNORM,
198
  DXGI_FORMAT_BC5_TYPELESS,
199
  DXGI_FORMAT_BC5_UNORM,
200
  DXGI_FORMAT_BC5_SNORM,
201
  DXGI_FORMAT_B5G6R5_UNORM,
202
  DXGI_FORMAT_B5G5R5A1_UNORM,
203
  DXGI_FORMAT_B8G8R8A8_UNORM,
204
  DXGI_FORMAT_B8G8R8X8_UNORM,
205
  DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM,
206
  DXGI_FORMAT_B8G8R8A8_TYPELESS,
207
  DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
208
  DXGI_FORMAT_B8G8R8X8_TYPELESS,
209
  DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,
210
  DXGI_FORMAT_BC6H_TYPELESS,
211
  DXGI_FORMAT_BC6H_UF16,
212
  DXGI_FORMAT_BC6H_SF16,
213
  DXGI_FORMAT_BC7_TYPELESS,
214
  DXGI_FORMAT_BC7_UNORM,
215
  DXGI_FORMAT_BC7_UNORM_SRGB,
216
  DXGI_FORMAT_AYUV,
217
  DXGI_FORMAT_Y410,
218
  DXGI_FORMAT_Y416,
219
  DXGI_FORMAT_NV12,
220
  DXGI_FORMAT_P010,
221
  DXGI_FORMAT_P016,
222
  DXGI_FORMAT_420_OPAQUE,
223
  DXGI_FORMAT_YUY2,
224
  DXGI_FORMAT_Y210,
225
  DXGI_FORMAT_Y216,
226
  DXGI_FORMAT_NV11,
227
  DXGI_FORMAT_AI44,
228
  DXGI_FORMAT_IA44,
229
  DXGI_FORMAT_P8,
230
  DXGI_FORMAT_A8P8,
231
  DXGI_FORMAT_B4G4R4A4_UNORM,
232
  DXGI_FORMAT_P208,
233
  DXGI_FORMAT_V208,
234
  DXGI_FORMAT_V408,
235
  DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE,
236
  DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE,
237
  DXGI_FORMAT_FORCE_UINT
238
} DXGI_FORMAT;
239
240
241
#ifndef SIZE_MAX
242
#define SIZE_MAX ((size_t) -1)
243
#endif
244
245
/*
246
  Structure declarations.
247
*/
248
typedef struct _DDSPixelFormat
249
{
250
  size_t
251
    flags,
252
    fourcc,
253
    rgb_bitcount,
254
    r_bitmask,
255
    g_bitmask,
256
    b_bitmask,
257
    alpha_bitmask;
258
} DDSPixelFormat;
259
260
typedef struct _DDSInfo
261
{
262
  size_t
263
    flags,
264
    height,
265
    width,
266
    pitchOrLinearSize,
267
    depth,
268
    mipmapcount,
269
    ddscaps1,
270
    ddscaps2,
271
    extFormat,
272
    extDimension,
273
    extFlags,
274
    extArraySize,
275
    extFlags2;
276
  
277
  DDSPixelFormat
278
    pixelformat;
279
} DDSInfo;
280
281
typedef struct _DDSColors
282
{
283
  unsigned char
284
    r[4],
285
    g[4],
286
    b[4],
287
    a[4];
288
} DDSColors;
289
290
typedef struct _BC5Colors
291
{
292
  unsigned char
293
    r[8],
294
    g[8];
295
} BC5Colors;
296
297
typedef struct _BC7Colors
298
{
299
  unsigned char
300
    r[6],
301
    g[6],
302
    b[6],
303
    a[6];
304
} BC7Colors;
305
306
typedef struct _DDSVector4
307
{
308
  float
309
    x,
310
    y,
311
    z,
312
    w;
313
} DDSVector4;
314
315
typedef struct _DDSVector3
316
{
317
  float
318
    x,
319
    y,
320
    z;
321
} DDSVector3;
322
323
typedef struct _DDSSourceBlock
324
{
325
  unsigned char
326
    start,
327
    end,
328
    error;
329
} DDSSourceBlock;
330
331
typedef struct _DDSSingleColorLookup
332
{
333
  DDSSourceBlock sources[2];
334
} DDSSingleColorLookup;
335
336
typedef struct _BC7ModeInfo
337
{
338
  unsigned char
339
    partition_bits,
340
    num_subsets,
341
    color_precision,
342
    alpha_precision,
343
    num_pbits,
344
    index_precision,
345
    index2_precision;
346
} BC7ModeInfo;
347
348
typedef MagickBooleanType
349
  DDSDecoder(const ImageInfo *,Image *,const DDSInfo *,const MagickBooleanType,
350
    ExceptionInfo *);
351
352
typedef MagickBooleanType
353
  DDSPixelDecoder(Image *,const DDSInfo *,ExceptionInfo *);
354
355
static const DDSSingleColorLookup DDSLookup_5_4[] =
356
{
357
  { { { 0, 0, 0 }, { 0, 0, 0 } } },
358
  { { { 0, 0, 1 }, { 0, 1, 1 } } },
359
  { { { 0, 0, 2 }, { 0, 1, 0 } } },
360
  { { { 0, 0, 3 }, { 0, 1, 1 } } },
361
  { { { 0, 0, 4 }, { 0, 2, 1 } } },
362
  { { { 1, 0, 3 }, { 0, 2, 0 } } },
363
  { { { 1, 0, 2 }, { 0, 2, 1 } } },
364
  { { { 1, 0, 1 }, { 0, 3, 1 } } },
365
  { { { 1, 0, 0 }, { 0, 3, 0 } } },
366
  { { { 1, 0, 1 }, { 1, 2, 1 } } },
367
  { { { 1, 0, 2 }, { 1, 2, 0 } } },
368
  { { { 1, 0, 3 }, { 0, 4, 0 } } },
369
  { { { 1, 0, 4 }, { 0, 5, 1 } } },
370
  { { { 2, 0, 3 }, { 0, 5, 0 } } },
371
  { { { 2, 0, 2 }, { 0, 5, 1 } } },
372
  { { { 2, 0, 1 }, { 0, 6, 1 } } },
373
  { { { 2, 0, 0 }, { 0, 6, 0 } } },
374
  { { { 2, 0, 1 }, { 2, 3, 1 } } },
375
  { { { 2, 0, 2 }, { 2, 3, 0 } } },
376
  { { { 2, 0, 3 }, { 0, 7, 0 } } },
377
  { { { 2, 0, 4 }, { 1, 6, 1 } } },
378
  { { { 3, 0, 3 }, { 1, 6, 0 } } },
379
  { { { 3, 0, 2 }, { 0, 8, 0 } } },
380
  { { { 3, 0, 1 }, { 0, 9, 1 } } },
381
  { { { 3, 0, 0 }, { 0, 9, 0 } } },
382
  { { { 3, 0, 1 }, { 0, 9, 1 } } },
383
  { { { 3, 0, 2 }, { 0, 10, 1 } } },
384
  { { { 3, 0, 3 }, { 0, 10, 0 } } },
385
  { { { 3, 0, 4 }, { 2, 7, 1 } } },
386
  { { { 4, 0, 4 }, { 2, 7, 0 } } },
387
  { { { 4, 0, 3 }, { 0, 11, 0 } } },
388
  { { { 4, 0, 2 }, { 1, 10, 1 } } },
389
  { { { 4, 0, 1 }, { 1, 10, 0 } } },
390
  { { { 4, 0, 0 }, { 0, 12, 0 } } },
391
  { { { 4, 0, 1 }, { 0, 13, 1 } } },
392
  { { { 4, 0, 2 }, { 0, 13, 0 } } },
393
  { { { 4, 0, 3 }, { 0, 13, 1 } } },
394
  { { { 4, 0, 4 }, { 0, 14, 1 } } },
395
  { { { 5, 0, 3 }, { 0, 14, 0 } } },
396
  { { { 5, 0, 2 }, { 2, 11, 1 } } },
397
  { { { 5, 0, 1 }, { 2, 11, 0 } } },
398
  { { { 5, 0, 0 }, { 0, 15, 0 } } },
399
  { { { 5, 0, 1 }, { 1, 14, 1 } } },
400
  { { { 5, 0, 2 }, { 1, 14, 0 } } },
401
  { { { 5, 0, 3 }, { 0, 16, 0 } } },
402
  { { { 5, 0, 4 }, { 0, 17, 1 } } },
403
  { { { 6, 0, 3 }, { 0, 17, 0 } } },
404
  { { { 6, 0, 2 }, { 0, 17, 1 } } },
405
  { { { 6, 0, 1 }, { 0, 18, 1 } } },
406
  { { { 6, 0, 0 }, { 0, 18, 0 } } },
407
  { { { 6, 0, 1 }, { 2, 15, 1 } } },
408
  { { { 6, 0, 2 }, { 2, 15, 0 } } },
409
  { { { 6, 0, 3 }, { 0, 19, 0 } } },
410
  { { { 6, 0, 4 }, { 1, 18, 1 } } },
411
  { { { 7, 0, 3 }, { 1, 18, 0 } } },
412
  { { { 7, 0, 2 }, { 0, 20, 0 } } },
413
  { { { 7, 0, 1 }, { 0, 21, 1 } } },
414
  { { { 7, 0, 0 }, { 0, 21, 0 } } },
415
  { { { 7, 0, 1 }, { 0, 21, 1 } } },
416
  { { { 7, 0, 2 }, { 0, 22, 1 } } },
417
  { { { 7, 0, 3 }, { 0, 22, 0 } } },
418
  { { { 7, 0, 4 }, { 2, 19, 1 } } },
419
  { { { 8, 0, 4 }, { 2, 19, 0 } } },
420
  { { { 8, 0, 3 }, { 0, 23, 0 } } },
421
  { { { 8, 0, 2 }, { 1, 22, 1 } } },
422
  { { { 8, 0, 1 }, { 1, 22, 0 } } },
423
  { { { 8, 0, 0 }, { 0, 24, 0 } } },
424
  { { { 8, 0, 1 }, { 0, 25, 1 } } },
425
  { { { 8, 0, 2 }, { 0, 25, 0 } } },
426
  { { { 8, 0, 3 }, { 0, 25, 1 } } },
427
  { { { 8, 0, 4 }, { 0, 26, 1 } } },
428
  { { { 9, 0, 3 }, { 0, 26, 0 } } },
429
  { { { 9, 0, 2 }, { 2, 23, 1 } } },
430
  { { { 9, 0, 1 }, { 2, 23, 0 } } },
431
  { { { 9, 0, 0 }, { 0, 27, 0 } } },
432
  { { { 9, 0, 1 }, { 1, 26, 1 } } },
433
  { { { 9, 0, 2 }, { 1, 26, 0 } } },
434
  { { { 9, 0, 3 }, { 0, 28, 0 } } },
435
  { { { 9, 0, 4 }, { 0, 29, 1 } } },
436
  { { { 10, 0, 3 }, { 0, 29, 0 } } },
437
  { { { 10, 0, 2 }, { 0, 29, 1 } } },
438
  { { { 10, 0, 1 }, { 0, 30, 1 } } },
439
  { { { 10, 0, 0 }, { 0, 30, 0 } } },
440
  { { { 10, 0, 1 }, { 2, 27, 1 } } },
441
  { { { 10, 0, 2 }, { 2, 27, 0 } } },
442
  { { { 10, 0, 3 }, { 0, 31, 0 } } },
443
  { { { 10, 0, 4 }, { 1, 30, 1 } } },
444
  { { { 11, 0, 3 }, { 1, 30, 0 } } },
445
  { { { 11, 0, 2 }, { 4, 24, 0 } } },
446
  { { { 11, 0, 1 }, { 1, 31, 1 } } },
447
  { { { 11, 0, 0 }, { 1, 31, 0 } } },
448
  { { { 11, 0, 1 }, { 1, 31, 1 } } },
449
  { { { 11, 0, 2 }, { 2, 30, 1 } } },
450
  { { { 11, 0, 3 }, { 2, 30, 0 } } },
451
  { { { 11, 0, 4 }, { 2, 31, 1 } } },
452
  { { { 12, 0, 4 }, { 2, 31, 0 } } },
453
  { { { 12, 0, 3 }, { 4, 27, 0 } } },
454
  { { { 12, 0, 2 }, { 3, 30, 1 } } },
455
  { { { 12, 0, 1 }, { 3, 30, 0 } } },
456
  { { { 12, 0, 0 }, { 4, 28, 0 } } },
457
  { { { 12, 0, 1 }, { 3, 31, 1 } } },
458
  { { { 12, 0, 2 }, { 3, 31, 0 } } },
459
  { { { 12, 0, 3 }, { 3, 31, 1 } } },
460
  { { { 12, 0, 4 }, { 4, 30, 1 } } },
461
  { { { 13, 0, 3 }, { 4, 30, 0 } } },
462
  { { { 13, 0, 2 }, { 6, 27, 1 } } },
463
  { { { 13, 0, 1 }, { 6, 27, 0 } } },
464
  { { { 13, 0, 0 }, { 4, 31, 0 } } },
465
  { { { 13, 0, 1 }, { 5, 30, 1 } } },
466
  { { { 13, 0, 2 }, { 5, 30, 0 } } },
467
  { { { 13, 0, 3 }, { 8, 24, 0 } } },
468
  { { { 13, 0, 4 }, { 5, 31, 1 } } },
469
  { { { 14, 0, 3 }, { 5, 31, 0 } } },
470
  { { { 14, 0, 2 }, { 5, 31, 1 } } },
471
  { { { 14, 0, 1 }, { 6, 30, 1 } } },
472
  { { { 14, 0, 0 }, { 6, 30, 0 } } },
473
  { { { 14, 0, 1 }, { 6, 31, 1 } } },
474
  { { { 14, 0, 2 }, { 6, 31, 0 } } },
475
  { { { 14, 0, 3 }, { 8, 27, 0 } } },
476
  { { { 14, 0, 4 }, { 7, 30, 1 } } },
477
  { { { 15, 0, 3 }, { 7, 30, 0 } } },
478
  { { { 15, 0, 2 }, { 8, 28, 0 } } },
479
  { { { 15, 0, 1 }, { 7, 31, 1 } } },
480
  { { { 15, 0, 0 }, { 7, 31, 0 } } },
481
  { { { 15, 0, 1 }, { 7, 31, 1 } } },
482
  { { { 15, 0, 2 }, { 8, 30, 1 } } },
483
  { { { 15, 0, 3 }, { 8, 30, 0 } } },
484
  { { { 15, 0, 4 }, { 10, 27, 1 } } },
485
  { { { 16, 0, 4 }, { 10, 27, 0 } } },
486
  { { { 16, 0, 3 }, { 8, 31, 0 } } },
487
  { { { 16, 0, 2 }, { 9, 30, 1 } } },
488
  { { { 16, 0, 1 }, { 9, 30, 0 } } },
489
  { { { 16, 0, 0 }, { 12, 24, 0 } } },
490
  { { { 16, 0, 1 }, { 9, 31, 1 } } },
491
  { { { 16, 0, 2 }, { 9, 31, 0 } } },
492
  { { { 16, 0, 3 }, { 9, 31, 1 } } },
493
  { { { 16, 0, 4 }, { 10, 30, 1 } } },
494
  { { { 17, 0, 3 }, { 10, 30, 0 } } },
495
  { { { 17, 0, 2 }, { 10, 31, 1 } } },
496
  { { { 17, 0, 1 }, { 10, 31, 0 } } },
497
  { { { 17, 0, 0 }, { 12, 27, 0 } } },
498
  { { { 17, 0, 1 }, { 11, 30, 1 } } },
499
  { { { 17, 0, 2 }, { 11, 30, 0 } } },
500
  { { { 17, 0, 3 }, { 12, 28, 0 } } },
501
  { { { 17, 0, 4 }, { 11, 31, 1 } } },
502
  { { { 18, 0, 3 }, { 11, 31, 0 } } },
503
  { { { 18, 0, 2 }, { 11, 31, 1 } } },
504
  { { { 18, 0, 1 }, { 12, 30, 1 } } },
505
  { { { 18, 0, 0 }, { 12, 30, 0 } } },
506
  { { { 18, 0, 1 }, { 14, 27, 1 } } },
507
  { { { 18, 0, 2 }, { 14, 27, 0 } } },
508
  { { { 18, 0, 3 }, { 12, 31, 0 } } },
509
  { { { 18, 0, 4 }, { 13, 30, 1 } } },
510
  { { { 19, 0, 3 }, { 13, 30, 0 } } },
511
  { { { 19, 0, 2 }, { 16, 24, 0 } } },
512
  { { { 19, 0, 1 }, { 13, 31, 1 } } },
513
  { { { 19, 0, 0 }, { 13, 31, 0 } } },
514
  { { { 19, 0, 1 }, { 13, 31, 1 } } },
515
  { { { 19, 0, 2 }, { 14, 30, 1 } } },
516
  { { { 19, 0, 3 }, { 14, 30, 0 } } },
517
  { { { 19, 0, 4 }, { 14, 31, 1 } } },
518
  { { { 20, 0, 4 }, { 14, 31, 0 } } },
519
  { { { 20, 0, 3 }, { 16, 27, 0 } } },
520
  { { { 20, 0, 2 }, { 15, 30, 1 } } },
521
  { { { 20, 0, 1 }, { 15, 30, 0 } } },
522
  { { { 20, 0, 0 }, { 16, 28, 0 } } },
523
  { { { 20, 0, 1 }, { 15, 31, 1 } } },
524
  { { { 20, 0, 2 }, { 15, 31, 0 } } },
525
  { { { 20, 0, 3 }, { 15, 31, 1 } } },
526
  { { { 20, 0, 4 }, { 16, 30, 1 } } },
527
  { { { 21, 0, 3 }, { 16, 30, 0 } } },
528
  { { { 21, 0, 2 }, { 18, 27, 1 } } },
529
  { { { 21, 0, 1 }, { 18, 27, 0 } } },
530
  { { { 21, 0, 0 }, { 16, 31, 0 } } },
531
  { { { 21, 0, 1 }, { 17, 30, 1 } } },
532
  { { { 21, 0, 2 }, { 17, 30, 0 } } },
533
  { { { 21, 0, 3 }, { 20, 24, 0 } } },
534
  { { { 21, 0, 4 }, { 17, 31, 1 } } },
535
  { { { 22, 0, 3 }, { 17, 31, 0 } } },
536
  { { { 22, 0, 2 }, { 17, 31, 1 } } },
537
  { { { 22, 0, 1 }, { 18, 30, 1 } } },
538
  { { { 22, 0, 0 }, { 18, 30, 0 } } },
539
  { { { 22, 0, 1 }, { 18, 31, 1 } } },
540
  { { { 22, 0, 2 }, { 18, 31, 0 } } },
541
  { { { 22, 0, 3 }, { 20, 27, 0 } } },
542
  { { { 22, 0, 4 }, { 19, 30, 1 } } },
543
  { { { 23, 0, 3 }, { 19, 30, 0 } } },
544
  { { { 23, 0, 2 }, { 20, 28, 0 } } },
545
  { { { 23, 0, 1 }, { 19, 31, 1 } } },
546
  { { { 23, 0, 0 }, { 19, 31, 0 } } },
547
  { { { 23, 0, 1 }, { 19, 31, 1 } } },
548
  { { { 23, 0, 2 }, { 20, 30, 1 } } },
549
  { { { 23, 0, 3 }, { 20, 30, 0 } } },
550
  { { { 23, 0, 4 }, { 22, 27, 1 } } },
551
  { { { 24, 0, 4 }, { 22, 27, 0 } } },
552
  { { { 24, 0, 3 }, { 20, 31, 0 } } },
553
  { { { 24, 0, 2 }, { 21, 30, 1 } } },
554
  { { { 24, 0, 1 }, { 21, 30, 0 } } },
555
  { { { 24, 0, 0 }, { 24, 24, 0 } } },
556
  { { { 24, 0, 1 }, { 21, 31, 1 } } },
557
  { { { 24, 0, 2 }, { 21, 31, 0 } } },
558
  { { { 24, 0, 3 }, { 21, 31, 1 } } },
559
  { { { 24, 0, 4 }, { 22, 30, 1 } } },
560
  { { { 25, 0, 3 }, { 22, 30, 0 } } },
561
  { { { 25, 0, 2 }, { 22, 31, 1 } } },
562
  { { { 25, 0, 1 }, { 22, 31, 0 } } },
563
  { { { 25, 0, 0 }, { 24, 27, 0 } } },
564
  { { { 25, 0, 1 }, { 23, 30, 1 } } },
565
  { { { 25, 0, 2 }, { 23, 30, 0 } } },
566
  { { { 25, 0, 3 }, { 24, 28, 0 } } },
567
  { { { 25, 0, 4 }, { 23, 31, 1 } } },
568
  { { { 26, 0, 3 }, { 23, 31, 0 } } },
569
  { { { 26, 0, 2 }, { 23, 31, 1 } } },
570
  { { { 26, 0, 1 }, { 24, 30, 1 } } },
571
  { { { 26, 0, 0 }, { 24, 30, 0 } } },
572
  { { { 26, 0, 1 }, { 26, 27, 1 } } },
573
  { { { 26, 0, 2 }, { 26, 27, 0 } } },
574
  { { { 26, 0, 3 }, { 24, 31, 0 } } },
575
  { { { 26, 0, 4 }, { 25, 30, 1 } } },
576
  { { { 27, 0, 3 }, { 25, 30, 0 } } },
577
  { { { 27, 0, 2 }, { 28, 24, 0 } } },
578
  { { { 27, 0, 1 }, { 25, 31, 1 } } },
579
  { { { 27, 0, 0 }, { 25, 31, 0 } } },
580
  { { { 27, 0, 1 }, { 25, 31, 1 } } },
581
  { { { 27, 0, 2 }, { 26, 30, 1 } } },
582
  { { { 27, 0, 3 }, { 26, 30, 0 } } },
583
  { { { 27, 0, 4 }, { 26, 31, 1 } } },
584
  { { { 28, 0, 4 }, { 26, 31, 0 } } },
585
  { { { 28, 0, 3 }, { 28, 27, 0 } } },
586
  { { { 28, 0, 2 }, { 27, 30, 1 } } },
587
  { { { 28, 0, 1 }, { 27, 30, 0 } } },
588
  { { { 28, 0, 0 }, { 28, 28, 0 } } },
589
  { { { 28, 0, 1 }, { 27, 31, 1 } } },
590
  { { { 28, 0, 2 }, { 27, 31, 0 } } },
591
  { { { 28, 0, 3 }, { 27, 31, 1 } } },
592
  { { { 28, 0, 4 }, { 28, 30, 1 } } },
593
  { { { 29, 0, 3 }, { 28, 30, 0 } } },
594
  { { { 29, 0, 2 }, { 30, 27, 1 } } },
595
  { { { 29, 0, 1 }, { 30, 27, 0 } } },
596
  { { { 29, 0, 0 }, { 28, 31, 0 } } },
597
  { { { 29, 0, 1 }, { 29, 30, 1 } } },
598
  { { { 29, 0, 2 }, { 29, 30, 0 } } },
599
  { { { 29, 0, 3 }, { 29, 30, 1 } } },
600
  { { { 29, 0, 4 }, { 29, 31, 1 } } },
601
  { { { 30, 0, 3 }, { 29, 31, 0 } } },
602
  { { { 30, 0, 2 }, { 29, 31, 1 } } },
603
  { { { 30, 0, 1 }, { 30, 30, 1 } } },
604
  { { { 30, 0, 0 }, { 30, 30, 0 } } },
605
  { { { 30, 0, 1 }, { 30, 31, 1 } } },
606
  { { { 30, 0, 2 }, { 30, 31, 0 } } },
607
  { { { 30, 0, 3 }, { 30, 31, 1 } } },
608
  { { { 30, 0, 4 }, { 31, 30, 1 } } },
609
  { { { 31, 0, 3 }, { 31, 30, 0 } } },
610
  { { { 31, 0, 2 }, { 31, 30, 1 } } },
611
  { { { 31, 0, 1 }, { 31, 31, 1 } } },
612
  { { { 31, 0, 0 }, { 31, 31, 0 } } }
613
};
614
615
static const DDSSingleColorLookup DDSLookup_6_4[] =
616
{
617
  { { { 0, 0, 0 }, { 0, 0, 0 } } },
618
  { { { 0, 0, 1 }, { 0, 1, 0 } } },
619
  { { { 0, 0, 2 }, { 0, 2, 0 } } },
620
  { { { 1, 0, 1 }, { 0, 3, 1 } } },
621
  { { { 1, 0, 0 }, { 0, 3, 0 } } },
622
  { { { 1, 0, 1 }, { 0, 4, 0 } } },
623
  { { { 1, 0, 2 }, { 0, 5, 0 } } },
624
  { { { 2, 0, 1 }, { 0, 6, 1 } } },
625
  { { { 2, 0, 0 }, { 0, 6, 0 } } },
626
  { { { 2, 0, 1 }, { 0, 7, 0 } } },
627
  { { { 2, 0, 2 }, { 0, 8, 0 } } },
628
  { { { 3, 0, 1 }, { 0, 9, 1 } } },
629
  { { { 3, 0, 0 }, { 0, 9, 0 } } },
630
  { { { 3, 0, 1 }, { 0, 10, 0 } } },
631
  { { { 3, 0, 2 }, { 0, 11, 0 } } },
632
  { { { 4, 0, 1 }, { 0, 12, 1 } } },
633
  { { { 4, 0, 0 }, { 0, 12, 0 } } },
634
  { { { 4, 0, 1 }, { 0, 13, 0 } } },
635
  { { { 4, 0, 2 }, { 0, 14, 0 } } },
636
  { { { 5, 0, 1 }, { 0, 15, 1 } } },
637
  { { { 5, 0, 0 }, { 0, 15, 0 } } },
638
  { { { 5, 0, 1 }, { 0, 16, 0 } } },
639
  { { { 5, 0, 2 }, { 1, 15, 0 } } },
640
  { { { 6, 0, 1 }, { 0, 17, 0 } } },
641
  { { { 6, 0, 0 }, { 0, 18, 0 } } },
642
  { { { 6, 0, 1 }, { 0, 19, 0 } } },
643
  { { { 6, 0, 2 }, { 3, 14, 0 } } },
644
  { { { 7, 0, 1 }, { 0, 20, 0 } } },
645
  { { { 7, 0, 0 }, { 0, 21, 0 } } },
646
  { { { 7, 0, 1 }, { 0, 22, 0 } } },
647
  { { { 7, 0, 2 }, { 4, 15, 0 } } },
648
  { { { 8, 0, 1 }, { 0, 23, 0 } } },
649
  { { { 8, 0, 0 }, { 0, 24, 0 } } },
650
  { { { 8, 0, 1 }, { 0, 25, 0 } } },
651
  { { { 8, 0, 2 }, { 6, 14, 0 } } },
652
  { { { 9, 0, 1 }, { 0, 26, 0 } } },
653
  { { { 9, 0, 0 }, { 0, 27, 0 } } },
654
  { { { 9, 0, 1 }, { 0, 28, 0 } } },
655
  { { { 9, 0, 2 }, { 7, 15, 0 } } },
656
  { { { 10, 0, 1 }, { 0, 29, 0 } } },
657
  { { { 10, 0, 0 }, { 0, 30, 0 } } },
658
  { { { 10, 0, 1 }, { 0, 31, 0 } } },
659
  { { { 10, 0, 2 }, { 9, 14, 0 } } },
660
  { { { 11, 0, 1 }, { 0, 32, 0 } } },
661
  { { { 11, 0, 0 }, { 0, 33, 0 } } },
662
  { { { 11, 0, 1 }, { 2, 30, 0 } } },
663
  { { { 11, 0, 2 }, { 0, 34, 0 } } },
664
  { { { 12, 0, 1 }, { 0, 35, 0 } } },
665
  { { { 12, 0, 0 }, { 0, 36, 0 } } },
666
  { { { 12, 0, 1 }, { 3, 31, 0 } } },
667
  { { { 12, 0, 2 }, { 0, 37, 0 } } },
668
  { { { 13, 0, 1 }, { 0, 38, 0 } } },
669
  { { { 13, 0, 0 }, { 0, 39, 0 } } },
670
  { { { 13, 0, 1 }, { 5, 30, 0 } } },
671
  { { { 13, 0, 2 }, { 0, 40, 0 } } },
672
  { { { 14, 0, 1 }, { 0, 41, 0 } } },
673
  { { { 14, 0, 0 }, { 0, 42, 0 } } },
674
  { { { 14, 0, 1 }, { 6, 31, 0 } } },
675
  { { { 14, 0, 2 }, { 0, 43, 0 } } },
676
  { { { 15, 0, 1 }, { 0, 44, 0 } } },
677
  { { { 15, 0, 0 }, { 0, 45, 0 } } },
678
  { { { 15, 0, 1 }, { 8, 30, 0 } } },
679
  { { { 15, 0, 2 }, { 0, 46, 0 } } },
680
  { { { 16, 0, 2 }, { 0, 47, 0 } } },
681
  { { { 16, 0, 1 }, { 1, 46, 0 } } },
682
  { { { 16, 0, 0 }, { 0, 48, 0 } } },
683
  { { { 16, 0, 1 }, { 0, 49, 0 } } },
684
  { { { 16, 0, 2 }, { 0, 50, 0 } } },
685
  { { { 17, 0, 1 }, { 2, 47, 0 } } },
686
  { { { 17, 0, 0 }, { 0, 51, 0 } } },
687
  { { { 17, 0, 1 }, { 0, 52, 0 } } },
688
  { { { 17, 0, 2 }, { 0, 53, 0 } } },
689
  { { { 18, 0, 1 }, { 4, 46, 0 } } },
690
  { { { 18, 0, 0 }, { 0, 54, 0 } } },
691
  { { { 18, 0, 1 }, { 0, 55, 0 } } },
692
  { { { 18, 0, 2 }, { 0, 56, 0 } } },
693
  { { { 19, 0, 1 }, { 5, 47, 0 } } },
694
  { { { 19, 0, 0 }, { 0, 57, 0 } } },
695
  { { { 19, 0, 1 }, { 0, 58, 0 } } },
696
  { { { 19, 0, 2 }, { 0, 59, 0 } } },
697
  { { { 20, 0, 1 }, { 7, 46, 0 } } },
698
  { { { 20, 0, 0 }, { 0, 60, 0 } } },
699
  { { { 20, 0, 1 }, { 0, 61, 0 } } },
700
  { { { 20, 0, 2 }, { 0, 62, 0 } } },
701
  { { { 21, 0, 1 }, { 8, 47, 0 } } },
702
  { { { 21, 0, 0 }, { 0, 63, 0 } } },
703
  { { { 21, 0, 1 }, { 1, 62, 0 } } },
704
  { { { 21, 0, 2 }, { 1, 63, 0 } } },
705
  { { { 22, 0, 1 }, { 10, 46, 0 } } },
706
  { { { 22, 0, 0 }, { 2, 62, 0 } } },
707
  { { { 22, 0, 1 }, { 2, 63, 0 } } },
708
  { { { 22, 0, 2 }, { 3, 62, 0 } } },
709
  { { { 23, 0, 1 }, { 11, 47, 0 } } },
710
  { { { 23, 0, 0 }, { 3, 63, 0 } } },
711
  { { { 23, 0, 1 }, { 4, 62, 0 } } },
712
  { { { 23, 0, 2 }, { 4, 63, 0 } } },
713
  { { { 24, 0, 1 }, { 13, 46, 0 } } },
714
  { { { 24, 0, 0 }, { 5, 62, 0 } } },
715
  { { { 24, 0, 1 }, { 5, 63, 0 } } },
716
  { { { 24, 0, 2 }, { 6, 62, 0 } } },
717
  { { { 25, 0, 1 }, { 14, 47, 0 } } },
718
  { { { 25, 0, 0 }, { 6, 63, 0 } } },
719
  { { { 25, 0, 1 }, { 7, 62, 0 } } },
720
  { { { 25, 0, 2 }, { 7, 63, 0 } } },
721
  { { { 26, 0, 1 }, { 16, 45, 0 } } },
722
  { { { 26, 0, 0 }, { 8, 62, 0 } } },
723
  { { { 26, 0, 1 }, { 8, 63, 0 } } },
724
  { { { 26, 0, 2 }, { 9, 62, 0 } } },
725
  { { { 27, 0, 1 }, { 16, 48, 0 } } },
726
  { { { 27, 0, 0 }, { 9, 63, 0 } } },
727
  { { { 27, 0, 1 }, { 10, 62, 0 } } },
728
  { { { 27, 0, 2 }, { 10, 63, 0 } } },
729
  { { { 28, 0, 1 }, { 16, 51, 0 } } },
730
  { { { 28, 0, 0 }, { 11, 62, 0 } } },
731
  { { { 28, 0, 1 }, { 11, 63, 0 } } },
732
  { { { 28, 0, 2 }, { 12, 62, 0 } } },
733
  { { { 29, 0, 1 }, { 16, 54, 0 } } },
734
  { { { 29, 0, 0 }, { 12, 63, 0 } } },
735
  { { { 29, 0, 1 }, { 13, 62, 0 } } },
736
  { { { 29, 0, 2 }, { 13, 63, 0 } } },
737
  { { { 30, 0, 1 }, { 16, 57, 0 } } },
738
  { { { 30, 0, 0 }, { 14, 62, 0 } } },
739
  { { { 30, 0, 1 }, { 14, 63, 0 } } },
740
  { { { 30, 0, 2 }, { 15, 62, 0 } } },
741
  { { { 31, 0, 1 }, { 16, 60, 0 } } },
742
  { { { 31, 0, 0 }, { 15, 63, 0 } } },
743
  { { { 31, 0, 1 }, { 24, 46, 0 } } },
744
  { { { 31, 0, 2 }, { 16, 62, 0 } } },
745
  { { { 32, 0, 2 }, { 16, 63, 0 } } },
746
  { { { 32, 0, 1 }, { 17, 62, 0 } } },
747
  { { { 32, 0, 0 }, { 25, 47, 0 } } },
748
  { { { 32, 0, 1 }, { 17, 63, 0 } } },
749
  { { { 32, 0, 2 }, { 18, 62, 0 } } },
750
  { { { 33, 0, 1 }, { 18, 63, 0 } } },
751
  { { { 33, 0, 0 }, { 27, 46, 0 } } },
752
  { { { 33, 0, 1 }, { 19, 62, 0 } } },
753
  { { { 33, 0, 2 }, { 19, 63, 0 } } },
754
  { { { 34, 0, 1 }, { 20, 62, 0 } } },
755
  { { { 34, 0, 0 }, { 28, 47, 0 } } },
756
  { { { 34, 0, 1 }, { 20, 63, 0 } } },
757
  { { { 34, 0, 2 }, { 21, 62, 0 } } },
758
  { { { 35, 0, 1 }, { 21, 63, 0 } } },
759
  { { { 35, 0, 0 }, { 30, 46, 0 } } },
760
  { { { 35, 0, 1 }, { 22, 62, 0 } } },
761
  { { { 35, 0, 2 }, { 22, 63, 0 } } },
762
  { { { 36, 0, 1 }, { 23, 62, 0 } } },
763
  { { { 36, 0, 0 }, { 31, 47, 0 } } },
764
  { { { 36, 0, 1 }, { 23, 63, 0 } } },
765
  { { { 36, 0, 2 }, { 24, 62, 0 } } },
766
  { { { 37, 0, 1 }, { 24, 63, 0 } } },
767
  { { { 37, 0, 0 }, { 32, 47, 0 } } },
768
  { { { 37, 0, 1 }, { 25, 62, 0 } } },
769
  { { { 37, 0, 2 }, { 25, 63, 0 } } },
770
  { { { 38, 0, 1 }, { 26, 62, 0 } } },
771
  { { { 38, 0, 0 }, { 32, 50, 0 } } },
772
  { { { 38, 0, 1 }, { 26, 63, 0 } } },
773
  { { { 38, 0, 2 }, { 27, 62, 0 } } },
774
  { { { 39, 0, 1 }, { 27, 63, 0 } } },
775
  { { { 39, 0, 0 }, { 32, 53, 0 } } },
776
  { { { 39, 0, 1 }, { 28, 62, 0 } } },
777
  { { { 39, 0, 2 }, { 28, 63, 0 } } },
778
  { { { 40, 0, 1 }, { 29, 62, 0 } } },
779
  { { { 40, 0, 0 }, { 32, 56, 0 } } },
780
  { { { 40, 0, 1 }, { 29, 63, 0 } } },
781
  { { { 40, 0, 2 }, { 30, 62, 0 } } },
782
  { { { 41, 0, 1 }, { 30, 63, 0 } } },
783
  { { { 41, 0, 0 }, { 32, 59, 0 } } },
784
  { { { 41, 0, 1 }, { 31, 62, 0 } } },
785
  { { { 41, 0, 2 }, { 31, 63, 0 } } },
786
  { { { 42, 0, 1 }, { 32, 61, 0 } } },
787
  { { { 42, 0, 0 }, { 32, 62, 0 } } },
788
  { { { 42, 0, 1 }, { 32, 63, 0 } } },
789
  { { { 42, 0, 2 }, { 41, 46, 0 } } },
790
  { { { 43, 0, 1 }, { 33, 62, 0 } } },
791
  { { { 43, 0, 0 }, { 33, 63, 0 } } },
792
  { { { 43, 0, 1 }, { 34, 62, 0 } } },
793
  { { { 43, 0, 2 }, { 42, 47, 0 } } },
794
  { { { 44, 0, 1 }, { 34, 63, 0 } } },
795
  { { { 44, 0, 0 }, { 35, 62, 0 } } },
796
  { { { 44, 0, 1 }, { 35, 63, 0 } } },
797
  { { { 44, 0, 2 }, { 44, 46, 0 } } },
798
  { { { 45, 0, 1 }, { 36, 62, 0 } } },
799
  { { { 45, 0, 0 }, { 36, 63, 0 } } },
800
  { { { 45, 0, 1 }, { 37, 62, 0 } } },
801
  { { { 45, 0, 2 }, { 45, 47, 0 } } },
802
  { { { 46, 0, 1 }, { 37, 63, 0 } } },
803
  { { { 46, 0, 0 }, { 38, 62, 0 } } },
804
  { { { 46, 0, 1 }, { 38, 63, 0 } } },
805
  { { { 46, 0, 2 }, { 47, 46, 0 } } },
806
  { { { 47, 0, 1 }, { 39, 62, 0 } } },
807
  { { { 47, 0, 0 }, { 39, 63, 0 } } },
808
  { { { 47, 0, 1 }, { 40, 62, 0 } } },
809
  { { { 47, 0, 2 }, { 48, 46, 0 } } },
810
  { { { 48, 0, 2 }, { 40, 63, 0 } } },
811
  { { { 48, 0, 1 }, { 41, 62, 0 } } },
812
  { { { 48, 0, 0 }, { 41, 63, 0 } } },
813
  { { { 48, 0, 1 }, { 48, 49, 0 } } },
814
  { { { 48, 0, 2 }, { 42, 62, 0 } } },
815
  { { { 49, 0, 1 }, { 42, 63, 0 } } },
816
  { { { 49, 0, 0 }, { 43, 62, 0 } } },
817
  { { { 49, 0, 1 }, { 48, 52, 0 } } },
818
  { { { 49, 0, 2 }, { 43, 63, 0 } } },
819
  { { { 50, 0, 1 }, { 44, 62, 0 } } },
820
  { { { 50, 0, 0 }, { 44, 63, 0 } } },
821
  { { { 50, 0, 1 }, { 48, 55, 0 } } },
822
  { { { 50, 0, 2 }, { 45, 62, 0 } } },
823
  { { { 51, 0, 1 }, { 45, 63, 0 } } },
824
  { { { 51, 0, 0 }, { 46, 62, 0 } } },
825
  { { { 51, 0, 1 }, { 48, 58, 0 } } },
826
  { { { 51, 0, 2 }, { 46, 63, 0 } } },
827
  { { { 52, 0, 1 }, { 47, 62, 0 } } },
828
  { { { 52, 0, 0 }, { 47, 63, 0 } } },
829
  { { { 52, 0, 1 }, { 48, 61, 0 } } },
830
  { { { 52, 0, 2 }, { 48, 62, 0 } } },
831
  { { { 53, 0, 1 }, { 56, 47, 0 } } },
832
  { { { 53, 0, 0 }, { 48, 63, 0 } } },
833
  { { { 53, 0, 1 }, { 49, 62, 0 } } },
834
  { { { 53, 0, 2 }, { 49, 63, 0 } } },
835
  { { { 54, 0, 1 }, { 58, 46, 0 } } },
836
  { { { 54, 0, 0 }, { 50, 62, 0 } } },
837
  { { { 54, 0, 1 }, { 50, 63, 0 } } },
838
  { { { 54, 0, 2 }, { 51, 62, 0 } } },
839
  { { { 55, 0, 1 }, { 59, 47, 0 } } },
840
  { { { 55, 0, 0 }, { 51, 63, 0 } } },
841
  { { { 55, 0, 1 }, { 52, 62, 0 } } },
842
  { { { 55, 0, 2 }, { 52, 63, 0 } } },
843
  { { { 56, 0, 1 }, { 61, 46, 0 } } },
844
  { { { 56, 0, 0 }, { 53, 62, 0 } } },
845
  { { { 56, 0, 1 }, { 53, 63, 0 } } },
846
  { { { 56, 0, 2 }, { 54, 62, 0 } } },
847
  { { { 57, 0, 1 }, { 62, 47, 0 } } },
848
  { { { 57, 0, 0 }, { 54, 63, 0 } } },
849
  { { { 57, 0, 1 }, { 55, 62, 0 } } },
850
  { { { 57, 0, 2 }, { 55, 63, 0 } } },
851
  { { { 58, 0, 1 }, { 56, 62, 1 } } },
852
  { { { 58, 0, 0 }, { 56, 62, 0 } } },
853
  { { { 58, 0, 1 }, { 56, 63, 0 } } },
854
  { { { 58, 0, 2 }, { 57, 62, 0 } } },
855
  { { { 59, 0, 1 }, { 57, 63, 1 } } },
856
  { { { 59, 0, 0 }, { 57, 63, 0 } } },
857
  { { { 59, 0, 1 }, { 58, 62, 0 } } },
858
  { { { 59, 0, 2 }, { 58, 63, 0 } } },
859
  { { { 60, 0, 1 }, { 59, 62, 1 } } },
860
  { { { 60, 0, 0 }, { 59, 62, 0 } } },
861
  { { { 60, 0, 1 }, { 59, 63, 0 } } },
862
  { { { 60, 0, 2 }, { 60, 62, 0 } } },
863
  { { { 61, 0, 1 }, { 60, 63, 1 } } },
864
  { { { 61, 0, 0 }, { 60, 63, 0 } } },
865
  { { { 61, 0, 1 }, { 61, 62, 0 } } },
866
  { { { 61, 0, 2 }, { 61, 63, 0 } } },
867
  { { { 62, 0, 1 }, { 62, 62, 1 } } },
868
  { { { 62, 0, 0 }, { 62, 62, 0 } } },
869
  { { { 62, 0, 1 }, { 62, 63, 0 } } },
870
  { { { 62, 0, 2 }, { 63, 62, 0 } } },
871
  { { { 63, 0, 1 }, { 63, 63, 1 } } },
872
  { { { 63, 0, 0 }, { 63, 63, 0 } } }
873
};
874
875
static const DDSSingleColorLookup*
876
  DDS_LOOKUP[] =
877
{
878
  DDSLookup_5_4,
879
  DDSLookup_6_4,
880
  DDSLookup_5_4
881
};
882
883
static const unsigned char BC7_weight2[] = { 0, 21, 43, 64 };
884
static const unsigned char BC7_weight3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
885
static const unsigned char BC7_weight4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34,
886
  38, 43, 47, 51, 55, 60, 64 };
887
888
/* stores info for each mode of BC7 */
889
static const BC7ModeInfo BC7_mode_info[8] =
890
{
891
  { 4, 3, 4, 0, 6, 3, 0 },   /* mode 0 */
892
  { 6, 2, 6, 0, 2, 3, 0 },   /* mode 1 */
893
  { 6, 3, 5, 0, 0, 2, 0 },   /* mode 2 */
894
  { 6, 2, 7, 0, 4, 2, 0 },   /* mode 3 */
895
  { 0, 1, 5, 6, 0, 2, 3 },   /* mode 4 */
896
  { 0, 1, 7, 8, 0, 2, 2 },   /* mode 5 */
897
  { 0, 1, 7, 7, 2, 4, 0 },   /* mode 6 */
898
  { 6, 2, 5, 5, 4, 2, 0 },   /* mode 7 */
899
};
900
901
static const unsigned char BC7_partition_table[2][64][16] =
902
{
903
  { /* BC7 Partition Set for 2 Subsets */
904
    { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
905
    { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
906
    { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
907
    { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
908
    { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 },
909
    { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
910
    { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
911
    { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
912
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 },
913
    { 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
914
    { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
915
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 },
916
    { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
917
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
918
    { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
919
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
920
    { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 },
921
    { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
922
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 },
923
    { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
924
    { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
925
    { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 },
926
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
927
    { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 },
928
    { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
929
    { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
930
    { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 },
931
    { 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 },
932
    { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 },
933
    { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
934
    { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 },
935
    { 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
936
    { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
937
    { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 },
938
    { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 },
939
    { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 },
940
    { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 },
941
    { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 },
942
    { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 },
943
    { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 },
944
    { 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 },
945
    { 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 },
946
    { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 },
947
    { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 },
948
    { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 },
949
    { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
950
    { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 },
951
    { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
952
    { 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
953
    { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 },
954
    { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 },
955
    { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 },
956
    { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 },
957
    { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
958
    { 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
959
    { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 },
960
    { 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
961
    { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 },
962
    { 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 },
963
    { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 },
964
    { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
965
    { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
966
    { 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 },
967
    { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 } 
968
  },
969
970
  {  /* BC7 Partition Set for 3 Subsets */
971
    { 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 },
972
    { 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 },
973
    { 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
974
    { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 },
975
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 },
976
    { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 },
977
    { 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 },
978
    { 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
979
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 },
980
    { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 },
981
    { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
982
    { 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 },
983
    { 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 },
984
    { 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 },
985
    { 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
986
    { 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 },
987
    { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 },
988
    { 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 },
989
    { 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 },
990
    { 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 },
991
    { 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 },
992
    { 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 },
993
    { 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 },
994
    { 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 },
995
    { 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 },
996
    { 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 },
997
    { 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 },
998
    { 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 },
999
    { 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 },
1000
    { 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 },
1001
    { 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 },
1002
    { 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 },
1003
    { 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
1004
    { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 },
1005
    { 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 },
1006
    { 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 },
1007
    { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 },
1008
    { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 },
1009
    { 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 },
1010
    { 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 },
1011
    { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 },
1012
    { 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
1013
    { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 },
1014
    { 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 },
1015
    { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 },
1016
    { 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 },
1017
    { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 },
1018
    { 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 },
1019
    { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 },
1020
    { 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 },
1021
    { 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 },
1022
    { 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 },
1023
    { 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 },
1024
    { 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 },
1025
    { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 },
1026
    { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 },
1027
    { 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 },
1028
    { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 },
1029
    { 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 },
1030
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 },
1031
    { 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 },
1032
    { 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 },
1033
    { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
1034
    { 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 }
1035
  }
1036
};
1037
1038
static const unsigned char BC7_anchor_index_table[4][64] =
1039
{
1040
  /* Anchor index values for the first subset */
1041
  {
1042
    0, 0, 0, 0, 0, 0, 0, 0,
1043
    0, 0, 0, 0, 0, 0, 0, 0,
1044
    0, 0, 0, 0, 0, 0, 0, 0,
1045
    0, 0, 0, 0, 0, 0, 0, 0,
1046
    0, 0, 0, 0, 0, 0, 0, 0,
1047
    0, 0, 0, 0, 0, 0, 0, 0,
1048
    0, 0, 0, 0, 0, 0, 0, 0,
1049
    0, 0, 0, 0, 0, 0, 0, 0
1050
  },
1051
  /* Anchor index values for the second subset of two-subset partitioning */
1052
  {
1053
    15,15,15,15,15,15,15,15,
1054
    15,15,15,15,15,15,15,15,
1055
    15, 2, 8, 2, 2, 8, 8,15,
1056
    2, 8, 2, 2, 8, 8, 2, 2,
1057
    15,15, 6, 8, 2, 8,15,15,
1058
    2, 8, 2, 2, 2,15,15, 6,
1059
    6, 2, 6, 8,15,15, 2, 2,
1060
    15,15,15,15,15, 2, 2,15
1061
  },
1062
  /* Anchor index values for the second subset of three-subset partitioning */
1063
  {
1064
    3, 3,15,15, 8, 3,15,15,
1065
    8, 8, 6, 6, 6, 5, 3, 3,
1066
    3, 3, 8,15, 3, 3, 6,10,
1067
    5, 8, 8, 6, 8, 5,15,15,
1068
    8,15, 3, 5, 6,10, 8,15,
1069
    15, 3,15, 5,15,15,15,15,
1070
    3,15, 5, 5, 5, 8, 5,10,
1071
    5,10, 8,13,15,12, 3, 3
1072
  },
1073
  /* Anchor index values for the third subset of three-subset partitioning */
1074
  {
1075
    15, 8, 8, 3,15,15, 3, 8,
1076
    15,15,15,15,15,15,15, 8,
1077
    15, 8,15, 3,15, 8,15, 8,
1078
    3,15, 6,10,15,15,10, 8,
1079
    15, 3,15,10,10, 8, 9,10,
1080
    6,15, 8,15, 3, 6, 6, 8,
1081
    15, 3,15,15,15,15,15,15,
1082
    15,15,15,15, 3,15,15, 8
1083
  }
1084
};
1085
1086
/*
1087
  Macros
1088
*/
1089
249k
#define C565_r(x) (((x) & 0xF800) >> 11)
1090
249k
#define C565_g(x) (((x) & 0x07E0) >> 5)
1091
249k
#define C565_b(x)  ((x) & 0x001F)
1092
1093
124k
#define C565_red(x)   ( (C565_r(x) << 3 | C565_r(x) >> 2))
1094
124k
#define C565_green(x) ( (C565_g(x) << 2 | C565_g(x) >> 4))
1095
124k
#define C565_blue(x)  ( (C565_b(x) << 3 | C565_b(x) >> 2))
1096
1097
34.7k
#define DIV2(x)  ((x) > 1 ? ((x) >> 1) : 1)
1098
1099
104k
#define FixRange(min, max, steps) \
1100
104k
if (min > max) \
1101
104k
  min = max; \
1102
104k
if ((max-min) < steps) \
1103
104k
  max = MagickMin(min+(ssize_t) steps, 255); \
1104
104k
if ((max- min) < steps) \
1105
104k
  min = (size_t) MagickMax(0L, (ssize_t) max-(ssize_t) steps)
1106
1107
1.13M
#define Dot(left, right) (left.x*right.x) + (left.y*right.y) + (left.z*right.z)
1108
1109
130k
#define VectorInit(vector, value) vector.x = vector.y = vector.z = vector.w \
1110
130k
  = value
1111
261k
#define VectorInit3(vector, value) vector.x = vector.y = vector.z = value
1112
1113
12.5k
#define IsBitMask(mask, r, g, b, a) (mask.r_bitmask == r && mask.g_bitmask == \
1114
4.79k
  g && mask.b_bitmask == b && mask.alpha_bitmask == a)
1115
1116
/*
1117
  Forward declarations
1118
*/
1119
static MagickBooleanType
1120
  WriteDDSImage(const ImageInfo *,Image *,ExceptionInfo *);
1121
1122
static inline void VectorAdd(const DDSVector4 left, const DDSVector4 right,
1123
  DDSVector4 *destination)
1124
0
{
1125
0
  destination->x = left.x + right.x;
1126
0
  destination->y = left.y + right.y;
1127
0
  destination->z = left.z + right.z;
1128
0
  destination->w = left.w + right.w;
1129
0
}
1130
1131
static inline void VectorClamp(DDSVector4 *value)
1132
0
{
1133
0
  value->x = MagickMin(1.0f,MagickMax(0.0f,value->x));
1134
0
  value->y = MagickMin(1.0f,MagickMax(0.0f,value->y));
1135
0
  value->z = MagickMin(1.0f,MagickMax(0.0f,value->z));
1136
0
  value->w = MagickMin(1.0f,MagickMax(0.0f,value->w));
1137
0
}
1138
1139
static inline void VectorClamp3(DDSVector3 *value)
1140
130k
{
1141
130k
  value->x = MagickMin(1.0f,MagickMax(0.0f,value->x));
1142
130k
  value->y = MagickMin(1.0f,MagickMax(0.0f,value->y));
1143
130k
  value->z = MagickMin(1.0f,MagickMax(0.0f,value->z));
1144
130k
}
1145
1146
static inline void VectorCopy43(const DDSVector4 source,
1147
  DDSVector3 *destination)
1148
315k
{
1149
315k
  destination->x = source.x;
1150
315k
  destination->y = source.y;
1151
315k
  destination->z = source.z;
1152
315k
}
1153
1154
static inline void VectorCopy44(const DDSVector4 source,
1155
  DDSVector4 *destination)
1156
0
{
1157
0
  destination->x = source.x;
1158
0
  destination->y = source.y;
1159
0
  destination->z = source.z;
1160
0
  destination->w = source.w;
1161
0
}
1162
1163
static inline void VectorNegativeMultiplySubtract(const DDSVector4 a,
1164
  const DDSVector4 b, const DDSVector4 c, DDSVector4 *destination)
1165
0
{
1166
0
  destination->x = c.x - (a.x * b.x);
1167
0
  destination->y = c.y - (a.y * b.y);
1168
0
  destination->z = c.z - (a.z * b.z);
1169
0
  destination->w = c.w - (a.w * b.w);
1170
0
}
1171
1172
static inline void VectorMultiply(const DDSVector4 left,
1173
  const DDSVector4 right, DDSVector4 *destination)
1174
0
{
1175
0
  destination->x = left.x * right.x;
1176
0
  destination->y = left.y * right.y;
1177
0
  destination->z = left.z * right.z;
1178
0
  destination->w = left.w * right.w;
1179
0
}
1180
1181
static inline void VectorMultiply3(const DDSVector3 left,
1182
  const DDSVector3 right, DDSVector3 *destination)
1183
130k
{
1184
130k
  destination->x = left.x * right.x;
1185
130k
  destination->y = left.y * right.y;
1186
130k
  destination->z = left.z * right.z;
1187
130k
}
1188
1189
static inline void VectorMultiplyAdd(const DDSVector4 a, const DDSVector4 b,
1190
  const DDSVector4 c, DDSVector4 *destination)
1191
0
{
1192
0
  destination->x = (a.x * b.x) + c.x;
1193
0
  destination->y = (a.y * b.y) + c.y;
1194
0
  destination->z = (a.z * b.z) + c.z;
1195
0
  destination->w = (a.w * b.w) + c.w;
1196
0
}
1197
1198
static inline void VectorMultiplyAdd3(const DDSVector3 a, const DDSVector3 b,
1199
  const DDSVector3 c, DDSVector3 *destination)
1200
130k
{
1201
130k
  destination->x = (a.x * b.x) + c.x;
1202
130k
  destination->y = (a.y * b.y) + c.y;
1203
130k
  destination->z = (a.z * b.z) + c.z;
1204
130k
}
1205
1206
static inline void VectorReciprocal(const DDSVector4 value,
1207
  DDSVector4 *destination)
1208
0
{
1209
0
  destination->x = 1.0f / value.x;
1210
0
  destination->y = 1.0f / value.y;
1211
0
  destination->z = 1.0f / value.z;
1212
0
  destination->w = 1.0f / value.w;
1213
0
}
1214
1215
static inline void VectorSubtract(const DDSVector4 left,
1216
  const DDSVector4 right, DDSVector4 *destination)
1217
0
{
1218
0
  destination->x = left.x - right.x;
1219
0
  destination->y = left.y - right.y;
1220
0
  destination->z = left.z - right.z;
1221
0
  destination->w = left.w - right.w;
1222
0
}
1223
1224
static inline void VectorSubtract3(const DDSVector3 left,
1225
  const DDSVector3 right, DDSVector3 *destination)
1226
0
{
1227
0
  destination->x = left.x - right.x;
1228
0
  destination->y = left.y - right.y;
1229
0
  destination->z = left.z - right.z;
1230
0
}
1231
1232
static inline void VectorTruncate(DDSVector4 *value)
1233
0
{
1234
0
  value->x = value->x > 0.0f ? floorf(value->x) : ceilf(value->x);
1235
0
  value->y = value->y > 0.0f ? floorf(value->y) : ceilf(value->y);
1236
0
  value->z = value->z > 0.0f ? floorf(value->z) : ceilf(value->z);
1237
0
  value->w = value->w > 0.0f ? floorf(value->w) : ceilf(value->w);
1238
0
}
1239
1240
static inline void VectorTruncate3(DDSVector3 *value)
1241
130k
{
1242
130k
  value->x = value->x > 0.0f ? floorf(value->x) : ceilf(value->x);
1243
130k
  value->y = value->y > 0.0f ? floorf(value->y) : ceilf(value->y);
1244
130k
  value->z = value->z > 0.0f ? floorf(value->z) : ceilf(value->z);
1245
130k
}
1246
1247
static inline size_t ClampToLimit(const float value, const size_t limit)
1248
918k
{
1249
918k
  size_t
1250
918k
    result = (size_t) (value + 0.5f);
1251
1252
918k
  if (result < 0.0f)
1253
0
    return(0);
1254
918k
  if (result > limit)
1255
0
    return(limit);
1256
918k
  return result;
1257
918k
}
1258
1259
static inline size_t ColorTo565(const DDSVector3 point)
1260
247k
{
1261
247k
  size_t r = ClampToLimit(31.0f*point.x,31);
1262
247k
  size_t g = ClampToLimit(63.0f*point.y,63);
1263
247k
  size_t b = ClampToLimit(31.0f*point.z,31);
1264
1265
247k
  return (r << 11) | (g << 5) | b;
1266
247k
}
1267
1268
static inline unsigned char GetSubsetIndex(unsigned char numSubsets,
1269
  unsigned char partition_id,size_t pixelIndex)
1270
234k
{
1271
234k
  if (numSubsets == 2)
1272
69.4k
    return BC7_partition_table[0][partition_id][pixelIndex];
1273
165k
  if (numSubsets == 3)
1274
64.8k
    return BC7_partition_table[1][partition_id][pixelIndex];
1275
100k
  return 0;
1276
165k
}
1277
1278
/*
1279
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1280
%                                                                             %
1281
%                                                                             %
1282
%                                                                             %
1283
%   I s D D S                                                                 %
1284
%                                                                             %
1285
%                                                                             %
1286
%                                                                             %
1287
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1288
%
1289
%  IsDDS() returns MagickTrue if the image format type, identified by the
1290
%  magick string, is DDS.
1291
%
1292
%  The format of the IsDDS method is:
1293
%
1294
%      MagickBooleanType IsDDS(const unsigned char *magick,const size_t length)
1295
%
1296
%  A description of each parameter follows:
1297
%
1298
%    o magick: compare image format pattern against these bytes.
1299
%
1300
%    o length: Specifies the length of the magick string.
1301
%
1302
*/
1303
static MagickBooleanType IsDDS(const unsigned char *magick, const size_t length)
1304
0
{
1305
0
  if (length < 4)
1306
0
    return(MagickFalse);
1307
0
  if (LocaleNCompare((char *) magick,"DDS ", 4) == 0)
1308
0
    return(MagickTrue);
1309
0
  return(MagickFalse);
1310
0
}
1311
1312
static MagickBooleanType ReadDDSInfo(Image *image, DDSInfo *dds_info)
1313
9.48k
{
1314
9.48k
  size_t
1315
9.48k
    hdr_size,
1316
9.48k
    required;
1317
1318
  /* Seek to start of header */
1319
9.48k
  (void) SeekBlob(image, 4, SEEK_SET);
1320
1321
  /* Check header field */
1322
9.48k
  hdr_size = ReadBlobLSBLong(image);
1323
9.48k
  if (hdr_size != 124)
1324
208
    return MagickFalse;
1325
1326
  /* Fill in DDS info struct */
1327
9.27k
  dds_info->flags = ReadBlobLSBLong(image);
1328
1329
  /* Check required flags */
1330
9.27k
  required=(size_t) (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT);
1331
9.27k
  if ((dds_info->flags & required) != required)
1332
15
    return MagickFalse;
1333
1334
9.26k
  dds_info->height = ReadBlobLSBLong(image);
1335
9.26k
  dds_info->width = ReadBlobLSBLong(image);
1336
9.26k
  dds_info->pitchOrLinearSize = ReadBlobLSBLong(image);
1337
9.26k
  dds_info->depth = ReadBlobLSBLong(image);
1338
9.26k
  dds_info->mipmapcount = ReadBlobLSBLong(image);
1339
  
1340
9.26k
  (void) SeekBlob(image, 44, SEEK_CUR);   /* reserved region of 11 DWORDs */
1341
1342
  /* Read pixel format structure */
1343
9.26k
  hdr_size = ReadBlobLSBLong(image);
1344
9.26k
  if (hdr_size != 32)
1345
170
    return MagickFalse;
1346
1347
9.09k
  dds_info->pixelformat.flags = ReadBlobLSBLong(image);
1348
9.09k
  dds_info->pixelformat.fourcc = ReadBlobLSBLong(image);
1349
9.09k
  dds_info->pixelformat.rgb_bitcount = ReadBlobLSBLong(image);
1350
9.09k
  dds_info->pixelformat.r_bitmask = ReadBlobLSBLong(image);
1351
9.09k
  dds_info->pixelformat.g_bitmask = ReadBlobLSBLong(image);
1352
9.09k
  dds_info->pixelformat.b_bitmask = ReadBlobLSBLong(image);
1353
9.09k
  dds_info->pixelformat.alpha_bitmask = ReadBlobLSBLong(image);
1354
1355
9.09k
  dds_info->ddscaps1 = ReadBlobLSBLong(image);
1356
9.09k
  dds_info->ddscaps2 = ReadBlobLSBLong(image);
1357
9.09k
  (void) SeekBlob(image, 12, SEEK_CUR); /* 3 reserved DWORDs */
1358
1359
  /* Read optional DX10 header if available */
1360
9.09k
  if ((dds_info->pixelformat.flags & DDPF_FOURCC) &&
1361
7.35k
      (dds_info->pixelformat.fourcc == FOURCC_DX10))
1362
1.16k
    {
1363
1.16k
      dds_info->extFormat = ReadBlobLSBLong(image);
1364
1.16k
      dds_info->extDimension = ReadBlobLSBLong(image);
1365
1.16k
      dds_info->extFlags = ReadBlobLSBLong(image);
1366
1.16k
      dds_info->extArraySize = ReadBlobLSBLong(image);
1367
1.16k
      dds_info->extFlags2 = ReadBlobLSBLong(image);
1368
1.16k
    }
1369
7.92k
  else
1370
7.92k
    {
1371
7.92k
      dds_info->extFormat = 0;
1372
7.92k
      dds_info->extDimension = 0;
1373
7.92k
      dds_info->extFlags = 0;
1374
7.92k
      dds_info->extArraySize = 0;
1375
7.92k
      dds_info->extFlags2 = 0;
1376
7.92k
    }
1377
1378
9.09k
  return(MagickTrue);
1379
9.26k
}
1380
1381
static MagickBooleanType SetDXT1Pixels(Image *image,ssize_t x,ssize_t y,
1382
  DDSColors colors,size_t bits,Quantum *q)
1383
54.1k
{
1384
54.1k
  ssize_t
1385
54.1k
    i;
1386
1387
54.1k
  ssize_t
1388
54.1k
    j;
1389
1390
54.1k
  unsigned char
1391
54.1k
    code;
1392
1393
262k
  for (j = 0; j < 4; j++)
1394
210k
  {
1395
1.04M
    for (i = 0; i < 4; i++)
1396
835k
    {
1397
835k
      if ((x + i) < (ssize_t) image->columns &&
1398
741k
          (y + j) < (ssize_t) image->rows)
1399
658k
        {
1400
658k
          code=(unsigned char) ((bits >> ((j*4+i)*2)) & 0x3);
1401
658k
          SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1402
658k
          SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1403
658k
          SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1404
658k
          SetPixelOpacity(image,ScaleCharToQuantum(colors.a[code]),q);
1405
658k
          if ((colors.a[code] != 0) &&
1406
138k
              ((image->alpha_trait & BlendPixelTrait) == 0))
1407
2.52k
            return(MagickFalse);
1408
655k
          q+=(ptrdiff_t) GetPixelChannels(image);
1409
655k
        }
1410
835k
    }
1411
210k
  }
1412
51.5k
  return(MagickTrue);
1413
54.1k
}
1414
1415
static MagickBooleanType ReadMipmaps(const ImageInfo *image_info,Image *image,
1416
  const DDSInfo *dds_info,DDSPixelDecoder decoder,ExceptionInfo *exception)
1417
0
{
1418
0
  MagickBooleanType
1419
0
    status;
1420
1421
  /*
1422
    Only read mipmaps for textures and cube maps
1423
  */
1424
0
  if (EOFBlob(image) != MagickFalse)
1425
0
    {
1426
0
      ThrowFileException(exception,CorruptImageWarning,"UnexpectedEndOfFile",
1427
0
        image->filename);
1428
0
      return(MagickFalse);
1429
0
    }
1430
0
  status=MagickTrue;
1431
0
  if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1432
0
      && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1433
0
          || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1434
0
    {
1435
0
      ssize_t
1436
0
        i;
1437
1438
0
      size_t
1439
0
        h,
1440
0
        w;
1441
1442
0
      w=DIV2(dds_info->width);
1443
0
      h=DIV2(dds_info->height);
1444
1445
      /*
1446
        Mipmapcount includes the main image, so start from one
1447
      */
1448
0
      for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1449
0
      {
1450
0
        AcquireNextImage(image_info,image,exception);
1451
0
        if (image->next == (Image *) NULL)
1452
0
          return(MagickFalse);
1453
0
        image->next->alpha_trait=image->alpha_trait;
1454
0
        image=SyncNextImageInList(image);
1455
0
        status=SetImageExtent(image,w,h,exception);
1456
0
        if (status == MagickFalse)
1457
0
          break;
1458
0
        status=decoder(image,dds_info,exception);
1459
0
        if (status == MagickFalse)
1460
0
          break;
1461
0
        if ((w == 1) && (h == 1))
1462
0
          break;
1463
1464
0
        w=DIV2(w);
1465
0
        h=DIV2(h);
1466
0
      }
1467
0
    }
1468
0
  return(status);
1469
0
}
1470
1471
static void CalculateColors(unsigned short c0, unsigned short c1,
1472
  DDSColors *c, MagickBooleanType ignoreAlpha)
1473
62.3k
{
1474
62.3k
  c->a[0] = c->a[1] = c->a[2] = c->a[3] = 0;
1475
1476
62.3k
  c->r[0] = (unsigned char) C565_red(c0);
1477
62.3k
  c->g[0] = (unsigned char) C565_green(c0);
1478
62.3k
  c->b[0] = (unsigned char) C565_blue(c0);
1479
1480
62.3k
  c->r[1] = (unsigned char) C565_red(c1);
1481
62.3k
  c->g[1] = (unsigned char) C565_green(c1);
1482
62.3k
  c->b[1] = (unsigned char) C565_blue(c1);
1483
1484
62.3k
  if (ignoreAlpha != MagickFalse || c0 > c1)
1485
24.5k
    {
1486
24.5k
      c->r[2] = (unsigned char) ((2 * c->r[0] + c->r[1]) / 3);
1487
24.5k
      c->g[2] = (unsigned char) ((2 * c->g[0] + c->g[1]) / 3);
1488
24.5k
      c->b[2] = (unsigned char) ((2 * c->b[0] + c->b[1]) / 3);
1489
1490
24.5k
      c->r[3] = (unsigned char) ((c->r[0] + 2 * c->r[1]) / 3);
1491
24.5k
      c->g[3] = (unsigned char) ((c->g[0] + 2 * c->g[1]) / 3);
1492
24.5k
      c->b[3] = (unsigned char) ((c->b[0] + 2 * c->b[1]) / 3);
1493
24.5k
    }
1494
37.7k
  else
1495
37.7k
    {
1496
37.7k
      c->r[2] = (unsigned char) ((c->r[0] + c->r[1]) / 2);
1497
37.7k
      c->g[2] = (unsigned char) ((c->g[0] + c->g[1]) / 2);
1498
37.7k
      c->b[2] = (unsigned char) ((c->b[0] + c->b[1]) / 2);
1499
1500
37.7k
      c->r[3] = c->g[3] = c->b[3] = 0;
1501
37.7k
      c->a[3] = 255;
1502
37.7k
    }
1503
62.3k
}
1504
1505
static MagickBooleanType ReadDXT1Pixels(Image *image,
1506
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1507
3.67k
{
1508
3.67k
  DDSColors
1509
3.67k
    colors;
1510
1511
3.67k
  Quantum
1512
3.67k
    *q;
1513
1514
3.67k
  ssize_t
1515
3.67k
    x;
1516
1517
3.67k
  size_t
1518
3.67k
    bits;
1519
1520
3.67k
  ssize_t
1521
3.67k
    y;
1522
1523
3.67k
  unsigned short
1524
3.67k
    c0,
1525
3.67k
    c1;
1526
1527
3.67k
  magick_unreferenced(dds_info);
1528
20.6k
  for (y = 0; y < (ssize_t) image->rows; y += 4)
1529
17.9k
  {
1530
69.5k
    for (x = 0; x < (ssize_t) image->columns; x += 4)
1531
52.5k
    {
1532
      /* Get 4x4 patch of pixels to write on */
1533
52.5k
      q=QueueAuthenticPixels(image,x,y,(size_t)
1534
52.5k
        (MagickMin(4,(ssize_t) image->columns-x)),(size_t)
1535
52.5k
        (MagickMin(4,(ssize_t) image->rows-y)),exception);
1536
1537
52.5k
      if (q == (Quantum *) NULL)
1538
0
        return(MagickFalse);
1539
1540
      /* Read 8 bytes of data from the image */
1541
52.5k
      c0=ReadBlobLSBShort(image);
1542
52.5k
      c1=ReadBlobLSBShort(image);
1543
52.5k
      bits=ReadBlobLSBLong(image);
1544
1545
52.5k
      CalculateColors(c0,c1,&colors,MagickFalse);
1546
52.5k
      if (EOFBlob(image) != MagickFalse)
1547
961
        return(MagickFalse);
1548
1549
      /* Write the pixels */
1550
51.5k
      if (SetDXT1Pixels(image,x,y,colors,bits,q) == MagickFalse)
1551
2.52k
        {
1552
          /* Correct alpha */
1553
2.52k
          SetImageAlpha(image,QuantumRange,exception);
1554
2.52k
          q=QueueAuthenticPixels(image,x,y,(size_t) MagickMin(4,(ssize_t)
1555
2.52k
            image->columns-x),(size_t) MagickMin(4,(ssize_t) image->rows-y),
1556
2.52k
            exception);
1557
2.52k
          if (q != (Quantum *) NULL)
1558
2.52k
            SetDXT1Pixels(image,x,y,colors,bits,q);
1559
2.52k
        }
1560
51.5k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
1561
0
        return(MagickFalse);
1562
51.5k
    }
1563
16.9k
    if (EOFBlob(image) != MagickFalse)
1564
0
      return(MagickFalse);
1565
16.9k
  }
1566
2.70k
  return(MagickTrue);
1567
3.67k
}
1568
1569
/*
1570
  Skip the mipmap images for compressed (DXTn) dds files
1571
*/
1572
static MagickBooleanType SkipMipmaps(Image *image,const DDSInfo *dds_info,
1573
  int texel_size,ExceptionInfo *exception)
1574
3.57k
{
1575
  /*
1576
    Only skip mipmaps for textures and cube maps
1577
  */
1578
3.57k
  if (EOFBlob(image) != MagickFalse)
1579
0
    {
1580
0
      ThrowFileException(exception,CorruptImageWarning,"UnexpectedEndOfFile",
1581
0
        image->filename);
1582
0
      return(MagickFalse);
1583
0
    }
1584
3.57k
  if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1585
1.81k
      && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1586
931
          || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1587
1.27k
    {
1588
1.27k
      MagickOffsetType
1589
1.27k
        offset;
1590
1591
1.27k
      size_t
1592
1.27k
        h,
1593
1.27k
        w;
1594
1595
1.27k
      ssize_t
1596
1.27k
        i;
1597
1598
1.27k
      w=DIV2(dds_info->width);
1599
1.27k
      h=DIV2(dds_info->height);
1600
1601
      /*
1602
        Mipmapcount includes the main image, so start from one
1603
      */
1604
3.13k
      for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1605
2.38k
      {
1606
2.38k
        offset=(MagickOffsetType) (((w+3U)/4U)*((h+3U)/4U)*(size_t)
1607
2.38k
          texel_size);
1608
2.38k
        if (SeekBlob(image,offset,SEEK_CUR) < 0)
1609
0
          break;
1610
2.38k
        if ((w == 1) && (h == 1))
1611
525
          break;
1612
1.85k
        w=DIV2(w);
1613
1.85k
        h=DIV2(h);
1614
1.85k
      }
1615
1.27k
    }
1616
3.57k
  return(MagickTrue);
1617
3.57k
}
1618
1619
static MagickBooleanType ReadDXT1(const ImageInfo *image_info,Image *image,
1620
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1621
  ExceptionInfo *exception)
1622
3.67k
{
1623
3.67k
  if (ReadDXT1Pixels(image,dds_info,exception) == MagickFalse)
1624
961
    return(MagickFalse);
1625
1626
2.70k
  if (read_mipmaps != MagickFalse)
1627
0
    return(ReadMipmaps(image_info,image,dds_info,ReadDXT1Pixels,exception));
1628
2.70k
  else
1629
2.70k
    return(SkipMipmaps(image,dds_info,8,exception));
1630
2.70k
}
1631
1632
static MagickBooleanType ReadDXT3Pixels(Image *image,
1633
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1634
354
{
1635
354
  DDSColors
1636
354
    colors;
1637
1638
354
  Quantum
1639
354
    *q;
1640
1641
354
  ssize_t
1642
354
    i,
1643
354
    x;
1644
1645
354
  unsigned char
1646
354
    alpha;
1647
1648
354
  size_t
1649
354
    a0,
1650
354
    a1,
1651
354
    bits,
1652
354
    code;
1653
1654
354
  ssize_t
1655
354
    j,
1656
354
    y;
1657
1658
354
  unsigned short
1659
354
    c0,
1660
354
    c1;
1661
1662
354
  magick_unreferenced(dds_info);
1663
2.17k
  for (y = 0; y < (ssize_t) image->rows; y += 4)
1664
2.00k
  {
1665
5.70k
    for (x = 0; x < (ssize_t) image->columns; x += 4)
1666
3.87k
    {
1667
      /* Get 4x4 patch of pixels to write on */
1668
3.87k
      q = QueueAuthenticPixels(image, x, y, (size_t)
1669
3.87k
        MagickMin(4, (ssize_t) image->columns - x),(size_t)
1670
3.87k
        MagickMin(4, (ssize_t) image->rows - y),exception);
1671
1672
3.87k
      if (q == (Quantum *) NULL)
1673
0
        return(MagickFalse);
1674
1675
      /* Read alpha values (8 bytes) */
1676
3.87k
      a0 = ReadBlobLSBLong(image);
1677
3.87k
      a1 = ReadBlobLSBLong(image);
1678
1679
      /* Read 8 bytes of data from the image */
1680
3.87k
      c0 = ReadBlobLSBShort(image);
1681
3.87k
      c1 = ReadBlobLSBShort(image);
1682
3.87k
      bits = ReadBlobLSBLong(image);
1683
1684
3.87k
      CalculateColors(c0, c1, &colors, MagickTrue);
1685
1686
3.87k
      if (EOFBlob(image) != MagickFalse)
1687
180
        return(MagickFalse);
1688
1689
      /* Write the pixels */
1690
18.4k
      for (j = 0; j < 4; j++)
1691
14.7k
      {
1692
73.9k
        for (i = 0; i < 4; i++)
1693
59.1k
        {
1694
59.1k
          if ((x + i) < (ssize_t) image->columns && (y + j) < (ssize_t) image->rows)
1695
37.3k
            {
1696
37.3k
              code = (bits >> ((4*j+i)*2)) & 0x3;
1697
37.3k
              SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1698
37.3k
              SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1699
37.3k
              SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1700
              /*
1701
                Extract alpha value: multiply 0..15 by 17 to get range 0..255
1702
              */
1703
37.3k
              if (j < 2)
1704
20.3k
                alpha = 17U * (unsigned char) ((a0 >> (4*(4*j+i))) & 0xf);
1705
17.0k
              else
1706
17.0k
                alpha = 17U * (unsigned char) ((a1 >> (4*(4*(j-2)+i))) & 0xf);
1707
37.3k
              SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) alpha),q);
1708
37.3k
              q+=(ptrdiff_t) GetPixelChannels(image);
1709
37.3k
            }
1710
59.1k
        }
1711
14.7k
      }
1712
3.69k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
1713
0
        return(MagickFalse);
1714
3.69k
    }
1715
1.82k
    if (EOFBlob(image) != MagickFalse)
1716
0
      return(MagickFalse);
1717
1.82k
  }
1718
174
  return(MagickTrue);
1719
354
}
1720
1721
static MagickBooleanType ReadDXT3(const ImageInfo *image_info,Image *image,
1722
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1723
  ExceptionInfo *exception)
1724
354
{
1725
354
  if (ReadDXT3Pixels(image,dds_info,exception) == MagickFalse)
1726
180
    return(MagickFalse);
1727
1728
174
  if (read_mipmaps != MagickFalse)
1729
0
    return(ReadMipmaps(image_info,image,dds_info,ReadDXT3Pixels,exception));
1730
174
  else
1731
174
    return(SkipMipmaps(image,dds_info,16,exception));
1732
174
}
1733
1734
static MagickBooleanType ReadDXT5Pixels(Image *image,
1735
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1736
463
{
1737
463
  DDSColors
1738
463
    colors;
1739
1740
463
  MagickSizeType
1741
463
    alpha_bits;
1742
1743
463
  Quantum
1744
463
    *q;
1745
1746
463
  ssize_t
1747
463
    i,
1748
463
    x;
1749
1750
463
  unsigned char
1751
463
    a0,
1752
463
    a1;
1753
1754
463
  size_t
1755
463
    alpha,
1756
463
    bits,
1757
463
    code,
1758
463
    alpha_code;
1759
1760
463
  ssize_t
1761
463
    j,
1762
463
    y;
1763
1764
463
  unsigned short
1765
463
    c0,
1766
463
    c1;
1767
1768
463
  magick_unreferenced(dds_info);
1769
3.13k
  for (y = 0; y < (ssize_t) image->rows; y += 4)
1770
2.92k
  {
1771
8.58k
    for (x = 0; x < (ssize_t) image->columns; x += 4)
1772
5.91k
    {
1773
      /* Get 4x4 patch of pixels to write on */
1774
5.91k
      q = QueueAuthenticPixels(image, x, y, (size_t) MagickMin(4, (ssize_t) image->columns - x),(size_t)
1775
5.91k
       MagickMin(4, (ssize_t) image->rows - y),exception);
1776
1777
5.91k
      if (q == (Quantum *) NULL)
1778
0
        return(MagickFalse);
1779
1780
      /* Read alpha values (8 bytes) */
1781
5.91k
      a0 = (unsigned char) ReadBlobByte(image);
1782
5.91k
      a1 = (unsigned char) ReadBlobByte(image);
1783
1784
5.91k
      alpha_bits = (MagickSizeType)ReadBlobLSBLong(image);
1785
5.91k
      alpha_bits = alpha_bits | ((MagickSizeType)ReadBlobLSBShort(image) << 32);
1786
1787
      /* Read 8 bytes of data from the image */
1788
5.91k
      c0 = ReadBlobLSBShort(image);
1789
5.91k
      c1 = ReadBlobLSBShort(image);
1790
5.91k
      bits = ReadBlobLSBLong(image);
1791
1792
5.91k
      CalculateColors(c0, c1, &colors, MagickTrue);
1793
5.91k
      if (EOFBlob(image) != MagickFalse)
1794
255
        return(MagickFalse);
1795
1796
      /* Write the pixels */
1797
28.3k
      for (j = 0; j < 4; j++)
1798
22.6k
      {
1799
113k
        for (i = 0; i < 4; i++)
1800
90.5k
        {
1801
90.5k
          if ((x + i) < (ssize_t) image->columns &&
1802
68.9k
              (y + j) < (ssize_t) image->rows)
1803
53.7k
            {
1804
53.7k
              code = (bits >> ((4*j+i)*2)) & 0x3;
1805
53.7k
              SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1806
53.7k
              SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1807
53.7k
              SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1808
              /* Extract alpha value */
1809
53.7k
              alpha_code = (size_t) (alpha_bits >> (3*(4*j+i))) & 0x7;
1810
53.7k
              if (alpha_code == 0)
1811
18.4k
                alpha = a0;
1812
35.3k
              else if (alpha_code == 1)
1813
4.48k
                alpha = a1;
1814
30.8k
              else if (a0 > a1)
1815
5.76k
                alpha = ((8-alpha_code) * a0 + (alpha_code-1) * a1) / 7;
1816
25.0k
              else if (alpha_code == 6)
1817
3.42k
                alpha = 0;
1818
21.6k
              else if (alpha_code == 7)
1819
9.07k
                alpha = 255;
1820
12.6k
              else
1821
12.6k
                alpha = (((6-alpha_code) * a0 + (alpha_code-1) * a1) / 5);
1822
53.7k
              SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) alpha),q);
1823
53.7k
              q+=(ptrdiff_t) GetPixelChannels(image);
1824
53.7k
            }
1825
90.5k
        }
1826
22.6k
      }
1827
5.66k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
1828
0
        return(MagickFalse);
1829
5.66k
    }
1830
2.67k
    if (EOFBlob(image) != MagickFalse)
1831
0
      return(MagickFalse);
1832
2.67k
  }
1833
208
  return(MagickTrue);
1834
463
}
1835
1836
static MagickBooleanType ReadDXT5(const ImageInfo *image_info,Image *image,
1837
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1838
  ExceptionInfo *exception)
1839
463
{
1840
463
  if (ReadDXT5Pixels(image,dds_info,exception) == MagickFalse)
1841
255
    return(MagickFalse);
1842
1843
208
  if (read_mipmaps != MagickFalse)
1844
0
    return(ReadMipmaps(image_info,image,dds_info,ReadDXT5Pixels,exception));
1845
208
  else
1846
208
    return(SkipMipmaps(image,dds_info,16,exception));
1847
208
}
1848
1849
static unsigned char GetBit(const unsigned char *block,size_t *start_bit)
1850
102k
{
1851
102k
  size_t
1852
102k
    base,
1853
102k
    index;
1854
1855
102k
  index=(*start_bit) >> 3;
1856
102k
  base=(*start_bit) - (index << 3);
1857
102k
  (*start_bit)++;
1858
102k
  if (index > 15)
1859
0
    return(0);
1860
102k
  return((block[index] >> base) & 0x01);
1861
102k
}
1862
1863
static unsigned char GetBits(const unsigned char *block,size_t *start_bit,
1864
  unsigned char num_bits)
1865
682k
{
1866
682k
  size_t
1867
682k
    base,
1868
682k
    first_bits,
1869
682k
    index,
1870
682k
    next_bits;
1871
1872
682k
  unsigned char
1873
682k
    ret;
1874
1875
682k
  index=(*start_bit) >> 3;
1876
682k
  base=(*start_bit)-(index << 3);
1877
682k
  if (index > 15)
1878
0
    return(0);
1879
682k
  if (base + num_bits > 8)
1880
209k
    {
1881
209k
      first_bits=8-base;
1882
209k
      next_bits=num_bits-first_bits;
1883
209k
      ret=((block[index] >> base) | (((block[index + 1]) &
1884
209k
        ((1u << next_bits) - 1)) << first_bits));
1885
209k
    }
1886
472k
  else
1887
472k
    {
1888
472k
      ret=((block[index] >> base) & ((1 << num_bits) - 1));
1889
472k
    }
1890
682k
  (*start_bit)+=num_bits;
1891
682k
  return(ret);
1892
682k
}
1893
1894
static MagickBooleanType IsPixelAnchorIndex(unsigned char subset_index,
1895
  unsigned char num_subsets,size_t pixelIndex,unsigned char partition_id)
1896
234k
{
1897
234k
  size_t
1898
234k
    table_index;
1899
1900
  /* for first subset */
1901
234k
  if (subset_index == 0)
1902
155k
    table_index=0;
1903
  /* for second subset of two subset partitioning */
1904
79.5k
  else if ((subset_index == 1) && (num_subsets == 2))
1905
37.7k
    table_index=1;
1906
  /* for second subset of three subset partitioning */
1907
41.8k
  else if ((subset_index == 1) && (num_subsets == 3))
1908
18.4k
    table_index=2;
1909
  /* for third subset of three subset partitioning */
1910
23.3k
  else
1911
23.3k
    table_index=3;
1912
1913
234k
  if (BC7_anchor_index_table[table_index][partition_id] == pixelIndex)
1914
27.1k
    return(MagickTrue);
1915
207k
  else
1916
207k
    return(MagickFalse);
1917
234k
}
1918
1919
static void ReadEndpoints(BC7Colors *endpoints,const unsigned char *block,
1920
  size_t mode,size_t *start_bit)
1921
14.6k
{
1922
14.6k
  MagickBooleanType
1923
14.6k
    has_alpha,
1924
14.6k
    has_pbits;
1925
1926
14.6k
  unsigned char
1927
14.6k
    alpha_bits,
1928
14.6k
    color_bits,
1929
14.6k
    pbit,
1930
14.6k
    pbit0,
1931
14.6k
    pbit1;
1932
1933
14.6k
  size_t
1934
14.6k
    num_subsets,
1935
14.6k
    i;
1936
1937
14.6k
  num_subsets=(size_t) BC7_mode_info[mode].num_subsets;
1938
14.6k
  color_bits=BC7_mode_info[mode].color_precision;
1939
1940
  /* red */
1941
68.9k
  for (i=0; i < num_subsets * 2; i++)
1942
54.2k
    endpoints->r[i]=GetBits(block,start_bit,color_bits);
1943
1944
  /* green */
1945
68.9k
  for (i=0; i < num_subsets * 2; i++)
1946
54.2k
    endpoints->g[i]=GetBits(block,start_bit,color_bits);
1947
1948
  /* blue */
1949
68.9k
  for (i=0; i < num_subsets * 2; i++)
1950
54.2k
    endpoints->b[i]=GetBits(block,start_bit,color_bits);
1951
1952
  /* alpha */
1953
68.9k
  for (i=0; i < num_subsets * 2; i++)
1954
54.2k
    endpoints->a[i]=255;
1955
14.6k
  alpha_bits=BC7_mode_info[mode].alpha_precision;
1956
14.6k
  has_alpha=mode >= 4 ? MagickTrue : MagickFalse;
1957
1958
14.6k
  if (has_alpha != MagickFalse)
1959
7.99k
    {
1960
27.3k
      for (i=0; i < num_subsets * 2; i++)
1961
19.4k
        endpoints->a[i]=GetBits(block,start_bit,alpha_bits);
1962
7.99k
    }
1963
1964
  /* handle modes that have p bits */
1965
14.6k
  has_pbits=(mode == 0) || (mode == 1) || (mode == 3) || (mode == 6) || (mode == 7) ? MagickTrue : MagickFalse;
1966
1967
14.6k
  if (has_pbits != MagickFalse)
1968
7.81k
    {
1969
42.7k
      for (i=0; i < num_subsets * 2; i++)
1970
34.8k
      {
1971
34.8k
        endpoints->r[i] <<= 1;
1972
34.8k
        endpoints->g[i] <<= 1;
1973
34.8k
        endpoints->b[i] <<= 1;
1974
34.8k
        endpoints->a[i] <<= 1;
1975
34.8k
      }
1976
1977
      /* mode 1 shares a p-bit for both endpoints */
1978
7.81k
      if (mode == 1)
1979
1.23k
        {
1980
1.23k
          pbit0=GetBit(block,start_bit);
1981
1.23k
          pbit1=GetBit(block,start_bit);
1982
1983
1.23k
          endpoints->r[0] |= pbit0;
1984
1.23k
          endpoints->g[0] |= pbit0;
1985
1.23k
          endpoints->b[0] |= pbit0;
1986
1.23k
          endpoints->r[1] |= pbit0;
1987
1.23k
          endpoints->g[1] |= pbit0;
1988
1.23k
          endpoints->b[1] |= pbit0;
1989
1990
1.23k
          endpoints->r[2] |= pbit1;
1991
1.23k
          endpoints->g[2] |= pbit1;
1992
1.23k
          endpoints->b[2] |= pbit1;
1993
1.23k
          endpoints->r[3] |= pbit1;
1994
1.23k
          endpoints->g[3] |= pbit1;
1995
1.23k
          endpoints->b[3] |= pbit1;
1996
1.23k
        }
1997
6.57k
      else
1998
6.57k
      {
1999
36.5k
        for (i=0; i < num_subsets * 2; i++)
2000
29.9k
        {
2001
29.9k
          pbit=GetBit(block,start_bit);
2002
29.9k
          endpoints->r[i] |= pbit;
2003
29.9k
          endpoints->g[i] |= pbit;
2004
29.9k
          endpoints->b[i] |= pbit;
2005
29.9k
          endpoints->a[i] |= pbit;
2006
29.9k
        }
2007
6.57k
      }
2008
7.81k
    }
2009
2010
  /* 1 bit increased due to the pbit */
2011
14.6k
  if (has_pbits != MagickFalse)
2012
7.81k
    {
2013
7.81k
      color_bits++;
2014
7.81k
      alpha_bits++;
2015
7.81k
    }
2016
2017
  /* color and alpha bit shifting so that MSB lies in bit 7 */
2018
68.9k
  for (i=0; i < num_subsets * 2; i++)
2019
54.2k
  {
2020
54.2k
    endpoints->r[i] <<= (8 - color_bits);
2021
54.2k
    endpoints->g[i] <<= (8 - color_bits);
2022
54.2k
    endpoints->b[i] <<= (8 - color_bits);
2023
54.2k
    endpoints->a[i] <<= (8 - alpha_bits);
2024
2025
54.2k
    endpoints->r[i]=endpoints->r[i] | (endpoints->r[i] >> color_bits);
2026
54.2k
    endpoints->g[i]=endpoints->g[i] | (endpoints->g[i] >> color_bits);
2027
54.2k
    endpoints->b[i]=endpoints->b[i] | (endpoints->b[i] >> color_bits);
2028
54.2k
    endpoints->a[i]=endpoints->a[i] | (endpoints->a[i] >> alpha_bits);
2029
54.2k
  }
2030
2031
14.6k
  if (has_alpha == MagickFalse)
2032
6.68k
    {
2033
41.5k
      for (i=0; i < num_subsets * 2; i++)
2034
34.8k
        endpoints->a[i]=255;
2035
6.68k
    }
2036
14.6k
}
2037
2038
static MagickBooleanType ReadBC5Pixels(Image *image,
2039
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
2040
527
{
2041
527
  BC5Colors
2042
527
    colors = { { 0 }, { 0 } };
2043
2044
527
  Quantum
2045
527
    *q;
2046
2047
527
  size_t
2048
527
    start_bit_g,
2049
527
    start_bit_r;
2050
2051
527
  ssize_t
2052
527
    i,
2053
527
    x,
2054
527
    y;
2055
2056
527
  unsigned char
2057
527
    block[16],
2058
527
    mode;
2059
2060
527
  magick_unreferenced(dds_info);
2061
3.42k
  for (y = 0; y < (ssize_t)image->rows; y += 4)
2062
3.23k
  {
2063
11.6k
    for (x = 0; x < (ssize_t)image->columns; x += 4)
2064
8.75k
    {
2065
8.75k
      size_t
2066
8.75k
        area;
2067
2068
8.75k
      ssize_t
2069
8.75k
        count;
2070
2071
      /* Get 4x4 patch of pixels to write on */
2072
8.75k
      q=QueueAuthenticPixels(image,x,y,(size_t)
2073
8.75k
        MagickMin(4,(ssize_t) image->columns-x),(size_t)
2074
8.75k
        MagickMin(4,(ssize_t) image->rows-y),exception);
2075
2076
8.75k
      if (q == (Quantum *)NULL)
2077
0
        return(MagickFalse);
2078
2079
      /* Read 16 bytes of data from the image */
2080
8.75k
      count=ReadBlob(image,16,block);
2081
8.75k
      if ((count != 16) || (EOFBlob(image) != MagickFalse))
2082
334
        return(MagickFalse);
2083
2084
      /* Get the mode of the block, 6 colors or 4 colors */
2085
8.41k
      colors.r[0]=block[0];
2086
8.41k
      colors.r[1]=block[1];
2087
8.41k
      colors.g[0]=block[8];
2088
8.41k
      colors.g[1]=block[9];
2089
2090
      /* Red palette */
2091
8.41k
      mode=4;
2092
8.41k
      if (colors.r[0] > colors.r[1])
2093
2.74k
        mode=6;
2094
47.5k
      for (i = 0; i < mode; i++)
2095
39.1k
      {
2096
39.1k
        colors.r[i+2]=(unsigned char) (((mode-i)*(float)colors.r[0]+(i+1)*
2097
39.1k
          (float)colors.r[1])/((float)(mode+1)));
2098
39.1k
      }
2099
8.41k
      if (mode == 4)
2100
5.67k
        {
2101
5.67k
          colors.r[6]=0;
2102
5.67k
          colors.r[7]=255;
2103
5.67k
        }
2104
2105
      /* Green palette */
2106
8.41k
      mode=4;
2107
8.41k
      if (colors.g[0] > colors.g[1])
2108
2.80k
        mode=6;
2109
47.6k
      for (i = 0; i < mode; i++)
2110
39.2k
      {
2111
39.2k
        colors.g[i+2]=(unsigned char) (((mode-i)*(float)colors.g[0]+(i+1)*
2112
39.2k
          (float)colors.g[1])/((float)(mode+1)));
2113
39.2k
      }
2114
8.41k
      if (mode == 4) {
2115
5.61k
        colors.g[6]=0;
2116
5.61k
        colors.g[7]=255;
2117
5.61k
      }
2118
2119
      /* Write the pixels */
2120
8.41k
      area=(size_t) (MagickMin(MagickMin(4,(ssize_t) image->columns-x)*
2121
8.41k
        MagickMin(4,(ssize_t) image->rows-y),16));
2122
8.41k
      start_bit_r=16;
2123
8.41k
      start_bit_g=80;
2124
92.1k
      for (i = 0; i < (ssize_t) area; i++)
2125
83.6k
      {
2126
83.6k
        SetPixelRed(image,ScaleCharToQuantum(colors.r[GetBits(block,
2127
83.6k
          &start_bit_r,3)]),q);
2128
83.6k
        SetPixelGreen(image,ScaleCharToQuantum(colors.g[GetBits(block,
2129
83.6k
          &start_bit_g,3)]),q);
2130
83.6k
        SetPixelBlue(image,(Quantum) 0,q);
2131
2132
83.6k
        q+=(ptrdiff_t) GetPixelChannels(image);
2133
83.6k
      }
2134
8.41k
      if (SyncAuthenticPixels(image, exception) == MagickFalse)
2135
0
        return(MagickFalse);
2136
8.41k
    }
2137
2.89k
    if (EOFBlob(image) != MagickFalse)
2138
0
      return(MagickFalse);
2139
2.89k
  }
2140
193
  return(MagickTrue);
2141
527
}
2142
2143
static MagickBooleanType ReadBC5(const ImageInfo *image_info,Image *image,
2144
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2145
  ExceptionInfo *exception)
2146
527
{
2147
527
  if (ReadBC5Pixels(image,dds_info,exception) == MagickFalse)
2148
334
    return(MagickFalse);
2149
2150
193
  if (read_mipmaps != MagickFalse)
2151
0
    return(ReadMipmaps(image_info,image,dds_info,ReadBC5Pixels,exception));
2152
193
  else
2153
193
    return(SkipMipmaps(image,dds_info,16,exception));
2154
193
}
2155
2156
static MagickBooleanType ReadBC7Pixels(Image *image,
2157
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
2158
849
{
2159
849
  BC7Colors
2160
849
    colors = { { 0 }, { 0 }, { 0 }, { 0 } };
2161
2162
849
  Quantum
2163
849
    *q;
2164
2165
849
  size_t
2166
849
    mode,
2167
849
    start_bit;
2168
2169
849
  ssize_t
2170
849
    count,
2171
849
    i,
2172
849
    x,
2173
849
    y;
2174
2175
849
  unsigned char
2176
849
    a,
2177
849
    alpha_indices[16],
2178
849
    b,
2179
849
    block[16],
2180
849
    c0,
2181
849
    c1,
2182
849
    color_indices[16],
2183
849
    g,
2184
849
    index_prec,
2185
849
    index2_prec,
2186
849
    num_bits,
2187
849
    num_subsets,
2188
849
    partition_id,
2189
849
    r,
2190
849
    rotation,
2191
849
    selector_bit,
2192
849
    subset_indices[16],
2193
849
    weight;
2194
2195
849
  magick_unreferenced(dds_info);
2196
2197
849
  memset(alpha_indices,0,sizeof(alpha_indices));
2198
849
  memset(block,0,sizeof(block));
2199
849
  memset(color_indices,0,sizeof(color_indices));
2200
849
  memset(subset_indices,0,sizeof(subset_indices));
2201
2202
4.19k
  for (y = 0; y < (ssize_t) image->rows; y += 4)
2203
3.90k
  {
2204
18.5k
    for (x = 0; x < (ssize_t) image->columns; x += 4)
2205
15.2k
    {
2206
15.2k
      size_t
2207
15.2k
        area;
2208
2209
      /* Get 4x4 patch of pixels to write on */
2210
15.2k
      q=QueueAuthenticPixels(image,x,y,(size_t)
2211
15.2k
        MagickMin(4,(ssize_t) image->columns-x),(size_t)
2212
15.2k
        MagickMin(4,(ssize_t) image->rows-y),exception);
2213
2214
15.2k
      if (q == (Quantum *) NULL)
2215
0
        return(MagickFalse);
2216
2217
      /* Read 16 bytes of data from the image */
2218
15.2k
      count=ReadBlob(image,16,block);
2219
      
2220
15.2k
      if (count != 16)
2221
544
        return(MagickFalse);
2222
2223
14.6k
      if (EOFBlob(image) != MagickFalse)
2224
0
        return(MagickFalse);
2225
2226
      /* Get the mode of the block */
2227
14.6k
      start_bit=0;
2228
62.9k
      while (start_bit <= 8 && !GetBit(block, &start_bit)) {}
2229
14.6k
      mode=start_bit-1;
2230
2231
14.6k
      if (mode > 7)
2232
13
        return(MagickFalse);
2233
2234
14.6k
      num_subsets=BC7_mode_info[mode].num_subsets;
2235
14.6k
      partition_id=0;
2236
2237
      /* only these modes have more than 1 subset */
2238
14.6k
      if ((mode == 0) || (mode == 1) || (mode == 2) || (mode == 3) || (mode == 7))
2239
8.39k
        {
2240
8.39k
          partition_id=GetBits(block,&start_bit,BC7_mode_info[mode].partition_bits);
2241
8.39k
          if (partition_id > 63)
2242
0
            return(MagickFalse);
2243
8.39k
        }
2244
2245
14.6k
      rotation=0;
2246
14.6k
      if ((mode == 4) || (mode == 5))
2247
5.45k
        rotation=GetBits(block,&start_bit,2);
2248
      
2249
14.6k
      selector_bit=0;
2250
14.6k
      if (mode == 4)
2251
4.31k
        selector_bit=GetBit(block, &start_bit);
2252
2253
14.6k
      ReadEndpoints(&colors,block,mode,&start_bit);
2254
2255
14.6k
      index_prec=BC7_mode_info[mode].index_precision;
2256
14.6k
      index2_prec=BC7_mode_info[mode].index2_precision;
2257
2258
14.6k
      if ((mode == 4) && (selector_bit == 1))
2259
2.80k
        {
2260
2.80k
          index_prec=3;
2261
2.80k
          alpha_indices[0]=GetBit(block,&start_bit);
2262
44.9k
          for (i = 1; i < 16; i++)
2263
42.1k
            alpha_indices[i]=GetBits(block,&start_bit,2);
2264
2.80k
        }
2265
2266
      /* get color and subset indices */
2267
249k
      for (i=0; i < 16; i++)
2268
234k
      {
2269
234k
        subset_indices[i]=GetSubsetIndex(num_subsets,partition_id,(size_t) i);
2270
234k
        num_bits=index_prec;
2271
234k
        if (IsPixelAnchorIndex(subset_indices[i],num_subsets,(size_t) i,partition_id))
2272
27.1k
          num_bits--;
2273
234k
        color_indices[i]=GetBits(block,&start_bit,num_bits);
2274
234k
      }
2275
2276
      /* get alpha indices if the block has it */
2277
14.6k
      if ((mode == 5) || ((mode == 4) && (selector_bit == 0)))
2278
2.64k
        {
2279
2.64k
          alpha_indices[0]=GetBits(block,&start_bit,index2_prec - 1);
2280
42.3k
          for (i=1; i < 16; i++)
2281
39.7k
            alpha_indices[i]=GetBits(block,&start_bit,index2_prec);
2282
2.64k
        }
2283
2284
      /* Write the pixels */
2285
14.6k
      area=(size_t) (MagickMin(MagickMin(4,(ssize_t) image->columns-x)*
2286
14.6k
        MagickMin(4,(ssize_t) image->rows-y),16));
2287
180k
      for (i=0; i < (ssize_t) area; i++)
2288
165k
      {
2289
165k
        unsigned char
2290
165k
          c2;
2291
2292
165k
        c0=2 * subset_indices[i];
2293
165k
        c1=(2 * subset_indices[i]) + 1;
2294
165k
        c2=color_indices[i];
2295
2296
165k
        weight=64;
2297
        /* Color Interpolation */
2298
165k
        switch(index_prec)
2299
165k
        {
2300
89.3k
          case 2:
2301
89.3k
            if (c2 < sizeof(BC7_weight2))
2302
89.3k
              weight=BC7_weight2[c2];
2303
89.3k
            break;
2304
67.2k
          case 3:
2305
67.2k
            if (c2 < sizeof(BC7_weight3))
2306
67.2k
              weight=BC7_weight3[c2];
2307
67.2k
            break;
2308
9.13k
          default:
2309
9.13k
            if (c2 < sizeof(BC7_weight4))
2310
9.13k
              weight=BC7_weight4[c2];
2311
165k
        }
2312
165k
        r=((64 - weight) * colors.r[c0] + weight * colors.r[c1] + 32) >> 6;
2313
165k
        g=((64 - weight) * colors.g[c0] + weight * colors.g[c1] + 32) >> 6;
2314
165k
        b=((64 - weight) * colors.b[c0] + weight * colors.b[c1] + 32) >> 6;
2315
165k
        a=((64 - weight) * colors.a[c0] + weight * colors.a[c1] + 32) >> 6;
2316
2317
        /* Interpolate alpha for mode 4 and 5 blocks */
2318
165k
        if (mode == 4 || mode == 5)
2319
62.7k
          {
2320
62.7k
            unsigned char
2321
62.7k
              a0;
2322
2323
62.7k
            a0=alpha_indices[i];
2324
62.7k
            if (a0 < sizeof(BC7_weight2))
2325
57.2k
              weight=BC7_weight2[a0];
2326
62.7k
            if ((mode == 4) && (selector_bit == 0) && (a0 < sizeof(BC7_weight3)))
2327
18.2k
              weight=BC7_weight3[a0];
2328
62.7k
            if ((c0 < sizeof(colors.a)) && (c1 < sizeof(colors.a)))
2329
62.7k
              a=((64 - weight) * colors.a[c0] + weight * colors.a[c1] + 32) >> 6;
2330
62.7k
          }
2331
165k
        switch (rotation)
2332
165k
        {
2333
27.5k
          case 1:
2334
27.5k
            Swap(a,r);
2335
27.5k
            break;
2336
6.33k
          case 2:
2337
6.33k
            Swap(a,g);
2338
6.33k
            break;
2339
10.1k
          case 3:
2340
10.1k
            Swap(a,b);
2341
10.1k
            break;
2342
165k
        }
2343
2344
165k
        SetPixelRed(image,ScaleCharToQuantum((unsigned char)r),q);
2345
165k
        SetPixelGreen(image,ScaleCharToQuantum((unsigned char)g),q);
2346
165k
        SetPixelBlue(image,ScaleCharToQuantum((unsigned char)b),q);
2347
165k
        SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)a),q);
2348
2349
165k
        q+=(ptrdiff_t) GetPixelChannels(image);
2350
165k
      }
2351
14.6k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
2352
0
        return(MagickFalse);
2353
14.6k
    }
2354
3.34k
    if (EOFBlob(image) != MagickFalse)
2355
0
      return(MagickFalse);
2356
3.34k
  }
2357
292
  return(MagickTrue);
2358
849
}
2359
2360
static MagickBooleanType ReadBC7(const ImageInfo *image_info,Image *image,
2361
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2362
  ExceptionInfo *exception)
2363
849
{
2364
849
  if (ReadBC7Pixels(image,dds_info,exception) == MagickFalse)
2365
557
    return(MagickFalse);
2366
2367
292
  if (read_mipmaps != MagickFalse)
2368
0
    return(ReadMipmaps(image_info,image,dds_info,ReadBC7Pixels,exception));
2369
292
  else
2370
292
    return(SkipMipmaps(image,dds_info,16,exception));
2371
292
}
2372
2373
static MagickBooleanType ReadUncompressedRGBPixels(Image *image,
2374
  const DDSInfo *dds_info,ExceptionInfo *exception)
2375
3.93k
{
2376
3.93k
  MagickBooleanType
2377
3.93k
    is_rgb;
2378
2379
3.93k
  Quantum
2380
3.93k
    *q;
2381
2382
3.93k
  ssize_t
2383
3.93k
    x,
2384
3.93k
    y;
2385
2386
3.93k
  unsigned short
2387
3.93k
    color;
2388
2389
3.93k
  is_rgb=IsBitMask(dds_info->pixelformat,0x000000ff,0x0000ff00,0x00ff0000,0x0000000) ? MagickTrue : MagickFalse;
2390
122k
  for (y = 0; y < (ssize_t) image->rows; y++)
2391
120k
  {
2392
120k
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2393
2394
120k
    if (q == (Quantum *) NULL)
2395
0
      return(MagickFalse);
2396
2397
826k
    for (x = 0; x < (ssize_t) image->columns; x++)
2398
706k
    {
2399
706k
      if ((dds_info->pixelformat.rgb_bitcount == 8) ||
2400
321k
          (dds_info->extFormat == DXGI_FORMAT_R8_UNORM))
2401
396k
        SetPixelGray(image,ScaleCharToQuantum((unsigned char) ReadBlobByte(image)),q);
2402
310k
      else if ((dds_info->pixelformat.rgb_bitcount == 16) ||
2403
304k
               (dds_info->extFormat == DXGI_FORMAT_B5G6R5_UNORM))
2404
10.3k
        {
2405
10.3k
           color=ReadBlobShort(image);
2406
10.3k
           SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2407
10.3k
             (((color >> 11)/31.0)*255)),q);
2408
10.3k
           SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2409
10.3k
             ((((unsigned short)(color << 5) >> 10)/63.0)*255)),q);
2410
10.3k
           SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2411
10.3k
             ((((unsigned short)(color << 11) >> 11)/31.0)*255)),q);
2412
10.3k
        }
2413
299k
      else
2414
299k
        {
2415
299k
          if (is_rgb != MagickFalse)
2416
1.26k
            {
2417
1.26k
              SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2418
1.26k
                ReadBlobByte(image)),q);
2419
1.26k
              SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2420
1.26k
                ReadBlobByte(image)),q);
2421
1.26k
              SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2422
1.26k
                ReadBlobByte(image)),q);
2423
1.26k
            }
2424
298k
          else
2425
298k
            {
2426
298k
              SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2427
298k
                ReadBlobByte(image)),q);
2428
298k
              SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2429
298k
                ReadBlobByte(image)),q);
2430
298k
              SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2431
298k
                ReadBlobByte(image)),q);
2432
298k
            }
2433
299k
          if (dds_info->pixelformat.rgb_bitcount == 32 || 
2434
290k
              dds_info->extFormat == DXGI_FORMAT_B8G8R8X8_UNORM)
2435
13.1k
            (void) ReadBlobByte(image);
2436
299k
        }
2437
706k
      q+=(ptrdiff_t) GetPixelChannels(image);
2438
706k
    }
2439
120k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
2440
0
      return(MagickFalse);
2441
120k
    if (EOFBlob(image) != MagickFalse)
2442
1.64k
      return(MagickFalse);
2443
120k
  }
2444
2.28k
  return(MagickTrue);
2445
3.93k
}
2446
2447
static MagickBooleanType ReadUncompressedAlphaPixels(Image *image,
2448
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
2449
1.68k
{
2450
1.68k
  Quantum
2451
1.68k
    *q;
2452
2453
1.68k
  ssize_t
2454
1.68k
    x,
2455
1.68k
    y;
2456
2457
1.68k
  magick_unreferenced(dds_info);
2458
32.1k
  for (y = 0; y < (ssize_t) image->rows; y++)
2459
30.8k
  {
2460
30.8k
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2461
2462
30.8k
    if (q == (Quantum *) NULL)
2463
0
      return(MagickFalse);
2464
2465
175k
    for (x = 0; x < (ssize_t) image->columns; x++)
2466
144k
    {
2467
144k
      SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2468
144k
        ReadBlobByte(image)),q);
2469
144k
      q+=(ptrdiff_t) GetPixelChannels(image);
2470
144k
    }
2471
30.8k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
2472
0
      return(MagickFalse);
2473
30.8k
    if (EOFBlob(image) != MagickFalse)
2474
385
      return(MagickFalse);
2475
30.8k
  }
2476
1.30k
  return(MagickTrue);
2477
1.68k
}
2478
2479
/*
2480
  Skip the mipmap images for uncompressed (RGB or RGBA) dds files
2481
*/
2482
static MagickBooleanType SkipRGBMipmaps(Image *image,const DDSInfo *dds_info,
2483
  int pixel_size,ExceptionInfo *exception)
2484
4.19k
{
2485
  /*
2486
    Only skip mipmaps for textures and cube maps
2487
  */
2488
4.19k
  if (EOFBlob(image) != MagickFalse)
2489
0
    {
2490
0
      ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
2491
0
        image->filename);
2492
0
      return(MagickFalse);
2493
0
    }
2494
4.19k
  if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
2495
2.17k
      && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
2496
1.02k
          || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
2497
1.76k
    {
2498
1.76k
      MagickOffsetType
2499
1.76k
        offset;
2500
  
2501
1.76k
      ssize_t
2502
1.76k
        i;
2503
2504
1.76k
      size_t
2505
1.76k
        h,
2506
1.76k
        w;
2507
2508
1.76k
      w=DIV2(dds_info->width);
2509
1.76k
      h=DIV2(dds_info->height);
2510
2511
      /*
2512
        Mipmapcount includes the main image, so start from one
2513
      */
2514
4.14k
      for (i=1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
2515
3.47k
      {
2516
3.47k
        offset=(MagickOffsetType) (w*h*(size_t) pixel_size);
2517
3.47k
        if (SeekBlob(image,offset,SEEK_CUR) < 0)
2518
0
          break;
2519
3.47k
        w=DIV2(w);
2520
3.47k
        h=DIV2(h);
2521
3.47k
        if ((w == 1) && (h == 1))
2522
1.09k
          break;
2523
3.47k
      }
2524
1.76k
    }
2525
4.19k
  return(MagickTrue);
2526
4.19k
}
2527
2528
static MagickBooleanType ReadUncompressedRGB(const ImageInfo *image_info,
2529
  Image *image,const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2530
  ExceptionInfo *exception)
2531
4.23k
{
2532
4.23k
  if (dds_info->pixelformat.rgb_bitcount == 8 || 
2533
1.44k
      dds_info->extFormat == DXGI_FORMAT_R8_UNORM)
2534
2.86k
    (void) SetImageType(image,GrayscaleType,exception);
2535
1.36k
  else if (dds_info->pixelformat.rgb_bitcount == 16 && !IsBitMask(
2536
1.36k
    dds_info->pixelformat,0xf800,0x07e0,0x001f,0x0000))
2537
299
    ThrowBinaryException(CorruptImageError,"ImageTypeNotSupported",
2538
4.23k
      image->filename);
2539
2540
3.93k
  if (ReadUncompressedRGBPixels(image,dds_info,exception) == MagickFalse)
2541
1.64k
    return(MagickFalse);
2542
2543
2.28k
  if (read_mipmaps != MagickFalse)
2544
0
    return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedRGBPixels,
2545
0
      exception));
2546
2.28k
  else
2547
2.28k
    return(SkipRGBMipmaps(image,dds_info,3,exception));
2548
2.28k
}
2549
2550
static MagickBooleanType ReadUncompressedAlpha(const ImageInfo *image_info,
2551
  Image *image,const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2552
  ExceptionInfo *exception)
2553
1.78k
{
2554
1.78k
  if (dds_info->pixelformat.rgb_bitcount != 8)
2555
101
    ThrowBinaryException(CorruptImageError,"ImageTypeNotSupported",
2556
1.78k
      image->filename);
2557
2558
1.68k
  if (ReadUncompressedAlphaPixels(image,dds_info,exception) == MagickFalse)
2559
385
    return(MagickFalse);
2560
2561
1.30k
  if (read_mipmaps != MagickFalse)
2562
0
    return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedAlphaPixels,
2563
0
      exception));
2564
1.30k
  else
2565
1.30k
    return(SkipRGBMipmaps(image,dds_info,1,exception));
2566
1.30k
}
2567
2568
static MagickBooleanType ReadUncompressedRGBAPixels(Image *image,
2569
  const DDSInfo *dds_info,ExceptionInfo *exception)
2570
2.91k
{
2571
2.91k
  MagickBooleanType
2572
2.91k
    is_rgba;
2573
2574
2.91k
  Quantum
2575
2.91k
    *q;
2576
2577
2.91k
  ssize_t
2578
2.91k
    alphaBits,
2579
2.91k
    x,
2580
2.91k
    y;
2581
2582
2.91k
  unsigned short
2583
2.91k
    color;
2584
2585
2.91k
  alphaBits=0;
2586
2.91k
  if (dds_info->pixelformat.rgb_bitcount == 16)
2587
1.95k
    {
2588
1.95k
      if (IsBitMask(dds_info->pixelformat,0x7c00,0x03e0,0x001f,0x8000))
2589
277
        alphaBits=1;
2590
1.68k
      else if ((IsBitMask(dds_info->pixelformat,0x00ff,0x00ff,0x00ff,0xff00)) ||
2591
1.54k
               (IsBitMask(dds_info->pixelformat,0x00ff,0x0000,0x0000,0xff00)))
2592
333
        {
2593
333
          alphaBits=2;
2594
333
          (void) SetImageType(image,GrayscaleAlphaType,exception);
2595
333
        }
2596
1.34k
      else if (IsBitMask(dds_info->pixelformat,0x0f00,0x00f0,0x000f,0xf000))
2597
140
        alphaBits=4;
2598
1.20k
      else
2599
1.20k
        ThrowBinaryException(CorruptImageError,"ImageTypeNotSupported",
2600
1.95k
          image->filename);
2601
750
    }
2602
2603
1.70k
  if (dds_info->extFormat == DXGI_FORMAT_B5G5R5A1_UNORM)
2604
79
    alphaBits=1;
2605
2606
1.70k
  is_rgba=IsBitMask(dds_info->pixelformat,0x000000ff,0x0000ff00,0x00ff0000,0xff00000) ? MagickTrue : MagickFalse;
2607
7.08k
  for (y = 0; y < (ssize_t) image->rows; y++)
2608
6.48k
  {
2609
6.48k
    q = QueueAuthenticPixels(image, 0, y, image->columns, 1,exception);
2610
2611
6.48k
    if (q == (Quantum *) NULL)
2612
0
      return(MagickFalse);
2613
2614
291k
    for (x = 0; x < (ssize_t) image->columns; x++)
2615
285k
    {
2616
285k
      if (dds_info->pixelformat.rgb_bitcount == 16 ||
2617
247k
          dds_info->extFormat == DXGI_FORMAT_B5G5R5A1_UNORM)
2618
43.9k
        {
2619
43.9k
           color=ReadBlobShort(image);
2620
43.9k
           if (alphaBits == 1)
2621
17.3k
             {
2622
17.3k
               SetPixelAlpha(image,(color & (1 << 15)) ? QuantumRange : 0,q);
2623
17.3k
               SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2624
17.3k
                 ((((unsigned short)(color << 1) >> 11)/31.0)*255)),q);
2625
17.3k
               SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2626
17.3k
                 ((((unsigned short)(color << 6) >> 11)/31.0)*255)),q);
2627
17.3k
               SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2628
17.3k
                 ((((unsigned short)(color << 11) >> 11)/31.0)*255)),q);
2629
17.3k
             }
2630
26.5k
          else if (alphaBits == 2)
2631
17.7k
            {
2632
17.7k
               SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2633
17.7k
                 (color >> 8)),q);
2634
17.7k
               SetPixelGray(image,ScaleCharToQuantum((unsigned char)color),q);
2635
17.7k
            }
2636
8.80k
          else
2637
8.80k
            {
2638
8.80k
               SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2639
8.80k
                 (((color >> 12)/15.0)*255)),q);
2640
8.80k
               SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2641
8.80k
                 ((((unsigned short)(color << 4) >> 12)/15.0)*255)),q);
2642
8.80k
               SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2643
8.80k
                 ((((unsigned short)(color << 8) >> 12)/15.0)*255)),q);
2644
8.80k
               SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2645
8.80k
                 ((((unsigned short)(color << 12) >> 12)/15.0)*255)),q);
2646
8.80k
            }
2647
43.9k
        }
2648
241k
      else if (dds_info->extFormat == DXGI_FORMAT_R10G10B10A2_UNORM)
2649
6.92k
        {
2650
6.92k
          const unsigned int
2651
6.92k
            pixel=ReadBlobLSBLong(image);
2652
2653
6.92k
          SetPixelRed(image,ScaleShortToQuantum((unsigned short)
2654
6.92k
            ((pixel & 0x3ff)/1023.0)*65535),q);
2655
6.92k
          SetPixelBlue(image,ScaleShortToQuantum((unsigned short)
2656
6.92k
            (((pixel >> 10) & 0x3ff)/1023.0)*65535),q);
2657
6.92k
          SetPixelGreen(image,ScaleShortToQuantum((unsigned short)
2658
6.92k
            (((pixel >> 20) & 0x3ff)/1023.0)*65535),q);
2659
6.92k
          SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
2660
6.92k
            (((pixel >> 30) & 3)/3.0)*65535),q);
2661
6.92k
        }
2662
234k
      else if ((dds_info->extFormat == DXGI_FORMAT_R8G8B8A8_UNORM) ||
2663
232k
               (is_rgba != MagickFalse))
2664
2.53k
        {
2665
2.53k
          SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2666
2.53k
            ReadBlobByte(image)),q);
2667
2.53k
          SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2668
2.53k
            ReadBlobByte(image)),q);
2669
2.53k
          SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2670
2.53k
            ReadBlobByte(image)),q);
2671
2.53k
          SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2672
2.53k
            ReadBlobByte(image)),q);
2673
2.53k
        }
2674
232k
      else
2675
232k
        {
2676
232k
          SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2677
232k
            ReadBlobByte(image)),q);
2678
232k
          SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2679
232k
            ReadBlobByte(image)),q);
2680
232k
          SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2681
232k
            ReadBlobByte(image)),q);
2682
232k
          SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2683
232k
            ReadBlobByte(image)),q);
2684
232k
        }
2685
285k
      q+=(ptrdiff_t) GetPixelChannels(image);
2686
285k
    }
2687
6.48k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
2688
0
      return(MagickFalse);
2689
6.48k
    if (EOFBlob(image) != MagickFalse)
2690
1.10k
      return(MagickFalse);
2691
6.48k
  }
2692
606
  return(MagickTrue);
2693
1.70k
}
2694
2695
static MagickBooleanType ReadUncompressedRGBA(const ImageInfo *image_info,
2696
  Image *image,const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2697
  ExceptionInfo *exception)
2698
2.91k
{
2699
2.91k
  if (ReadUncompressedRGBAPixels(image,dds_info,exception) == MagickFalse)
2700
2.30k
    return(MagickFalse);
2701
2702
606
  if (read_mipmaps != MagickFalse)
2703
0
    return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedRGBAPixels,
2704
0
      exception));
2705
606
  else
2706
606
    return(SkipRGBMipmaps(image,dds_info,4,exception));
2707
606
}
2708

2709
/*
2710
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711
%                                                                             %
2712
%                                                                             %
2713
%                                                                             %
2714
%   R e a d D D S I m a g e                                                   %
2715
%                                                                             %
2716
%                                                                             %
2717
%                                                                             %
2718
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719
%
2720
%  ReadDDSImage() reads a DirectDraw Surface image file and returns it.  It
2721
%  allocates the memory necessary for the new Image structure and returns a
2722
%  pointer to the new image.
2723
%
2724
%  The format of the ReadDDSImage method is:
2725
%
2726
%      Image *ReadDDSImage(const ImageInfo *image_info,ExceptionInfo *exception)
2727
%
2728
%  A description of each parameter follows:
2729
%
2730
%    o image_info: The image info.
2731
%
2732
%    o exception: return any errors or warnings in this structure.
2733
%
2734
*/
2735
static Image *ReadDDSImage(const ImageInfo *image_info,ExceptionInfo *exception)
2736
9.56k
{
2737
9.56k
  const char
2738
9.56k
    *option;
2739
2740
9.56k
  CompressionType
2741
9.56k
    compression;
2742
2743
9.56k
  DDSInfo
2744
9.56k
    dds_info;
2745
2746
9.56k
  DDSDecoder
2747
9.56k
    *decoder;
2748
2749
9.56k
  Image
2750
9.56k
    *image;
2751
2752
9.56k
  MagickBooleanType
2753
9.56k
    status,
2754
9.56k
    cubemap,
2755
9.56k
    volume,
2756
9.56k
    read_mipmaps;
2757
2758
9.56k
  PixelTrait
2759
9.56k
    alpha_trait;
2760
2761
9.56k
  size_t
2762
9.56k
    n,
2763
9.56k
    num_images;
2764
2765
  /*
2766
    Open image file.
2767
  */
2768
9.56k
  assert(image_info != (const ImageInfo *) NULL);
2769
9.56k
  assert(image_info->signature == MagickCoreSignature);
2770
9.56k
  assert(exception != (ExceptionInfo *) NULL);
2771
9.56k
  assert(exception->signature == MagickCoreSignature);
2772
9.56k
  if (IsEventLogging() != MagickFalse)
2773
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2774
0
      image_info->filename);
2775
9.56k
  cubemap=MagickFalse,
2776
9.56k
  volume=MagickFalse,
2777
9.56k
  read_mipmaps=MagickFalse;
2778
9.56k
  image=AcquireImage(image_info,exception);
2779
9.56k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2780
9.56k
  if (status == MagickFalse)
2781
74
    {
2782
74
      image=DestroyImageList(image);
2783
74
      return((Image *) NULL);
2784
74
    }
2785
  
2786
  /*
2787
    Initialize image structure.
2788
  */
2789
9.48k
  if (ReadDDSInfo(image,&dds_info) != MagickTrue)
2790
9.09k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2791
2792
9.09k
  if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP)
2793
2.22k
    cubemap=MagickTrue;
2794
2795
9.09k
  if (dds_info.ddscaps2 & DDSCAPS2_VOLUME && dds_info.depth > 0)
2796
1.99k
    volume=MagickTrue;
2797
2798
  /*
2799
    Determine pixel format
2800
  */
2801
9.09k
  if (dds_info.pixelformat.flags & DDPF_RGB)
2802
3.45k
    {
2803
3.45k
      compression=NoCompression;
2804
3.45k
      if (dds_info.pixelformat.flags & DDPF_ALPHAPIXELS)
2805
2.11k
        {
2806
2.11k
          alpha_trait=BlendPixelTrait;
2807
2.11k
          decoder=ReadUncompressedRGBA;
2808
2.11k
        }
2809
1.33k
      else
2810
1.33k
        {
2811
1.33k
          alpha_trait=UndefinedPixelTrait;
2812
1.33k
          decoder=ReadUncompressedRGB;
2813
1.33k
        }
2814
3.45k
    }
2815
5.63k
  else if (dds_info.pixelformat.flags & DDPF_ALPHA)
2816
696
    {
2817
696
      compression=NoCompression;
2818
696
      alpha_trait=BlendPixelTrait;
2819
696
      decoder=ReadUncompressedAlpha;
2820
696
    }
2821
4.94k
  else if (dds_info.pixelformat.flags & DDPF_LUMINANCE)
2822
1.32k
   {
2823
1.32k
      compression=NoCompression;
2824
1.32k
      if (dds_info.pixelformat.flags & DDPF_ALPHAPIXELS)
2825
378
        {
2826
378
          alpha_trait=BlendPixelTrait;
2827
378
          decoder=ReadUncompressedRGBA;
2828
378
        }
2829
944
      else
2830
944
        {
2831
944
          alpha_trait=UndefinedPixelTrait;
2832
944
          decoder=ReadUncompressedRGB;
2833
944
        }
2834
1.32k
    }
2835
3.62k
  else if (dds_info.pixelformat.flags & DDPF_FOURCC)
2836
3.61k
    {
2837
3.61k
      switch (dds_info.pixelformat.fourcc)
2838
3.61k
      {
2839
327
        case FOURCC_ATI2:
2840
348
        case FOURCC_BC5U:
2841
348
        {
2842
348
          alpha_trait=UndefinedPixelTrait;
2843
348
          compression=BC5Compression;
2844
348
          decoder=ReadBC5;
2845
348
          break;
2846
327
        }
2847
1.15k
        case FOURCC_DXT1:
2848
1.15k
        {
2849
1.15k
          alpha_trait=UndefinedPixelTrait;
2850
1.15k
          compression=DXT1Compression;
2851
1.15k
          decoder=ReadDXT1;
2852
1.15k
          break;
2853
327
        }
2854
195
        case FOURCC_DXT3:
2855
195
        {
2856
195
          alpha_trait=BlendPixelTrait;
2857
195
          compression=DXT3Compression;
2858
195
          decoder=ReadDXT3;
2859
195
          break;
2860
327
        }
2861
275
        case FOURCC_DXT5:
2862
275
        {
2863
275
          alpha_trait=BlendPixelTrait;
2864
275
          compression=DXT5Compression;
2865
275
          decoder=ReadDXT5;
2866
275
          break;
2867
327
        }
2868
736
        case FOURCC_DX10:
2869
736
        {
2870
736
          if (dds_info.extDimension != DDSEXT_DIMENSION_TEX2D)
2871
96
            {
2872
96
              ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
2873
0
            }
2874
2875
640
          switch (dds_info.extFormat)
2876
640
          {
2877
16
            case DXGI_FORMAT_R8_UNORM:
2878
16
            {
2879
16
              alpha_trait=UndefinedPixelTrait;
2880
16
              compression=NoCompression;
2881
16
              decoder=ReadUncompressedRGB;
2882
16
              break;
2883
0
            }
2884
3
            case DXGI_FORMAT_B5G6R5_UNORM:
2885
3
            {
2886
3
              alpha_trait=UndefinedPixelTrait;
2887
3
              compression=NoCompression;
2888
3
              decoder=ReadUncompressedRGB;
2889
3
              break;
2890
0
            }
2891
13
            case DXGI_FORMAT_B5G5R5A1_UNORM:
2892
13
            {
2893
13
              alpha_trait=BlendPixelTrait;
2894
13
              compression=NoCompression;
2895
13
              decoder=ReadUncompressedRGBA;
2896
13
              break;
2897
0
            }
2898
3
            case DXGI_FORMAT_B8G8R8A8_UNORM:
2899
3
            {
2900
3
              alpha_trait=BlendPixelTrait;
2901
3
              compression=NoCompression;
2902
3
              decoder=ReadUncompressedRGBA;
2903
3
              break;
2904
0
            }
2905
3
            case DXGI_FORMAT_R8G8B8A8_UNORM:
2906
3
            {
2907
3
              alpha_trait=BlendPixelTrait;
2908
3
              compression=NoCompression;
2909
3
              decoder=ReadUncompressedRGBA;
2910
3
              break;
2911
0
            }
2912
8
            case DXGI_FORMAT_R10G10B10A2_UNORM:
2913
8
            {
2914
8
              compression=NoCompression;
2915
8
              alpha_trait=BlendPixelTrait;
2916
8
              decoder=ReadUncompressedRGBA;
2917
8
              break;
2918
0
            }
2919
3
            case DXGI_FORMAT_B8G8R8X8_UNORM:
2920
3
            {
2921
3
              alpha_trait=UndefinedPixelTrait;
2922
3
              compression=NoCompression;
2923
3
              decoder=ReadUncompressedRGB;
2924
3
              break;
2925
0
            }
2926
3
            case DXGI_FORMAT_BC1_UNORM:
2927
3
            {
2928
3
              alpha_trait = UndefinedPixelTrait;
2929
3
              compression = DXT1Compression;
2930
3
              decoder = ReadDXT1;
2931
3
              break;
2932
0
            }
2933
3
            case DXGI_FORMAT_BC2_UNORM:
2934
3
            {
2935
3
              alpha_trait=BlendPixelTrait;
2936
3
              compression=DXT3Compression;
2937
3
              decoder=ReadDXT3;
2938
3
              break;
2939
0
            }
2940
3
            case DXGI_FORMAT_BC3_UNORM:
2941
3
            {
2942
3
              alpha_trait = BlendPixelTrait;
2943
3
              compression = DXT5Compression;
2944
3
              decoder = ReadDXT5;
2945
3
              break;
2946
0
            }
2947
3
            case DXGI_FORMAT_BC5_UNORM:
2948
3
            {
2949
3
              alpha_trait=UndefinedPixelTrait;
2950
3
              compression=BC5Compression;
2951
3
              decoder=ReadBC5;
2952
3
              break;
2953
0
            }
2954
364
            case DXGI_FORMAT_BC7_UNORM:
2955
576
            case DXGI_FORMAT_BC7_UNORM_SRGB:
2956
576
            {
2957
576
              alpha_trait=BlendPixelTrait;
2958
576
              compression=BC7Compression;
2959
576
              decoder=ReadBC7;
2960
576
              break;
2961
364
            }
2962
3
            default:
2963
3
            {
2964
              /* Unknown format */
2965
3
              ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
2966
0
            }
2967
640
          }
2968
2969
637
          if (dds_info.extFlags & DDSEXTFLAGS_CUBEMAP)
2970
268
            cubemap=MagickTrue;
2971
2972
637
          num_images=dds_info.extArraySize;
2973
637
          break;
2974
640
        }
2975
908
        default:
2976
908
        {
2977
          /* Unknown FOURCC */
2978
908
          ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
2979
0
        }
2980
3.61k
      }
2981
3.61k
    }
2982
3
  else
2983
3
    {
2984
      /* Neither compressed nor uncompressed... thus unsupported */
2985
3
      ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
2986
0
    }
2987
  
2988
8.08k
  num_images = 1;
2989
8.08k
  if (cubemap)
2990
2.41k
    {
2991
      /*
2992
        Determine number of faces defined in the cubemap
2993
      */
2994
2.41k
      num_images = 0;
2995
2.41k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEX) num_images++;
2996
2.41k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) num_images++;
2997
2.41k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEY) num_images++;
2998
2.41k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) num_images++;
2999
2.41k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) num_images++;
3000
2.41k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) num_images++;
3001
2.41k
    }
3002
  
3003
8.08k
  if (volume)
3004
1.96k
    num_images = dds_info.depth;
3005
3006
8.08k
  if ((num_images == 0) || (num_images > GetBlobSize(image)))
3007
7.93k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3008
3009
7.93k
  if (AcquireMagickResource(ListLengthResource,num_images) == MagickFalse)
3010
7.89k
    ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
3011
3012
7.89k
  option=GetImageOption(image_info,"dds:skip-mipmaps");
3013
7.89k
  if (IsStringFalse(option) != MagickFalse)
3014
0
    read_mipmaps=MagickTrue;
3015
3016
15.6k
  for (n = 0; n < num_images; n++)
3017
15.0k
  {
3018
15.0k
    if (n != 0)
3019
7.18k
      {
3020
        /* Start a new image */
3021
7.18k
        if (EOFBlob(image) != MagickFalse)
3022
7.18k
          ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
3023
7.18k
        AcquireNextImage(image_info,image,exception);
3024
7.18k
        if (GetNextImageInList(image) == (Image *) NULL)
3025
0
          return(DestroyImageList(image));
3026
7.18k
        image=SyncNextImageInList(image);
3027
7.18k
      }
3028
    
3029
15.0k
    image->alpha_trait=alpha_trait;
3030
15.0k
    image->compression=compression;
3031
15.0k
    image->columns=dds_info.width;
3032
15.0k
    image->rows=dds_info.height;
3033
15.0k
    image->storage_class=DirectClass;
3034
15.0k
    image->endian=LSBEndian;
3035
15.0k
    image->depth=8;
3036
15.0k
    if (image_info->ping != MagickFalse)
3037
0
      continue;
3038
15.0k
    status=SetImageExtent(image,image->columns,image->rows,exception);
3039
15.0k
    if (status == MagickFalse)
3040
280
      return(DestroyImageList(image));
3041
14.7k
    (void) SetImageBackgroundColor(image,exception);
3042
14.7k
    status=(decoder)(image_info,image,&dds_info,read_mipmaps,exception);
3043
14.7k
    if (status == MagickFalse)
3044
7.02k
      {
3045
7.02k
        (void) CloseBlob(image);
3046
7.02k
        if (n == 0)
3047
5.03k
          return(DestroyImageList(image));
3048
1.99k
        return(GetFirstImageInList(image));
3049
7.02k
      }
3050
14.7k
  }
3051
592
  if (CloseBlob(image) == MagickFalse)
3052
0
    status=MagickFalse;
3053
592
  if (status == MagickFalse)
3054
0
    return(DestroyImageList(image));
3055
592
  return(GetFirstImageInList(image));
3056
592
}
3057

3058
/*
3059
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3060
%                                                                             %
3061
%                                                                             %
3062
%                                                                             %
3063
%   R e g i s t e r D D S I m a g e                                           %
3064
%                                                                             %
3065
%                                                                             %
3066
%                                                                             %
3067
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3068
%
3069
%  RegisterDDSImage() adds attributes for the DDS image format to
3070
%  the list of supported formats.  The attributes include the image format
3071
%  tag, a method to read and/or write the format, whether the format
3072
%  supports the saving of more than one frame to the same file or blob,
3073
%  whether the format supports native in-memory I/O, and a brief
3074
%  description of the format.
3075
%
3076
%  The format of the RegisterDDSImage method is:
3077
%
3078
%      RegisterDDSImage(void)
3079
%
3080
*/
3081
ModuleExport size_t RegisterDDSImage(void)
3082
10
{
3083
10
  MagickInfo
3084
10
    *entry;
3085
3086
10
  entry = AcquireMagickInfo("DDS","DDS","Microsoft DirectDraw Surface");
3087
10
  entry->decoder = (DecodeImageHandler *) ReadDDSImage;
3088
10
  entry->encoder = (EncodeImageHandler *) WriteDDSImage;
3089
10
  entry->magick = (IsImageFormatHandler *) IsDDS;
3090
10
  entry->flags|=CoderDecoderSeekableStreamFlag;
3091
10
  (void) RegisterMagickInfo(entry);
3092
10
  entry = AcquireMagickInfo("DDS","DXT1","Microsoft DirectDraw Surface");
3093
10
  entry->decoder = (DecodeImageHandler *) ReadDDSImage;
3094
10
  entry->encoder = (EncodeImageHandler *) WriteDDSImage;
3095
10
  entry->magick = (IsImageFormatHandler *) IsDDS;
3096
10
  entry->flags|=CoderDecoderSeekableStreamFlag;
3097
10
  (void) RegisterMagickInfo(entry);
3098
10
  entry = AcquireMagickInfo("DDS","DXT5","Microsoft DirectDraw Surface");
3099
10
  entry->decoder = (DecodeImageHandler *) ReadDDSImage;
3100
10
  entry->encoder = (EncodeImageHandler *) WriteDDSImage;
3101
10
  entry->magick = (IsImageFormatHandler *) IsDDS;
3102
10
  entry->flags|=CoderDecoderSeekableStreamFlag;
3103
10
  (void) RegisterMagickInfo(entry);
3104
10
  return(MagickImageCoderSignature);
3105
10
}
3106
3107
static void RemapIndices(const ssize_t *map, const unsigned char *source,
3108
  unsigned char *target)
3109
123k
{
3110
123k
  ssize_t
3111
123k
    i;
3112
3113
2.10M
  for (i = 0; i < 16; i++)
3114
1.98M
  {
3115
1.98M
    if (map[i] == -1)
3116
1.12M
      target[i] = 3;
3117
852k
    else
3118
852k
      target[i] = source[map[i]];
3119
1.98M
  }
3120
123k
}
3121

3122
/*
3123
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3124
%                                                                             %
3125
%                                                                             %
3126
%                                                                             %
3127
%   U n r e g i s t e r D D S I m a g e                                       %
3128
%                                                                             %
3129
%                                                                             %
3130
%                                                                             %
3131
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3132
%
3133
%  UnregisterDDSImage() removes format registrations made by the
3134
%  DDS module from the list of supported formats.
3135
%
3136
%  The format of the UnregisterDDSImage method is:
3137
%
3138
%      UnregisterDDSImage(void)
3139
%
3140
*/
3141
ModuleExport void UnregisterDDSImage(void)
3142
0
{
3143
0
  (void) UnregisterMagickInfo("DDS");
3144
0
  (void) UnregisterMagickInfo("DXT1");
3145
0
  (void) UnregisterMagickInfo("DXT5");
3146
0
}
3147
3148
/*
3149
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3150
%                                                                             %
3151
%                                                                             %
3152
%                                                                             %
3153
%   W r i t e D D S I m a g e                                                 %
3154
%                                                                             %
3155
%                                                                             %
3156
%                                                                             %
3157
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3158
%
3159
%  WriteDDSImage() writes a DirectDraw Surface image file in the DXT5 format.
3160
%
3161
%  The format of the WriteDDSImage method is:
3162
%
3163
%     MagickBooleanType WriteDDSImage(const ImageInfo *image_info,Image *image)
3164
%
3165
%  A description of each parameter follows.
3166
%
3167
%    o image_info: the image info.
3168
%
3169
%    o image:  The image.
3170
%
3171
*/
3172
3173
static size_t CompressAlpha(const size_t min, const size_t max,
3174
  const size_t steps, const ssize_t *alphas, unsigned char* indices)
3175
104k
{
3176
104k
  unsigned char
3177
104k
    codes[8];
3178
3179
104k
  size_t
3180
104k
    error,
3181
104k
    index,
3182
104k
    j,
3183
104k
    least,
3184
104k
    value;
3185
3186
104k
  ssize_t
3187
104k
    i;
3188
3189
104k
  codes[0] = (unsigned char) min;
3190
104k
  codes[1] = (unsigned char) max;
3191
104k
  codes[6] = 0;
3192
104k
  codes[7] = 255;
3193
3194
628k
  for (i=1; i <  (ssize_t) steps; i++)
3195
523k
    codes[i+1] = (unsigned char) ((((ssize_t) steps-i)*(ssize_t) min +
3196
523k
      i*(ssize_t) max) / (ssize_t) steps);
3197
3198
104k
  error = 0;
3199
1.78M
  for (i=0; i<16; i++)
3200
1.67M
  {
3201
1.67M
    if (alphas[i] == -1)
3202
814k
      {
3203
814k
        indices[i] = 0;
3204
814k
        continue;
3205
814k
      }
3206
3207
861k
    value = (size_t) alphas[i];
3208
861k
    least = SIZE_MAX;
3209
861k
    index = 0;
3210
7.75M
    for (j=0; j<8; j++)
3211
6.88M
    {
3212
6.88M
      size_t
3213
6.88M
        dist;
3214
3215
6.88M
      dist = value - (size_t)codes[j];
3216
6.88M
      dist *= dist;
3217
3218
6.88M
      if (dist < least)
3219
1.83M
        {
3220
1.83M
          least = dist;
3221
1.83M
          index = j;
3222
1.83M
        }
3223
6.88M
    }
3224
3225
861k
    indices[i] = (unsigned char)index;
3226
861k
    error += least;
3227
861k
  }
3228
3229
104k
  return error;
3230
104k
}
3231
3232
static MagickBooleanType ConstructOrdering(const size_t count,
3233
  const DDSVector4 *points, const DDSVector3 axis, DDSVector4 *pointsWeights,
3234
  DDSVector4 *xSumwSum, unsigned char *order, size_t iteration)
3235
0
{
3236
0
  float
3237
0
     dps[16],
3238
0
     f;
3239
3240
0
  ssize_t
3241
0
    i,
3242
0
    j;
3243
3244
0
  unsigned char
3245
0
    c,
3246
0
    *o,
3247
0
    *p;
3248
3249
0
  o = order + (16*iteration);
3250
3251
0
  for (i=0; i < (ssize_t) count; i++)
3252
0
  {
3253
0
    dps[i] = Dot(points[i],axis);
3254
0
    o[i] = (unsigned char)i;
3255
0
  }
3256
3257
0
  for (i=0; i < (ssize_t) count; i++)
3258
0
  {
3259
0
    for (j=i; j > 0 && dps[j] < dps[j - 1]; j--)
3260
0
    {
3261
0
      f = dps[j];
3262
0
      dps[j] = dps[j - 1];
3263
0
      dps[j - 1] = f;
3264
3265
0
      c = o[j];
3266
0
      o[j] = o[j - 1];
3267
0
      o[j - 1] = c;
3268
0
    }
3269
0
  }
3270
3271
0
  for (i=0; i < (ssize_t) iteration; i++)
3272
0
  {
3273
0
    MagickBooleanType
3274
0
      same;
3275
3276
0
    p = order + (16*i);
3277
0
    same = MagickTrue;
3278
3279
0
    for (j=0; j < (ssize_t) count; j++)
3280
0
    {
3281
0
      if (o[j] != p[j])
3282
0
        {
3283
0
          same = MagickFalse;
3284
0
          break;
3285
0
        }
3286
0
    }
3287
3288
0
    if (same != MagickFalse)
3289
0
      return MagickFalse;
3290
0
  }
3291
3292
0
  xSumwSum->x = 0;
3293
0
  xSumwSum->y = 0;
3294
0
  xSumwSum->z = 0;
3295
0
  xSumwSum->w = 0;
3296
3297
0
  for (i=0; i < (ssize_t) count; i++)
3298
0
  {
3299
0
    DDSVector4
3300
0
      v;
3301
3302
0
    j = (ssize_t) o[i];
3303
3304
0
    v.x = points[j].w * points[j].x;
3305
0
    v.y = points[j].w * points[j].y;
3306
0
    v.z = points[j].w * points[j].z;
3307
0
    v.w = points[j].w * 1.0f;
3308
3309
0
    VectorCopy44(v,&pointsWeights[i]);
3310
0
    VectorAdd(*xSumwSum,v,xSumwSum);
3311
0
  }
3312
3313
0
  return MagickTrue;
3314
0
}
3315
3316
static void CompressClusterFit(const size_t count,
3317
  const DDSVector4 *points, const ssize_t *map, const DDSVector3 principle,
3318
  const DDSVector4 metric, DDSVector3 *start, DDSVector3* end,
3319
  unsigned char *indices)
3320
0
{
3321
0
  DDSVector3
3322
0
    axis;
3323
3324
0
  DDSVector4
3325
0
    grid,
3326
0
    gridrcp,
3327
0
    half,
3328
0
    onethird_onethird2,
3329
0
    pointsWeights[16],
3330
0
    two,
3331
0
    twonineths,
3332
0
    twothirds_twothirds2,
3333
0
    xSumwSum;
3334
3335
0
  float
3336
0
    bestError = 1e+37f;
3337
3338
0
  size_t
3339
0
    bestIteration = 0,
3340
0
    iterationIndex;
3341
3342
0
  ssize_t
3343
0
    besti = 0,
3344
0
    bestj = 0,
3345
0
    bestk = 0,
3346
0
    i;
3347
3348
0
  unsigned char
3349
0
    *o,
3350
0
    order[128],
3351
0
    unordered[16];
3352
3353
0
  VectorInit(half,0.5f);
3354
0
  VectorInit(two,2.0f);
3355
3356
0
  VectorInit(onethird_onethird2,1.0f/3.0f);
3357
0
  onethird_onethird2.w = 1.0f/9.0f;
3358
0
  VectorInit(twothirds_twothirds2,2.0f/3.0f);
3359
0
  twothirds_twothirds2.w = 4.0f/9.0f;
3360
0
  VectorInit(twonineths,2.0f/9.0f);
3361
3362
0
  grid.x = 31.0f;
3363
0
  grid.y = 63.0f;
3364
0
  grid.z = 31.0f;
3365
0
  grid.w = 0.0f;
3366
3367
0
  gridrcp.x = 1.0f/31.0f;
3368
0
  gridrcp.y = 1.0f/63.0f;
3369
0
  gridrcp.z = 1.0f/31.0f;
3370
0
  gridrcp.w = 0.0f;
3371
3372
0
  xSumwSum.x = 0.0f;
3373
0
  xSumwSum.y = 0.0f;
3374
0
  xSumwSum.z = 0.0f;
3375
0
  xSumwSum.w = 0.0f;
3376
3377
0
  ConstructOrdering(count,points,principle,pointsWeights,&xSumwSum,order,0);
3378
3379
0
  for (iterationIndex = 0;;)
3380
0
  {
3381
#if defined(MAGICKCORE_OPENMP_SUPPORT)
3382
  #pragma omp parallel for schedule(dynamic,1) \
3383
    num_threads((int) GetMagickResourceLimit(ThreadResource))
3384
#endif
3385
0
    for (i=0; i < (ssize_t) count; i++)
3386
0
    {
3387
0
      DDSVector4
3388
0
        part0,
3389
0
        part1,
3390
0
        part2;
3391
3392
0
      ssize_t
3393
0
        ii,
3394
0
        j,
3395
0
        k,
3396
0
        kmin;
3397
3398
0
      VectorInit(part0,0.0f);
3399
0
      for (ii=0; ii < i; ii++)
3400
0
        VectorAdd(pointsWeights[ii],part0,&part0);
3401
3402
0
      VectorInit(part1,0.0f);
3403
0
      for (j=i; ; )
3404
0
      {
3405
0
        if (j == 0)
3406
0
          {
3407
0
            VectorCopy44(pointsWeights[0],&part2);
3408
0
            kmin = 1;
3409
0
          }
3410
0
          else
3411
0
          {
3412
0
            VectorInit(part2,0.0f);
3413
0
            kmin = j;
3414
0
          }
3415
3416
0
        for (k=kmin;;)
3417
0
        {
3418
0
          DDSVector4
3419
0
            a,
3420
0
            alpha2_sum,
3421
0
            alphax_sum,
3422
0
            alphabeta_sum,
3423
0
            b,
3424
0
            beta2_sum,
3425
0
            betax_sum,
3426
0
            e1,
3427
0
            e2,
3428
0
            factor,
3429
0
            part3;
3430
3431
0
          float
3432
0
            error;
3433
3434
0
          VectorSubtract(xSumwSum,part2,&part3);
3435
0
          VectorSubtract(part3,part1,&part3);
3436
0
          VectorSubtract(part3,part0,&part3);
3437
3438
0
          VectorMultiplyAdd(part1,twothirds_twothirds2,part0,&alphax_sum);
3439
0
          VectorMultiplyAdd(part2,onethird_onethird2,alphax_sum,&alphax_sum);
3440
0
          VectorInit(alpha2_sum,alphax_sum.w);
3441
3442
0
          VectorMultiplyAdd(part2,twothirds_twothirds2,part3,&betax_sum);
3443
0
          VectorMultiplyAdd(part1,onethird_onethird2,betax_sum,&betax_sum);
3444
0
          VectorInit(beta2_sum,betax_sum.w);
3445
3446
0
          VectorAdd(part1,part2,&alphabeta_sum);
3447
0
          VectorInit(alphabeta_sum,alphabeta_sum.w);
3448
0
          VectorMultiply(twonineths,alphabeta_sum,&alphabeta_sum);
3449
3450
0
          VectorMultiply(alpha2_sum,beta2_sum,&factor);
3451
0
          VectorNegativeMultiplySubtract(alphabeta_sum,alphabeta_sum,factor,
3452
0
            &factor);
3453
0
          VectorReciprocal(factor,&factor);
3454
3455
0
          VectorMultiply(alphax_sum,beta2_sum,&a);
3456
0
          VectorNegativeMultiplySubtract(betax_sum,alphabeta_sum,a,&a);
3457
0
          VectorMultiply(a,factor,&a);
3458
3459
0
          VectorMultiply(betax_sum,alpha2_sum,&b);
3460
0
          VectorNegativeMultiplySubtract(alphax_sum,alphabeta_sum,b,&b);
3461
0
          VectorMultiply(b,factor,&b);
3462
3463
0
          VectorClamp(&a);
3464
0
          VectorMultiplyAdd(grid,a,half,&a);
3465
0
          VectorTruncate(&a);
3466
0
          VectorMultiply(a,gridrcp,&a);
3467
3468
0
          VectorClamp(&b);
3469
0
          VectorMultiplyAdd(grid,b,half,&b);
3470
0
          VectorTruncate(&b);
3471
0
          VectorMultiply(b,gridrcp,&b);
3472
3473
0
          VectorMultiply(b,b,&e1);
3474
0
          VectorMultiply(e1,beta2_sum,&e1);
3475
0
          VectorMultiply(a,a,&e2);
3476
0
          VectorMultiplyAdd(e2,alpha2_sum,e1,&e1);
3477
3478
0
          VectorMultiply(a,b,&e2);
3479
0
          VectorMultiply(e2,alphabeta_sum,&e2);
3480
0
          VectorNegativeMultiplySubtract(a,alphax_sum,e2,&e2);
3481
0
          VectorNegativeMultiplySubtract(b,betax_sum,e2,&e2);
3482
0
          VectorMultiplyAdd(two,e2,e1,&e2);
3483
0
          VectorMultiply(e2,metric,&e2);
3484
3485
0
          error = e2.x + e2.y + e2.z;
3486
3487
0
          if (error < bestError)
3488
0
            {
3489
#if defined(MAGICKCORE_OPENMP_SUPPORT)
3490
              #pragma omp critical (DDS_CompressClusterFit)
3491
#endif
3492
0
              {
3493
0
                if (error < bestError)
3494
0
                  {
3495
0
                    VectorCopy43(a,start);
3496
0
                    VectorCopy43(b,end);
3497
0
                    bestError = error;
3498
0
                    besti = i;
3499
0
                    bestj = j;
3500
0
                    bestk = k;
3501
0
                    bestIteration = iterationIndex;
3502
0
                  }
3503
0
              }
3504
0
            }
3505
3506
0
          if (k == (ssize_t) count)
3507
0
            break;
3508
3509
0
          VectorAdd(pointsWeights[k],part2,&part2);
3510
0
          k++;
3511
0
        }
3512
3513
0
        if (j == (ssize_t) count)
3514
0
          break;
3515
3516
0
        VectorAdd(pointsWeights[j],part1,&part1);
3517
0
        j++;
3518
0
      }
3519
0
    }
3520
3521
0
    if (bestIteration != iterationIndex)
3522
0
      break;
3523
3524
0
    iterationIndex++;
3525
0
    if (iterationIndex == 8)
3526
0
      break;
3527
3528
0
    VectorSubtract3(*end,*start,&axis);
3529
0
    if (ConstructOrdering(count,points,axis,pointsWeights,&xSumwSum,order,
3530
0
      iterationIndex) == MagickFalse)
3531
0
      break;
3532
0
  }
3533
3534
0
  o = order + (16*bestIteration);
3535
3536
0
  for (i=0; i < (ssize_t) besti; i++)
3537
0
    unordered[o[i]] = 0;
3538
0
  for (i=besti; i < (ssize_t) bestj; i++)
3539
0
    unordered[o[i]] = 2;
3540
0
  for (i=bestj; i < (ssize_t) bestk; i++)
3541
0
    unordered[o[i]] = 3;
3542
0
  for (i=bestk; i < (ssize_t) count; i++)
3543
0
    unordered[o[i]] = 1;
3544
3545
0
  RemapIndices(map,unordered,indices);
3546
0
}
3547
3548
static void CompressRangeFit(const size_t count,
3549
  const DDSVector4* points, const ssize_t *map, const DDSVector3 principle,
3550
  const DDSVector4 metric, DDSVector3 *start, DDSVector3 *end,
3551
  unsigned char *indices)
3552
65.4k
{
3553
65.4k
  float
3554
65.4k
    d,
3555
65.4k
    bestDist,
3556
65.4k
    max,
3557
65.4k
    min,
3558
65.4k
    val;
3559
3560
65.4k
  DDSVector3
3561
65.4k
    codes[4],
3562
65.4k
    grid,
3563
65.4k
    gridrcp,
3564
65.4k
    half,
3565
65.4k
    dist;
3566
3567
65.4k
  ssize_t
3568
65.4k
    i;
3569
3570
65.4k
  size_t
3571
65.4k
    bestj,
3572
65.4k
    j;
3573
3574
65.4k
  unsigned char
3575
65.4k
    closest[16];
3576
3577
65.4k
  VectorInit3(half,0.5f);
3578
3579
65.4k
  grid.x = 31.0f;
3580
65.4k
  grid.y = 63.0f;
3581
65.4k
  grid.z = 31.0f;
3582
3583
65.4k
  gridrcp.x = 1.0f/31.0f;
3584
65.4k
  gridrcp.y = 1.0f/63.0f;
3585
65.4k
  gridrcp.z = 1.0f/31.0f;
3586
3587
65.4k
  if (count > 0)
3588
65.4k
    {
3589
65.4k
      VectorCopy43(points[0],start);
3590
65.4k
      VectorCopy43(points[0],end);
3591
3592
65.4k
      min = max = Dot(points[0],principle);
3593
227k
      for (i=1; i < (ssize_t) count; i++)
3594
162k
      {
3595
162k
        val = Dot(points[i],principle);
3596
162k
        if (val < min)
3597
60.4k
        {
3598
60.4k
          VectorCopy43(points[i],start);
3599
60.4k
          min = val;
3600
60.4k
        }
3601
101k
        else if (val > max)
3602
58.2k
        {
3603
58.2k
          VectorCopy43(points[i],end);
3604
58.2k
          max = val;
3605
58.2k
        }
3606
162k
      }
3607
65.4k
    }
3608
3609
65.4k
  VectorClamp3(start);
3610
65.4k
  VectorMultiplyAdd3(grid,*start,half,start);
3611
65.4k
  VectorTruncate3(start);
3612
65.4k
  VectorMultiply3(*start,gridrcp,start);
3613
3614
65.4k
  VectorClamp3(end);
3615
65.4k
  VectorMultiplyAdd3(grid,*end,half,end);
3616
65.4k
  VectorTruncate3(end);
3617
65.4k
  VectorMultiply3(*end,gridrcp,end);
3618
3619
65.4k
  codes[0] = *start;
3620
65.4k
  codes[1] = *end;
3621
65.4k
  codes[2].x = (start->x * (2.0f/3.0f)) + (end->x * (1.0f/3.0f));
3622
65.4k
  codes[2].y = (start->y * (2.0f/3.0f)) + (end->y * (1.0f/3.0f));
3623
65.4k
  codes[2].z = (start->z * (2.0f/3.0f)) + (end->z * (1.0f/3.0f));
3624
65.4k
  codes[3].x = (start->x * (1.0f/3.0f)) + (end->x * (2.0f/3.0f));
3625
65.4k
  codes[3].y = (start->y * (1.0f/3.0f)) + (end->y * (2.0f/3.0f));
3626
65.4k
  codes[3].z = (start->z * (1.0f/3.0f)) + (end->z * (2.0f/3.0f));
3627
3628
293k
  for (i=0; i < (ssize_t) count; i++)
3629
227k
  {
3630
227k
    bestDist = 1e+37f;
3631
227k
    bestj = 0;
3632
1.13M
    for (j=0; j < 4; j++)
3633
910k
    {
3634
910k
      dist.x = (points[i].x - codes[j].x) * metric.x;
3635
910k
      dist.y = (points[i].y - codes[j].y) * metric.y;
3636
910k
      dist.z = (points[i].z - codes[j].z) * metric.z;
3637
3638
910k
      d = Dot(dist,dist);
3639
910k
      if (d < bestDist)
3640
413k
        {
3641
413k
          bestDist = d;
3642
413k
          bestj = j;
3643
413k
        }
3644
910k
    }
3645
3646
227k
    closest[i] = (unsigned char) bestj;
3647
227k
  }
3648
3649
65.4k
  RemapIndices(map, closest, indices);
3650
65.4k
}
3651
3652
static void ComputeEndPoints(const DDSSingleColorLookup *lookup[],
3653
  const unsigned char *color, DDSVector3 *start, DDSVector3 *end,
3654
  unsigned char *index)
3655
58.3k
{
3656
58.3k
  ssize_t
3657
58.3k
    i;
3658
3659
58.3k
  size_t
3660
58.3k
    c,
3661
58.3k
    maxError = SIZE_MAX;
3662
3663
175k
  for (i=0; i < 2; i++)
3664
116k
  {
3665
116k
    const DDSSourceBlock*
3666
116k
      sources[3];
3667
3668
116k
      size_t
3669
116k
        error = 0;
3670
3671
467k
    for (c=0; c < 3; c++)
3672
350k
    {
3673
350k
      sources[c] = &lookup[c][color[c]].sources[i];
3674
350k
      error += ((size_t) sources[c]->error) * ((size_t) sources[c]->error);
3675
350k
    }
3676
3677
116k
    if (error > maxError)
3678
0
      continue;
3679
3680
116k
    start->x = (float) sources[0]->start / 31.0f;
3681
116k
    start->y = (float) sources[1]->start / 63.0f;
3682
116k
    start->z = (float) sources[2]->start / 31.0f;
3683
3684
116k
    end->x = (float) sources[0]->end / 31.0f;
3685
116k
    end->y = (float) sources[1]->end / 63.0f;
3686
116k
    end->z = (float) sources[2]->end / 31.0f;
3687
3688
116k
    *index = (unsigned char) (2*i);
3689
116k
    maxError = error;
3690
116k
  }
3691
58.3k
}
3692
3693
static void ComputePrincipleComponent(const float *covariance,
3694
  DDSVector3 *principle)
3695
65.4k
{
3696
65.4k
  DDSVector4
3697
65.4k
    row0,
3698
65.4k
    row1,
3699
65.4k
    row2,
3700
65.4k
    v;
3701
3702
65.4k
  ssize_t
3703
65.4k
    i;
3704
3705
65.4k
  row0.x = covariance[0];
3706
65.4k
  row0.y = covariance[1];
3707
65.4k
  row0.z = covariance[2];
3708
65.4k
  row0.w = 0.0f;
3709
3710
65.4k
  row1.x = covariance[1];
3711
65.4k
  row1.y = covariance[3];
3712
65.4k
  row1.z = covariance[4];
3713
65.4k
  row1.w = 0.0f;
3714
3715
65.4k
  row2.x = covariance[2];
3716
65.4k
  row2.y = covariance[4];
3717
65.4k
  row2.z = covariance[5];
3718
65.4k
  row2.w = 0.0f;
3719
3720
65.4k
  VectorInit(v,1.0f);
3721
3722
589k
  for (i=0; i < 8; i++)
3723
523k
  {
3724
523k
    DDSVector4
3725
523k
      w;
3726
3727
523k
    float
3728
523k
      a;
3729
3730
523k
    w.x = row0.x * v.x;
3731
523k
    w.y = row0.y * v.x;
3732
523k
    w.z = row0.z * v.x;
3733
523k
    w.w = row0.w * v.x;
3734
3735
523k
    w.x = (row1.x * v.y) + w.x;
3736
523k
    w.y = (row1.y * v.y) + w.y;
3737
523k
    w.z = (row1.z * v.y) + w.z;
3738
523k
    w.w = (row1.w * v.y) + w.w;
3739
3740
523k
    w.x = (row2.x * v.z) + w.x;
3741
523k
    w.y = (row2.y * v.z) + w.y;
3742
523k
    w.z = (row2.z * v.z) + w.z;
3743
523k
    w.w = (row2.w * v.z) + w.w;
3744
3745
523k
    a = (float) MagickSafeReciprocal(MagickMax(w.x,MagickMax(w.y,w.z)));
3746
3747
523k
    v.x = w.x * a;
3748
523k
    v.y = w.y * a;
3749
523k
    v.z = w.z * a;
3750
523k
    v.w = w.w * a;
3751
523k
  }
3752
3753
65.4k
  VectorCopy43(v,principle);
3754
65.4k
}
3755
3756
static void ComputeWeightedCovariance(const size_t count,
3757
  const DDSVector4 *points, float *covariance)
3758
65.4k
{
3759
65.4k
  DDSVector3
3760
65.4k
    centroid;
3761
3762
65.4k
  float
3763
65.4k
    total;
3764
3765
65.4k
  size_t
3766
65.4k
    i;
3767
3768
65.4k
  total = 0.0f;
3769
65.4k
  VectorInit3(centroid,0.0f);
3770
3771
293k
  for (i=0; i < count; i++)
3772
227k
  {
3773
227k
    total += points[i].w;
3774
227k
    centroid.x += (points[i].x * points[i].w);
3775
227k
    centroid.y += (points[i].y * points[i].w);
3776
227k
    centroid.z += (points[i].z * points[i].w);
3777
227k
  }
3778
3779
65.4k
  if( total > 1.192092896e-07F)
3780
65.4k
    {
3781
65.4k
      centroid.x /= total;
3782
65.4k
      centroid.y /= total;
3783
65.4k
      centroid.z /= total;
3784
65.4k
    }
3785
3786
458k
  for (i=0; i < 6; i++)
3787
392k
    covariance[i] = 0.0f;
3788
3789
293k
  for (i = 0; i < count; i++)
3790
227k
  {
3791
227k
    DDSVector3
3792
227k
      a,
3793
227k
      b;
3794
3795
227k
    a.x = points[i].x - centroid.x;
3796
227k
    a.y = points[i].y - centroid.y;
3797
227k
    a.z = points[i].z - centroid.z;
3798
3799
227k
    b.x = points[i].w * a.x;
3800
227k
    b.y = points[i].w * a.y;
3801
227k
    b.z = points[i].w * a.z;
3802
3803
227k
    covariance[0] += a.x*b.x;
3804
227k
    covariance[1] += a.x*b.y;
3805
227k
    covariance[2] += a.x*b.z;
3806
227k
    covariance[3] += a.y*b.y;
3807
227k
    covariance[4] += a.y*b.z;
3808
227k
    covariance[5] += a.z*b.z;
3809
227k
  }
3810
65.4k
}
3811
3812
static void WriteAlphas(Image *image, const ssize_t *alphas, size_t min5,
3813
  size_t max5, size_t min7, size_t max7)
3814
52.3k
{
3815
52.3k
  size_t
3816
52.3k
    err5,
3817
52.3k
    err7;
3818
3819
52.3k
  ssize_t
3820
52.3k
    i,
3821
52.3k
    j;
3822
3823
52.3k
  unsigned char
3824
52.3k
    indices5[16],
3825
52.3k
    indices7[16];
3826
3827
52.3k
  FixRange(min5,max5,5);
3828
52.3k
  err5 = CompressAlpha(min5,max5,5,alphas,indices5);
3829
3830
52.3k
  FixRange(min7,max7,7);
3831
52.3k
  err7 = CompressAlpha(min7,max7,7,alphas,indices7);
3832
3833
52.3k
  if (err7 < err5)
3834
6.99k
  {
3835
118k
    for (i=0; i < 16; i++)
3836
111k
    {
3837
111k
      unsigned char
3838
111k
        index;
3839
3840
111k
      index = indices7[i];
3841
111k
      if( index == 0 )
3842
80.4k
        indices5[i] = 1;
3843
31.4k
      else if (index == 1)
3844
12.4k
        indices5[i] = 0;
3845
18.9k
      else
3846
18.9k
        indices5[i] = 9 - index;
3847
111k
    }
3848
3849
6.99k
    min5 = max7;
3850
6.99k
    max5 = min7;
3851
6.99k
  }
3852
  
3853
52.3k
  (void) WriteBlobByte(image,(unsigned char) min5);
3854
52.3k
  (void) WriteBlobByte(image,(unsigned char) max5);
3855
  
3856
157k
  for(i=0; i < 2; i++)
3857
104k
  {
3858
104k
    size_t
3859
104k
      value = 0;
3860
3861
942k
    for (j=0; j < 8; j++)
3862
837k
    {
3863
837k
      size_t index = (size_t) indices5[j + i*8];
3864
837k
      value |= ( index << 3*j );
3865
837k
    }
3866
3867
418k
    for (j=0; j < 3; j++)
3868
314k
    {
3869
314k
      size_t byte = (value >> 8*j) & 0xff;
3870
314k
      (void) WriteBlobByte(image,(unsigned char) byte);
3871
314k
    }
3872
104k
  }
3873
52.3k
}
3874
3875
static void WriteIndices(Image *image, const DDSVector3 start,
3876
  const DDSVector3 end, unsigned char *indices)
3877
123k
{
3878
123k
  ssize_t
3879
123k
    i;
3880
3881
123k
  size_t
3882
123k
    a,
3883
123k
    b;
3884
3885
123k
  unsigned char
3886
123k
    remapped[16];
3887
3888
123k
  const unsigned char
3889
123k
    *ind;
3890
3891
123k
  a = ColorTo565(start);
3892
123k
  b = ColorTo565(end);
3893
3894
2.10M
  for (i=0; i<16; i++)
3895
1.98M
  {
3896
1.98M
    if( a < b )
3897
1.24M
      remapped[i] = (indices[i] ^ 0x1) & 0x3;
3898
737k
    else if( a == b )
3899
662k
      remapped[i] = 0;
3900
75.0k
    else
3901
75.0k
      remapped[i] = indices[i];
3902
1.98M
  }
3903
3904
123k
  if( a < b )
3905
77.7k
    Swap(a,b);
3906
3907
123k
  (void) WriteBlobByte(image,(unsigned char) (a & 0xff));
3908
123k
  (void) WriteBlobByte(image,(unsigned char) (a >> 8));
3909
123k
  (void) WriteBlobByte(image,(unsigned char) (b & 0xff));
3910
123k
  (void) WriteBlobByte(image,(unsigned char) (b >> 8));
3911
3912
619k
  for (i=0; i<4; i++)
3913
495k
  {
3914
495k
     ind = remapped + 4*i;
3915
495k
     (void) WriteBlobByte(image,ind[0] | (ind[1] << 2) | (ind[2] << 4) |
3916
495k
       (ind[3] << 6));
3917
495k
  }
3918
123k
}
3919
3920
static void WriteCompressed(Image *image, const size_t count,
3921
  DDSVector4 *points, const ssize_t *map, const MagickBooleanType clusterFit)
3922
65.4k
{
3923
65.4k
  float
3924
65.4k
    covariance[16];
3925
3926
65.4k
  DDSVector3
3927
65.4k
    end,
3928
65.4k
    principle,
3929
65.4k
    start;
3930
3931
65.4k
  DDSVector4
3932
65.4k
    metric;
3933
3934
65.4k
  unsigned char
3935
65.4k
    indices[16];
3936
3937
65.4k
  VectorInit(metric,1.0f);
3938
65.4k
  VectorInit3(start,0.0f);
3939
65.4k
  VectorInit3(end,0.0f);
3940
3941
65.4k
  ComputeWeightedCovariance(count,points,covariance);
3942
65.4k
  ComputePrincipleComponent(covariance,&principle);
3943
3944
65.4k
  if ((clusterFit == MagickFalse) || (count == 0))
3945
65.4k
    CompressRangeFit(count,points,map,principle,metric,&start,&end,indices);
3946
0
  else
3947
0
    CompressClusterFit(count,points,map,principle,metric,&start,&end,indices);
3948
3949
65.4k
  WriteIndices(image,start,end,indices);
3950
65.4k
}
3951
3952
static void WriteSingleColorFit(Image *image, const DDSVector4 *points,
3953
  const ssize_t *map)
3954
58.3k
{
3955
58.3k
  DDSVector3
3956
58.3k
    start,
3957
58.3k
    end;
3958
3959
58.3k
  ssize_t
3960
58.3k
    i;
3961
3962
58.3k
  unsigned char
3963
58.3k
    color[3],
3964
58.3k
    index,
3965
58.3k
    indexes[16],
3966
58.3k
    indices[16];
3967
3968
58.3k
  color[0] = (unsigned char) ClampToLimit(255.0f*points->x,255);
3969
58.3k
  color[1] = (unsigned char) ClampToLimit(255.0f*points->y,255);
3970
58.3k
  color[2] = (unsigned char) ClampToLimit(255.0f*points->z,255);
3971
3972
58.3k
  index=0;
3973
58.3k
  ComputeEndPoints(DDS_LOOKUP,color,&start,&end,&index);
3974
3975
992k
  for (i=0; i< 16; i++)
3976
934k
    indexes[i]=index;
3977
58.3k
  RemapIndices(map,indexes,indices);
3978
58.3k
  WriteIndices(image,start,end,indices);
3979
58.3k
}
3980
3981
static void WriteFourCC(Image *image, const size_t compression,
3982
  const MagickBooleanType clusterFit, const MagickBooleanType weightByAlpha,
3983
  ExceptionInfo *exception)
3984
6.52k
{
3985
6.52k
  ssize_t
3986
6.52k
    bx,
3987
6.52k
    by,
3988
6.52k
    i,
3989
6.52k
    y,
3990
6.52k
    x;
3991
3992
6.52k
  const Quantum
3993
6.52k
    *p;
3994
3995
61.8k
  for (y=0; y < (ssize_t) image->rows; y+=4)
3996
55.3k
  {
3997
179k
    for (x=0; x < (ssize_t) image->columns; x+=4)
3998
123k
    {
3999
123k
      MagickBooleanType
4000
123k
        match;
4001
4002
123k
      DDSVector4
4003
123k
        point,
4004
123k
        points[16] = { { 0, 0, 0, 0 } };
4005
4006
123k
      size_t
4007
123k
        count = 0,
4008
123k
        max5 = 0,
4009
123k
        max7 = 0,
4010
123k
        min5 = 255,
4011
123k
        min7 = 255,
4012
123k
        columns = 4,
4013
123k
        rows = 4;
4014
4015
123k
      ssize_t
4016
123k
        alphas[16],
4017
123k
        map[16];
4018
4019
123k
      unsigned char
4020
123k
        alpha;
4021
4022
123k
      if ((size_t) (x+(ssize_t) columns) >= image->columns)
4023
55.3k
        columns = (size_t) ((ssize_t) image->columns-x);
4024
4025
123k
      if ((size_t) (y+(ssize_t) rows) >= image->rows)
4026
65.1k
        rows = (size_t) ((ssize_t) image->rows-y);
4027
4028
123k
      p=GetVirtualPixels(image,x,y,columns,rows,exception);
4029
123k
      if (p == (const Quantum *) NULL)
4030
0
        break;
4031
4032
2.10M
      for (i=0; i<16; i++)
4033
1.98M
      {
4034
1.98M
        map[i] = -1;
4035
1.98M
        alphas[i] = -1;
4036
1.98M
      }
4037
4038
467k
      for (by=0; by < (ssize_t) rows; by++)
4039
344k
      {
4040
1.19M
        for (bx=0; bx < (ssize_t) columns; bx++)
4041
852k
        {
4042
852k
          if (compression == FOURCC_DXT5)
4043
430k
            alpha = ScaleQuantumToChar(GetPixelAlpha(image,p));
4044
422k
          else
4045
422k
            alpha = 255;
4046
4047
852k
          if (compression == FOURCC_DXT5)
4048
430k
            {
4049
430k
              if (alpha < min7)
4050
54.1k
                min7 = alpha;
4051
430k
              if (alpha > max7)
4052
63.6k
                max7 = alpha;
4053
430k
              if (alpha != 0 && alpha < min5)
4054
38.8k
                min5 = alpha;
4055
430k
              if (alpha != 255 && alpha > max5)
4056
38.0k
                max5 = alpha;
4057
430k
            }
4058
          
4059
852k
          alphas[4*by + bx] = (ssize_t)alpha;
4060
4061
852k
          point.x = (float)ScaleQuantumToChar(GetPixelRed(image,p)) / 255.0f;
4062
852k
          point.y = (float)ScaleQuantumToChar(GetPixelGreen(image,p)) / 255.0f;
4063
852k
          point.z = (float)ScaleQuantumToChar(GetPixelBlue(image,p)) / 255.0f;
4064
852k
          point.w = weightByAlpha ? (float)(alpha + 1) / 256.0f : 1.0f;
4065
852k
          p+=(ptrdiff_t) GetPixelChannels(image);
4066
4067
852k
          match = MagickFalse;
4068
1.46M
          for (i=0; i < (ssize_t) count; i++)
4069
1.18M
          {
4070
1.18M
            if ((points[i].x == point.x) &&
4071
631k
                (points[i].y == point.y) &&
4072
577k
                (points[i].z == point.z) &&
4073
566k
                (alpha       >= 128 || compression == FOURCC_DXT5))
4074
566k
              {
4075
566k
                points[i].w += point.w;
4076
566k
                map[4*by + bx] = i;
4077
566k
                match = MagickTrue;
4078
566k
                break;
4079
566k
              }
4080
1.18M
          }
4081
4082
852k
          if (match != MagickFalse)
4083
566k
            continue;
4084
4085
286k
          points[count].x = point.x;
4086
286k
          points[count].y = point.y;
4087
286k
          points[count].z = point.z;
4088
286k
          points[count].w = point.w;
4089
286k
          map[4*by + bx] = (ssize_t) count;
4090
286k
          count++;
4091
286k
        }
4092
344k
      }
4093
4094
409k
      for (i=0; i < (ssize_t) count; i++)
4095
286k
        points[i].w=sqrtf(points[i].w);
4096
4097
123k
      if (compression == FOURCC_DXT5)
4098
52.3k
        WriteAlphas(image,alphas,min5,max5,min7,max7);
4099
4100
123k
      if (count == 1)
4101
58.3k
        WriteSingleColorFit(image,points,map);
4102
65.4k
      else
4103
65.4k
        WriteCompressed(image,count,points,map,clusterFit);
4104
123k
    }
4105
55.3k
  }
4106
6.52k
}
4107
4108
static void WriteUncompressed(Image *image, ExceptionInfo *exception)
4109
0
{
4110
0
  const Quantum
4111
0
    *p;
4112
4113
0
  ssize_t
4114
0
    x;
4115
4116
0
  ssize_t
4117
0
    y;
4118
4119
0
  for (y=0; y < (ssize_t) image->rows; y++)
4120
0
  {
4121
0
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
4122
0
    if (p == (const Quantum *) NULL)
4123
0
      break;
4124
4125
0
    for (x=0; x < (ssize_t) image->columns; x++)
4126
0
    {
4127
0
      (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelBlue(image,p)));
4128
0
      (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelGreen(image,p)));
4129
0
      (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelRed(image,p)));
4130
0
      if (image->alpha_trait != UndefinedPixelTrait)
4131
0
        (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelAlpha(image,p)));
4132
0
      p+=(ptrdiff_t) GetPixelChannels(image);
4133
0
    }
4134
0
  }
4135
0
}
4136
4137
static void WriteImageData(Image *image, const size_t pixelFormat,
4138
  const size_t compression,const MagickBooleanType clusterFit,
4139
  const MagickBooleanType weightByAlpha, ExceptionInfo *exception)
4140
6.52k
{
4141
6.52k
  if (pixelFormat == DDPF_FOURCC)
4142
6.52k
    WriteFourCC(image,compression,clusterFit,weightByAlpha,exception);
4143
0
  else
4144
0
    WriteUncompressed(image,exception);
4145
6.52k
}
4146
4147
static MagickBooleanType WriteMipmaps(Image *image,const ImageInfo *image_info,
4148
  const size_t pixelFormat,const size_t compression,const size_t mipmaps,
4149
  const MagickBooleanType fromlist,const MagickBooleanType clusterFit,
4150
  const MagickBooleanType weightByAlpha,ExceptionInfo *exception)
4151
1.12k
{
4152
1.12k
  const char
4153
1.12k
    *option;
4154
4155
1.12k
  Image
4156
1.12k
    *mipmap_image,
4157
1.12k
    *resize_image;
4158
4159
1.12k
  MagickBooleanType
4160
1.12k
    fast_mipmaps,
4161
1.12k
    status;
4162
4163
1.12k
  ssize_t
4164
1.12k
    i;
4165
4166
1.12k
  size_t
4167
1.12k
    columns,
4168
1.12k
    rows;
4169
4170
1.12k
  columns=DIV2(image->columns);
4171
1.12k
  rows=DIV2(image->rows);
4172
4173
1.12k
  option=GetImageOption(image_info,"dds:fast-mipmaps");
4174
1.12k
  fast_mipmaps=IsStringTrue(option);
4175
1.12k
  mipmap_image=image;
4176
1.12k
  resize_image=image;
4177
1.12k
  status=MagickTrue;
4178
5.06k
  for (i=0; i < (ssize_t) mipmaps; i++)
4179
3.94k
  {
4180
3.94k
    if (fromlist == MagickFalse)
4181
3.94k
      {
4182
3.94k
        mipmap_image=ResizeImage(resize_image,columns,rows,TriangleFilter,
4183
3.94k
          exception);
4184
4185
3.94k
        if (mipmap_image == (Image *) NULL)
4186
0
          {
4187
0
            status=MagickFalse;
4188
0
            break;
4189
0
          }
4190
3.94k
      }
4191
0
    else
4192
0
      {
4193
0
        mipmap_image=mipmap_image->next;
4194
0
        if ((mipmap_image->columns != columns) || (mipmap_image->rows != rows))
4195
0
          ThrowBinaryException(CoderError,"ImageColumnOrRowSizeIsNotSupported",
4196
0
            image->filename);
4197
0
      }
4198
4199
3.94k
    DestroyBlob(mipmap_image);
4200
3.94k
    mipmap_image->blob=ReferenceBlob(image->blob);
4201
4202
3.94k
    WriteImageData(mipmap_image,pixelFormat,compression,weightByAlpha,
4203
3.94k
      clusterFit,exception);
4204
4205
3.94k
    if (fromlist == MagickFalse)
4206
3.94k
      {
4207
3.94k
        if (fast_mipmaps == MagickFalse)
4208
3.94k
          mipmap_image=DestroyImage(mipmap_image);
4209
0
        else
4210
0
          {
4211
0
            if (resize_image != image)
4212
0
              resize_image=DestroyImage(resize_image);
4213
0
            resize_image=mipmap_image;
4214
0
          }
4215
3.94k
      }
4216
4217
3.94k
    columns=DIV2(columns);
4218
3.94k
    rows=DIV2(rows);
4219
3.94k
  }
4220
4221
1.12k
  if (resize_image != image)
4222
0
    resize_image=DestroyImage(resize_image);
4223
4224
1.12k
  return(status);
4225
1.12k
}
4226
4227
static void WriteDDSInfo(Image *image, const size_t pixelFormat,
4228
  const size_t compression, const size_t mipmaps)
4229
2.58k
{
4230
2.58k
  char
4231
2.58k
    software[MagickPathExtent];
4232
4233
2.58k
  ssize_t
4234
2.58k
    i;
4235
4236
2.58k
  unsigned int
4237
2.58k
    format,
4238
2.58k
    caps,
4239
2.58k
    flags;
4240
4241
2.58k
  flags=(unsigned int) (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT |
4242
2.58k
    DDSD_PIXELFORMAT);
4243
2.58k
  caps=(unsigned int) DDSCAPS_TEXTURE;
4244
2.58k
  format=(unsigned int) pixelFormat;
4245
4246
2.58k
  if (format == DDPF_FOURCC)
4247
2.58k
      flags=flags | DDSD_LINEARSIZE;
4248
0
  else
4249
0
      flags=flags | DDSD_PITCH;
4250
4251
2.58k
  if (mipmaps > 0)
4252
1.12k
    {
4253
1.12k
      flags=flags | (unsigned int) DDSD_MIPMAPCOUNT;
4254
1.12k
      caps=caps | (unsigned int) (DDSCAPS_MIPMAP | DDSCAPS_COMPLEX);
4255
1.12k
    }
4256
4257
2.58k
  if (format != DDPF_FOURCC && image->alpha_trait != UndefinedPixelTrait)
4258
0
    format=format | DDPF_ALPHAPIXELS;
4259
4260
2.58k
  (void) WriteBlob(image,4,(unsigned char *) "DDS ");
4261
2.58k
  (void) WriteBlobLSBLong(image,124);
4262
2.58k
  (void) WriteBlobLSBLong(image,flags);
4263
2.58k
  (void) WriteBlobLSBLong(image,(unsigned int) image->rows);
4264
2.58k
  (void) WriteBlobLSBLong(image,(unsigned int) image->columns);
4265
4266
2.58k
  if (pixelFormat == DDPF_FOURCC)
4267
2.58k
    {
4268
      /* Compressed DDS requires linear compressed size of first image */
4269
2.58k
      if (compression == FOURCC_DXT1)
4270
1.47k
        (void) WriteBlobLSBLong(image,(unsigned int) (MagickMax(1,
4271
1.47k
          (image->columns+3)/4)*MagickMax(1,(image->rows+3)/4)*8));
4272
1.10k
      else /* DXT5 */
4273
1.10k
        (void) WriteBlobLSBLong(image,(unsigned int) (MagickMax(1,
4274
1.10k
          (image->columns+3)/4)*MagickMax(1,(image->rows+3)/4)*16));
4275
2.58k
    }
4276
0
  else
4277
0
    {
4278
      /* Uncompressed DDS requires byte pitch of first image */
4279
0
      if (image->alpha_trait != UndefinedPixelTrait)
4280
0
        (void) WriteBlobLSBLong(image,(unsigned int) (image->columns * 4));
4281
0
      else
4282
0
        (void) WriteBlobLSBLong(image,(unsigned int) (image->columns * 3));
4283
0
    }
4284
4285
2.58k
  (void) WriteBlobLSBLong(image,0x00);
4286
2.58k
  (void) WriteBlobLSBLong(image,(unsigned int) mipmaps+1);
4287
2.58k
  (void) memset(software,0,sizeof(software));
4288
2.58k
  (void) CopyMagickString(software,"IMAGEMAGICK",MagickPathExtent);
4289
2.58k
  (void) WriteBlob(image,44,(unsigned char *) software);
4290
4291
2.58k
  (void) WriteBlobLSBLong(image,32);
4292
2.58k
  (void) WriteBlobLSBLong(image,format);
4293
4294
2.58k
  if (pixelFormat == DDPF_FOURCC)
4295
2.58k
    {
4296
2.58k
      (void) WriteBlobLSBLong(image,(unsigned int) compression);
4297
15.4k
      for(i=0;i < 5;i++)  /* bitcount / masks */
4298
12.9k
        (void) WriteBlobLSBLong(image,0x00);
4299
2.58k
    }
4300
0
  else
4301
0
    {
4302
0
      (void) WriteBlobLSBLong(image,0x00);
4303
0
      if (image->alpha_trait != UndefinedPixelTrait)
4304
0
        {
4305
0
          (void) WriteBlobLSBLong(image,32);
4306
0
          (void) WriteBlobLSBLong(image,0xff0000);
4307
0
          (void) WriteBlobLSBLong(image,0xff00);
4308
0
          (void) WriteBlobLSBLong(image,0xff);
4309
0
          (void) WriteBlobLSBLong(image,0xff000000);
4310
0
        }
4311
0
      else
4312
0
        {
4313
0
          (void) WriteBlobLSBLong(image,24);
4314
0
          (void) WriteBlobLSBLong(image,0xff0000);
4315
0
          (void) WriteBlobLSBLong(image,0xff00);
4316
0
          (void) WriteBlobLSBLong(image,0xff);
4317
0
          (void) WriteBlobLSBLong(image,0x00);
4318
0
        }
4319
0
    }
4320
  
4321
2.58k
  (void) WriteBlobLSBLong(image,caps);
4322
12.9k
  for(i=0;i < 4;i++)   /* ddscaps2 + reserved region */
4323
10.3k
    (void) WriteBlobLSBLong(image,0x00);
4324
2.58k
}
4325
4326
static MagickBooleanType WriteDDSImage(const ImageInfo *image_info,
4327
  Image *image, ExceptionInfo *exception)
4328
2.58k
{
4329
2.58k
  const char
4330
2.58k
    *option;
4331
4332
2.58k
  size_t
4333
2.58k
    compression,
4334
2.58k
    columns,
4335
2.58k
    maxMipmaps,
4336
2.58k
    mipmaps,
4337
2.58k
    pixelFormat,
4338
2.58k
    rows;
4339
4340
2.58k
  MagickBooleanType
4341
2.58k
    clusterFit,
4342
2.58k
    fromlist,
4343
2.58k
    status,
4344
2.58k
    weightByAlpha;
4345
4346
2.58k
  assert(image_info != (const ImageInfo *) NULL);
4347
2.58k
  assert(image_info->signature == MagickCoreSignature);
4348
2.58k
  assert(image != (Image *) NULL);
4349
2.58k
  assert(image->signature == MagickCoreSignature);
4350
2.58k
  if (IsEventLogging() != MagickFalse)
4351
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4352
2.58k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
4353
2.58k
  if (status == MagickFalse)
4354
0
    return(status);
4355
2.58k
  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
4356
0
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
4357
2.58k
  pixelFormat=DDPF_FOURCC;
4358
2.58k
  compression=FOURCC_DXT5;
4359
2.58k
  if (((image->alpha_trait & BlendPixelTrait) == 0) ||
4360
1.56k
      (LocaleCompare(image_info->magick,"dxt1") == 0) ||
4361
1.10k
      (image_info->compression == DXT1Compression))
4362
1.47k
    compression=FOURCC_DXT1;
4363
1.10k
  else if (image_info->compression == NoCompression)
4364
0
    pixelFormat=DDPF_RGB;
4365
2.58k
  option=GetImageOption(image_info,"dds:compression");
4366
2.58k
  if (option != (char *) NULL)
4367
0
    {
4368
0
       if (LocaleCompare(option,"dxt1") == 0)
4369
0
         compression=FOURCC_DXT1;
4370
0
       if (LocaleCompare(option,"dxt5") == 0)
4371
0
         compression=FOURCC_DXT5;
4372
0
       if (LocaleCompare(option,"none") == 0)
4373
0
         pixelFormat=DDPF_RGB;
4374
0
    }
4375
2.58k
  clusterFit=MagickFalse;
4376
2.58k
  weightByAlpha=MagickFalse;
4377
2.58k
  if (pixelFormat == DDPF_FOURCC)
4378
2.58k
    {
4379
2.58k
      option=GetImageOption(image_info,"dds:cluster-fit");
4380
2.58k
      if (IsStringTrue(option) != MagickFalse)
4381
0
        {
4382
0
          clusterFit=MagickTrue;
4383
0
          if (compression != FOURCC_DXT1)
4384
0
            {
4385
0
              option=GetImageOption(image_info,"dds:weight-by-alpha");
4386
0
              if (IsStringTrue(option) != MagickFalse)
4387
0
                weightByAlpha=MagickTrue;
4388
0
            }
4389
0
        }
4390
2.58k
    }
4391
2.58k
  mipmaps=0;
4392
2.58k
  fromlist=MagickFalse;
4393
2.58k
  option=GetImageOption(image_info,"dds:mipmaps");
4394
2.58k
  if (option != (char *) NULL)
4395
0
    {
4396
0
      if (LocaleNCompare(option,"fromlist",8) == 0)
4397
0
        {
4398
0
          Image
4399
0
            *next;
4400
4401
0
          fromlist=MagickTrue;
4402
0
          next=image->next;
4403
0
          while(next != (Image *) NULL)
4404
0
          {
4405
0
            mipmaps++;
4406
0
            next=next->next;
4407
0
          }
4408
0
        }
4409
0
    }
4410
2.58k
  if ((mipmaps == 0) &&
4411
2.58k
      ((image->columns & (image->columns - 1)) == 0) &&
4412
1.93k
      ((image->rows & (image->rows - 1)) == 0))
4413
1.58k
    {
4414
1.58k
      maxMipmaps=SIZE_MAX;
4415
1.58k
      if (option != (char *) NULL)
4416
0
        maxMipmaps=StringToUnsignedLong(option);
4417
4418
1.58k
      if (maxMipmaps != 0)
4419
1.58k
        {
4420
1.58k
          columns=image->columns;
4421
1.58k
          rows=image->rows;
4422
5.52k
          while ((columns != 1 || rows != 1) && mipmaps != maxMipmaps)
4423
3.94k
          {
4424
3.94k
            columns=DIV2(columns);
4425
3.94k
            rows=DIV2(rows);
4426
3.94k
            mipmaps++;
4427
3.94k
          }
4428
1.58k
        }
4429
1.58k
    }
4430
2.58k
  option=GetImageOption(image_info,"dds:raw");
4431
2.58k
  if (IsStringTrue(option) == MagickFalse)
4432
2.58k
    WriteDDSInfo(image,pixelFormat,compression,mipmaps);
4433
0
  else
4434
0
    mipmaps=0;
4435
2.58k
  WriteImageData(image,pixelFormat,compression,clusterFit,weightByAlpha,
4436
2.58k
    exception);
4437
2.58k
  if ((mipmaps > 0) && (WriteMipmaps(image,image_info,pixelFormat,compression,
4438
1.12k
       mipmaps,fromlist,clusterFit,weightByAlpha,exception) == MagickFalse))
4439
0
    return(MagickFalse);
4440
2.58k
  if (CloseBlob(image) == MagickFalse)
4441
0
    status=MagickFalse;
4442
2.58k
  return(status);
4443
2.58k
}