• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2021 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/script/license.php                               %
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 #define DDSD_CAPS         0x00000001
77 #define DDSD_HEIGHT       0x00000002
78 #define DDSD_WIDTH        0x00000004
79 #define DDSD_PITCH        0x00000008
80 #define DDSD_PIXELFORMAT  0x00001000
81 #define DDSD_MIPMAPCOUNT  0x00020000
82 #define DDSD_LINEARSIZE   0x00080000
83 #define DDSD_DEPTH        0x00800000
84 
85 #define DDPF_ALPHAPIXELS  0x00000001
86 #define DDPF_FOURCC       0x00000004
87 #define DDPF_RGB          0x00000040
88 #define DDPF_LUMINANCE    0x00020000
89 
90 #define FOURCC_DXT1       0x31545844
91 #define FOURCC_DXT3       0x33545844
92 #define FOURCC_DXT5       0x35545844
93 #define FOURCC_DX10       0x30315844
94 
95 #define DDSCAPS_COMPLEX   0x00000008
96 #define DDSCAPS_TEXTURE   0x00001000
97 #define DDSCAPS_MIPMAP    0x00400000
98 
99 #define DDSCAPS2_CUBEMAP  0x00000200
100 #define DDSCAPS2_CUBEMAP_POSITIVEX  0x00000400
101 #define DDSCAPS2_CUBEMAP_NEGATIVEX  0x00000800
102 #define DDSCAPS2_CUBEMAP_POSITIVEY  0x00001000
103 #define DDSCAPS2_CUBEMAP_NEGATIVEY  0x00002000
104 #define DDSCAPS2_CUBEMAP_POSITIVEZ  0x00004000
105 #define DDSCAPS2_CUBEMAP_NEGATIVEZ  0x00008000
106 #define DDSCAPS2_VOLUME   0x00200000
107 
108 #define DDSEXT_DIMENSION_TEX2D      0x00000003
109 #define DDSEXTFLAGS_CUBEMAP         0x00000004
110 
111 typedef enum DXGI_FORMAT
112 {
113   DXGI_FORMAT_UNKNOWN,
114   DXGI_FORMAT_R32G32B32A32_TYPELESS,
115   DXGI_FORMAT_R32G32B32A32_FLOAT,
116   DXGI_FORMAT_R32G32B32A32_UINT,
117   DXGI_FORMAT_R32G32B32A32_SINT,
118   DXGI_FORMAT_R32G32B32_TYPELESS,
119   DXGI_FORMAT_R32G32B32_FLOAT,
120   DXGI_FORMAT_R32G32B32_UINT,
121   DXGI_FORMAT_R32G32B32_SINT,
122   DXGI_FORMAT_R16G16B16A16_TYPELESS,
123   DXGI_FORMAT_R16G16B16A16_FLOAT,
124   DXGI_FORMAT_R16G16B16A16_UNORM,
125   DXGI_FORMAT_R16G16B16A16_UINT,
126   DXGI_FORMAT_R16G16B16A16_SNORM,
127   DXGI_FORMAT_R16G16B16A16_SINT,
128   DXGI_FORMAT_R32G32_TYPELESS,
129   DXGI_FORMAT_R32G32_FLOAT,
130   DXGI_FORMAT_R32G32_UINT,
131   DXGI_FORMAT_R32G32_SINT,
132   DXGI_FORMAT_R32G8X24_TYPELESS,
133   DXGI_FORMAT_D32_FLOAT_S8X24_UINT,
134   DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS,
135   DXGI_FORMAT_X32_TYPELESS_G8X24_UINT,
136   DXGI_FORMAT_R10G10B10A2_TYPELESS,
137   DXGI_FORMAT_R10G10B10A2_UNORM,
138   DXGI_FORMAT_R10G10B10A2_UINT,
139   DXGI_FORMAT_R11G11B10_FLOAT,
140   DXGI_FORMAT_R8G8B8A8_TYPELESS,
141   DXGI_FORMAT_R8G8B8A8_UNORM,
142   DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
143   DXGI_FORMAT_R8G8B8A8_UINT,
144   DXGI_FORMAT_R8G8B8A8_SNORM,
145   DXGI_FORMAT_R8G8B8A8_SINT,
146   DXGI_FORMAT_R16G16_TYPELESS,
147   DXGI_FORMAT_R16G16_FLOAT,
148   DXGI_FORMAT_R16G16_UNORM,
149   DXGI_FORMAT_R16G16_UINT,
150   DXGI_FORMAT_R16G16_SNORM,
151   DXGI_FORMAT_R16G16_SINT,
152   DXGI_FORMAT_R32_TYPELESS,
153   DXGI_FORMAT_D32_FLOAT,
154   DXGI_FORMAT_R32_FLOAT,
155   DXGI_FORMAT_R32_UINT,
156   DXGI_FORMAT_R32_SINT,
157   DXGI_FORMAT_R24G8_TYPELESS,
158   DXGI_FORMAT_D24_UNORM_S8_UINT,
159   DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
160   DXGI_FORMAT_X24_TYPELESS_G8_UINT,
161   DXGI_FORMAT_R8G8_TYPELESS,
162   DXGI_FORMAT_R8G8_UNORM,
163   DXGI_FORMAT_R8G8_UINT,
164   DXGI_FORMAT_R8G8_SNORM,
165   DXGI_FORMAT_R8G8_SINT,
166   DXGI_FORMAT_R16_TYPELESS,
167   DXGI_FORMAT_R16_FLOAT,
168   DXGI_FORMAT_D16_UNORM,
169   DXGI_FORMAT_R16_UNORM,
170   DXGI_FORMAT_R16_UINT,
171   DXGI_FORMAT_R16_SNORM,
172   DXGI_FORMAT_R16_SINT,
173   DXGI_FORMAT_R8_TYPELESS,
174   DXGI_FORMAT_R8_UNORM,
175   DXGI_FORMAT_R8_UINT,
176   DXGI_FORMAT_R8_SNORM,
177   DXGI_FORMAT_R8_SINT,
178   DXGI_FORMAT_A8_UNORM,
179   DXGI_FORMAT_R1_UNORM,
180   DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
181   DXGI_FORMAT_R8G8_B8G8_UNORM,
182   DXGI_FORMAT_G8R8_G8B8_UNORM,
183   DXGI_FORMAT_BC1_TYPELESS,
184   DXGI_FORMAT_BC1_UNORM,
185   DXGI_FORMAT_BC1_UNORM_SRGB,
186   DXGI_FORMAT_BC2_TYPELESS,
187   DXGI_FORMAT_BC2_UNORM,
188   DXGI_FORMAT_BC2_UNORM_SRGB,
189   DXGI_FORMAT_BC3_TYPELESS,
190   DXGI_FORMAT_BC3_UNORM,
191   DXGI_FORMAT_BC3_UNORM_SRGB,
192   DXGI_FORMAT_BC4_TYPELESS,
193   DXGI_FORMAT_BC4_UNORM,
194   DXGI_FORMAT_BC4_SNORM,
195   DXGI_FORMAT_BC5_TYPELESS,
196   DXGI_FORMAT_BC5_UNORM,
197   DXGI_FORMAT_BC5_SNORM,
198   DXGI_FORMAT_B5G6R5_UNORM,
199   DXGI_FORMAT_B5G5R5A1_UNORM,
200   DXGI_FORMAT_B8G8R8A8_UNORM,
201   DXGI_FORMAT_B8G8R8X8_UNORM,
202   DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM,
203   DXGI_FORMAT_B8G8R8A8_TYPELESS,
204   DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
205   DXGI_FORMAT_B8G8R8X8_TYPELESS,
206   DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,
207   DXGI_FORMAT_BC6H_TYPELESS,
208   DXGI_FORMAT_BC6H_UF16,
209   DXGI_FORMAT_BC6H_SF16,
210   DXGI_FORMAT_BC7_TYPELESS,
211   DXGI_FORMAT_BC7_UNORM,
212   DXGI_FORMAT_BC7_UNORM_SRGB,
213   DXGI_FORMAT_AYUV,
214   DXGI_FORMAT_Y410,
215   DXGI_FORMAT_Y416,
216   DXGI_FORMAT_NV12,
217   DXGI_FORMAT_P010,
218   DXGI_FORMAT_P016,
219   DXGI_FORMAT_420_OPAQUE,
220   DXGI_FORMAT_YUY2,
221   DXGI_FORMAT_Y210,
222   DXGI_FORMAT_Y216,
223   DXGI_FORMAT_NV11,
224   DXGI_FORMAT_AI44,
225   DXGI_FORMAT_IA44,
226   DXGI_FORMAT_P8,
227   DXGI_FORMAT_A8P8,
228   DXGI_FORMAT_B4G4R4A4_UNORM,
229   DXGI_FORMAT_P208,
230   DXGI_FORMAT_V208,
231   DXGI_FORMAT_V408,
232   DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE,
233   DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE,
234   DXGI_FORMAT_FORCE_UINT
235 } DXGI_FORMAT;
236 
237 
238 #ifndef SIZE_MAX
239 #define SIZE_MAX ((size_t) -1)
240 #endif
241 
242 /*
243   Structure declarations.
244 */
245 typedef struct _DDSPixelFormat
246 {
247   size_t
248     flags,
249     fourcc,
250     rgb_bitcount,
251     r_bitmask,
252     g_bitmask,
253     b_bitmask,
254     alpha_bitmask;
255 } DDSPixelFormat;
256 
257 typedef struct _DDSInfo
258 {
259   size_t
260     flags,
261     height,
262     width,
263     pitchOrLinearSize,
264     depth,
265     mipmapcount,
266     ddscaps1,
267     ddscaps2,
268     extFormat,
269     extDimension,
270     extFlags,
271     extArraySize,
272     extFlags2;
273 
274   DDSPixelFormat
275     pixelformat;
276 } DDSInfo;
277 
278 typedef struct _DDSColors
279 {
280   unsigned char
281     r[4],
282     g[4],
283     b[4],
284     a[4];
285 } DDSColors;
286 
287 typedef struct _DDSVector4
288 {
289   float
290     x,
291     y,
292     z,
293     w;
294 } DDSVector4;
295 
296 typedef struct _DDSVector3
297 {
298   float
299     x,
300     y,
301     z;
302 } DDSVector3;
303 
304 typedef struct _DDSSourceBlock
305 {
306   unsigned char
307     start,
308     end,
309     error;
310 } DDSSourceBlock;
311 
312 typedef struct _DDSSingleColorLookup
313 {
314   DDSSourceBlock sources[2];
315 } DDSSingleColorLookup;
316 
317 typedef MagickBooleanType
318   DDSDecoder(const ImageInfo *,Image *,DDSInfo *,const MagickBooleanType,
319     ExceptionInfo *);
320 
321 typedef MagickBooleanType
322   DDSPixelDecoder(Image *,DDSInfo *,ExceptionInfo *);
323 
324 static const DDSSingleColorLookup DDSLookup_5_4[] =
325 {
326   { { { 0, 0, 0 }, { 0, 0, 0 } } },
327   { { { 0, 0, 1 }, { 0, 1, 1 } } },
328   { { { 0, 0, 2 }, { 0, 1, 0 } } },
329   { { { 0, 0, 3 }, { 0, 1, 1 } } },
330   { { { 0, 0, 4 }, { 0, 2, 1 } } },
331   { { { 1, 0, 3 }, { 0, 2, 0 } } },
332   { { { 1, 0, 2 }, { 0, 2, 1 } } },
333   { { { 1, 0, 1 }, { 0, 3, 1 } } },
334   { { { 1, 0, 0 }, { 0, 3, 0 } } },
335   { { { 1, 0, 1 }, { 1, 2, 1 } } },
336   { { { 1, 0, 2 }, { 1, 2, 0 } } },
337   { { { 1, 0, 3 }, { 0, 4, 0 } } },
338   { { { 1, 0, 4 }, { 0, 5, 1 } } },
339   { { { 2, 0, 3 }, { 0, 5, 0 } } },
340   { { { 2, 0, 2 }, { 0, 5, 1 } } },
341   { { { 2, 0, 1 }, { 0, 6, 1 } } },
342   { { { 2, 0, 0 }, { 0, 6, 0 } } },
343   { { { 2, 0, 1 }, { 2, 3, 1 } } },
344   { { { 2, 0, 2 }, { 2, 3, 0 } } },
345   { { { 2, 0, 3 }, { 0, 7, 0 } } },
346   { { { 2, 0, 4 }, { 1, 6, 1 } } },
347   { { { 3, 0, 3 }, { 1, 6, 0 } } },
348   { { { 3, 0, 2 }, { 0, 8, 0 } } },
349   { { { 3, 0, 1 }, { 0, 9, 1 } } },
350   { { { 3, 0, 0 }, { 0, 9, 0 } } },
351   { { { 3, 0, 1 }, { 0, 9, 1 } } },
352   { { { 3, 0, 2 }, { 0, 10, 1 } } },
353   { { { 3, 0, 3 }, { 0, 10, 0 } } },
354   { { { 3, 0, 4 }, { 2, 7, 1 } } },
355   { { { 4, 0, 4 }, { 2, 7, 0 } } },
356   { { { 4, 0, 3 }, { 0, 11, 0 } } },
357   { { { 4, 0, 2 }, { 1, 10, 1 } } },
358   { { { 4, 0, 1 }, { 1, 10, 0 } } },
359   { { { 4, 0, 0 }, { 0, 12, 0 } } },
360   { { { 4, 0, 1 }, { 0, 13, 1 } } },
361   { { { 4, 0, 2 }, { 0, 13, 0 } } },
362   { { { 4, 0, 3 }, { 0, 13, 1 } } },
363   { { { 4, 0, 4 }, { 0, 14, 1 } } },
364   { { { 5, 0, 3 }, { 0, 14, 0 } } },
365   { { { 5, 0, 2 }, { 2, 11, 1 } } },
366   { { { 5, 0, 1 }, { 2, 11, 0 } } },
367   { { { 5, 0, 0 }, { 0, 15, 0 } } },
368   { { { 5, 0, 1 }, { 1, 14, 1 } } },
369   { { { 5, 0, 2 }, { 1, 14, 0 } } },
370   { { { 5, 0, 3 }, { 0, 16, 0 } } },
371   { { { 5, 0, 4 }, { 0, 17, 1 } } },
372   { { { 6, 0, 3 }, { 0, 17, 0 } } },
373   { { { 6, 0, 2 }, { 0, 17, 1 } } },
374   { { { 6, 0, 1 }, { 0, 18, 1 } } },
375   { { { 6, 0, 0 }, { 0, 18, 0 } } },
376   { { { 6, 0, 1 }, { 2, 15, 1 } } },
377   { { { 6, 0, 2 }, { 2, 15, 0 } } },
378   { { { 6, 0, 3 }, { 0, 19, 0 } } },
379   { { { 6, 0, 4 }, { 1, 18, 1 } } },
380   { { { 7, 0, 3 }, { 1, 18, 0 } } },
381   { { { 7, 0, 2 }, { 0, 20, 0 } } },
382   { { { 7, 0, 1 }, { 0, 21, 1 } } },
383   { { { 7, 0, 0 }, { 0, 21, 0 } } },
384   { { { 7, 0, 1 }, { 0, 21, 1 } } },
385   { { { 7, 0, 2 }, { 0, 22, 1 } } },
386   { { { 7, 0, 3 }, { 0, 22, 0 } } },
387   { { { 7, 0, 4 }, { 2, 19, 1 } } },
388   { { { 8, 0, 4 }, { 2, 19, 0 } } },
389   { { { 8, 0, 3 }, { 0, 23, 0 } } },
390   { { { 8, 0, 2 }, { 1, 22, 1 } } },
391   { { { 8, 0, 1 }, { 1, 22, 0 } } },
392   { { { 8, 0, 0 }, { 0, 24, 0 } } },
393   { { { 8, 0, 1 }, { 0, 25, 1 } } },
394   { { { 8, 0, 2 }, { 0, 25, 0 } } },
395   { { { 8, 0, 3 }, { 0, 25, 1 } } },
396   { { { 8, 0, 4 }, { 0, 26, 1 } } },
397   { { { 9, 0, 3 }, { 0, 26, 0 } } },
398   { { { 9, 0, 2 }, { 2, 23, 1 } } },
399   { { { 9, 0, 1 }, { 2, 23, 0 } } },
400   { { { 9, 0, 0 }, { 0, 27, 0 } } },
401   { { { 9, 0, 1 }, { 1, 26, 1 } } },
402   { { { 9, 0, 2 }, { 1, 26, 0 } } },
403   { { { 9, 0, 3 }, { 0, 28, 0 } } },
404   { { { 9, 0, 4 }, { 0, 29, 1 } } },
405   { { { 10, 0, 3 }, { 0, 29, 0 } } },
406   { { { 10, 0, 2 }, { 0, 29, 1 } } },
407   { { { 10, 0, 1 }, { 0, 30, 1 } } },
408   { { { 10, 0, 0 }, { 0, 30, 0 } } },
409   { { { 10, 0, 1 }, { 2, 27, 1 } } },
410   { { { 10, 0, 2 }, { 2, 27, 0 } } },
411   { { { 10, 0, 3 }, { 0, 31, 0 } } },
412   { { { 10, 0, 4 }, { 1, 30, 1 } } },
413   { { { 11, 0, 3 }, { 1, 30, 0 } } },
414   { { { 11, 0, 2 }, { 4, 24, 0 } } },
415   { { { 11, 0, 1 }, { 1, 31, 1 } } },
416   { { { 11, 0, 0 }, { 1, 31, 0 } } },
417   { { { 11, 0, 1 }, { 1, 31, 1 } } },
418   { { { 11, 0, 2 }, { 2, 30, 1 } } },
419   { { { 11, 0, 3 }, { 2, 30, 0 } } },
420   { { { 11, 0, 4 }, { 2, 31, 1 } } },
421   { { { 12, 0, 4 }, { 2, 31, 0 } } },
422   { { { 12, 0, 3 }, { 4, 27, 0 } } },
423   { { { 12, 0, 2 }, { 3, 30, 1 } } },
424   { { { 12, 0, 1 }, { 3, 30, 0 } } },
425   { { { 12, 0, 0 }, { 4, 28, 0 } } },
426   { { { 12, 0, 1 }, { 3, 31, 1 } } },
427   { { { 12, 0, 2 }, { 3, 31, 0 } } },
428   { { { 12, 0, 3 }, { 3, 31, 1 } } },
429   { { { 12, 0, 4 }, { 4, 30, 1 } } },
430   { { { 13, 0, 3 }, { 4, 30, 0 } } },
431   { { { 13, 0, 2 }, { 6, 27, 1 } } },
432   { { { 13, 0, 1 }, { 6, 27, 0 } } },
433   { { { 13, 0, 0 }, { 4, 31, 0 } } },
434   { { { 13, 0, 1 }, { 5, 30, 1 } } },
435   { { { 13, 0, 2 }, { 5, 30, 0 } } },
436   { { { 13, 0, 3 }, { 8, 24, 0 } } },
437   { { { 13, 0, 4 }, { 5, 31, 1 } } },
438   { { { 14, 0, 3 }, { 5, 31, 0 } } },
439   { { { 14, 0, 2 }, { 5, 31, 1 } } },
440   { { { 14, 0, 1 }, { 6, 30, 1 } } },
441   { { { 14, 0, 0 }, { 6, 30, 0 } } },
442   { { { 14, 0, 1 }, { 6, 31, 1 } } },
443   { { { 14, 0, 2 }, { 6, 31, 0 } } },
444   { { { 14, 0, 3 }, { 8, 27, 0 } } },
445   { { { 14, 0, 4 }, { 7, 30, 1 } } },
446   { { { 15, 0, 3 }, { 7, 30, 0 } } },
447   { { { 15, 0, 2 }, { 8, 28, 0 } } },
448   { { { 15, 0, 1 }, { 7, 31, 1 } } },
449   { { { 15, 0, 0 }, { 7, 31, 0 } } },
450   { { { 15, 0, 1 }, { 7, 31, 1 } } },
451   { { { 15, 0, 2 }, { 8, 30, 1 } } },
452   { { { 15, 0, 3 }, { 8, 30, 0 } } },
453   { { { 15, 0, 4 }, { 10, 27, 1 } } },
454   { { { 16, 0, 4 }, { 10, 27, 0 } } },
455   { { { 16, 0, 3 }, { 8, 31, 0 } } },
456   { { { 16, 0, 2 }, { 9, 30, 1 } } },
457   { { { 16, 0, 1 }, { 9, 30, 0 } } },
458   { { { 16, 0, 0 }, { 12, 24, 0 } } },
459   { { { 16, 0, 1 }, { 9, 31, 1 } } },
460   { { { 16, 0, 2 }, { 9, 31, 0 } } },
461   { { { 16, 0, 3 }, { 9, 31, 1 } } },
462   { { { 16, 0, 4 }, { 10, 30, 1 } } },
463   { { { 17, 0, 3 }, { 10, 30, 0 } } },
464   { { { 17, 0, 2 }, { 10, 31, 1 } } },
465   { { { 17, 0, 1 }, { 10, 31, 0 } } },
466   { { { 17, 0, 0 }, { 12, 27, 0 } } },
467   { { { 17, 0, 1 }, { 11, 30, 1 } } },
468   { { { 17, 0, 2 }, { 11, 30, 0 } } },
469   { { { 17, 0, 3 }, { 12, 28, 0 } } },
470   { { { 17, 0, 4 }, { 11, 31, 1 } } },
471   { { { 18, 0, 3 }, { 11, 31, 0 } } },
472   { { { 18, 0, 2 }, { 11, 31, 1 } } },
473   { { { 18, 0, 1 }, { 12, 30, 1 } } },
474   { { { 18, 0, 0 }, { 12, 30, 0 } } },
475   { { { 18, 0, 1 }, { 14, 27, 1 } } },
476   { { { 18, 0, 2 }, { 14, 27, 0 } } },
477   { { { 18, 0, 3 }, { 12, 31, 0 } } },
478   { { { 18, 0, 4 }, { 13, 30, 1 } } },
479   { { { 19, 0, 3 }, { 13, 30, 0 } } },
480   { { { 19, 0, 2 }, { 16, 24, 0 } } },
481   { { { 19, 0, 1 }, { 13, 31, 1 } } },
482   { { { 19, 0, 0 }, { 13, 31, 0 } } },
483   { { { 19, 0, 1 }, { 13, 31, 1 } } },
484   { { { 19, 0, 2 }, { 14, 30, 1 } } },
485   { { { 19, 0, 3 }, { 14, 30, 0 } } },
486   { { { 19, 0, 4 }, { 14, 31, 1 } } },
487   { { { 20, 0, 4 }, { 14, 31, 0 } } },
488   { { { 20, 0, 3 }, { 16, 27, 0 } } },
489   { { { 20, 0, 2 }, { 15, 30, 1 } } },
490   { { { 20, 0, 1 }, { 15, 30, 0 } } },
491   { { { 20, 0, 0 }, { 16, 28, 0 } } },
492   { { { 20, 0, 1 }, { 15, 31, 1 } } },
493   { { { 20, 0, 2 }, { 15, 31, 0 } } },
494   { { { 20, 0, 3 }, { 15, 31, 1 } } },
495   { { { 20, 0, 4 }, { 16, 30, 1 } } },
496   { { { 21, 0, 3 }, { 16, 30, 0 } } },
497   { { { 21, 0, 2 }, { 18, 27, 1 } } },
498   { { { 21, 0, 1 }, { 18, 27, 0 } } },
499   { { { 21, 0, 0 }, { 16, 31, 0 } } },
500   { { { 21, 0, 1 }, { 17, 30, 1 } } },
501   { { { 21, 0, 2 }, { 17, 30, 0 } } },
502   { { { 21, 0, 3 }, { 20, 24, 0 } } },
503   { { { 21, 0, 4 }, { 17, 31, 1 } } },
504   { { { 22, 0, 3 }, { 17, 31, 0 } } },
505   { { { 22, 0, 2 }, { 17, 31, 1 } } },
506   { { { 22, 0, 1 }, { 18, 30, 1 } } },
507   { { { 22, 0, 0 }, { 18, 30, 0 } } },
508   { { { 22, 0, 1 }, { 18, 31, 1 } } },
509   { { { 22, 0, 2 }, { 18, 31, 0 } } },
510   { { { 22, 0, 3 }, { 20, 27, 0 } } },
511   { { { 22, 0, 4 }, { 19, 30, 1 } } },
512   { { { 23, 0, 3 }, { 19, 30, 0 } } },
513   { { { 23, 0, 2 }, { 20, 28, 0 } } },
514   { { { 23, 0, 1 }, { 19, 31, 1 } } },
515   { { { 23, 0, 0 }, { 19, 31, 0 } } },
516   { { { 23, 0, 1 }, { 19, 31, 1 } } },
517   { { { 23, 0, 2 }, { 20, 30, 1 } } },
518   { { { 23, 0, 3 }, { 20, 30, 0 } } },
519   { { { 23, 0, 4 }, { 22, 27, 1 } } },
520   { { { 24, 0, 4 }, { 22, 27, 0 } } },
521   { { { 24, 0, 3 }, { 20, 31, 0 } } },
522   { { { 24, 0, 2 }, { 21, 30, 1 } } },
523   { { { 24, 0, 1 }, { 21, 30, 0 } } },
524   { { { 24, 0, 0 }, { 24, 24, 0 } } },
525   { { { 24, 0, 1 }, { 21, 31, 1 } } },
526   { { { 24, 0, 2 }, { 21, 31, 0 } } },
527   { { { 24, 0, 3 }, { 21, 31, 1 } } },
528   { { { 24, 0, 4 }, { 22, 30, 1 } } },
529   { { { 25, 0, 3 }, { 22, 30, 0 } } },
530   { { { 25, 0, 2 }, { 22, 31, 1 } } },
531   { { { 25, 0, 1 }, { 22, 31, 0 } } },
532   { { { 25, 0, 0 }, { 24, 27, 0 } } },
533   { { { 25, 0, 1 }, { 23, 30, 1 } } },
534   { { { 25, 0, 2 }, { 23, 30, 0 } } },
535   { { { 25, 0, 3 }, { 24, 28, 0 } } },
536   { { { 25, 0, 4 }, { 23, 31, 1 } } },
537   { { { 26, 0, 3 }, { 23, 31, 0 } } },
538   { { { 26, 0, 2 }, { 23, 31, 1 } } },
539   { { { 26, 0, 1 }, { 24, 30, 1 } } },
540   { { { 26, 0, 0 }, { 24, 30, 0 } } },
541   { { { 26, 0, 1 }, { 26, 27, 1 } } },
542   { { { 26, 0, 2 }, { 26, 27, 0 } } },
543   { { { 26, 0, 3 }, { 24, 31, 0 } } },
544   { { { 26, 0, 4 }, { 25, 30, 1 } } },
545   { { { 27, 0, 3 }, { 25, 30, 0 } } },
546   { { { 27, 0, 2 }, { 28, 24, 0 } } },
547   { { { 27, 0, 1 }, { 25, 31, 1 } } },
548   { { { 27, 0, 0 }, { 25, 31, 0 } } },
549   { { { 27, 0, 1 }, { 25, 31, 1 } } },
550   { { { 27, 0, 2 }, { 26, 30, 1 } } },
551   { { { 27, 0, 3 }, { 26, 30, 0 } } },
552   { { { 27, 0, 4 }, { 26, 31, 1 } } },
553   { { { 28, 0, 4 }, { 26, 31, 0 } } },
554   { { { 28, 0, 3 }, { 28, 27, 0 } } },
555   { { { 28, 0, 2 }, { 27, 30, 1 } } },
556   { { { 28, 0, 1 }, { 27, 30, 0 } } },
557   { { { 28, 0, 0 }, { 28, 28, 0 } } },
558   { { { 28, 0, 1 }, { 27, 31, 1 } } },
559   { { { 28, 0, 2 }, { 27, 31, 0 } } },
560   { { { 28, 0, 3 }, { 27, 31, 1 } } },
561   { { { 28, 0, 4 }, { 28, 30, 1 } } },
562   { { { 29, 0, 3 }, { 28, 30, 0 } } },
563   { { { 29, 0, 2 }, { 30, 27, 1 } } },
564   { { { 29, 0, 1 }, { 30, 27, 0 } } },
565   { { { 29, 0, 0 }, { 28, 31, 0 } } },
566   { { { 29, 0, 1 }, { 29, 30, 1 } } },
567   { { { 29, 0, 2 }, { 29, 30, 0 } } },
568   { { { 29, 0, 3 }, { 29, 30, 1 } } },
569   { { { 29, 0, 4 }, { 29, 31, 1 } } },
570   { { { 30, 0, 3 }, { 29, 31, 0 } } },
571   { { { 30, 0, 2 }, { 29, 31, 1 } } },
572   { { { 30, 0, 1 }, { 30, 30, 1 } } },
573   { { { 30, 0, 0 }, { 30, 30, 0 } } },
574   { { { 30, 0, 1 }, { 30, 31, 1 } } },
575   { { { 30, 0, 2 }, { 30, 31, 0 } } },
576   { { { 30, 0, 3 }, { 30, 31, 1 } } },
577   { { { 30, 0, 4 }, { 31, 30, 1 } } },
578   { { { 31, 0, 3 }, { 31, 30, 0 } } },
579   { { { 31, 0, 2 }, { 31, 30, 1 } } },
580   { { { 31, 0, 1 }, { 31, 31, 1 } } },
581   { { { 31, 0, 0 }, { 31, 31, 0 } } }
582 };
583 
584 static const DDSSingleColorLookup DDSLookup_6_4[] =
585 {
586   { { { 0, 0, 0 }, { 0, 0, 0 } } },
587   { { { 0, 0, 1 }, { 0, 1, 0 } } },
588   { { { 0, 0, 2 }, { 0, 2, 0 } } },
589   { { { 1, 0, 1 }, { 0, 3, 1 } } },
590   { { { 1, 0, 0 }, { 0, 3, 0 } } },
591   { { { 1, 0, 1 }, { 0, 4, 0 } } },
592   { { { 1, 0, 2 }, { 0, 5, 0 } } },
593   { { { 2, 0, 1 }, { 0, 6, 1 } } },
594   { { { 2, 0, 0 }, { 0, 6, 0 } } },
595   { { { 2, 0, 1 }, { 0, 7, 0 } } },
596   { { { 2, 0, 2 }, { 0, 8, 0 } } },
597   { { { 3, 0, 1 }, { 0, 9, 1 } } },
598   { { { 3, 0, 0 }, { 0, 9, 0 } } },
599   { { { 3, 0, 1 }, { 0, 10, 0 } } },
600   { { { 3, 0, 2 }, { 0, 11, 0 } } },
601   { { { 4, 0, 1 }, { 0, 12, 1 } } },
602   { { { 4, 0, 0 }, { 0, 12, 0 } } },
603   { { { 4, 0, 1 }, { 0, 13, 0 } } },
604   { { { 4, 0, 2 }, { 0, 14, 0 } } },
605   { { { 5, 0, 1 }, { 0, 15, 1 } } },
606   { { { 5, 0, 0 }, { 0, 15, 0 } } },
607   { { { 5, 0, 1 }, { 0, 16, 0 } } },
608   { { { 5, 0, 2 }, { 1, 15, 0 } } },
609   { { { 6, 0, 1 }, { 0, 17, 0 } } },
610   { { { 6, 0, 0 }, { 0, 18, 0 } } },
611   { { { 6, 0, 1 }, { 0, 19, 0 } } },
612   { { { 6, 0, 2 }, { 3, 14, 0 } } },
613   { { { 7, 0, 1 }, { 0, 20, 0 } } },
614   { { { 7, 0, 0 }, { 0, 21, 0 } } },
615   { { { 7, 0, 1 }, { 0, 22, 0 } } },
616   { { { 7, 0, 2 }, { 4, 15, 0 } } },
617   { { { 8, 0, 1 }, { 0, 23, 0 } } },
618   { { { 8, 0, 0 }, { 0, 24, 0 } } },
619   { { { 8, 0, 1 }, { 0, 25, 0 } } },
620   { { { 8, 0, 2 }, { 6, 14, 0 } } },
621   { { { 9, 0, 1 }, { 0, 26, 0 } } },
622   { { { 9, 0, 0 }, { 0, 27, 0 } } },
623   { { { 9, 0, 1 }, { 0, 28, 0 } } },
624   { { { 9, 0, 2 }, { 7, 15, 0 } } },
625   { { { 10, 0, 1 }, { 0, 29, 0 } } },
626   { { { 10, 0, 0 }, { 0, 30, 0 } } },
627   { { { 10, 0, 1 }, { 0, 31, 0 } } },
628   { { { 10, 0, 2 }, { 9, 14, 0 } } },
629   { { { 11, 0, 1 }, { 0, 32, 0 } } },
630   { { { 11, 0, 0 }, { 0, 33, 0 } } },
631   { { { 11, 0, 1 }, { 2, 30, 0 } } },
632   { { { 11, 0, 2 }, { 0, 34, 0 } } },
633   { { { 12, 0, 1 }, { 0, 35, 0 } } },
634   { { { 12, 0, 0 }, { 0, 36, 0 } } },
635   { { { 12, 0, 1 }, { 3, 31, 0 } } },
636   { { { 12, 0, 2 }, { 0, 37, 0 } } },
637   { { { 13, 0, 1 }, { 0, 38, 0 } } },
638   { { { 13, 0, 0 }, { 0, 39, 0 } } },
639   { { { 13, 0, 1 }, { 5, 30, 0 } } },
640   { { { 13, 0, 2 }, { 0, 40, 0 } } },
641   { { { 14, 0, 1 }, { 0, 41, 0 } } },
642   { { { 14, 0, 0 }, { 0, 42, 0 } } },
643   { { { 14, 0, 1 }, { 6, 31, 0 } } },
644   { { { 14, 0, 2 }, { 0, 43, 0 } } },
645   { { { 15, 0, 1 }, { 0, 44, 0 } } },
646   { { { 15, 0, 0 }, { 0, 45, 0 } } },
647   { { { 15, 0, 1 }, { 8, 30, 0 } } },
648   { { { 15, 0, 2 }, { 0, 46, 0 } } },
649   { { { 16, 0, 2 }, { 0, 47, 0 } } },
650   { { { 16, 0, 1 }, { 1, 46, 0 } } },
651   { { { 16, 0, 0 }, { 0, 48, 0 } } },
652   { { { 16, 0, 1 }, { 0, 49, 0 } } },
653   { { { 16, 0, 2 }, { 0, 50, 0 } } },
654   { { { 17, 0, 1 }, { 2, 47, 0 } } },
655   { { { 17, 0, 0 }, { 0, 51, 0 } } },
656   { { { 17, 0, 1 }, { 0, 52, 0 } } },
657   { { { 17, 0, 2 }, { 0, 53, 0 } } },
658   { { { 18, 0, 1 }, { 4, 46, 0 } } },
659   { { { 18, 0, 0 }, { 0, 54, 0 } } },
660   { { { 18, 0, 1 }, { 0, 55, 0 } } },
661   { { { 18, 0, 2 }, { 0, 56, 0 } } },
662   { { { 19, 0, 1 }, { 5, 47, 0 } } },
663   { { { 19, 0, 0 }, { 0, 57, 0 } } },
664   { { { 19, 0, 1 }, { 0, 58, 0 } } },
665   { { { 19, 0, 2 }, { 0, 59, 0 } } },
666   { { { 20, 0, 1 }, { 7, 46, 0 } } },
667   { { { 20, 0, 0 }, { 0, 60, 0 } } },
668   { { { 20, 0, 1 }, { 0, 61, 0 } } },
669   { { { 20, 0, 2 }, { 0, 62, 0 } } },
670   { { { 21, 0, 1 }, { 8, 47, 0 } } },
671   { { { 21, 0, 0 }, { 0, 63, 0 } } },
672   { { { 21, 0, 1 }, { 1, 62, 0 } } },
673   { { { 21, 0, 2 }, { 1, 63, 0 } } },
674   { { { 22, 0, 1 }, { 10, 46, 0 } } },
675   { { { 22, 0, 0 }, { 2, 62, 0 } } },
676   { { { 22, 0, 1 }, { 2, 63, 0 } } },
677   { { { 22, 0, 2 }, { 3, 62, 0 } } },
678   { { { 23, 0, 1 }, { 11, 47, 0 } } },
679   { { { 23, 0, 0 }, { 3, 63, 0 } } },
680   { { { 23, 0, 1 }, { 4, 62, 0 } } },
681   { { { 23, 0, 2 }, { 4, 63, 0 } } },
682   { { { 24, 0, 1 }, { 13, 46, 0 } } },
683   { { { 24, 0, 0 }, { 5, 62, 0 } } },
684   { { { 24, 0, 1 }, { 5, 63, 0 } } },
685   { { { 24, 0, 2 }, { 6, 62, 0 } } },
686   { { { 25, 0, 1 }, { 14, 47, 0 } } },
687   { { { 25, 0, 0 }, { 6, 63, 0 } } },
688   { { { 25, 0, 1 }, { 7, 62, 0 } } },
689   { { { 25, 0, 2 }, { 7, 63, 0 } } },
690   { { { 26, 0, 1 }, { 16, 45, 0 } } },
691   { { { 26, 0, 0 }, { 8, 62, 0 } } },
692   { { { 26, 0, 1 }, { 8, 63, 0 } } },
693   { { { 26, 0, 2 }, { 9, 62, 0 } } },
694   { { { 27, 0, 1 }, { 16, 48, 0 } } },
695   { { { 27, 0, 0 }, { 9, 63, 0 } } },
696   { { { 27, 0, 1 }, { 10, 62, 0 } } },
697   { { { 27, 0, 2 }, { 10, 63, 0 } } },
698   { { { 28, 0, 1 }, { 16, 51, 0 } } },
699   { { { 28, 0, 0 }, { 11, 62, 0 } } },
700   { { { 28, 0, 1 }, { 11, 63, 0 } } },
701   { { { 28, 0, 2 }, { 12, 62, 0 } } },
702   { { { 29, 0, 1 }, { 16, 54, 0 } } },
703   { { { 29, 0, 0 }, { 12, 63, 0 } } },
704   { { { 29, 0, 1 }, { 13, 62, 0 } } },
705   { { { 29, 0, 2 }, { 13, 63, 0 } } },
706   { { { 30, 0, 1 }, { 16, 57, 0 } } },
707   { { { 30, 0, 0 }, { 14, 62, 0 } } },
708   { { { 30, 0, 1 }, { 14, 63, 0 } } },
709   { { { 30, 0, 2 }, { 15, 62, 0 } } },
710   { { { 31, 0, 1 }, { 16, 60, 0 } } },
711   { { { 31, 0, 0 }, { 15, 63, 0 } } },
712   { { { 31, 0, 1 }, { 24, 46, 0 } } },
713   { { { 31, 0, 2 }, { 16, 62, 0 } } },
714   { { { 32, 0, 2 }, { 16, 63, 0 } } },
715   { { { 32, 0, 1 }, { 17, 62, 0 } } },
716   { { { 32, 0, 0 }, { 25, 47, 0 } } },
717   { { { 32, 0, 1 }, { 17, 63, 0 } } },
718   { { { 32, 0, 2 }, { 18, 62, 0 } } },
719   { { { 33, 0, 1 }, { 18, 63, 0 } } },
720   { { { 33, 0, 0 }, { 27, 46, 0 } } },
721   { { { 33, 0, 1 }, { 19, 62, 0 } } },
722   { { { 33, 0, 2 }, { 19, 63, 0 } } },
723   { { { 34, 0, 1 }, { 20, 62, 0 } } },
724   { { { 34, 0, 0 }, { 28, 47, 0 } } },
725   { { { 34, 0, 1 }, { 20, 63, 0 } } },
726   { { { 34, 0, 2 }, { 21, 62, 0 } } },
727   { { { 35, 0, 1 }, { 21, 63, 0 } } },
728   { { { 35, 0, 0 }, { 30, 46, 0 } } },
729   { { { 35, 0, 1 }, { 22, 62, 0 } } },
730   { { { 35, 0, 2 }, { 22, 63, 0 } } },
731   { { { 36, 0, 1 }, { 23, 62, 0 } } },
732   { { { 36, 0, 0 }, { 31, 47, 0 } } },
733   { { { 36, 0, 1 }, { 23, 63, 0 } } },
734   { { { 36, 0, 2 }, { 24, 62, 0 } } },
735   { { { 37, 0, 1 }, { 24, 63, 0 } } },
736   { { { 37, 0, 0 }, { 32, 47, 0 } } },
737   { { { 37, 0, 1 }, { 25, 62, 0 } } },
738   { { { 37, 0, 2 }, { 25, 63, 0 } } },
739   { { { 38, 0, 1 }, { 26, 62, 0 } } },
740   { { { 38, 0, 0 }, { 32, 50, 0 } } },
741   { { { 38, 0, 1 }, { 26, 63, 0 } } },
742   { { { 38, 0, 2 }, { 27, 62, 0 } } },
743   { { { 39, 0, 1 }, { 27, 63, 0 } } },
744   { { { 39, 0, 0 }, { 32, 53, 0 } } },
745   { { { 39, 0, 1 }, { 28, 62, 0 } } },
746   { { { 39, 0, 2 }, { 28, 63, 0 } } },
747   { { { 40, 0, 1 }, { 29, 62, 0 } } },
748   { { { 40, 0, 0 }, { 32, 56, 0 } } },
749   { { { 40, 0, 1 }, { 29, 63, 0 } } },
750   { { { 40, 0, 2 }, { 30, 62, 0 } } },
751   { { { 41, 0, 1 }, { 30, 63, 0 } } },
752   { { { 41, 0, 0 }, { 32, 59, 0 } } },
753   { { { 41, 0, 1 }, { 31, 62, 0 } } },
754   { { { 41, 0, 2 }, { 31, 63, 0 } } },
755   { { { 42, 0, 1 }, { 32, 61, 0 } } },
756   { { { 42, 0, 0 }, { 32, 62, 0 } } },
757   { { { 42, 0, 1 }, { 32, 63, 0 } } },
758   { { { 42, 0, 2 }, { 41, 46, 0 } } },
759   { { { 43, 0, 1 }, { 33, 62, 0 } } },
760   { { { 43, 0, 0 }, { 33, 63, 0 } } },
761   { { { 43, 0, 1 }, { 34, 62, 0 } } },
762   { { { 43, 0, 2 }, { 42, 47, 0 } } },
763   { { { 44, 0, 1 }, { 34, 63, 0 } } },
764   { { { 44, 0, 0 }, { 35, 62, 0 } } },
765   { { { 44, 0, 1 }, { 35, 63, 0 } } },
766   { { { 44, 0, 2 }, { 44, 46, 0 } } },
767   { { { 45, 0, 1 }, { 36, 62, 0 } } },
768   { { { 45, 0, 0 }, { 36, 63, 0 } } },
769   { { { 45, 0, 1 }, { 37, 62, 0 } } },
770   { { { 45, 0, 2 }, { 45, 47, 0 } } },
771   { { { 46, 0, 1 }, { 37, 63, 0 } } },
772   { { { 46, 0, 0 }, { 38, 62, 0 } } },
773   { { { 46, 0, 1 }, { 38, 63, 0 } } },
774   { { { 46, 0, 2 }, { 47, 46, 0 } } },
775   { { { 47, 0, 1 }, { 39, 62, 0 } } },
776   { { { 47, 0, 0 }, { 39, 63, 0 } } },
777   { { { 47, 0, 1 }, { 40, 62, 0 } } },
778   { { { 47, 0, 2 }, { 48, 46, 0 } } },
779   { { { 48, 0, 2 }, { 40, 63, 0 } } },
780   { { { 48, 0, 1 }, { 41, 62, 0 } } },
781   { { { 48, 0, 0 }, { 41, 63, 0 } } },
782   { { { 48, 0, 1 }, { 48, 49, 0 } } },
783   { { { 48, 0, 2 }, { 42, 62, 0 } } },
784   { { { 49, 0, 1 }, { 42, 63, 0 } } },
785   { { { 49, 0, 0 }, { 43, 62, 0 } } },
786   { { { 49, 0, 1 }, { 48, 52, 0 } } },
787   { { { 49, 0, 2 }, { 43, 63, 0 } } },
788   { { { 50, 0, 1 }, { 44, 62, 0 } } },
789   { { { 50, 0, 0 }, { 44, 63, 0 } } },
790   { { { 50, 0, 1 }, { 48, 55, 0 } } },
791   { { { 50, 0, 2 }, { 45, 62, 0 } } },
792   { { { 51, 0, 1 }, { 45, 63, 0 } } },
793   { { { 51, 0, 0 }, { 46, 62, 0 } } },
794   { { { 51, 0, 1 }, { 48, 58, 0 } } },
795   { { { 51, 0, 2 }, { 46, 63, 0 } } },
796   { { { 52, 0, 1 }, { 47, 62, 0 } } },
797   { { { 52, 0, 0 }, { 47, 63, 0 } } },
798   { { { 52, 0, 1 }, { 48, 61, 0 } } },
799   { { { 52, 0, 2 }, { 48, 62, 0 } } },
800   { { { 53, 0, 1 }, { 56, 47, 0 } } },
801   { { { 53, 0, 0 }, { 48, 63, 0 } } },
802   { { { 53, 0, 1 }, { 49, 62, 0 } } },
803   { { { 53, 0, 2 }, { 49, 63, 0 } } },
804   { { { 54, 0, 1 }, { 58, 46, 0 } } },
805   { { { 54, 0, 0 }, { 50, 62, 0 } } },
806   { { { 54, 0, 1 }, { 50, 63, 0 } } },
807   { { { 54, 0, 2 }, { 51, 62, 0 } } },
808   { { { 55, 0, 1 }, { 59, 47, 0 } } },
809   { { { 55, 0, 0 }, { 51, 63, 0 } } },
810   { { { 55, 0, 1 }, { 52, 62, 0 } } },
811   { { { 55, 0, 2 }, { 52, 63, 0 } } },
812   { { { 56, 0, 1 }, { 61, 46, 0 } } },
813   { { { 56, 0, 0 }, { 53, 62, 0 } } },
814   { { { 56, 0, 1 }, { 53, 63, 0 } } },
815   { { { 56, 0, 2 }, { 54, 62, 0 } } },
816   { { { 57, 0, 1 }, { 62, 47, 0 } } },
817   { { { 57, 0, 0 }, { 54, 63, 0 } } },
818   { { { 57, 0, 1 }, { 55, 62, 0 } } },
819   { { { 57, 0, 2 }, { 55, 63, 0 } } },
820   { { { 58, 0, 1 }, { 56, 62, 1 } } },
821   { { { 58, 0, 0 }, { 56, 62, 0 } } },
822   { { { 58, 0, 1 }, { 56, 63, 0 } } },
823   { { { 58, 0, 2 }, { 57, 62, 0 } } },
824   { { { 59, 0, 1 }, { 57, 63, 1 } } },
825   { { { 59, 0, 0 }, { 57, 63, 0 } } },
826   { { { 59, 0, 1 }, { 58, 62, 0 } } },
827   { { { 59, 0, 2 }, { 58, 63, 0 } } },
828   { { { 60, 0, 1 }, { 59, 62, 1 } } },
829   { { { 60, 0, 0 }, { 59, 62, 0 } } },
830   { { { 60, 0, 1 }, { 59, 63, 0 } } },
831   { { { 60, 0, 2 }, { 60, 62, 0 } } },
832   { { { 61, 0, 1 }, { 60, 63, 1 } } },
833   { { { 61, 0, 0 }, { 60, 63, 0 } } },
834   { { { 61, 0, 1 }, { 61, 62, 0 } } },
835   { { { 61, 0, 2 }, { 61, 63, 0 } } },
836   { { { 62, 0, 1 }, { 62, 62, 1 } } },
837   { { { 62, 0, 0 }, { 62, 62, 0 } } },
838   { { { 62, 0, 1 }, { 62, 63, 0 } } },
839   { { { 62, 0, 2 }, { 63, 62, 0 } } },
840   { { { 63, 0, 1 }, { 63, 63, 1 } } },
841   { { { 63, 0, 0 }, { 63, 63, 0 } } }
842 };
843 
844 static const DDSSingleColorLookup*
845   DDS_LOOKUP[] =
846 {
847   DDSLookup_5_4,
848   DDSLookup_6_4,
849   DDSLookup_5_4
850 };
851 
852 /*
853   Macros
854 */
855 #define C565_r(x) (((x) & 0xF800) >> 11)
856 #define C565_g(x) (((x) & 0x07E0) >> 5)
857 #define C565_b(x)  ((x) & 0x001F)
858 
859 #define C565_red(x)   ( (C565_r(x) << 3 | C565_r(x) >> 2))
860 #define C565_green(x) ( (C565_g(x) << 2 | C565_g(x) >> 4))
861 #define C565_blue(x)  ( (C565_b(x) << 3 | C565_b(x) >> 2))
862 
863 #define DIV2(x)  ((x) > 1 ? ((x) >> 1) : 1)
864 
865 #define FixRange(min, max, steps) \
866 if (min > max) \
867   min = max; \
868 if ((ssize_t) max - min < steps) \
869   max = MagickMin(min + steps, 255); \
870 if ((ssize_t) max - min < steps) \
871   min = MagickMax(0, (ssize_t) max - steps)
872 
873 #define Dot(left, right) (left.x*right.x) + (left.y*right.y) + (left.z*right.z)
874 
875 #define VectorInit(vector, value) vector.x = vector.y = vector.z = vector.w \
876   = value
877 #define VectorInit3(vector, value) vector.x = vector.y = vector.z = value
878 
879 #define IsBitMask(mask, r, g, b, a) (mask.r_bitmask == r && mask.g_bitmask == \
880   g && mask.b_bitmask == b && mask.alpha_bitmask == a)
881 
882 /*
883   Forward declarations
884 */
885 static MagickBooleanType
886   WriteDDSImage(const ImageInfo *,Image *,ExceptionInfo *);
887 
VectorAdd(const DDSVector4 left,const DDSVector4 right,DDSVector4 * destination)888 static inline void VectorAdd(const DDSVector4 left, const DDSVector4 right,
889   DDSVector4 *destination)
890 {
891   destination->x = left.x + right.x;
892   destination->y = left.y + right.y;
893   destination->z = left.z + right.z;
894   destination->w = left.w + right.w;
895 }
896 
VectorClamp(DDSVector4 * value)897 static inline void VectorClamp(DDSVector4 *value)
898 {
899   value->x = MagickMin(1.0f,MagickMax(0.0f,value->x));
900   value->y = MagickMin(1.0f,MagickMax(0.0f,value->y));
901   value->z = MagickMin(1.0f,MagickMax(0.0f,value->z));
902   value->w = MagickMin(1.0f,MagickMax(0.0f,value->w));
903 }
904 
VectorClamp3(DDSVector3 * value)905 static inline void VectorClamp3(DDSVector3 *value)
906 {
907   value->x = MagickMin(1.0f,MagickMax(0.0f,value->x));
908   value->y = MagickMin(1.0f,MagickMax(0.0f,value->y));
909   value->z = MagickMin(1.0f,MagickMax(0.0f,value->z));
910 }
911 
VectorCopy43(const DDSVector4 source,DDSVector3 * destination)912 static inline void VectorCopy43(const DDSVector4 source,
913   DDSVector3 *destination)
914 {
915   destination->x = source.x;
916   destination->y = source.y;
917   destination->z = source.z;
918 }
919 
VectorCopy44(const DDSVector4 source,DDSVector4 * destination)920 static inline void VectorCopy44(const DDSVector4 source,
921   DDSVector4 *destination)
922 {
923   destination->x = source.x;
924   destination->y = source.y;
925   destination->z = source.z;
926   destination->w = source.w;
927 }
928 
VectorNegativeMultiplySubtract(const DDSVector4 a,const DDSVector4 b,const DDSVector4 c,DDSVector4 * destination)929 static inline void VectorNegativeMultiplySubtract(const DDSVector4 a,
930   const DDSVector4 b, const DDSVector4 c, DDSVector4 *destination)
931 {
932   destination->x = c.x - (a.x * b.x);
933   destination->y = c.y - (a.y * b.y);
934   destination->z = c.z - (a.z * b.z);
935   destination->w = c.w - (a.w * b.w);
936 }
937 
VectorMultiply(const DDSVector4 left,const DDSVector4 right,DDSVector4 * destination)938 static inline void VectorMultiply(const DDSVector4 left,
939   const DDSVector4 right, DDSVector4 *destination)
940 {
941   destination->x = left.x * right.x;
942   destination->y = left.y * right.y;
943   destination->z = left.z * right.z;
944   destination->w = left.w * right.w;
945 }
946 
VectorMultiply3(const DDSVector3 left,const DDSVector3 right,DDSVector3 * destination)947 static inline void VectorMultiply3(const DDSVector3 left,
948   const DDSVector3 right, DDSVector3 *destination)
949 {
950   destination->x = left.x * right.x;
951   destination->y = left.y * right.y;
952   destination->z = left.z * right.z;
953 }
954 
VectorMultiplyAdd(const DDSVector4 a,const DDSVector4 b,const DDSVector4 c,DDSVector4 * destination)955 static inline void VectorMultiplyAdd(const DDSVector4 a, const DDSVector4 b,
956   const DDSVector4 c, DDSVector4 *destination)
957 {
958   destination->x = (a.x * b.x) + c.x;
959   destination->y = (a.y * b.y) + c.y;
960   destination->z = (a.z * b.z) + c.z;
961   destination->w = (a.w * b.w) + c.w;
962 }
963 
VectorMultiplyAdd3(const DDSVector3 a,const DDSVector3 b,const DDSVector3 c,DDSVector3 * destination)964 static inline void VectorMultiplyAdd3(const DDSVector3 a, const DDSVector3 b,
965   const DDSVector3 c, DDSVector3 *destination)
966 {
967   destination->x = (a.x * b.x) + c.x;
968   destination->y = (a.y * b.y) + c.y;
969   destination->z = (a.z * b.z) + c.z;
970 }
971 
VectorReciprocal(const DDSVector4 value,DDSVector4 * destination)972 static inline void VectorReciprocal(const DDSVector4 value,
973   DDSVector4 *destination)
974 {
975   destination->x = 1.0f / value.x;
976   destination->y = 1.0f / value.y;
977   destination->z = 1.0f / value.z;
978   destination->w = 1.0f / value.w;
979 }
980 
VectorSubtract(const DDSVector4 left,const DDSVector4 right,DDSVector4 * destination)981 static inline void VectorSubtract(const DDSVector4 left,
982   const DDSVector4 right, DDSVector4 *destination)
983 {
984   destination->x = left.x - right.x;
985   destination->y = left.y - right.y;
986   destination->z = left.z - right.z;
987   destination->w = left.w - right.w;
988 }
989 
VectorSubtract3(const DDSVector3 left,const DDSVector3 right,DDSVector3 * destination)990 static inline void VectorSubtract3(const DDSVector3 left,
991   const DDSVector3 right, DDSVector3 *destination)
992 {
993   destination->x = left.x - right.x;
994   destination->y = left.y - right.y;
995   destination->z = left.z - right.z;
996 }
997 
VectorTruncate(DDSVector4 * value)998 static inline void VectorTruncate(DDSVector4 *value)
999 {
1000   value->x = value->x > 0.0f ? floor(value->x) : ceil(value->x);
1001   value->y = value->y > 0.0f ? floor(value->y) : ceil(value->y);
1002   value->z = value->z > 0.0f ? floor(value->z) : ceil(value->z);
1003   value->w = value->w > 0.0f ? floor(value->w) : ceil(value->w);
1004 }
1005 
VectorTruncate3(DDSVector3 * value)1006 static inline void VectorTruncate3(DDSVector3 *value)
1007 {
1008   value->x = value->x > 0.0f ? floor(value->x) : ceil(value->x);
1009   value->y = value->y > 0.0f ? floor(value->y) : ceil(value->y);
1010   value->z = value->z > 0.0f ? floor(value->z) : ceil(value->z);
1011 }
1012 
ClampToLimit(const float value,const size_t limit)1013 static inline size_t ClampToLimit(const float value, const size_t limit)
1014 {
1015   size_t
1016     result = (int) (value + 0.5f);
1017 
1018   if (result < 0.0f)
1019     return(0);
1020   if (result > limit)
1021     return(limit);
1022   return result;
1023 }
1024 
ColorTo565(const DDSVector3 point)1025 static inline size_t ColorTo565(const DDSVector3 point)
1026 {
1027   size_t r = ClampToLimit(31.0f*point.x,31);
1028   size_t g = ClampToLimit(63.0f*point.y,63);
1029   size_t b = ClampToLimit(31.0f*point.z,31);
1030 
1031   return (r << 11) | (g << 5) | b;
1032 }
1033 
1034 /*
1035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1036 %                                                                             %
1037 %                                                                             %
1038 %                                                                             %
1039 %   I s D D S                                                                 %
1040 %                                                                             %
1041 %                                                                             %
1042 %                                                                             %
1043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1044 %
1045 %  IsDDS() returns MagickTrue if the image format type, identified by the
1046 %  magick string, is DDS.
1047 %
1048 %  The format of the IsDDS method is:
1049 %
1050 %      MagickBooleanType IsDDS(const unsigned char *magick,const size_t length)
1051 %
1052 %  A description of each parameter follows:
1053 %
1054 %    o magick: compare image format pattern against these bytes.
1055 %
1056 %    o length: Specifies the length of the magick string.
1057 %
1058 */
IsDDS(const unsigned char * magick,const size_t length)1059 static MagickBooleanType IsDDS(const unsigned char *magick, const size_t length)
1060 {
1061   if (length < 4)
1062     return(MagickFalse);
1063   if (LocaleNCompare((char *) magick,"DDS ", 4) == 0)
1064     return(MagickTrue);
1065   return(MagickFalse);
1066 }
1067 
1068 /*
1069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1070 %                                                                             %
1071 %                                                                             %
1072 %                                                                             %
1073 %   R e a d D D S I m a g e                                                   %
1074 %                                                                             %
1075 %                                                                             %
1076 %                                                                             %
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 %
1079 %  ReadDDSImage() reads a DirectDraw Surface image file and returns it.  It
1080 %  allocates the memory necessary for the new Image structure and returns a
1081 %  pointer to the new image.
1082 %
1083 %  The format of the ReadDDSImage method is:
1084 %
1085 %      Image *ReadDDSImage(const ImageInfo *image_info,ExceptionInfo *exception)
1086 %
1087 %  A description of each parameter follows:
1088 %
1089 %    o image_info: The image info.
1090 %
1091 %    o exception: return any errors or warnings in this structure.
1092 %
1093 */
ReadDDSInfo(Image * image,DDSInfo * dds_info)1094 static MagickBooleanType ReadDDSInfo(Image *image, DDSInfo *dds_info)
1095 {
1096   size_t
1097     hdr_size,
1098     required;
1099 
1100   /* Seek to start of header */
1101   (void) SeekBlob(image, 4, SEEK_SET);
1102 
1103   /* Check header field */
1104   hdr_size = ReadBlobLSBLong(image);
1105   if (hdr_size != 124)
1106     return MagickFalse;
1107 
1108   /* Fill in DDS info struct */
1109   dds_info->flags = ReadBlobLSBLong(image);
1110 
1111   /* Check required flags */
1112   required=(size_t) (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT);
1113   if ((dds_info->flags & required) != required)
1114     return MagickFalse;
1115 
1116   dds_info->height = ReadBlobLSBLong(image);
1117   dds_info->width = ReadBlobLSBLong(image);
1118   dds_info->pitchOrLinearSize = ReadBlobLSBLong(image);
1119   dds_info->depth = ReadBlobLSBLong(image);
1120   dds_info->mipmapcount = ReadBlobLSBLong(image);
1121 
1122   (void) SeekBlob(image, 44, SEEK_CUR);   /* reserved region of 11 DWORDs */
1123 
1124   /* Read pixel format structure */
1125   hdr_size = ReadBlobLSBLong(image);
1126   if (hdr_size != 32)
1127     return MagickFalse;
1128 
1129   dds_info->pixelformat.flags = ReadBlobLSBLong(image);
1130   dds_info->pixelformat.fourcc = ReadBlobLSBLong(image);
1131   dds_info->pixelformat.rgb_bitcount = ReadBlobLSBLong(image);
1132   dds_info->pixelformat.r_bitmask = ReadBlobLSBLong(image);
1133   dds_info->pixelformat.g_bitmask = ReadBlobLSBLong(image);
1134   dds_info->pixelformat.b_bitmask = ReadBlobLSBLong(image);
1135   dds_info->pixelformat.alpha_bitmask = ReadBlobLSBLong(image);
1136 
1137   dds_info->ddscaps1 = ReadBlobLSBLong(image);
1138   dds_info->ddscaps2 = ReadBlobLSBLong(image);
1139   (void) SeekBlob(image, 12, SEEK_CUR); /* 3 reserved DWORDs */
1140 
1141   /* Read optional DX10 header if available */
1142   if ((dds_info->pixelformat.flags & DDPF_FOURCC) &&
1143       (dds_info->pixelformat.fourcc == FOURCC_DX10))
1144     {
1145       dds_info->extFormat = ReadBlobLSBLong(image);
1146       dds_info->extDimension = ReadBlobLSBLong(image);
1147       dds_info->extFlags = ReadBlobLSBLong(image);
1148       dds_info->extArraySize = ReadBlobLSBLong(image);
1149       dds_info->extFlags2 = ReadBlobLSBLong(image);
1150     }
1151   else
1152     {
1153       dds_info->extFormat = 0;
1154       dds_info->extDimension = 0;
1155       dds_info->extFlags = 0;
1156       dds_info->extArraySize = 0;
1157       dds_info->extFlags2 = 0;
1158     }
1159 
1160   return MagickTrue;
1161 }
1162 
SetDXT1Pixels(Image * image,ssize_t x,ssize_t y,DDSColors colors,size_t bits,Quantum * q)1163 static MagickBooleanType SetDXT1Pixels(Image *image,ssize_t x,ssize_t y,
1164   DDSColors colors,size_t bits,Quantum *q)
1165 {
1166   ssize_t
1167     i;
1168 
1169   ssize_t
1170     j;
1171 
1172   unsigned char
1173     code;
1174 
1175   for (j = 0; j < 4; j++)
1176   {
1177     for (i = 0; i < 4; i++)
1178     {
1179       if ((x + i) < (ssize_t) image->columns &&
1180           (y + j) < (ssize_t) image->rows)
1181         {
1182           code=(unsigned char) ((bits >> ((j*4+i)*2)) & 0x3);
1183           SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1184           SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1185           SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1186           SetPixelOpacity(image,ScaleCharToQuantum(colors.a[code]),q);
1187           if ((colors.a[code] != 0) &&
1188               (image->alpha_trait == UndefinedPixelTrait))
1189             return(MagickFalse);
1190           q+=GetPixelChannels(image);
1191         }
1192     }
1193   }
1194   return(MagickTrue);
1195 }
1196 
ReadMipmaps(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,DDSPixelDecoder decoder,ExceptionInfo * exception)1197 static MagickBooleanType ReadMipmaps(const ImageInfo *image_info,Image *image,
1198   DDSInfo *dds_info,DDSPixelDecoder decoder,ExceptionInfo *exception)
1199 {
1200   MagickBooleanType
1201     status;
1202 
1203   /*
1204     Only skip mipmaps for textures and cube maps
1205   */
1206   if (EOFBlob(image) != MagickFalse)
1207     {
1208       ThrowFileException(exception,CorruptImageWarning,"UnexpectedEndOfFile",
1209         image->filename);
1210       return(MagickFalse);
1211     }
1212   status=MagickTrue;
1213   if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1214       && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1215           || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1216     {
1217       ssize_t
1218         i;
1219 
1220       size_t
1221         h,
1222         w;
1223 
1224       w=DIV2(dds_info->width);
1225       h=DIV2(dds_info->height);
1226 
1227       /*
1228         Mipmapcount includes the main image, so start from one
1229       */
1230       for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1231       {
1232         AcquireNextImage(image_info,image,exception);
1233         if (image->next == (Image *) NULL)
1234           return(MagickFalse);
1235         image->next->alpha_trait=image->alpha_trait;
1236         image=SyncNextImageInList(image);
1237         status=SetImageExtent(image,w,h,exception);
1238         if (status == MagickFalse)
1239           break;
1240         status=decoder(image,dds_info,exception);
1241         if (status == MagickFalse)
1242           break;
1243         if ((w == 1) && (h == 1))
1244           break;
1245 
1246         w=DIV2(w);
1247         h=DIV2(h);
1248       }
1249     }
1250   return(status);
1251 }
1252 
CalculateColors(unsigned short c0,unsigned short c1,DDSColors * c,MagickBooleanType ignoreAlpha)1253 static void CalculateColors(unsigned short c0, unsigned short c1,
1254   DDSColors *c, MagickBooleanType ignoreAlpha)
1255 {
1256   c->a[0] = c->a[1] = c->a[2] = c->a[3] = 0;
1257 
1258   c->r[0] = (unsigned char) C565_red(c0);
1259   c->g[0] = (unsigned char) C565_green(c0);
1260   c->b[0] = (unsigned char) C565_blue(c0);
1261 
1262   c->r[1] = (unsigned char) C565_red(c1);
1263   c->g[1] = (unsigned char) C565_green(c1);
1264   c->b[1] = (unsigned char) C565_blue(c1);
1265 
1266   if (ignoreAlpha != MagickFalse || c0 > c1)
1267     {
1268       c->r[2] = (unsigned char) ((2 * c->r[0] + c->r[1]) / 3);
1269       c->g[2] = (unsigned char) ((2 * c->g[0] + c->g[1]) / 3);
1270       c->b[2] = (unsigned char) ((2 * c->b[0] + c->b[1]) / 3);
1271 
1272       c->r[3] = (unsigned char) ((c->r[0] + 2 * c->r[1]) / 3);
1273       c->g[3] = (unsigned char) ((c->g[0] + 2 * c->g[1]) / 3);
1274       c->b[3] = (unsigned char) ((c->b[0] + 2 * c->b[1]) / 3);
1275     }
1276   else
1277     {
1278       c->r[2] = (unsigned char) ((c->r[0] + c->r[1]) / 2);
1279       c->g[2] = (unsigned char) ((c->g[0] + c->g[1]) / 2);
1280       c->b[2] = (unsigned char) ((c->b[0] + c->b[1]) / 2);
1281 
1282       c->r[3] = c->g[3] = c->b[3] = 0;
1283       c->a[3] = 255;
1284     }
1285 }
1286 
ReadDXT1Pixels(Image * image,DDSInfo * magick_unused (dds_info),ExceptionInfo * exception)1287 static MagickBooleanType ReadDXT1Pixels(Image *image,
1288   DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1289 {
1290   DDSColors
1291     colors;
1292 
1293   Quantum
1294     *q;
1295 
1296   ssize_t
1297     x;
1298 
1299   size_t
1300     bits;
1301 
1302   ssize_t
1303     y;
1304 
1305   unsigned short
1306     c0,
1307     c1;
1308 
1309   magick_unreferenced(dds_info);
1310   for (y = 0; y < (ssize_t) image->rows; y += 4)
1311   {
1312     for (x = 0; x < (ssize_t) image->columns; x += 4)
1313     {
1314       /* Get 4x4 patch of pixels to write on */
1315       q=QueueAuthenticPixels(image,x,y,MagickMin(4,image->columns-x),
1316         MagickMin(4,image->rows-y),exception);
1317 
1318       if (q == (Quantum *) NULL)
1319         return(MagickFalse);
1320 
1321       /* Read 8 bytes of data from the image */
1322       c0=ReadBlobLSBShort(image);
1323       c1=ReadBlobLSBShort(image);
1324       bits=ReadBlobLSBLong(image);
1325 
1326       CalculateColors(c0,c1,&colors,MagickFalse);
1327       if (EOFBlob(image) != MagickFalse)
1328         return(MagickFalse);
1329 
1330       /* Write the pixels */
1331       if (SetDXT1Pixels(image,x,y,colors,bits,q) == MagickFalse)
1332         {
1333           /* Correct alpha */
1334           SetImageAlpha(image,QuantumRange,exception);
1335           q=QueueAuthenticPixels(image,x,y,MagickMin(4,image->columns-x),
1336             MagickMin(4,image->rows-y),exception);
1337           if (q != (Quantum *) NULL)
1338             SetDXT1Pixels(image,x,y,colors,bits,q);
1339         }
1340       if (SyncAuthenticPixels(image,exception) == MagickFalse)
1341         return(MagickFalse);
1342     }
1343     if (EOFBlob(image) != MagickFalse)
1344       return(MagickFalse);
1345   }
1346   return(MagickTrue);
1347 }
1348 
1349 /*
1350   Skip the mipmap images for compressed (DXTn) dds files
1351 */
SkipDXTMipmaps(Image * image,DDSInfo * dds_info,int texel_size,ExceptionInfo * exception)1352 static MagickBooleanType SkipDXTMipmaps(Image *image,DDSInfo *dds_info,
1353   int texel_size,ExceptionInfo *exception)
1354 {
1355   /*
1356     Only skip mipmaps for textures and cube maps
1357   */
1358   if (EOFBlob(image) != MagickFalse)
1359     {
1360       ThrowFileException(exception,CorruptImageWarning,"UnexpectedEndOfFile",
1361         image->filename);
1362       return(MagickFalse);
1363     }
1364   if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1365       && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1366           || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1367     {
1368       MagickOffsetType
1369         offset;
1370 
1371       ssize_t
1372         i;
1373 
1374       size_t
1375         h,
1376         w;
1377 
1378       w=DIV2(dds_info->width);
1379       h=DIV2(dds_info->height);
1380 
1381       /*
1382         Mipmapcount includes the main image, so start from one
1383       */
1384       for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1385       {
1386         offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;
1387         if (SeekBlob(image,offset,SEEK_CUR) < 0)
1388           break;
1389         w=DIV2(w);
1390         h=DIV2(h);
1391         if ((w == 1) && (h == 1))
1392           break;
1393       }
1394     }
1395   return(MagickTrue);
1396 }
1397 
ReadDXT1(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1398 static MagickBooleanType ReadDXT1(const ImageInfo *image_info,Image *image,
1399   DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1400   ExceptionInfo *exception)
1401 {
1402   if (ReadDXT1Pixels(image,dds_info,exception) == MagickFalse)
1403     return(MagickFalse);
1404 
1405   if (read_mipmaps != MagickFalse)
1406     return(ReadMipmaps(image_info,image,dds_info,ReadDXT1Pixels,exception));
1407   else
1408     return(SkipDXTMipmaps(image,dds_info,8,exception));
1409 }
1410 
ReadDXT3Pixels(Image * image,DDSInfo * magick_unused (dds_info),ExceptionInfo * exception)1411 static MagickBooleanType ReadDXT3Pixels(Image *image,
1412   DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1413 {
1414   DDSColors
1415     colors;
1416 
1417   Quantum
1418     *q;
1419 
1420   ssize_t
1421     i,
1422     x;
1423 
1424   unsigned char
1425     alpha;
1426 
1427   size_t
1428     a0,
1429     a1,
1430     bits,
1431     code;
1432 
1433   ssize_t
1434     j,
1435     y;
1436 
1437   unsigned short
1438     c0,
1439     c1;
1440 
1441   magick_unreferenced(dds_info);
1442   for (y = 0; y < (ssize_t) image->rows; y += 4)
1443   {
1444     for (x = 0; x < (ssize_t) image->columns; x += 4)
1445     {
1446       /* Get 4x4 patch of pixels to write on */
1447       q = QueueAuthenticPixels(image, x, y, MagickMin(4, image->columns - x),
1448                          MagickMin(4, image->rows - y),exception);
1449 
1450       if (q == (Quantum *) NULL)
1451         return(MagickFalse);
1452 
1453       /* Read alpha values (8 bytes) */
1454       a0 = ReadBlobLSBLong(image);
1455       a1 = ReadBlobLSBLong(image);
1456 
1457       /* Read 8 bytes of data from the image */
1458       c0 = ReadBlobLSBShort(image);
1459       c1 = ReadBlobLSBShort(image);
1460       bits = ReadBlobLSBLong(image);
1461 
1462       CalculateColors(c0, c1, &colors, MagickTrue);
1463 
1464       if (EOFBlob(image) != MagickFalse)
1465         return(MagickFalse);
1466 
1467       /* Write the pixels */
1468       for (j = 0; j < 4; j++)
1469       {
1470         for (i = 0; i < 4; i++)
1471         {
1472           if ((x + i) < (ssize_t) image->columns && (y + j) < (ssize_t) image->rows)
1473             {
1474               code = (bits >> ((4*j+i)*2)) & 0x3;
1475               SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1476               SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1477               SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1478               /*
1479                 Extract alpha value: multiply 0..15 by 17 to get range 0..255
1480               */
1481               if (j < 2)
1482                 alpha = 17U * (unsigned char) ((a0 >> (4*(4*j+i))) & 0xf);
1483               else
1484                 alpha = 17U * (unsigned char) ((a1 >> (4*(4*(j-2)+i))) & 0xf);
1485               SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) alpha),q);
1486               q+=GetPixelChannels(image);
1487             }
1488         }
1489       }
1490       if (SyncAuthenticPixels(image,exception) == MagickFalse)
1491         return(MagickFalse);
1492     }
1493     if (EOFBlob(image) != MagickFalse)
1494       return(MagickFalse);
1495   }
1496   return(MagickTrue);
1497 }
1498 
ReadDXT3(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1499 static MagickBooleanType ReadDXT3(const ImageInfo *image_info,Image *image,
1500   DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1501   ExceptionInfo *exception)
1502 {
1503   if (ReadDXT3Pixels(image,dds_info,exception) == MagickFalse)
1504     return(MagickFalse);
1505 
1506   if (read_mipmaps != MagickFalse)
1507     return(ReadMipmaps(image_info,image,dds_info,ReadDXT3Pixels,exception));
1508   else
1509     return(SkipDXTMipmaps(image,dds_info,16,exception));
1510 }
1511 
ReadDXT5Pixels(Image * image,DDSInfo * magick_unused (dds_info),ExceptionInfo * exception)1512 static MagickBooleanType ReadDXT5Pixels(Image *image,
1513   DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1514 {
1515   DDSColors
1516     colors;
1517 
1518   MagickSizeType
1519     alpha_bits;
1520 
1521   Quantum
1522     *q;
1523 
1524   ssize_t
1525     i,
1526     x;
1527 
1528   unsigned char
1529     a0,
1530     a1;
1531 
1532   size_t
1533     alpha,
1534     bits,
1535     code,
1536     alpha_code;
1537 
1538   ssize_t
1539     j,
1540     y;
1541 
1542   unsigned short
1543     c0,
1544     c1;
1545 
1546   magick_unreferenced(dds_info);
1547   for (y = 0; y < (ssize_t) image->rows; y += 4)
1548   {
1549     for (x = 0; x < (ssize_t) image->columns; x += 4)
1550     {
1551       /* Get 4x4 patch of pixels to write on */
1552       q = QueueAuthenticPixels(image, x, y, MagickMin(4, image->columns - x),
1553                          MagickMin(4, image->rows - y),exception);
1554 
1555       if (q == (Quantum *) NULL)
1556         return(MagickFalse);
1557 
1558       /* Read alpha values (8 bytes) */
1559       a0 = (unsigned char) ReadBlobByte(image);
1560       a1 = (unsigned char) ReadBlobByte(image);
1561 
1562       alpha_bits = (MagickSizeType)ReadBlobLSBLong(image);
1563       alpha_bits = alpha_bits | ((MagickSizeType)ReadBlobLSBShort(image) << 32);
1564 
1565       /* Read 8 bytes of data from the image */
1566       c0 = ReadBlobLSBShort(image);
1567       c1 = ReadBlobLSBShort(image);
1568       bits = ReadBlobLSBLong(image);
1569 
1570       CalculateColors(c0, c1, &colors, MagickTrue);
1571       if (EOFBlob(image) != MagickFalse)
1572         return(MagickFalse);
1573 
1574       /* Write the pixels */
1575       for (j = 0; j < 4; j++)
1576       {
1577         for (i = 0; i < 4; i++)
1578         {
1579           if ((x + i) < (ssize_t) image->columns &&
1580               (y + j) < (ssize_t) image->rows)
1581             {
1582               code = (bits >> ((4*j+i)*2)) & 0x3;
1583               SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1584               SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1585               SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1586               /* Extract alpha value */
1587               alpha_code = (size_t) (alpha_bits >> (3*(4*j+i))) & 0x7;
1588               if (alpha_code == 0)
1589                 alpha = a0;
1590               else if (alpha_code == 1)
1591                 alpha = a1;
1592               else if (a0 > a1)
1593                 alpha = ((8-alpha_code) * a0 + (alpha_code-1) * a1) / 7;
1594               else if (alpha_code == 6)
1595                 alpha = 0;
1596               else if (alpha_code == 7)
1597                 alpha = 255;
1598               else
1599                 alpha = (((6-alpha_code) * a0 + (alpha_code-1) * a1) / 5);
1600               SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) alpha),q);
1601               q+=GetPixelChannels(image);
1602             }
1603         }
1604       }
1605       if (SyncAuthenticPixels(image,exception) == MagickFalse)
1606         return(MagickFalse);
1607     }
1608     if (EOFBlob(image) != MagickFalse)
1609       return(MagickFalse);
1610   }
1611   return(MagickTrue);
1612 }
1613 
ReadDXT5(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1614 static MagickBooleanType ReadDXT5(const ImageInfo *image_info,Image *image,
1615   DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1616   ExceptionInfo *exception)
1617 {
1618   if (ReadDXT5Pixels(image,dds_info,exception) == MagickFalse)
1619     return(MagickFalse);
1620 
1621   if (read_mipmaps != MagickFalse)
1622     return(ReadMipmaps(image_info,image,dds_info,ReadDXT5Pixels,exception));
1623   else
1624     return(SkipDXTMipmaps(image,dds_info,16,exception));
1625 }
1626 
ReadUncompressedRGBPixels(Image * image,DDSInfo * dds_info,ExceptionInfo * exception)1627 static MagickBooleanType ReadUncompressedRGBPixels(Image *image,
1628   DDSInfo *dds_info,ExceptionInfo *exception)
1629 {
1630   Quantum
1631     *q;
1632 
1633   ssize_t
1634     x, y;
1635 
1636   unsigned short
1637     color;
1638 
1639   for (y = 0; y < (ssize_t) image->rows; y++)
1640   {
1641     q = QueueAuthenticPixels(image, 0, y, image->columns, 1,exception);
1642 
1643     if (q == (Quantum *) NULL)
1644       return(MagickFalse);
1645 
1646     for (x = 0; x < (ssize_t) image->columns; x++)
1647     {
1648       if (dds_info->pixelformat.rgb_bitcount == 8 ||
1649           dds_info->extFormat == DXGI_FORMAT_R8_UNORM)
1650         SetPixelGray(image,ScaleCharToQuantum(ReadBlobByte(image)),q);
1651       else if (dds_info->pixelformat.rgb_bitcount == 16 ||
1652           dds_info->extFormat == DXGI_FORMAT_B5G6R5_UNORM)
1653         {
1654            color=ReadBlobShort(image);
1655            SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1656              (((color >> 11)/31.0)*255)),q);
1657            SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1658              ((((unsigned short)(color << 5) >> 10)/63.0)*255)),q);
1659            SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1660              ((((unsigned short)(color << 11) >> 11)/31.0)*255)),q);
1661         }
1662       else
1663         {
1664           SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1665             ReadBlobByte(image)),q);
1666           SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1667             ReadBlobByte(image)),q);
1668           SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1669             ReadBlobByte(image)),q);
1670           if (dds_info->pixelformat.rgb_bitcount == 32 ||
1671               dds_info->extFormat == DXGI_FORMAT_B8G8R8X8_UNORM)
1672             (void) ReadBlobByte(image);
1673         }
1674       q+=GetPixelChannels(image);
1675     }
1676     if (SyncAuthenticPixels(image,exception) == MagickFalse)
1677       return(MagickFalse);
1678     if (EOFBlob(image) != MagickFalse)
1679       return(MagickFalse);
1680   }
1681   return(MagickTrue);
1682 }
1683 
1684 /*
1685   Skip the mipmap images for uncompressed (RGB or RGBA) dds files
1686 */
SkipRGBMipmaps(Image * image,DDSInfo * dds_info,int pixel_size,ExceptionInfo * exception)1687 static MagickBooleanType SkipRGBMipmaps(Image *image,DDSInfo *dds_info,
1688   int pixel_size,ExceptionInfo *exception)
1689 {
1690   /*
1691     Only skip mipmaps for textures and cube maps
1692   */
1693   if (EOFBlob(image) != MagickFalse)
1694     {
1695       ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1696         image->filename);
1697       return(MagickFalse);
1698     }
1699   if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1700       && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1701           || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1702     {
1703       MagickOffsetType
1704         offset;
1705 
1706       ssize_t
1707         i;
1708 
1709       size_t
1710         h,
1711         w;
1712 
1713       w=DIV2(dds_info->width);
1714       h=DIV2(dds_info->height);
1715 
1716       /*
1717         Mipmapcount includes the main image, so start from one
1718       */
1719       for (i=1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1720       {
1721         offset=(MagickOffsetType)w*h*pixel_size;
1722         if (SeekBlob(image,offset,SEEK_CUR) < 0)
1723           break;
1724         w=DIV2(w);
1725         h=DIV2(h);
1726         if ((w == 1) && (h == 1))
1727           break;
1728       }
1729     }
1730   return(MagickTrue);
1731 }
1732 
ReadUncompressedRGB(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1733 static MagickBooleanType ReadUncompressedRGB(const ImageInfo *image_info,
1734   Image *image,DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1735   ExceptionInfo *exception)
1736 {
1737   if (dds_info->pixelformat.rgb_bitcount == 8 ||
1738       dds_info->extFormat == DXGI_FORMAT_R8_UNORM)
1739     (void) SetImageType(image,GrayscaleType,exception);
1740   else if (dds_info->pixelformat.rgb_bitcount == 16 && !IsBitMask(
1741     dds_info->pixelformat,0xf800,0x07e0,0x001f,0x0000))
1742     ThrowBinaryException(CorruptImageError,"ImageTypeNotSupported",
1743       image->filename);
1744 
1745   if (ReadUncompressedRGBPixels(image,dds_info,exception) == MagickFalse)
1746     return(MagickFalse);
1747 
1748   if (read_mipmaps != MagickFalse)
1749     return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedRGBPixels,
1750       exception));
1751   else
1752     return(SkipRGBMipmaps(image,dds_info,3,exception));
1753 }
1754 
ReadUncompressedRGBAPixels(Image * image,DDSInfo * dds_info,ExceptionInfo * exception)1755 static MagickBooleanType ReadUncompressedRGBAPixels(Image *image,
1756   DDSInfo *dds_info,ExceptionInfo *exception)
1757 {
1758   Quantum
1759     *q;
1760 
1761   ssize_t
1762     alphaBits,
1763     x,
1764     y;
1765 
1766   unsigned short
1767     color;
1768 
1769   alphaBits=0;
1770   if (dds_info->pixelformat.rgb_bitcount == 16)
1771     {
1772       if (IsBitMask(dds_info->pixelformat,0x7c00,0x03e0,0x001f,0x8000))
1773         alphaBits=1;
1774       else if (IsBitMask(dds_info->pixelformat,0x00ff,0x00ff,0x00ff,0xff00))
1775         {
1776           alphaBits=2;
1777           (void) SetImageType(image,GrayscaleAlphaType,exception);
1778         }
1779       else if (IsBitMask(dds_info->pixelformat,0x0f00,0x00f0,0x000f,0xf000))
1780         alphaBits=4;
1781       else
1782         ThrowBinaryException(CorruptImageError,"ImageTypeNotSupported",
1783           image->filename);
1784     }
1785 
1786   if (dds_info->extFormat == DXGI_FORMAT_B5G5R5A1_UNORM)
1787     alphaBits=1;
1788 
1789   for (y = 0; y < (ssize_t) image->rows; y++)
1790   {
1791     q = QueueAuthenticPixels(image, 0, y, image->columns, 1,exception);
1792 
1793     if (q == (Quantum *) NULL)
1794       return(MagickFalse);
1795 
1796     for (x = 0; x < (ssize_t) image->columns; x++)
1797     {
1798       if (dds_info->pixelformat.rgb_bitcount == 16 ||
1799           dds_info->extFormat == DXGI_FORMAT_B5G5R5A1_UNORM)
1800         {
1801            color=ReadBlobShort(image);
1802            if (alphaBits == 1)
1803              {
1804                SetPixelAlpha(image,(color & (1 << 15)) ? QuantumRange : 0,q);
1805                SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1806                  ((((unsigned short)(color << 1) >> 11)/31.0)*255)),q);
1807                SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1808                  ((((unsigned short)(color << 6) >> 11)/31.0)*255)),q);
1809                SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1810                  ((((unsigned short)(color << 11) >> 11)/31.0)*255)),q);
1811              }
1812           else if (alphaBits == 2)
1813             {
1814                SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1815                  (color >> 8)),q);
1816                SetPixelGray(image,ScaleCharToQuantum((unsigned char)color),q);
1817             }
1818           else
1819             {
1820                SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1821                  (((color >> 12)/15.0)*255)),q);
1822                SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1823                  ((((unsigned short)(color << 4) >> 12)/15.0)*255)),q);
1824                SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1825                  ((((unsigned short)(color << 8) >> 12)/15.0)*255)),q);
1826                SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1827                  ((((unsigned short)(color << 12) >> 12)/15.0)*255)),q);
1828             }
1829         }
1830       else if (dds_info->extFormat == DXGI_FORMAT_R8G8B8A8_UNORM ||
1831           IsBitMask(dds_info->pixelformat,0x000000ff,0x0000ff00,0x00ff0000,0xff000000))
1832         {
1833           SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1834             ReadBlobByte(image)),q);
1835           SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1836             ReadBlobByte(image)),q);
1837           SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1838             ReadBlobByte(image)),q);
1839           SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1840             ReadBlobByte(image)),q);
1841         }
1842       else
1843         {
1844           SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1845             ReadBlobByte(image)),q);
1846           SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1847             ReadBlobByte(image)),q);
1848           SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1849             ReadBlobByte(image)),q);
1850           SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1851             ReadBlobByte(image)),q);
1852         }
1853       q+=GetPixelChannels(image);
1854     }
1855     if (SyncAuthenticPixels(image,exception) == MagickFalse)
1856       return(MagickFalse);
1857     if (EOFBlob(image) != MagickFalse)
1858       return(MagickFalse);
1859   }
1860   return(MagickTrue);
1861 }
1862 
ReadUncompressedRGBA(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1863 static MagickBooleanType ReadUncompressedRGBA(const ImageInfo *image_info,
1864   Image *image,DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1865   ExceptionInfo *exception)
1866 {
1867   if (ReadUncompressedRGBAPixels(image,dds_info,exception) == MagickFalse)
1868     return(MagickFalse);
1869 
1870   if (read_mipmaps != MagickFalse)
1871     return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedRGBAPixels,
1872       exception));
1873   else
1874     return(SkipRGBMipmaps(image,dds_info,4,exception));
1875 }
1876 
ReadDDSImage(const ImageInfo * image_info,ExceptionInfo * exception)1877 static Image *ReadDDSImage(const ImageInfo *image_info,ExceptionInfo *exception)
1878 {
1879   const char
1880     *option;
1881 
1882   CompressionType
1883     compression;
1884 
1885   DDSInfo
1886     dds_info;
1887 
1888   DDSDecoder
1889     *decoder;
1890 
1891   Image
1892     *image;
1893 
1894   MagickBooleanType
1895     status,
1896     cubemap,
1897     volume,
1898     read_mipmaps;
1899 
1900   PixelTrait
1901     alpha_trait;
1902 
1903   size_t
1904     n,
1905     num_images;
1906 
1907   /*
1908     Open image file.
1909   */
1910   assert(image_info != (const ImageInfo *) NULL);
1911   assert(image_info->signature == MagickCoreSignature);
1912   if (image_info->debug != MagickFalse)
1913     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1914       image_info->filename);
1915   assert(exception != (ExceptionInfo *) NULL);
1916   assert(exception->signature == MagickCoreSignature);
1917   cubemap=MagickFalse,
1918   volume=MagickFalse,
1919   read_mipmaps=MagickFalse;
1920   image=AcquireImage(image_info,exception);
1921   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1922   if (status == MagickFalse)
1923     {
1924       image=DestroyImageList(image);
1925       return((Image *) NULL);
1926     }
1927 
1928   /*
1929     Initialize image structure.
1930   */
1931   if (ReadDDSInfo(image, &dds_info) != MagickTrue)
1932     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1933 
1934   if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP)
1935     cubemap = MagickTrue;
1936 
1937   if (dds_info.ddscaps2 & DDSCAPS2_VOLUME && dds_info.depth > 0)
1938     volume = MagickTrue;
1939 
1940   /*
1941     Determine pixel format
1942   */
1943   if (dds_info.pixelformat.flags & DDPF_RGB)
1944     {
1945       compression = NoCompression;
1946       if (dds_info.pixelformat.flags & DDPF_ALPHAPIXELS)
1947         {
1948           alpha_trait = BlendPixelTrait;
1949           decoder = ReadUncompressedRGBA;
1950         }
1951       else
1952         {
1953           alpha_trait = UndefinedPixelTrait;
1954           decoder = ReadUncompressedRGB;
1955         }
1956     }
1957   else if (dds_info.pixelformat.flags & DDPF_LUMINANCE)
1958    {
1959       compression = NoCompression;
1960       if (dds_info.pixelformat.flags & DDPF_ALPHAPIXELS)
1961         {
1962           /* Not sure how to handle this */
1963           ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
1964         }
1965       else
1966         {
1967           alpha_trait = UndefinedPixelTrait;
1968           decoder = ReadUncompressedRGB;
1969         }
1970     }
1971   else if (dds_info.pixelformat.flags & DDPF_FOURCC)
1972     {
1973       switch (dds_info.pixelformat.fourcc)
1974       {
1975         case FOURCC_DXT1:
1976         {
1977           alpha_trait = UndefinedPixelTrait;
1978           compression = DXT1Compression;
1979           decoder = ReadDXT1;
1980           break;
1981         }
1982         case FOURCC_DXT3:
1983         {
1984           alpha_trait = BlendPixelTrait;
1985           compression = DXT3Compression;
1986           decoder = ReadDXT3;
1987           break;
1988         }
1989         case FOURCC_DXT5:
1990         {
1991           alpha_trait = BlendPixelTrait;
1992           compression = DXT5Compression;
1993           decoder = ReadDXT5;
1994           break;
1995         }
1996         case FOURCC_DX10:
1997         {
1998           if (dds_info.extDimension != DDSEXT_DIMENSION_TEX2D)
1999             {
2000               ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
2001             }
2002 
2003           switch (dds_info.extFormat)
2004           {
2005             case DXGI_FORMAT_R8_UNORM:
2006             {
2007               compression = NoCompression;
2008               alpha_trait = UndefinedPixelTrait;
2009               decoder = ReadUncompressedRGB;
2010               break;
2011             }
2012             case DXGI_FORMAT_B5G6R5_UNORM:
2013             {
2014               compression = NoCompression;
2015               alpha_trait = UndefinedPixelTrait;
2016               decoder = ReadUncompressedRGB;
2017               break;
2018             }
2019             case DXGI_FORMAT_B5G5R5A1_UNORM:
2020             {
2021               compression = NoCompression;
2022               alpha_trait = BlendPixelTrait;
2023               decoder = ReadUncompressedRGBA;
2024               break;
2025             }
2026             case DXGI_FORMAT_B8G8R8A8_UNORM:
2027             {
2028               compression = NoCompression;
2029               alpha_trait = BlendPixelTrait;
2030               decoder = ReadUncompressedRGBA;
2031               break;
2032             }
2033             case DXGI_FORMAT_R8G8B8A8_UNORM:
2034             {
2035               compression = NoCompression;
2036               alpha_trait = BlendPixelTrait;
2037               decoder = ReadUncompressedRGBA;
2038               break;
2039             }
2040             case DXGI_FORMAT_B8G8R8X8_UNORM:
2041             {
2042               compression = NoCompression;
2043               alpha_trait = UndefinedPixelTrait;
2044               decoder = ReadUncompressedRGB;
2045               break;
2046             }
2047             case DXGI_FORMAT_BC1_UNORM:
2048             {
2049               alpha_trait = UndefinedPixelTrait;
2050               compression = DXT1Compression;
2051               decoder = ReadDXT1;
2052               break;
2053             }
2054             case DXGI_FORMAT_BC2_UNORM:
2055             {
2056               alpha_trait = BlendPixelTrait;
2057               compression = DXT3Compression;
2058               decoder = ReadDXT3;
2059               break;
2060             }
2061             case DXGI_FORMAT_BC3_UNORM:
2062             {
2063               alpha_trait = BlendPixelTrait;
2064               compression = DXT5Compression;
2065               decoder = ReadDXT5;
2066               break;
2067             }
2068             default:
2069             {
2070               /* Unknown format */
2071               ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
2072             }
2073           }
2074 
2075           if (dds_info.extFlags & DDSEXTFLAGS_CUBEMAP)
2076             cubemap = MagickTrue;
2077 
2078           num_images = dds_info.extArraySize;
2079           break;
2080         }
2081         default:
2082         {
2083           /* Unknown FOURCC */
2084           ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
2085         }
2086       }
2087     }
2088   else
2089     {
2090       /* Neither compressed nor uncompressed... thus unsupported */
2091       ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
2092     }
2093 
2094   num_images = 1;
2095   if (cubemap)
2096     {
2097       /*
2098         Determine number of faces defined in the cubemap
2099       */
2100       num_images = 0;
2101       if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEX) num_images++;
2102       if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) num_images++;
2103       if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEY) num_images++;
2104       if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) num_images++;
2105       if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) num_images++;
2106       if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) num_images++;
2107     }
2108 
2109   if (volume)
2110     num_images = dds_info.depth;
2111 
2112   if ((num_images == 0) || (num_images > GetBlobSize(image)))
2113     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2114 
2115   if (AcquireMagickResource(ListLengthResource,num_images) == MagickFalse)
2116     ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
2117 
2118   option=GetImageOption(image_info,"dds:skip-mipmaps");
2119   if (IsStringFalse(option) != MagickFalse)
2120     read_mipmaps=MagickTrue;
2121 
2122   for (n = 0; n < num_images; n++)
2123   {
2124     if (n != 0)
2125       {
2126         /* Start a new image */
2127         if (EOFBlob(image) != MagickFalse)
2128           ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
2129         AcquireNextImage(image_info,image,exception);
2130         if (GetNextImageInList(image) == (Image *) NULL)
2131           return(DestroyImageList(image));
2132         image=SyncNextImageInList(image);
2133       }
2134 
2135     image->alpha_trait=alpha_trait;
2136     image->compression=compression;
2137     image->columns=dds_info.width;
2138     image->rows=dds_info.height;
2139     image->storage_class=DirectClass;
2140     image->endian=LSBEndian;
2141     image->depth=8;
2142     if (image_info->ping != MagickFalse)
2143       {
2144         (void) CloseBlob(image);
2145         return(GetFirstImageInList(image));
2146       }
2147     status=SetImageExtent(image,image->columns,image->rows,exception);
2148     if (status == MagickFalse)
2149       return(DestroyImageList(image));
2150     (void) SetImageBackgroundColor(image,exception);
2151     status=(decoder)(image_info,image,&dds_info,read_mipmaps,exception);
2152     if (status == MagickFalse)
2153       {
2154         (void) CloseBlob(image);
2155         if (n == 0)
2156           return(DestroyImageList(image));
2157         return(GetFirstImageInList(image));
2158       }
2159   }
2160   (void) CloseBlob(image);
2161   return(GetFirstImageInList(image));
2162 }
2163 
2164 /*
2165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166 %                                                                             %
2167 %                                                                             %
2168 %                                                                             %
2169 %   R e g i s t e r D D S I m a g e                                           %
2170 %                                                                             %
2171 %                                                                             %
2172 %                                                                             %
2173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2174 %
2175 %  RegisterDDSImage() adds attributes for the DDS image format to
2176 %  the list of supported formats.  The attributes include the image format
2177 %  tag, a method to read and/or write the format, whether the format
2178 %  supports the saving of more than one frame to the same file or blob,
2179 %  whether the format supports native in-memory I/O, and a brief
2180 %  description of the format.
2181 %
2182 %  The format of the RegisterDDSImage method is:
2183 %
2184 %      RegisterDDSImage(void)
2185 %
2186 */
RegisterDDSImage(void)2187 ModuleExport size_t RegisterDDSImage(void)
2188 {
2189   MagickInfo
2190     *entry;
2191 
2192   entry = AcquireMagickInfo("DDS","DDS","Microsoft DirectDraw Surface");
2193   entry->decoder = (DecodeImageHandler *) ReadDDSImage;
2194   entry->encoder = (EncodeImageHandler *) WriteDDSImage;
2195   entry->magick = (IsImageFormatHandler *) IsDDS;
2196   entry->flags|=CoderDecoderSeekableStreamFlag;
2197   (void) RegisterMagickInfo(entry);
2198   entry = AcquireMagickInfo("DDS","DXT1","Microsoft DirectDraw Surface");
2199   entry->decoder = (DecodeImageHandler *) ReadDDSImage;
2200   entry->encoder = (EncodeImageHandler *) WriteDDSImage;
2201   entry->magick = (IsImageFormatHandler *) IsDDS;
2202   entry->flags|=CoderDecoderSeekableStreamFlag;
2203   (void) RegisterMagickInfo(entry);
2204   entry = AcquireMagickInfo("DDS","DXT5","Microsoft DirectDraw Surface");
2205   entry->decoder = (DecodeImageHandler *) ReadDDSImage;
2206   entry->encoder = (EncodeImageHandler *) WriteDDSImage;
2207   entry->magick = (IsImageFormatHandler *) IsDDS;
2208   entry->flags|=CoderDecoderSeekableStreamFlag;
2209   (void) RegisterMagickInfo(entry);
2210   return(MagickImageCoderSignature);
2211 }
2212 
RemapIndices(const ssize_t * map,const unsigned char * source,unsigned char * target)2213 static void RemapIndices(const ssize_t *map, const unsigned char *source,
2214   unsigned char *target)
2215 {
2216   ssize_t
2217     i;
2218 
2219   for (i = 0; i < 16; i++)
2220   {
2221     if (map[i] == -1)
2222       target[i] = 3;
2223     else
2224       target[i] = source[map[i]];
2225   }
2226 }
2227 
2228 /*
2229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2230 %                                                                             %
2231 %                                                                             %
2232 %                                                                             %
2233 %   U n r e g i s t e r D D S I m a g e                                       %
2234 %                                                                             %
2235 %                                                                             %
2236 %                                                                             %
2237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2238 %
2239 %  UnregisterDDSImage() removes format registrations made by the
2240 %  DDS module from the list of supported formats.
2241 %
2242 %  The format of the UnregisterDDSImage method is:
2243 %
2244 %      UnregisterDDSImage(void)
2245 %
2246 */
UnregisterDDSImage(void)2247 ModuleExport void UnregisterDDSImage(void)
2248 {
2249   (void) UnregisterMagickInfo("DDS");
2250   (void) UnregisterMagickInfo("DXT1");
2251   (void) UnregisterMagickInfo("DXT5");
2252 }
2253 
2254 /*
2255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2256 %                                                                             %
2257 %                                                                             %
2258 %                                                                             %
2259 %   W r i t e D D S I m a g e                                                 %
2260 %                                                                             %
2261 %                                                                             %
2262 %                                                                             %
2263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2264 %
2265 %  WriteDDSImage() writes a DirectDraw Surface image file in the DXT5 format.
2266 %
2267 %  The format of the WriteBMPImage method is:
2268 %
2269 %     MagickBooleanType WriteDDSImage(const ImageInfo *image_info,Image *image)
2270 %
2271 %  A description of each parameter follows.
2272 %
2273 %    o image_info: the image info.
2274 %
2275 %    o image:  The image.
2276 %
2277 */
2278 
CompressAlpha(const size_t min,const size_t max,const size_t steps,const ssize_t * alphas,unsigned char * indices)2279 static size_t CompressAlpha(const size_t min, const size_t max,
2280   const size_t steps, const ssize_t *alphas, unsigned char* indices)
2281 {
2282   unsigned char
2283     codes[8];
2284 
2285   ssize_t
2286     i;
2287 
2288   size_t
2289     error,
2290     index,
2291     j,
2292     least,
2293     value;
2294 
2295   codes[0] = (unsigned char) min;
2296   codes[1] = (unsigned char) max;
2297   codes[6] = 0;
2298   codes[7] = 255;
2299 
2300   for (i=1; i <  (ssize_t) steps; i++)
2301     codes[i+1] = (unsigned char) (((steps-i)*min + i*max) / steps);
2302 
2303   error = 0;
2304   for (i=0; i<16; i++)
2305   {
2306     if (alphas[i] == -1)
2307       {
2308         indices[i] = 0;
2309         continue;
2310       }
2311 
2312     value = alphas[i];
2313     least = SIZE_MAX;
2314     index = 0;
2315     for (j=0; j<8; j++)
2316     {
2317       size_t
2318         dist;
2319 
2320       dist = value - (size_t)codes[j];
2321       dist *= dist;
2322 
2323       if (dist < least)
2324         {
2325           least = dist;
2326           index = j;
2327         }
2328     }
2329 
2330     indices[i] = (unsigned char)index;
2331     error += least;
2332   }
2333 
2334   return error;
2335 }
2336 
ConstructOrdering(const size_t count,const DDSVector4 * points,const DDSVector3 axis,DDSVector4 * pointsWeights,DDSVector4 * xSumwSum,unsigned char * order,size_t iteration)2337 static MagickBooleanType ConstructOrdering(const size_t count,
2338   const DDSVector4 *points, const DDSVector3 axis, DDSVector4 *pointsWeights,
2339   DDSVector4 *xSumwSum, unsigned char *order, size_t iteration)
2340 {
2341   float
2342      dps[16],
2343      f;
2344 
2345   ssize_t
2346     i;
2347 
2348   size_t
2349     j;
2350 
2351   unsigned char
2352     c,
2353     *o,
2354     *p;
2355 
2356   o = order + (16*iteration);
2357 
2358   for (i=0; i < (ssize_t) count; i++)
2359   {
2360     dps[i] = Dot(points[i],axis);
2361     o[i] = (unsigned char)i;
2362   }
2363 
2364   for (i=0; i < (ssize_t) count; i++)
2365   {
2366     for (j=i; j > 0 && dps[j] < dps[j - 1]; j--)
2367     {
2368       f = dps[j];
2369       dps[j] = dps[j - 1];
2370       dps[j - 1] = f;
2371 
2372       c = o[j];
2373       o[j] = o[j - 1];
2374       o[j - 1] = c;
2375     }
2376   }
2377 
2378   for (i=0; i < (ssize_t) iteration; i++)
2379   {
2380     MagickBooleanType
2381       same;
2382 
2383     p = order + (16*i);
2384     same = MagickTrue;
2385 
2386     for (j=0; j < count; j++)
2387     {
2388       if (o[j] != p[j])
2389         {
2390           same = MagickFalse;
2391           break;
2392         }
2393     }
2394 
2395     if (same != MagickFalse)
2396       return MagickFalse;
2397   }
2398 
2399   xSumwSum->x = 0;
2400   xSumwSum->y = 0;
2401   xSumwSum->z = 0;
2402   xSumwSum->w = 0;
2403 
2404   for (i=0; i < (ssize_t) count; i++)
2405   {
2406     DDSVector4
2407       v;
2408 
2409     j = (size_t) o[i];
2410 
2411     v.x = points[j].w * points[j].x;
2412     v.y = points[j].w * points[j].y;
2413     v.z = points[j].w * points[j].z;
2414     v.w = points[j].w * 1.0f;
2415 
2416     VectorCopy44(v,&pointsWeights[i]);
2417     VectorAdd(*xSumwSum,v,xSumwSum);
2418   }
2419 
2420   return MagickTrue;
2421 }
2422 
CompressClusterFit(const size_t count,const DDSVector4 * points,const ssize_t * map,const DDSVector3 principle,const DDSVector4 metric,DDSVector3 * start,DDSVector3 * end,unsigned char * indices)2423 static void CompressClusterFit(const size_t count,
2424   const DDSVector4 *points, const ssize_t *map, const DDSVector3 principle,
2425   const DDSVector4 metric, DDSVector3 *start, DDSVector3* end,
2426   unsigned char *indices)
2427 {
2428   DDSVector3
2429     axis;
2430 
2431   DDSVector4
2432     grid,
2433     gridrcp,
2434     half,
2435     onethird_onethird2,
2436     pointsWeights[16],
2437     two,
2438     twonineths,
2439     twothirds_twothirds2,
2440     xSumwSum;
2441 
2442   float
2443     bestError = 1e+37f;
2444 
2445   size_t
2446     bestIteration = 0,
2447     besti = 0,
2448     bestj = 0,
2449     bestk = 0,
2450     iterationIndex;
2451 
2452   ssize_t
2453     i;
2454 
2455   unsigned char
2456     *o,
2457     order[128],
2458     unordered[16];
2459 
2460   VectorInit(half,0.5f);
2461   VectorInit(two,2.0f);
2462 
2463   VectorInit(onethird_onethird2,1.0f/3.0f);
2464   onethird_onethird2.w = 1.0f/9.0f;
2465   VectorInit(twothirds_twothirds2,2.0f/3.0f);
2466   twothirds_twothirds2.w = 4.0f/9.0f;
2467   VectorInit(twonineths,2.0f/9.0f);
2468 
2469   grid.x = 31.0f;
2470   grid.y = 63.0f;
2471   grid.z = 31.0f;
2472   grid.w = 0.0f;
2473 
2474   gridrcp.x = 1.0f/31.0f;
2475   gridrcp.y = 1.0f/63.0f;
2476   gridrcp.z = 1.0f/31.0f;
2477   gridrcp.w = 0.0f;
2478 
2479   xSumwSum.x = 0.0f;
2480   xSumwSum.y = 0.0f;
2481   xSumwSum.z = 0.0f;
2482   xSumwSum.w = 0.0f;
2483 
2484   ConstructOrdering(count,points,principle,pointsWeights,&xSumwSum,order,0);
2485 
2486   for (iterationIndex = 0;;)
2487   {
2488 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2489   #pragma omp parallel for schedule(dynamic,1) \
2490     num_threads(GetMagickResourceLimit(ThreadResource))
2491 #endif
2492     for (i=0; i < (ssize_t) count; i++)
2493     {
2494       DDSVector4
2495         part0,
2496         part1,
2497         part2;
2498 
2499       size_t
2500         ii,
2501         j,
2502         k,
2503         kmin;
2504 
2505       VectorInit(part0,0.0f);
2506       for(ii=0; ii < (size_t) i; ii++)
2507         VectorAdd(pointsWeights[ii],part0,&part0);
2508 
2509       VectorInit(part1,0.0f);
2510       for (j=(size_t) i;;)
2511       {
2512         if (j == 0)
2513           {
2514             VectorCopy44(pointsWeights[0],&part2);
2515             kmin = 1;
2516           }
2517           else
2518           {
2519             VectorInit(part2,0.0f);
2520             kmin = j;
2521           }
2522 
2523         for (k=kmin;;)
2524         {
2525           DDSVector4
2526             a,
2527             alpha2_sum,
2528             alphax_sum,
2529             alphabeta_sum,
2530             b,
2531             beta2_sum,
2532             betax_sum,
2533             e1,
2534             e2,
2535             factor,
2536             part3;
2537 
2538           float
2539             error;
2540 
2541           VectorSubtract(xSumwSum,part2,&part3);
2542           VectorSubtract(part3,part1,&part3);
2543           VectorSubtract(part3,part0,&part3);
2544 
2545           VectorMultiplyAdd(part1,twothirds_twothirds2,part0,&alphax_sum);
2546           VectorMultiplyAdd(part2,onethird_onethird2,alphax_sum,&alphax_sum);
2547           VectorInit(alpha2_sum,alphax_sum.w);
2548 
2549           VectorMultiplyAdd(part2,twothirds_twothirds2,part3,&betax_sum);
2550           VectorMultiplyAdd(part1,onethird_onethird2,betax_sum,&betax_sum);
2551           VectorInit(beta2_sum,betax_sum.w);
2552 
2553           VectorAdd(part1,part2,&alphabeta_sum);
2554           VectorInit(alphabeta_sum,alphabeta_sum.w);
2555           VectorMultiply(twonineths,alphabeta_sum,&alphabeta_sum);
2556 
2557           VectorMultiply(alpha2_sum,beta2_sum,&factor);
2558           VectorNegativeMultiplySubtract(alphabeta_sum,alphabeta_sum,factor,
2559             &factor);
2560           VectorReciprocal(factor,&factor);
2561 
2562           VectorMultiply(alphax_sum,beta2_sum,&a);
2563           VectorNegativeMultiplySubtract(betax_sum,alphabeta_sum,a,&a);
2564           VectorMultiply(a,factor,&a);
2565 
2566           VectorMultiply(betax_sum,alpha2_sum,&b);
2567           VectorNegativeMultiplySubtract(alphax_sum,alphabeta_sum,b,&b);
2568           VectorMultiply(b,factor,&b);
2569 
2570           VectorClamp(&a);
2571           VectorMultiplyAdd(grid,a,half,&a);
2572           VectorTruncate(&a);
2573           VectorMultiply(a,gridrcp,&a);
2574 
2575           VectorClamp(&b);
2576           VectorMultiplyAdd(grid,b,half,&b);
2577           VectorTruncate(&b);
2578           VectorMultiply(b,gridrcp,&b);
2579 
2580           VectorMultiply(b,b,&e1);
2581           VectorMultiply(e1,beta2_sum,&e1);
2582           VectorMultiply(a,a,&e2);
2583           VectorMultiplyAdd(e2,alpha2_sum,e1,&e1);
2584 
2585           VectorMultiply(a,b,&e2);
2586           VectorMultiply(e2,alphabeta_sum,&e2);
2587           VectorNegativeMultiplySubtract(a,alphax_sum,e2,&e2);
2588           VectorNegativeMultiplySubtract(b,betax_sum,e2,&e2);
2589           VectorMultiplyAdd(two,e2,e1,&e2);
2590           VectorMultiply(e2,metric,&e2);
2591 
2592           error = e2.x + e2.y + e2.z;
2593 
2594           if (error < bestError)
2595             {
2596 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2597               #pragma omp critical (DDS_CompressClusterFit)
2598 #endif
2599               {
2600                 if (error < bestError)
2601                   {
2602                     VectorCopy43(a,start);
2603                     VectorCopy43(b,end);
2604                     bestError = error;
2605                     besti = i;
2606                     bestj = j;
2607                     bestk = k;
2608                     bestIteration = iterationIndex;
2609                   }
2610               }
2611             }
2612 
2613           if (k == count)
2614             break;
2615 
2616           VectorAdd(pointsWeights[k],part2,&part2);
2617           k++;
2618         }
2619 
2620         if (j == count)
2621           break;
2622 
2623         VectorAdd(pointsWeights[j],part1,&part1);
2624         j++;
2625       }
2626     }
2627 
2628     if (bestIteration != iterationIndex)
2629       break;
2630 
2631     iterationIndex++;
2632     if (iterationIndex == 8)
2633       break;
2634 
2635     VectorSubtract3(*end,*start,&axis);
2636     if (ConstructOrdering(count,points,axis,pointsWeights,&xSumwSum,order,
2637       iterationIndex) == MagickFalse)
2638       break;
2639   }
2640 
2641   o = order + (16*bestIteration);
2642 
2643   for (i=0; i < (ssize_t) besti; i++)
2644     unordered[o[i]] = 0;
2645   for (i=besti; i < (ssize_t) bestj; i++)
2646     unordered[o[i]] = 2;
2647   for (i=bestj; i < (ssize_t) bestk; i++)
2648     unordered[o[i]] = 3;
2649   for (i=bestk; i < (ssize_t) count; i++)
2650     unordered[o[i]] = 1;
2651 
2652   RemapIndices(map,unordered,indices);
2653 }
2654 
CompressRangeFit(const size_t count,const DDSVector4 * points,const ssize_t * map,const DDSVector3 principle,const DDSVector4 metric,DDSVector3 * start,DDSVector3 * end,unsigned char * indices)2655 static void CompressRangeFit(const size_t count,
2656   const DDSVector4* points, const ssize_t *map, const DDSVector3 principle,
2657   const DDSVector4 metric, DDSVector3 *start, DDSVector3 *end,
2658   unsigned char *indices)
2659 {
2660   float
2661     d,
2662     bestDist,
2663     max,
2664     min,
2665     val;
2666 
2667   DDSVector3
2668     codes[4],
2669     grid,
2670     gridrcp,
2671     half,
2672     dist;
2673 
2674   ssize_t
2675     i;
2676 
2677   size_t
2678     bestj,
2679     j;
2680 
2681   unsigned char
2682     closest[16];
2683 
2684   VectorInit3(half,0.5f);
2685 
2686   grid.x = 31.0f;
2687   grid.y = 63.0f;
2688   grid.z = 31.0f;
2689 
2690   gridrcp.x = 1.0f/31.0f;
2691   gridrcp.y = 1.0f/63.0f;
2692   gridrcp.z = 1.0f/31.0f;
2693 
2694   if (count > 0)
2695     {
2696       VectorCopy43(points[0],start);
2697       VectorCopy43(points[0],end);
2698 
2699       min = max = Dot(points[0],principle);
2700       for (i=1; i < (ssize_t) count; i++)
2701       {
2702         val = Dot(points[i],principle);
2703         if (val < min)
2704         {
2705           VectorCopy43(points[i],start);
2706           min = val;
2707         }
2708         else if (val > max)
2709         {
2710           VectorCopy43(points[i],end);
2711           max = val;
2712         }
2713       }
2714     }
2715 
2716   VectorClamp3(start);
2717   VectorMultiplyAdd3(grid,*start,half,start);
2718   VectorTruncate3(start);
2719   VectorMultiply3(*start,gridrcp,start);
2720 
2721   VectorClamp3(end);
2722   VectorMultiplyAdd3(grid,*end,half,end);
2723   VectorTruncate3(end);
2724   VectorMultiply3(*end,gridrcp,end);
2725 
2726   codes[0] = *start;
2727   codes[1] = *end;
2728   codes[2].x = (start->x * (2.0f/3.0f)) + (end->x * (1.0f/3.0f));
2729   codes[2].y = (start->y * (2.0f/3.0f)) + (end->y * (1.0f/3.0f));
2730   codes[2].z = (start->z * (2.0f/3.0f)) + (end->z * (1.0f/3.0f));
2731   codes[3].x = (start->x * (1.0f/3.0f)) + (end->x * (2.0f/3.0f));
2732   codes[3].y = (start->y * (1.0f/3.0f)) + (end->y * (2.0f/3.0f));
2733   codes[3].z = (start->z * (1.0f/3.0f)) + (end->z * (2.0f/3.0f));
2734 
2735   for (i=0; i < (ssize_t) count; i++)
2736   {
2737     bestDist = 1e+37f;
2738     bestj = 0;
2739     for (j=0; j < 4; j++)
2740     {
2741       dist.x = (points[i].x - codes[j].x) * metric.x;
2742       dist.y = (points[i].y - codes[j].y) * metric.y;
2743       dist.z = (points[i].z - codes[j].z) * metric.z;
2744 
2745       d = Dot(dist,dist);
2746       if (d < bestDist)
2747         {
2748           bestDist = d;
2749           bestj = j;
2750         }
2751     }
2752 
2753     closest[i] = (unsigned char) bestj;
2754   }
2755 
2756   RemapIndices(map, closest, indices);
2757 }
2758 
ComputeEndPoints(const DDSSingleColorLookup * lookup[],const unsigned char * color,DDSVector3 * start,DDSVector3 * end,unsigned char * index)2759 static void ComputeEndPoints(const DDSSingleColorLookup *lookup[],
2760   const unsigned char *color, DDSVector3 *start, DDSVector3 *end,
2761   unsigned char *index)
2762 {
2763   ssize_t
2764     i;
2765 
2766   size_t
2767     c,
2768     maxError = SIZE_MAX;
2769 
2770   for (i=0; i < 2; i++)
2771   {
2772     const DDSSourceBlock*
2773       sources[3];
2774 
2775       size_t
2776         error = 0;
2777 
2778     for (c=0; c < 3; c++)
2779     {
2780       sources[c] = &lookup[c][color[c]].sources[i];
2781       error += ((size_t) sources[c]->error) * ((size_t) sources[c]->error);
2782     }
2783 
2784     if (error > maxError)
2785       continue;
2786 
2787     start->x = (float) sources[0]->start / 31.0f;
2788     start->y = (float) sources[1]->start / 63.0f;
2789     start->z = (float) sources[2]->start / 31.0f;
2790 
2791     end->x = (float) sources[0]->end / 31.0f;
2792     end->y = (float) sources[1]->end / 63.0f;
2793     end->z = (float) sources[2]->end / 31.0f;
2794 
2795     *index = (unsigned char) (2*i);
2796     maxError = error;
2797   }
2798 }
2799 
ComputePrincipleComponent(const float * covariance,DDSVector3 * principle)2800 static void ComputePrincipleComponent(const float *covariance,
2801   DDSVector3 *principle)
2802 {
2803   DDSVector4
2804     row0,
2805     row1,
2806     row2,
2807     v;
2808 
2809   ssize_t
2810     i;
2811 
2812   row0.x = covariance[0];
2813   row0.y = covariance[1];
2814   row0.z = covariance[2];
2815   row0.w = 0.0f;
2816 
2817   row1.x = covariance[1];
2818   row1.y = covariance[3];
2819   row1.z = covariance[4];
2820   row1.w = 0.0f;
2821 
2822   row2.x = covariance[2];
2823   row2.y = covariance[4];
2824   row2.z = covariance[5];
2825   row2.w = 0.0f;
2826 
2827   VectorInit(v,1.0f);
2828 
2829   for (i=0; i < 8; i++)
2830   {
2831     DDSVector4
2832       w;
2833 
2834     float
2835       a;
2836 
2837     w.x = row0.x * v.x;
2838     w.y = row0.y * v.x;
2839     w.z = row0.z * v.x;
2840     w.w = row0.w * v.x;
2841 
2842     w.x = (row1.x * v.y) + w.x;
2843     w.y = (row1.y * v.y) + w.y;
2844     w.z = (row1.z * v.y) + w.z;
2845     w.w = (row1.w * v.y) + w.w;
2846 
2847     w.x = (row2.x * v.z) + w.x;
2848     w.y = (row2.y * v.z) + w.y;
2849     w.z = (row2.z * v.z) + w.z;
2850     w.w = (row2.w * v.z) + w.w;
2851 
2852     a = (float) PerceptibleReciprocal(MagickMax(w.x,MagickMax(w.y,w.z)));
2853 
2854     v.x = w.x * a;
2855     v.y = w.y * a;
2856     v.z = w.z * a;
2857     v.w = w.w * a;
2858   }
2859 
2860   VectorCopy43(v,principle);
2861 }
2862 
ComputeWeightedCovariance(const size_t count,const DDSVector4 * points,float * covariance)2863 static void ComputeWeightedCovariance(const size_t count,
2864   const DDSVector4 *points, float *covariance)
2865 {
2866   DDSVector3
2867     centroid;
2868 
2869   float
2870     total;
2871 
2872   size_t
2873     i;
2874 
2875   total = 0.0f;
2876   VectorInit3(centroid,0.0f);
2877 
2878   for (i=0; i < count; i++)
2879   {
2880     total += points[i].w;
2881     centroid.x += (points[i].x * points[i].w);
2882     centroid.y += (points[i].y * points[i].w);
2883     centroid.z += (points[i].z * points[i].w);
2884   }
2885 
2886   if( total > 1.192092896e-07F)
2887     {
2888       centroid.x /= total;
2889       centroid.y /= total;
2890       centroid.z /= total;
2891     }
2892 
2893   for (i=0; i < 6; i++)
2894     covariance[i] = 0.0f;
2895 
2896   for (i = 0; i < count; i++)
2897   {
2898     DDSVector3
2899       a,
2900       b;
2901 
2902     a.x = points[i].x - centroid.x;
2903     a.y = points[i].y - centroid.y;
2904     a.z = points[i].z - centroid.z;
2905 
2906     b.x = points[i].w * a.x;
2907     b.y = points[i].w * a.y;
2908     b.z = points[i].w * a.z;
2909 
2910     covariance[0] += a.x*b.x;
2911     covariance[1] += a.x*b.y;
2912     covariance[2] += a.x*b.z;
2913     covariance[3] += a.y*b.y;
2914     covariance[4] += a.y*b.z;
2915     covariance[5] += a.z*b.z;
2916   }
2917 }
2918 
WriteAlphas(Image * image,const ssize_t * alphas,size_t min5,size_t max5,size_t min7,size_t max7)2919 static void WriteAlphas(Image *image, const ssize_t *alphas, size_t min5,
2920   size_t max5, size_t min7, size_t max7)
2921 {
2922   ssize_t
2923     i;
2924 
2925   size_t
2926     err5,
2927     err7,
2928     j;
2929 
2930   unsigned char
2931     indices5[16],
2932     indices7[16];
2933 
2934   FixRange(min5,max5,5);
2935   err5 = CompressAlpha(min5,max5,5,alphas,indices5);
2936 
2937   FixRange(min7,max7,7);
2938   err7 = CompressAlpha(min7,max7,7,alphas,indices7);
2939 
2940   if (err7 < err5)
2941   {
2942     for (i=0; i < 16; i++)
2943     {
2944       unsigned char
2945         index;
2946 
2947       index = indices7[i];
2948       if( index == 0 )
2949         indices5[i] = 1;
2950       else if (index == 1)
2951         indices5[i] = 0;
2952       else
2953         indices5[i] = 9 - index;
2954     }
2955 
2956     min5 = max7;
2957     max5 = min7;
2958   }
2959 
2960   (void) WriteBlobByte(image,(unsigned char) min5);
2961   (void) WriteBlobByte(image,(unsigned char) max5);
2962 
2963   for(i=0; i < 2; i++)
2964   {
2965     size_t
2966       value = 0;
2967 
2968     for (j=0; j < 8; j++)
2969     {
2970       size_t index = (size_t) indices5[j + i*8];
2971       value |= ( index << 3*j );
2972     }
2973 
2974     for (j=0; j < 3; j++)
2975     {
2976       size_t byte = (value >> 8*j) & 0xff;
2977       (void) WriteBlobByte(image,(unsigned char) byte);
2978     }
2979   }
2980 }
2981 
WriteIndices(Image * image,const DDSVector3 start,const DDSVector3 end,unsigned char * indices)2982 static void WriteIndices(Image *image, const DDSVector3 start,
2983   const DDSVector3 end, unsigned char *indices)
2984 {
2985   ssize_t
2986     i;
2987 
2988   size_t
2989     a,
2990     b;
2991 
2992   unsigned char
2993     remapped[16];
2994 
2995   const unsigned char
2996     *ind;
2997 
2998   a = ColorTo565(start);
2999   b = ColorTo565(end);
3000 
3001   for (i=0; i<16; i++)
3002   {
3003     if( a < b )
3004       remapped[i] = (indices[i] ^ 0x1) & 0x3;
3005     else if( a == b )
3006       remapped[i] = 0;
3007     else
3008       remapped[i] = indices[i];
3009   }
3010 
3011   if( a < b )
3012     Swap(a,b);
3013 
3014   (void) WriteBlobByte(image,(unsigned char) (a & 0xff));
3015   (void) WriteBlobByte(image,(unsigned char) (a >> 8));
3016   (void) WriteBlobByte(image,(unsigned char) (b & 0xff));
3017   (void) WriteBlobByte(image,(unsigned char) (b >> 8));
3018 
3019   for (i=0; i<4; i++)
3020   {
3021      ind = remapped + 4*i;
3022      (void) WriteBlobByte(image,ind[0] | (ind[1] << 2) | (ind[2] << 4) |
3023        (ind[3] << 6));
3024   }
3025 }
3026 
WriteCompressed(Image * image,const size_t count,DDSVector4 * points,const ssize_t * map,const MagickBooleanType clusterFit)3027 static void WriteCompressed(Image *image, const size_t count,
3028   DDSVector4 *points, const ssize_t *map, const MagickBooleanType clusterFit)
3029 {
3030   float
3031     covariance[16];
3032 
3033   DDSVector3
3034     end,
3035     principle,
3036     start;
3037 
3038   DDSVector4
3039     metric;
3040 
3041   unsigned char
3042     indices[16];
3043 
3044   VectorInit(metric,1.0f);
3045   VectorInit3(start,0.0f);
3046   VectorInit3(end,0.0f);
3047 
3048   ComputeWeightedCovariance(count,points,covariance);
3049   ComputePrincipleComponent(covariance,&principle);
3050 
3051   if ((clusterFit == MagickFalse) || (count == 0))
3052     CompressRangeFit(count,points,map,principle,metric,&start,&end,indices);
3053   else
3054     CompressClusterFit(count,points,map,principle,metric,&start,&end,indices);
3055 
3056   WriteIndices(image,start,end,indices);
3057 }
3058 
WriteSingleColorFit(Image * image,const DDSVector4 * points,const ssize_t * map)3059 static void WriteSingleColorFit(Image *image, const DDSVector4 *points,
3060   const ssize_t *map)
3061 {
3062   DDSVector3
3063     start,
3064     end;
3065 
3066   ssize_t
3067     i;
3068 
3069   unsigned char
3070     color[3],
3071     index,
3072     indexes[16],
3073     indices[16];
3074 
3075   color[0] = (unsigned char) ClampToLimit(255.0f*points->x,255);
3076   color[1] = (unsigned char) ClampToLimit(255.0f*points->y,255);
3077   color[2] = (unsigned char) ClampToLimit(255.0f*points->z,255);
3078 
3079   index=0;
3080   ComputeEndPoints(DDS_LOOKUP,color,&start,&end,&index);
3081 
3082   for (i=0; i< 16; i++)
3083     indexes[i]=index;
3084   RemapIndices(map,indexes,indices);
3085   WriteIndices(image,start,end,indices);
3086 }
3087 
WriteFourCC(Image * image,const size_t compression,const MagickBooleanType clusterFit,const MagickBooleanType weightByAlpha,ExceptionInfo * exception)3088 static void WriteFourCC(Image *image, const size_t compression,
3089   const MagickBooleanType clusterFit, const MagickBooleanType weightByAlpha,
3090   ExceptionInfo *exception)
3091 {
3092   ssize_t
3093     x;
3094 
3095   ssize_t
3096     i,
3097     y,
3098     bx,
3099     by;
3100 
3101   const Quantum
3102     *p;
3103 
3104   for (y=0; y < (ssize_t) image->rows; y+=4)
3105   {
3106     for (x=0; x < (ssize_t) image->columns; x+=4)
3107     {
3108       MagickBooleanType
3109         match;
3110 
3111       DDSVector4
3112         point,
3113         points[16];
3114 
3115       size_t
3116         count = 0,
3117         max5 = 0,
3118         max7 = 0,
3119         min5 = 255,
3120         min7 = 255,
3121         columns = 4,
3122         rows = 4;
3123 
3124       ssize_t
3125         alphas[16],
3126         map[16];
3127 
3128       unsigned char
3129         alpha;
3130 
3131       if (x + columns >= image->columns)
3132         columns = image->columns - x;
3133 
3134       if (y + rows >= image->rows)
3135         rows = image->rows - y;
3136 
3137       p=GetVirtualPixels(image,x,y,columns,rows,exception);
3138       if (p == (const Quantum *) NULL)
3139         break;
3140 
3141       for (i=0; i<16; i++)
3142       {
3143         map[i] = -1;
3144         alphas[i] = -1;
3145       }
3146 
3147       for (by=0; by < (ssize_t) rows; by++)
3148       {
3149         for (bx=0; bx < (ssize_t) columns; bx++)
3150         {
3151           if (compression == FOURCC_DXT5)
3152             alpha = ScaleQuantumToChar(GetPixelAlpha(image,p));
3153           else
3154             alpha = 255;
3155 
3156           if (compression == FOURCC_DXT5)
3157             {
3158               if (alpha < min7)
3159                 min7 = alpha;
3160               if (alpha > max7)
3161                 max7 = alpha;
3162               if (alpha != 0 && alpha < min5)
3163                 min5 = alpha;
3164               if (alpha != 255 && alpha > max5)
3165                 max5 = alpha;
3166             }
3167 
3168           alphas[4*by + bx] = (size_t)alpha;
3169 
3170           point.x = (float)ScaleQuantumToChar(GetPixelRed(image,p)) / 255.0f;
3171           point.y = (float)ScaleQuantumToChar(GetPixelGreen(image,p)) / 255.0f;
3172           point.z = (float)ScaleQuantumToChar(GetPixelBlue(image,p)) / 255.0f;
3173           point.w = weightByAlpha ? (float)(alpha + 1) / 256.0f : 1.0f;
3174           p+=GetPixelChannels(image);
3175 
3176           match = MagickFalse;
3177           for (i=0; i < (ssize_t) count; i++)
3178           {
3179             if ((points[i].x == point.x) &&
3180                 (points[i].y == point.y) &&
3181                 (points[i].z == point.z) &&
3182                 (alpha       >= 128 || compression == FOURCC_DXT5))
3183               {
3184                 points[i].w += point.w;
3185                 map[4*by + bx] = i;
3186                 match = MagickTrue;
3187                 break;
3188               }
3189           }
3190 
3191           if (match != MagickFalse)
3192             continue;
3193 
3194           points[count].x = point.x;
3195           points[count].y = point.y;
3196           points[count].z = point.z;
3197           points[count].w = point.w;
3198           map[4*by + bx] = count;
3199           count++;
3200         }
3201       }
3202 
3203       for (i=0; i < (ssize_t) count; i++)
3204         points[i].w = sqrt(points[i].w);
3205 
3206       if (compression == FOURCC_DXT5)
3207         WriteAlphas(image,alphas,min5,max5,min7,max7);
3208 
3209       if (count == 1)
3210         WriteSingleColorFit(image,points,map);
3211       else
3212         WriteCompressed(image,count,points,map,clusterFit);
3213     }
3214   }
3215 }
3216 
WriteUncompressed(Image * image,ExceptionInfo * exception)3217 static void WriteUncompressed(Image *image, ExceptionInfo *exception)
3218 {
3219   const Quantum
3220     *p;
3221 
3222   ssize_t
3223     x;
3224 
3225   ssize_t
3226     y;
3227 
3228   for (y=0; y < (ssize_t) image->rows; y++)
3229   {
3230     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3231     if (p == (const Quantum *) NULL)
3232       break;
3233 
3234     for (x=0; x < (ssize_t) image->columns; x++)
3235     {
3236       (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelBlue(image,p)));
3237       (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelGreen(image,p)));
3238       (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelRed(image,p)));
3239       if (image->alpha_trait != UndefinedPixelTrait)
3240         (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelAlpha(image,p)));
3241       p+=GetPixelChannels(image);
3242     }
3243   }
3244 }
3245 
WriteImageData(Image * image,const size_t pixelFormat,const size_t compression,const MagickBooleanType clusterFit,const MagickBooleanType weightByAlpha,ExceptionInfo * exception)3246 static void WriteImageData(Image *image, const size_t pixelFormat,
3247   const size_t compression,const MagickBooleanType clusterFit,
3248   const MagickBooleanType weightByAlpha, ExceptionInfo *exception)
3249 {
3250   if (pixelFormat == DDPF_FOURCC)
3251     WriteFourCC(image,compression,clusterFit,weightByAlpha,exception);
3252   else
3253     WriteUncompressed(image,exception);
3254 }
3255 
WriteMipmaps(Image * image,const ImageInfo * image_info,const size_t pixelFormat,const size_t compression,const size_t mipmaps,const MagickBooleanType fromlist,const MagickBooleanType clusterFit,const MagickBooleanType weightByAlpha,ExceptionInfo * exception)3256 static MagickBooleanType WriteMipmaps(Image *image,const ImageInfo *image_info,
3257   const size_t pixelFormat,const size_t compression,const size_t mipmaps,
3258   const MagickBooleanType fromlist,const MagickBooleanType clusterFit,
3259   const MagickBooleanType weightByAlpha,ExceptionInfo *exception)
3260 {
3261   const char
3262     *option;
3263 
3264   Image
3265     *mipmap_image,
3266     *resize_image;
3267 
3268   MagickBooleanType
3269     fast_mipmaps,
3270     status;
3271 
3272   ssize_t
3273     i;
3274 
3275   size_t
3276     columns,
3277     rows;
3278 
3279   columns=DIV2(image->columns);
3280   rows=DIV2(image->rows);
3281 
3282   option=GetImageOption(image_info,"dds:fast-mipmaps");
3283   fast_mipmaps=IsStringTrue(option);
3284   mipmap_image=image;
3285   resize_image=image;
3286   status=MagickTrue;
3287   for (i=0; i < (ssize_t) mipmaps; i++)
3288   {
3289     if (fromlist == MagickFalse)
3290       {
3291         mipmap_image=ResizeImage(resize_image,columns,rows,TriangleFilter,
3292           exception);
3293 
3294         if (mipmap_image == (Image *) NULL)
3295           {
3296             status=MagickFalse;
3297             break;
3298           }
3299       }
3300     else
3301       {
3302         mipmap_image=mipmap_image->next;
3303         if ((mipmap_image->columns != columns) || (mipmap_image->rows != rows))
3304           ThrowBinaryException(CoderError,"ImageColumnOrRowSizeIsNotSupported",
3305             image->filename);
3306       }
3307 
3308     DestroyBlob(mipmap_image);
3309     mipmap_image->blob=ReferenceBlob(image->blob);
3310 
3311     WriteImageData(mipmap_image,pixelFormat,compression,weightByAlpha,
3312       clusterFit,exception);
3313 
3314     if (fromlist == MagickFalse)
3315       {
3316         if (fast_mipmaps == MagickFalse)
3317           mipmap_image=DestroyImage(mipmap_image);
3318         else
3319           {
3320             if (resize_image != image)
3321               resize_image=DestroyImage(resize_image);
3322             resize_image=mipmap_image;
3323           }
3324       }
3325 
3326     columns=DIV2(columns);
3327     rows=DIV2(rows);
3328   }
3329 
3330   if (resize_image != image)
3331     resize_image=DestroyImage(resize_image);
3332 
3333   return(status);
3334 }
3335 
WriteDDSInfo(Image * image,const size_t pixelFormat,const size_t compression,const size_t mipmaps)3336 static void WriteDDSInfo(Image *image, const size_t pixelFormat,
3337   const size_t compression, const size_t mipmaps)
3338 {
3339   char
3340     software[MagickPathExtent];
3341 
3342   ssize_t
3343     i;
3344 
3345   unsigned int
3346     format,
3347     caps,
3348     flags;
3349 
3350   flags=(unsigned int) (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT |
3351     DDSD_PIXELFORMAT);
3352   caps=(unsigned int) DDSCAPS_TEXTURE;
3353   format=(unsigned int) pixelFormat;
3354 
3355   if (format == DDPF_FOURCC)
3356       flags=flags | DDSD_LINEARSIZE;
3357   else
3358       flags=flags | DDSD_PITCH;
3359 
3360   if (mipmaps > 0)
3361     {
3362       flags=flags | (unsigned int) DDSD_MIPMAPCOUNT;
3363       caps=caps | (unsigned int) (DDSCAPS_MIPMAP | DDSCAPS_COMPLEX);
3364     }
3365 
3366   if (format != DDPF_FOURCC && image->alpha_trait != UndefinedPixelTrait)
3367     format=format | DDPF_ALPHAPIXELS;
3368 
3369   (void) WriteBlob(image,4,(unsigned char *) "DDS ");
3370   (void) WriteBlobLSBLong(image,124);
3371   (void) WriteBlobLSBLong(image,flags);
3372   (void) WriteBlobLSBLong(image,(unsigned int) image->rows);
3373   (void) WriteBlobLSBLong(image,(unsigned int) image->columns);
3374 
3375   if (pixelFormat == DDPF_FOURCC)
3376     {
3377       /* Compressed DDS requires linear compressed size of first image */
3378       if (compression == FOURCC_DXT1)
3379         (void) WriteBlobLSBLong(image,(unsigned int) (MagickMax(1,
3380           (image->columns+3)/4)*MagickMax(1,(image->rows+3)/4)*8));
3381       else /* DXT5 */
3382         (void) WriteBlobLSBLong(image,(unsigned int) (MagickMax(1,
3383           (image->columns+3)/4)*MagickMax(1,(image->rows+3)/4)*16));
3384     }
3385   else
3386     {
3387       /* Uncompressed DDS requires byte pitch of first image */
3388       if (image->alpha_trait != UndefinedPixelTrait)
3389         (void) WriteBlobLSBLong(image,(unsigned int) (image->columns * 4));
3390       else
3391         (void) WriteBlobLSBLong(image,(unsigned int) (image->columns * 3));
3392     }
3393 
3394   (void) WriteBlobLSBLong(image,0x00);
3395   (void) WriteBlobLSBLong(image,(unsigned int) mipmaps+1);
3396   (void) memset(software,0,sizeof(software));
3397   (void) CopyMagickString(software,"IMAGEMAGICK",MagickPathExtent);
3398   (void) WriteBlob(image,44,(unsigned char *) software);
3399 
3400   (void) WriteBlobLSBLong(image,32);
3401   (void) WriteBlobLSBLong(image,format);
3402 
3403   if (pixelFormat == DDPF_FOURCC)
3404     {
3405       (void) WriteBlobLSBLong(image,(unsigned int) compression);
3406       for(i=0;i < 5;i++)  /* bitcount / masks */
3407         (void) WriteBlobLSBLong(image,0x00);
3408     }
3409   else
3410     {
3411       (void) WriteBlobLSBLong(image,0x00);
3412       if (image->alpha_trait != UndefinedPixelTrait)
3413         {
3414           (void) WriteBlobLSBLong(image,32);
3415           (void) WriteBlobLSBLong(image,0xff0000);
3416           (void) WriteBlobLSBLong(image,0xff00);
3417           (void) WriteBlobLSBLong(image,0xff);
3418           (void) WriteBlobLSBLong(image,0xff000000);
3419         }
3420       else
3421         {
3422           (void) WriteBlobLSBLong(image,24);
3423           (void) WriteBlobLSBLong(image,0xff0000);
3424           (void) WriteBlobLSBLong(image,0xff00);
3425           (void) WriteBlobLSBLong(image,0xff);
3426           (void) WriteBlobLSBLong(image,0x00);
3427         }
3428     }
3429 
3430   (void) WriteBlobLSBLong(image,caps);
3431   for(i=0;i < 4;i++)   /* ddscaps2 + reserved region */
3432     (void) WriteBlobLSBLong(image,0x00);
3433 }
3434 
WriteDDSImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)3435 static MagickBooleanType WriteDDSImage(const ImageInfo *image_info,
3436   Image *image, ExceptionInfo *exception)
3437 {
3438   const char
3439     *option;
3440 
3441   size_t
3442     compression,
3443     columns,
3444     maxMipmaps,
3445     mipmaps,
3446     pixelFormat,
3447     rows;
3448 
3449   MagickBooleanType
3450     clusterFit,
3451     fromlist,
3452     status,
3453     weightByAlpha;
3454 
3455   assert(image_info != (const ImageInfo *) NULL);
3456   assert(image_info->signature == MagickCoreSignature);
3457   assert(image != (Image *) NULL);
3458   assert(image->signature == MagickCoreSignature);
3459   if (image->debug != MagickFalse)
3460     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3461   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3462   if (status == MagickFalse)
3463     return(status);
3464   (void) TransformImageColorspace(image,sRGBColorspace,exception);
3465   pixelFormat=DDPF_FOURCC;
3466   compression=FOURCC_DXT5;
3467   if (image->alpha_trait == UndefinedPixelTrait)
3468     compression=FOURCC_DXT1;
3469   if (LocaleCompare(image_info->magick,"dxt1") == 0)
3470     compression=FOURCC_DXT1;
3471   if (image_info->compression == DXT1Compression)
3472     compression=FOURCC_DXT1;
3473   else if (image_info->compression == NoCompression)
3474     pixelFormat=DDPF_RGB;
3475   option=GetImageOption(image_info,"dds:compression");
3476   if (option != (char *) NULL)
3477     {
3478        if (LocaleCompare(option,"dxt1") == 0)
3479          compression=FOURCC_DXT1;
3480        if (LocaleCompare(option,"none") == 0)
3481          pixelFormat=DDPF_RGB;
3482     }
3483   clusterFit=MagickFalse;
3484   weightByAlpha=MagickFalse;
3485   if (pixelFormat == DDPF_FOURCC)
3486     {
3487       option=GetImageOption(image_info,"dds:cluster-fit");
3488       if (IsStringTrue(option) != MagickFalse)
3489         {
3490           clusterFit=MagickTrue;
3491           if (compression != FOURCC_DXT1)
3492             {
3493               option=GetImageOption(image_info,"dds:weight-by-alpha");
3494               if (IsStringTrue(option) != MagickFalse)
3495                 weightByAlpha=MagickTrue;
3496             }
3497         }
3498     }
3499   mipmaps=0;
3500   fromlist=MagickFalse;
3501   option=GetImageOption(image_info,"dds:mipmaps");
3502   if (option != (char *) NULL)
3503     {
3504       if (LocaleNCompare(option,"fromlist",8) == 0)
3505         {
3506           Image
3507             *next;
3508 
3509           fromlist=MagickTrue;
3510           next=image->next;
3511           while(next != (Image *) NULL)
3512           {
3513             mipmaps++;
3514             next=next->next;
3515           }
3516         }
3517     }
3518   if ((mipmaps == 0) &&
3519       ((image->columns & (image->columns - 1)) == 0) &&
3520       ((image->rows & (image->rows - 1)) == 0))
3521     {
3522       maxMipmaps=SIZE_MAX;
3523       if (option != (char *) NULL)
3524         maxMipmaps=StringToUnsignedLong(option);
3525 
3526       if (maxMipmaps != 0)
3527         {
3528           columns=image->columns;
3529           rows=image->rows;
3530           while ((columns != 1 || rows != 1) && mipmaps != maxMipmaps)
3531           {
3532             columns=DIV2(columns);
3533             rows=DIV2(rows);
3534             mipmaps++;
3535           }
3536         }
3537     }
3538   option=GetImageOption(image_info,"dds:raw");
3539   if (IsStringTrue(option) == MagickFalse)
3540     WriteDDSInfo(image,pixelFormat,compression,mipmaps);
3541   else
3542     mipmaps=0;
3543   WriteImageData(image,pixelFormat,compression,clusterFit,weightByAlpha,
3544     exception);
3545   if ((mipmaps > 0) && (WriteMipmaps(image,image_info,pixelFormat,compression,
3546        mipmaps,fromlist,clusterFit,weightByAlpha,exception) == MagickFalse))
3547     return(MagickFalse);
3548   (void) CloseBlob(image);
3549   return(MagickTrue);
3550 }
3551