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