1 /*
2 ===========================================================================
3 png decoder
4 Copyright (C) 2007,2008 Joerg Dietrich
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 ===========================================================================
20 */
21
22 #include "tr_local.h"
23
24 #include "../qcommon/puff.h"
25
26 // we could limit the png size to a lower value here
27 #ifndef INT_MAX
28 #define INT_MAX 0x1fffffff
29 #endif
30
31 /*
32 =================
33 PNG LOADING
34 =================
35 */
36
37 /*
38 * Quake 3 image format : RGBA
39 */
40
41 #define Q3IMAGE_BYTESPERPIXEL (4)
42
43 /*
44 * PNG specifications
45 */
46
47 /*
48 * The first 8 Bytes of every PNG-File are a fixed signature
49 * to identify the file as a PNG.
50 */
51
52 #define PNG_Signature "\x89\x50\x4E\x47\xD\xA\x1A\xA"
53 #define PNG_Signature_Size (8)
54
55 /*
56 * After the signature diverse chunks follow.
57 * A chunk consists of a header and if Length
58 * is bigger than 0 a body and a CRC of the body follow.
59 */
60
61 struct PNG_ChunkHeader
62 {
63 uint32_t Length;
64 uint32_t Type;
65 };
66
67 #define PNG_ChunkHeader_Size (8)
68
69 typedef uint32_t PNG_ChunkCRC;
70
71 #define PNG_ChunkCRC_Size (4)
72
73 /*
74 * We use the following ChunkTypes.
75 * All others are ignored.
76 */
77
78 #define MAKE_CHUNKTYPE(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | ((d)))
79
80 #define PNG_ChunkType_IHDR MAKE_CHUNKTYPE('I', 'H', 'D', 'R')
81 #define PNG_ChunkType_PLTE MAKE_CHUNKTYPE('P', 'L', 'T', 'E')
82 #define PNG_ChunkType_IDAT MAKE_CHUNKTYPE('I', 'D', 'A', 'T')
83 #define PNG_ChunkType_IEND MAKE_CHUNKTYPE('I', 'E', 'N', 'D')
84 #define PNG_ChunkType_tRNS MAKE_CHUNKTYPE('t', 'R', 'N', 'S')
85
86 /*
87 * Per specification the first chunk after the signature SHALL be IHDR.
88 */
89
90 struct PNG_Chunk_IHDR
91 {
92 uint32_t Width;
93 uint32_t Height;
94 uint8_t BitDepth;
95 uint8_t ColourType;
96 uint8_t CompressionMethod;
97 uint8_t FilterMethod;
98 uint8_t InterlaceMethod;
99 };
100
101 #define PNG_Chunk_IHDR_Size (13)
102
103 /*
104 * ColourTypes
105 */
106
107 #define PNG_ColourType_Grey (0)
108 #define PNG_ColourType_True (2)
109 #define PNG_ColourType_Indexed (3)
110 #define PNG_ColourType_GreyAlpha (4)
111 #define PNG_ColourType_TrueAlpha (6)
112
113 /*
114 * number of colour components
115 *
116 * Grey : 1 grey
117 * True : 1 R, 1 G, 1 B
118 * Indexed : 1 index
119 * GreyAlpha : 1 grey, 1 alpha
120 * TrueAlpha : 1 R, 1 G, 1 B, 1 alpha
121 */
122
123 #define PNG_NumColourComponents_Grey (1)
124 #define PNG_NumColourComponents_True (3)
125 #define PNG_NumColourComponents_Indexed (1)
126 #define PNG_NumColourComponents_GreyAlpha (2)
127 #define PNG_NumColourComponents_TrueAlpha (4)
128
129 /*
130 * For the different ColourTypes
131 * different BitDepths are specified.
132 */
133
134 #define PNG_BitDepth_1 ( 1)
135 #define PNG_BitDepth_2 ( 2)
136 #define PNG_BitDepth_4 ( 4)
137 #define PNG_BitDepth_8 ( 8)
138 #define PNG_BitDepth_16 (16)
139
140 /*
141 * Only one valid CompressionMethod is standardized.
142 */
143
144 #define PNG_CompressionMethod_0 (0)
145
146 /*
147 * Only one valid FilterMethod is currently standardized.
148 */
149
150 #define PNG_FilterMethod_0 (0)
151
152 /*
153 * This FilterMethod defines 5 FilterTypes
154 */
155
156 #define PNG_FilterType_None (0)
157 #define PNG_FilterType_Sub (1)
158 #define PNG_FilterType_Up (2)
159 #define PNG_FilterType_Average (3)
160 #define PNG_FilterType_Paeth (4)
161
162 /*
163 * Two InterlaceMethods are standardized :
164 * 0 - NonInterlaced
165 * 1 - Interlaced
166 */
167
168 #define PNG_InterlaceMethod_NonInterlaced (0)
169 #define PNG_InterlaceMethod_Interlaced (1)
170
171 /*
172 * The Adam7 interlace method uses 7 passes.
173 */
174
175 #define PNG_Adam7_NumPasses (7)
176
177 /*
178 * The compressed data starts with a header ...
179 */
180
181 struct PNG_ZlibHeader
182 {
183 uint8_t CompressionMethod;
184 uint8_t Flags;
185 };
186
187 #define PNG_ZlibHeader_Size (2)
188
189 /*
190 * ... and is followed by a check value
191 */
192
193 #define PNG_ZlibCheckValue_Size (4)
194
195 /*
196 * Some support functions for buffered files follow.
197 */
198
199 /*
200 * buffered file representation
201 */
202
203 struct BufferedFile
204 {
205 byte *Buffer;
206 int Length;
207 byte *Ptr;
208 int BytesLeft;
209 };
210
211 /*
212 * Read a file into a buffer.
213 */
214
ReadBufferedFile(const char * name)215 static struct BufferedFile *ReadBufferedFile(const char *name)
216 {
217 struct BufferedFile *BF;
218
219 /*
220 * input verification
221 */
222
223 if(!name)
224 {
225 return(NULL);
226 }
227
228 /*
229 * Allocate control struct.
230 */
231
232 BF = ri.Malloc(sizeof(struct BufferedFile));
233 if(!BF)
234 {
235 return(NULL);
236 }
237
238 /*
239 * Initialize the structs components.
240 */
241
242 BF->Length = 0;
243 BF->Buffer = NULL;
244 BF->Ptr = NULL;
245 BF->BytesLeft = 0;
246
247 /*
248 * Read the file.
249 */
250
251 BF->Length = ri.FS_ReadFile((char *) name, (void **) &BF->Buffer);
252
253 /*
254 * Did we get it? Is it big enough?
255 */
256
257 if(!(BF->Buffer && (BF->Length > 0)))
258 {
259 ri.Free(BF);
260
261 return(NULL);
262 }
263
264 /*
265 * Set the pointers and counters.
266 */
267
268 BF->Ptr = BF->Buffer;
269 BF->BytesLeft = BF->Length;
270
271 return(BF);
272 }
273
274 /*
275 * Close a buffered file.
276 */
277
CloseBufferedFile(struct BufferedFile * BF)278 static void CloseBufferedFile(struct BufferedFile *BF)
279 {
280 if(BF)
281 {
282 if(BF->Buffer)
283 {
284 ri.FS_FreeFile(BF->Buffer);
285 }
286
287 ri.Free(BF);
288 }
289 }
290
291 /*
292 * Get a pointer to the requested bytes.
293 */
294
BufferedFileRead(struct BufferedFile * BF,unsigned Length)295 static void *BufferedFileRead(struct BufferedFile *BF, unsigned Length)
296 {
297 void *RetVal;
298
299 /*
300 * input verification
301 */
302
303 if(!(BF && Length))
304 {
305 return(NULL);
306 }
307
308 /*
309 * not enough bytes left
310 */
311
312 if(Length > BF->BytesLeft)
313 {
314 return(NULL);
315 }
316
317 /*
318 * the pointer to the requested data
319 */
320
321 RetVal = BF->Ptr;
322
323 /*
324 * Raise the pointer and counter.
325 */
326
327 BF->Ptr += Length;
328 BF->BytesLeft -= Length;
329
330 return(RetVal);
331 }
332
333 /*
334 * Rewind the buffer.
335 */
336
BufferedFileRewind(struct BufferedFile * BF,unsigned Offset)337 static qboolean BufferedFileRewind(struct BufferedFile *BF, unsigned Offset)
338 {
339 unsigned BytesRead;
340
341 /*
342 * input verification
343 */
344
345 if(!BF)
346 {
347 return(qfalse);
348 }
349
350 /*
351 * special trick to rewind to the beginning of the buffer
352 */
353
354 if(Offset == (unsigned)-1)
355 {
356 BF->Ptr = BF->Buffer;
357 BF->BytesLeft = BF->Length;
358
359 return(qtrue);
360 }
361
362 /*
363 * How many bytes do we have already read?
364 */
365
366 BytesRead = BF->Ptr - BF->Buffer;
367
368 /*
369 * We can only rewind to the beginning of the BufferedFile.
370 */
371
372 if(Offset > BytesRead)
373 {
374 return(qfalse);
375 }
376
377 /*
378 * lower the pointer and counter.
379 */
380
381 BF->Ptr -= Offset;
382 BF->BytesLeft += Offset;
383
384 return(qtrue);
385 }
386
387 /*
388 * Skip some bytes.
389 */
390
BufferedFileSkip(struct BufferedFile * BF,unsigned Offset)391 static qboolean BufferedFileSkip(struct BufferedFile *BF, unsigned Offset)
392 {
393 /*
394 * input verification
395 */
396
397 if(!BF)
398 {
399 return(qfalse);
400 }
401
402 /*
403 * We can only skip to the end of the BufferedFile.
404 */
405
406 if(Offset > BF->BytesLeft)
407 {
408 return(qfalse);
409 }
410
411 /*
412 * lower the pointer and counter.
413 */
414
415 BF->Ptr += Offset;
416 BF->BytesLeft -= Offset;
417
418 return(qtrue);
419 }
420
421 /*
422 * Find a chunk
423 */
424
FindChunk(struct BufferedFile * BF,uint32_t ChunkType)425 static qboolean FindChunk(struct BufferedFile *BF, uint32_t ChunkType)
426 {
427 struct PNG_ChunkHeader *CH;
428
429 uint32_t Length;
430 uint32_t Type;
431
432 /*
433 * input verification
434 */
435
436 if(!BF)
437 {
438 return(qfalse);
439 }
440
441 /*
442 * cycle trough the chunks
443 */
444
445 while(qtrue)
446 {
447 /*
448 * Read the chunk-header.
449 */
450
451 CH = BufferedFileRead(BF, PNG_ChunkHeader_Size);
452 if(!CH)
453 {
454 return(qfalse);
455 }
456
457 /*
458 * Do not swap the original types
459 * they might be needed later.
460 */
461
462 Length = BigLong(CH->Length);
463 Type = BigLong(CH->Type);
464
465 /*
466 * We found it!
467 */
468
469 if(Type == ChunkType)
470 {
471 /*
472 * Rewind to the start of the chunk.
473 */
474
475 BufferedFileRewind(BF, PNG_ChunkHeader_Size);
476
477 break;
478 }
479 else
480 {
481 /*
482 * Skip the rest of the chunk.
483 */
484
485 if(Length)
486 {
487 if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size))
488 {
489 return(qfalse);
490 }
491 }
492 }
493 }
494
495 return(qtrue);
496 }
497
498 /*
499 * Decompress all IDATs
500 */
501
DecompressIDATs(struct BufferedFile * BF,uint8_t ** Buffer)502 static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer)
503 {
504 uint8_t *DecompressedData;
505 uint32_t DecompressedDataLength;
506
507 uint8_t *CompressedData;
508 uint8_t *CompressedDataPtr;
509 uint32_t CompressedDataLength;
510
511 struct PNG_ChunkHeader *CH;
512
513 uint32_t Length;
514 uint32_t Type;
515
516 int BytesToRewind;
517
518 int32_t puffResult;
519 uint8_t *puffDest;
520 uint32_t puffDestLen;
521 uint8_t *puffSrc;
522 uint32_t puffSrcLen;
523
524 /*
525 * input verification
526 */
527
528 if(!(BF && Buffer))
529 {
530 return(-1);
531 }
532
533 /*
534 * some zeroing
535 */
536
537 DecompressedData = NULL;
538 DecompressedDataLength = 0;
539 *Buffer = DecompressedData;
540
541 CompressedData = NULL;
542 CompressedDataLength = 0;
543
544 BytesToRewind = 0;
545
546 /*
547 * Find the first IDAT chunk.
548 */
549
550 if(!FindChunk(BF, PNG_ChunkType_IDAT))
551 {
552 return(-1);
553 }
554
555 /*
556 * Count the size of the uncompressed data
557 */
558
559 while(qtrue)
560 {
561 /*
562 * Read chunk header
563 */
564
565 CH = BufferedFileRead(BF, PNG_ChunkHeader_Size);
566 if(!CH)
567 {
568 /*
569 * Rewind to the start of this adventure
570 * and return unsuccessfull
571 */
572
573 BufferedFileRewind(BF, BytesToRewind);
574
575 return(-1);
576 }
577
578 /*
579 * Length and Type of chunk
580 */
581
582 Length = BigLong(CH->Length);
583 Type = BigLong(CH->Type);
584
585 /*
586 * We have reached the end of the IDAT chunks
587 */
588
589 if(!(Type == PNG_ChunkType_IDAT))
590 {
591 BufferedFileRewind(BF, PNG_ChunkHeader_Size);
592
593 break;
594 }
595
596 /*
597 * Add chunk header to count.
598 */
599
600 BytesToRewind += PNG_ChunkHeader_Size;
601
602 /*
603 * Skip to next chunk
604 */
605
606 if(Length)
607 {
608 if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size))
609 {
610 BufferedFileRewind(BF, BytesToRewind);
611
612 return(-1);
613 }
614
615 BytesToRewind += Length + PNG_ChunkCRC_Size;
616 CompressedDataLength += Length;
617 }
618 }
619
620 BufferedFileRewind(BF, BytesToRewind);
621
622 CompressedData = ri.Malloc(CompressedDataLength);
623 if(!CompressedData)
624 {
625 return(-1);
626 }
627
628 CompressedDataPtr = CompressedData;
629
630 /*
631 * Collect the compressed Data
632 */
633
634 while(qtrue)
635 {
636 /*
637 * Read chunk header
638 */
639
640 CH = BufferedFileRead(BF, PNG_ChunkHeader_Size);
641 if(!CH)
642 {
643 ri.Free(CompressedData);
644
645 return(-1);
646 }
647
648 /*
649 * Length and Type of chunk
650 */
651
652 Length = BigLong(CH->Length);
653 Type = BigLong(CH->Type);
654
655 /*
656 * We have reached the end of the IDAT chunks
657 */
658
659 if(!(Type == PNG_ChunkType_IDAT))
660 {
661 BufferedFileRewind(BF, PNG_ChunkHeader_Size);
662
663 break;
664 }
665
666 /*
667 * Copy the Data
668 */
669
670 if(Length)
671 {
672 uint8_t *OrigCompressedData;
673
674 OrigCompressedData = BufferedFileRead(BF, Length);
675 if(!OrigCompressedData)
676 {
677 ri.Free(CompressedData);
678
679 return(-1);
680 }
681
682 if(!BufferedFileSkip(BF, PNG_ChunkCRC_Size))
683 {
684 ri.Free(CompressedData);
685
686 return(-1);
687 }
688
689 memcpy(CompressedDataPtr, OrigCompressedData, Length);
690 CompressedDataPtr += Length;
691 }
692 }
693
694 /*
695 * Let puff() calculate the decompressed data length.
696 */
697
698 puffDest = NULL;
699 puffDestLen = 0;
700
701 /*
702 * The zlib header and checkvalue don't belong to the compressed data.
703 */
704
705 puffSrc = CompressedData + PNG_ZlibHeader_Size;
706 puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size;
707
708 /*
709 * first puff() to calculate the size of the uncompressed data
710 */
711
712 puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen);
713 if(!((puffResult == 0) && (puffDestLen > 0)))
714 {
715 ri.Free(CompressedData);
716
717 return(-1);
718 }
719
720 /*
721 * Allocate the buffer for the uncompressed data.
722 */
723
724 DecompressedData = ri.Malloc(puffDestLen);
725 if(!DecompressedData)
726 {
727 ri.Free(CompressedData);
728
729 return(-1);
730 }
731
732 /*
733 * Set the input again in case something was changed by the last puff() .
734 */
735
736 puffDest = DecompressedData;
737 puffSrc = CompressedData + PNG_ZlibHeader_Size;
738 puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size;
739
740 /*
741 * decompression puff()
742 */
743
744 puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen);
745
746 /*
747 * The compressed data is not needed anymore.
748 */
749
750 ri.Free(CompressedData);
751
752 /*
753 * Check if the last puff() was successfull.
754 */
755
756 if(!((puffResult == 0) && (puffDestLen > 0)))
757 {
758 ri.Free(DecompressedData);
759
760 return(-1);
761 }
762
763 /*
764 * Set the output of this function.
765 */
766
767 DecompressedDataLength = puffDestLen;
768 *Buffer = DecompressedData;
769
770 return(DecompressedDataLength);
771 }
772
773 /*
774 * the Paeth predictor
775 */
776
PredictPaeth(uint8_t a,uint8_t b,uint8_t c)777 static uint8_t PredictPaeth(uint8_t a, uint8_t b, uint8_t c)
778 {
779 /*
780 * a == Left
781 * b == Up
782 * c == UpLeft
783 */
784
785 uint8_t Pr;
786 int p;
787 int pa, pb, pc;
788
789 Pr = 0;
790
791 p = ((int) a) + ((int) b) - ((int) c);
792 pa = abs(p - ((int) a));
793 pb = abs(p - ((int) b));
794 pc = abs(p - ((int) c));
795
796 if((pa <= pb) && (pa <= pc))
797 {
798 Pr = a;
799 }
800 else if(pb <= pc)
801 {
802 Pr = b;
803 }
804 else
805 {
806 Pr = c;
807 }
808
809 return(Pr);
810
811 }
812
813 /*
814 * Reverse the filters.
815 */
816
UnfilterImage(uint8_t * DecompressedData,uint32_t ImageHeight,uint32_t BytesPerScanline,uint32_t BytesPerPixel)817 static qboolean UnfilterImage(uint8_t *DecompressedData,
818 uint32_t ImageHeight,
819 uint32_t BytesPerScanline,
820 uint32_t BytesPerPixel)
821 {
822 uint8_t *DecompPtr;
823 uint8_t FilterType;
824 uint8_t *PixelLeft, *PixelUp, *PixelUpLeft;
825 uint32_t w, h, p;
826
827 /*
828 * some zeros for the filters
829 */
830
831 uint8_t Zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
832
833 /*
834 * input verification
835 */
836
837 if(!(DecompressedData && BytesPerPixel))
838 {
839 return(qfalse);
840 }
841
842 /*
843 * ImageHeight and BytesPerScanline can be zero in small interlaced images.
844 */
845
846 if((!ImageHeight) || (!BytesPerScanline))
847 {
848 return(qtrue);
849 }
850
851 /*
852 * Set the pointer to the start of the decompressed Data.
853 */
854
855 DecompPtr = DecompressedData;
856
857 /*
858 * Un-filtering is done in place.
859 */
860
861 /*
862 * Go trough all scanlines.
863 */
864
865 for(h = 0; h < ImageHeight; h++)
866 {
867 /*
868 * Every scanline starts with a FilterType byte.
869 */
870
871 FilterType = *DecompPtr;
872 DecompPtr++;
873
874 /*
875 * Left pixel of the first byte in a scanline is zero.
876 */
877
878 PixelLeft = Zeros;
879
880 /*
881 * Set PixelUp to previous line only if we are on the second line or above.
882 *
883 * Plus one byte for the FilterType
884 */
885
886 if(h > 0)
887 {
888 PixelUp = DecompPtr - (BytesPerScanline + 1);
889 }
890 else
891 {
892 PixelUp = Zeros;
893 }
894
895 /*
896 * The pixel left to the first pixel of the previous scanline is zero too.
897 */
898
899 PixelUpLeft = Zeros;
900
901 /*
902 * Cycle trough all pixels of the scanline.
903 */
904
905 for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++)
906 {
907 /*
908 * Cycle trough the bytes of the pixel.
909 */
910
911 for(p = 0; p < BytesPerPixel; p++)
912 {
913 switch(FilterType)
914 {
915 case PNG_FilterType_None :
916 {
917 /*
918 * The byte is unfiltered.
919 */
920
921 break;
922 }
923
924 case PNG_FilterType_Sub :
925 {
926 DecompPtr[p] += PixelLeft[p];
927
928 break;
929 }
930
931 case PNG_FilterType_Up :
932 {
933 DecompPtr[p] += PixelUp[p];
934
935 break;
936 }
937
938 case PNG_FilterType_Average :
939 {
940 DecompPtr[p] += ((uint8_t) ((((uint16_t) PixelLeft[p]) + ((uint16_t) PixelUp[p])) / 2));
941
942 break;
943 }
944
945 case PNG_FilterType_Paeth :
946 {
947 DecompPtr[p] += PredictPaeth(PixelLeft[p], PixelUp[p], PixelUpLeft[p]);
948
949 break;
950 }
951
952 default :
953 {
954 return(qfalse);
955 }
956 }
957 }
958
959 PixelLeft = DecompPtr;
960
961 /*
962 * We only have a upleft pixel if we are on the second line or above.
963 */
964
965 if(h > 0)
966 {
967 PixelUpLeft = DecompPtr - (BytesPerScanline + 1);
968 }
969
970 /*
971 * Skip to the next pixel.
972 */
973
974 DecompPtr += BytesPerPixel;
975
976 /*
977 * We only have a previous line if we are on the second line and above.
978 */
979
980 if(h > 0)
981 {
982 PixelUp = DecompPtr - (BytesPerScanline + 1);
983 }
984 }
985 }
986
987 return(qtrue);
988 }
989
990 /*
991 * Convert a raw input pixel to Quake 3 RGA format.
992 */
993
ConvertPixel(struct PNG_Chunk_IHDR * IHDR,byte * OutPtr,uint8_t * DecompPtr,qboolean HasTransparentColour,uint8_t * TransparentColour,uint8_t * OutPal)994 static qboolean ConvertPixel(struct PNG_Chunk_IHDR *IHDR,
995 byte *OutPtr,
996 uint8_t *DecompPtr,
997 qboolean HasTransparentColour,
998 uint8_t *TransparentColour,
999 uint8_t *OutPal)
1000 {
1001 /*
1002 * input verification
1003 */
1004
1005 if(!(IHDR && OutPtr && DecompPtr && TransparentColour && OutPal))
1006 {
1007 return(qfalse);
1008 }
1009
1010 switch(IHDR->ColourType)
1011 {
1012 case PNG_ColourType_Grey :
1013 {
1014 switch(IHDR->BitDepth)
1015 {
1016 case PNG_BitDepth_1 :
1017 case PNG_BitDepth_2 :
1018 case PNG_BitDepth_4 :
1019 {
1020 uint8_t Step;
1021 uint8_t GreyValue;
1022
1023 Step = 0xFF / ((1 << IHDR->BitDepth) - 1);
1024
1025 GreyValue = DecompPtr[0] * Step;
1026
1027 OutPtr[0] = GreyValue;
1028 OutPtr[1] = GreyValue;
1029 OutPtr[2] = GreyValue;
1030 OutPtr[3] = 0xFF;
1031
1032 /*
1033 * Grey supports full transparency for one specified colour
1034 */
1035
1036 if(HasTransparentColour)
1037 {
1038 if(TransparentColour[1] == DecompPtr[0])
1039 {
1040 OutPtr[3] = 0x00;
1041 }
1042 }
1043
1044
1045 break;
1046 }
1047
1048 case PNG_BitDepth_8 :
1049 case PNG_BitDepth_16 :
1050 {
1051 OutPtr[0] = DecompPtr[0];
1052 OutPtr[1] = DecompPtr[0];
1053 OutPtr[2] = DecompPtr[0];
1054 OutPtr[3] = 0xFF;
1055
1056 /*
1057 * Grey supports full transparency for one specified colour
1058 */
1059
1060 if(HasTransparentColour)
1061 {
1062 if(IHDR->BitDepth == PNG_BitDepth_8)
1063 {
1064 if(TransparentColour[1] == DecompPtr[0])
1065 {
1066 OutPtr[3] = 0x00;
1067 }
1068 }
1069 else
1070 {
1071 if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1]))
1072 {
1073 OutPtr[3] = 0x00;
1074 }
1075 }
1076 }
1077
1078 break;
1079 }
1080
1081 default :
1082 {
1083 return(qfalse);
1084 }
1085 }
1086
1087 break;
1088 }
1089
1090 case PNG_ColourType_True :
1091 {
1092 switch(IHDR->BitDepth)
1093 {
1094 case PNG_BitDepth_8 :
1095 {
1096 OutPtr[0] = DecompPtr[0];
1097 OutPtr[1] = DecompPtr[1];
1098 OutPtr[2] = DecompPtr[2];
1099 OutPtr[3] = 0xFF;
1100
1101 /*
1102 * True supports full transparency for one specified colour
1103 */
1104
1105 if(HasTransparentColour)
1106 {
1107 if((TransparentColour[1] == DecompPtr[0]) &&
1108 (TransparentColour[3] == DecompPtr[1]) &&
1109 (TransparentColour[5] == DecompPtr[2]))
1110 {
1111 OutPtr[3] = 0x00;
1112 }
1113 }
1114
1115 break;
1116 }
1117
1118 case PNG_BitDepth_16 :
1119 {
1120 /*
1121 * We use only the upper byte.
1122 */
1123
1124 OutPtr[0] = DecompPtr[0];
1125 OutPtr[1] = DecompPtr[2];
1126 OutPtr[2] = DecompPtr[4];
1127 OutPtr[3] = 0xFF;
1128
1129 /*
1130 * True supports full transparency for one specified colour
1131 */
1132
1133 if(HasTransparentColour)
1134 {
1135 if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1]) &&
1136 (TransparentColour[2] == DecompPtr[2]) && (TransparentColour[3] == DecompPtr[3]) &&
1137 (TransparentColour[4] == DecompPtr[4]) && (TransparentColour[5] == DecompPtr[5]))
1138 {
1139 OutPtr[3] = 0x00;
1140 }
1141 }
1142
1143 break;
1144 }
1145
1146 default :
1147 {
1148 return(qfalse);
1149 }
1150 }
1151
1152 break;
1153 }
1154
1155 case PNG_ColourType_Indexed :
1156 {
1157 OutPtr[0] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 0];
1158 OutPtr[1] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 1];
1159 OutPtr[2] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 2];
1160 OutPtr[3] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 3];
1161
1162 break;
1163 }
1164
1165 case PNG_ColourType_GreyAlpha :
1166 {
1167 switch(IHDR->BitDepth)
1168 {
1169 case PNG_BitDepth_8 :
1170 {
1171 OutPtr[0] = DecompPtr[0];
1172 OutPtr[1] = DecompPtr[0];
1173 OutPtr[2] = DecompPtr[0];
1174 OutPtr[3] = DecompPtr[1];
1175
1176 break;
1177 }
1178
1179 case PNG_BitDepth_16 :
1180 {
1181 /*
1182 * We use only the upper byte.
1183 */
1184
1185 OutPtr[0] = DecompPtr[0];
1186 OutPtr[1] = DecompPtr[0];
1187 OutPtr[2] = DecompPtr[0];
1188 OutPtr[3] = DecompPtr[2];
1189
1190 break;
1191 }
1192
1193 default :
1194 {
1195 return(qfalse);
1196 }
1197 }
1198
1199 break;
1200 }
1201
1202 case PNG_ColourType_TrueAlpha :
1203 {
1204 switch(IHDR->BitDepth)
1205 {
1206 case PNG_BitDepth_8 :
1207 {
1208 OutPtr[0] = DecompPtr[0];
1209 OutPtr[1] = DecompPtr[1];
1210 OutPtr[2] = DecompPtr[2];
1211 OutPtr[3] = DecompPtr[3];
1212
1213 break;
1214 }
1215
1216 case PNG_BitDepth_16 :
1217 {
1218 /*
1219 * We use only the upper byte.
1220 */
1221
1222 OutPtr[0] = DecompPtr[0];
1223 OutPtr[1] = DecompPtr[2];
1224 OutPtr[2] = DecompPtr[4];
1225 OutPtr[3] = DecompPtr[6];
1226
1227 break;
1228 }
1229
1230 default :
1231 {
1232 return(qfalse);
1233 }
1234 }
1235
1236 break;
1237 }
1238
1239 default :
1240 {
1241 return(qfalse);
1242 }
1243 }
1244
1245 return(qtrue);
1246 }
1247
1248
1249 /*
1250 * Decode a non-interlaced image.
1251 */
1252
DecodeImageNonInterlaced(struct PNG_Chunk_IHDR * IHDR,byte * OutBuffer,uint8_t * DecompressedData,uint32_t DecompressedDataLength,qboolean HasTransparentColour,uint8_t * TransparentColour,uint8_t * OutPal)1253 static qboolean DecodeImageNonInterlaced(struct PNG_Chunk_IHDR *IHDR,
1254 byte *OutBuffer,
1255 uint8_t *DecompressedData,
1256 uint32_t DecompressedDataLength,
1257 qboolean HasTransparentColour,
1258 uint8_t *TransparentColour,
1259 uint8_t *OutPal)
1260 {
1261 uint32_t IHDR_Width;
1262 uint32_t IHDR_Height;
1263 uint32_t BytesPerScanline, BytesPerPixel, PixelsPerByte;
1264 uint32_t w, h, p;
1265 byte *OutPtr;
1266 uint8_t *DecompPtr;
1267
1268 /*
1269 * input verification
1270 */
1271
1272 if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal))
1273 {
1274 return(qfalse);
1275 }
1276
1277 /*
1278 * byte swapping
1279 */
1280
1281 IHDR_Width = BigLong(IHDR->Width);
1282 IHDR_Height = BigLong(IHDR->Height);
1283
1284 /*
1285 * information for un-filtering
1286 */
1287
1288 switch(IHDR->ColourType)
1289 {
1290 case PNG_ColourType_Grey :
1291 {
1292 switch(IHDR->BitDepth)
1293 {
1294 case PNG_BitDepth_1 :
1295 case PNG_BitDepth_2 :
1296 case PNG_BitDepth_4 :
1297 {
1298 BytesPerPixel = 1;
1299 PixelsPerByte = 8 / IHDR->BitDepth;
1300
1301 break;
1302 }
1303
1304 case PNG_BitDepth_8 :
1305 case PNG_BitDepth_16 :
1306 {
1307 BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey;
1308 PixelsPerByte = 1;
1309
1310 break;
1311 }
1312
1313 default :
1314 {
1315 return(qfalse);
1316 }
1317 }
1318
1319 break;
1320 }
1321
1322 case PNG_ColourType_True :
1323 {
1324 switch(IHDR->BitDepth)
1325 {
1326 case PNG_BitDepth_8 :
1327 case PNG_BitDepth_16 :
1328 {
1329 BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True;
1330 PixelsPerByte = 1;
1331
1332 break;
1333 }
1334
1335 default :
1336 {
1337 return(qfalse);
1338 }
1339 }
1340
1341 break;
1342 }
1343
1344 case PNG_ColourType_Indexed :
1345 {
1346 switch(IHDR->BitDepth)
1347 {
1348 case PNG_BitDepth_1 :
1349 case PNG_BitDepth_2 :
1350 case PNG_BitDepth_4 :
1351 {
1352 BytesPerPixel = 1;
1353 PixelsPerByte = 8 / IHDR->BitDepth;
1354
1355 break;
1356 }
1357
1358 case PNG_BitDepth_8 :
1359 {
1360 BytesPerPixel = PNG_NumColourComponents_Indexed;
1361 PixelsPerByte = 1;
1362
1363 break;
1364 }
1365
1366 default :
1367 {
1368 return(qfalse);
1369 }
1370 }
1371
1372 break;
1373 }
1374
1375 case PNG_ColourType_GreyAlpha :
1376 {
1377 switch(IHDR->BitDepth)
1378 {
1379 case PNG_BitDepth_8 :
1380 case PNG_BitDepth_16 :
1381 {
1382 BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha;
1383 PixelsPerByte = 1;
1384
1385 break;
1386 }
1387
1388 default :
1389 {
1390 return(qfalse);
1391 }
1392 }
1393
1394 break;
1395 }
1396
1397 case PNG_ColourType_TrueAlpha :
1398 {
1399 switch(IHDR->BitDepth)
1400 {
1401 case PNG_BitDepth_8 :
1402 case PNG_BitDepth_16 :
1403 {
1404 BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha;
1405 PixelsPerByte = 1;
1406
1407 break;
1408 }
1409
1410 default :
1411 {
1412 return(qfalse);
1413 }
1414 }
1415
1416 break;
1417 }
1418
1419 default :
1420 {
1421 return(qfalse);
1422 }
1423 }
1424
1425 /*
1426 * Calculate the size of one scanline
1427 */
1428
1429 BytesPerScanline = (IHDR_Width * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte;
1430
1431 /*
1432 * Check if we have enough data for the whole image.
1433 */
1434
1435 if(!(DecompressedDataLength == ((BytesPerScanline + 1) * IHDR_Height)))
1436 {
1437 return(qfalse);
1438 }
1439
1440 /*
1441 * Unfilter the image.
1442 */
1443
1444 if(!UnfilterImage(DecompressedData, IHDR_Height, BytesPerScanline, BytesPerPixel))
1445 {
1446 return(qfalse);
1447 }
1448
1449 /*
1450 * Set the working pointers to the beginning of the buffers.
1451 */
1452
1453 OutPtr = OutBuffer;
1454 DecompPtr = DecompressedData;
1455
1456 /*
1457 * Create the output image.
1458 */
1459
1460 for(h = 0; h < IHDR_Height; h++)
1461 {
1462 /*
1463 * Count the pixels on the scanline for those multipixel bytes
1464 */
1465
1466 uint32_t CurrPixel;
1467
1468 /*
1469 * skip FilterType
1470 */
1471
1472 DecompPtr++;
1473
1474 /*
1475 * Reset the pixel count.
1476 */
1477
1478 CurrPixel = 0;
1479
1480 for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++)
1481 {
1482 if(PixelsPerByte > 1)
1483 {
1484 uint8_t Mask;
1485 uint32_t Shift;
1486 uint8_t SinglePixel;
1487
1488 for(p = 0; p < PixelsPerByte; p++)
1489 {
1490 if(CurrPixel < IHDR_Width)
1491 {
1492 Mask = (1 << IHDR->BitDepth) - 1;
1493 Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth;
1494
1495 SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift);
1496
1497 if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal))
1498 {
1499 return(qfalse);
1500 }
1501
1502 OutPtr += Q3IMAGE_BYTESPERPIXEL;
1503 CurrPixel++;
1504 }
1505 }
1506
1507 }
1508 else
1509 {
1510 if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal))
1511 {
1512 return(qfalse);
1513 }
1514
1515
1516 OutPtr += Q3IMAGE_BYTESPERPIXEL;
1517 }
1518
1519 DecompPtr += BytesPerPixel;
1520 }
1521 }
1522
1523 return(qtrue);
1524 }
1525
1526 /*
1527 * Decode an interlaced image.
1528 */
1529
DecodeImageInterlaced(struct PNG_Chunk_IHDR * IHDR,byte * OutBuffer,uint8_t * DecompressedData,uint32_t DecompressedDataLength,qboolean HasTransparentColour,uint8_t * TransparentColour,uint8_t * OutPal)1530 static qboolean DecodeImageInterlaced(struct PNG_Chunk_IHDR *IHDR,
1531 byte *OutBuffer,
1532 uint8_t *DecompressedData,
1533 uint32_t DecompressedDataLength,
1534 qboolean HasTransparentColour,
1535 uint8_t *TransparentColour,
1536 uint8_t *OutPal)
1537 {
1538 uint32_t IHDR_Width;
1539 uint32_t IHDR_Height;
1540 uint32_t BytesPerScanline[PNG_Adam7_NumPasses], BytesPerPixel, PixelsPerByte;
1541 uint32_t PassWidth[PNG_Adam7_NumPasses], PassHeight[PNG_Adam7_NumPasses];
1542 uint32_t WSkip[PNG_Adam7_NumPasses], WOffset[PNG_Adam7_NumPasses], HSkip[PNG_Adam7_NumPasses], HOffset[PNG_Adam7_NumPasses];
1543 uint32_t w, h, p, a;
1544 byte *OutPtr;
1545 uint8_t *DecompPtr;
1546 uint32_t TargetLength;
1547
1548 /*
1549 * input verification
1550 */
1551
1552 if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal))
1553 {
1554 return(qfalse);
1555 }
1556
1557 /*
1558 * byte swapping
1559 */
1560
1561 IHDR_Width = BigLong(IHDR->Width);
1562 IHDR_Height = BigLong(IHDR->Height);
1563
1564 /*
1565 * Skip and Offset for the passes.
1566 */
1567
1568 WSkip[0] = 8;
1569 WOffset[0] = 0;
1570 HSkip[0] = 8;
1571 HOffset[0] = 0;
1572
1573 WSkip[1] = 8;
1574 WOffset[1] = 4;
1575 HSkip[1] = 8;
1576 HOffset[1] = 0;
1577
1578 WSkip[2] = 4;
1579 WOffset[2] = 0;
1580 HSkip[2] = 8;
1581 HOffset[2] = 4;
1582
1583 WSkip[3] = 4;
1584 WOffset[3] = 2;
1585 HSkip[3] = 4;
1586 HOffset[3] = 0;
1587
1588 WSkip[4] = 2;
1589 WOffset[4] = 0;
1590 HSkip[4] = 4;
1591 HOffset[4] = 2;
1592
1593 WSkip[5] = 2;
1594 WOffset[5] = 1;
1595 HSkip[5] = 2;
1596 HOffset[5] = 0;
1597
1598 WSkip[6] = 1;
1599 WOffset[6] = 0;
1600 HSkip[6] = 2;
1601 HOffset[6] = 1;
1602
1603 /*
1604 * Calculate the sizes of the passes.
1605 */
1606
1607 PassWidth[0] = (IHDR_Width + 7) / 8;
1608 PassHeight[0] = (IHDR_Height + 7) / 8;
1609
1610 PassWidth[1] = (IHDR_Width + 3) / 8;
1611 PassHeight[1] = (IHDR_Height + 7) / 8;
1612
1613 PassWidth[2] = (IHDR_Width + 3) / 4;
1614 PassHeight[2] = (IHDR_Height + 3) / 8;
1615
1616 PassWidth[3] = (IHDR_Width + 1) / 4;
1617 PassHeight[3] = (IHDR_Height + 3) / 4;
1618
1619 PassWidth[4] = (IHDR_Width + 1) / 2;
1620 PassHeight[4] = (IHDR_Height + 1) / 4;
1621
1622 PassWidth[5] = (IHDR_Width + 0) / 2;
1623 PassHeight[5] = (IHDR_Height + 1) / 2;
1624
1625 PassWidth[6] = (IHDR_Width + 0) / 1;
1626 PassHeight[6] = (IHDR_Height + 0) / 2;
1627
1628 /*
1629 * information for un-filtering
1630 */
1631
1632 switch(IHDR->ColourType)
1633 {
1634 case PNG_ColourType_Grey :
1635 {
1636 switch(IHDR->BitDepth)
1637 {
1638 case PNG_BitDepth_1 :
1639 case PNG_BitDepth_2 :
1640 case PNG_BitDepth_4 :
1641 {
1642 BytesPerPixel = 1;
1643 PixelsPerByte = 8 / IHDR->BitDepth;
1644
1645 break;
1646 }
1647
1648 case PNG_BitDepth_8 :
1649 case PNG_BitDepth_16 :
1650 {
1651 BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey;
1652 PixelsPerByte = 1;
1653
1654 break;
1655 }
1656
1657 default :
1658 {
1659 return(qfalse);
1660 }
1661 }
1662
1663 break;
1664 }
1665
1666 case PNG_ColourType_True :
1667 {
1668 switch(IHDR->BitDepth)
1669 {
1670 case PNG_BitDepth_8 :
1671 case PNG_BitDepth_16 :
1672 {
1673 BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True;
1674 PixelsPerByte = 1;
1675
1676 break;
1677 }
1678
1679 default :
1680 {
1681 return(qfalse);
1682 }
1683 }
1684
1685 break;
1686 }
1687
1688 case PNG_ColourType_Indexed :
1689 {
1690 switch(IHDR->BitDepth)
1691 {
1692 case PNG_BitDepth_1 :
1693 case PNG_BitDepth_2 :
1694 case PNG_BitDepth_4 :
1695 {
1696 BytesPerPixel = 1;
1697 PixelsPerByte = 8 / IHDR->BitDepth;
1698
1699 break;
1700 }
1701
1702 case PNG_BitDepth_8 :
1703 {
1704 BytesPerPixel = PNG_NumColourComponents_Indexed;
1705 PixelsPerByte = 1;
1706
1707 break;
1708 }
1709
1710 default :
1711 {
1712 return(qfalse);
1713 }
1714 }
1715
1716 break;
1717 }
1718
1719 case PNG_ColourType_GreyAlpha :
1720 {
1721 switch(IHDR->BitDepth)
1722 {
1723 case PNG_BitDepth_8 :
1724 case PNG_BitDepth_16 :
1725 {
1726 BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha;
1727 PixelsPerByte = 1;
1728
1729 break;
1730 }
1731
1732 default :
1733 {
1734 return(qfalse);
1735 }
1736 }
1737
1738 break;
1739 }
1740
1741 case PNG_ColourType_TrueAlpha :
1742 {
1743 switch(IHDR->BitDepth)
1744 {
1745 case PNG_BitDepth_8 :
1746 case PNG_BitDepth_16 :
1747 {
1748 BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha;
1749 PixelsPerByte = 1;
1750
1751 break;
1752 }
1753
1754 default :
1755 {
1756 return(qfalse);
1757 }
1758 }
1759
1760 break;
1761 }
1762
1763 default :
1764 {
1765 return(qfalse);
1766 }
1767 }
1768
1769 /*
1770 * Calculate the size of the scanlines per pass
1771 */
1772
1773 for(a = 0; a < PNG_Adam7_NumPasses; a++)
1774 {
1775 BytesPerScanline[a] = (PassWidth[a] * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte;
1776 }
1777
1778 /*
1779 * Calculate the size of all passes
1780 */
1781
1782 TargetLength = 0;
1783
1784 for(a = 0; a < PNG_Adam7_NumPasses; a++)
1785 {
1786 TargetLength += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]);
1787 }
1788
1789 /*
1790 * Check if we have enough data for the whole image.
1791 */
1792
1793 if(!(DecompressedDataLength == TargetLength))
1794 {
1795 return(qfalse);
1796 }
1797
1798 /*
1799 * Unfilter the image.
1800 */
1801
1802 DecompPtr = DecompressedData;
1803
1804 for(a = 0; a < PNG_Adam7_NumPasses; a++)
1805 {
1806 if(!UnfilterImage(DecompPtr, PassHeight[a], BytesPerScanline[a], BytesPerPixel))
1807 {
1808 return(qfalse);
1809 }
1810
1811 DecompPtr += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]);
1812 }
1813
1814 /*
1815 * Set the working pointers to the beginning of the buffers.
1816 */
1817
1818 DecompPtr = DecompressedData;
1819
1820 /*
1821 * Create the output image.
1822 */
1823
1824 for(a = 0; a < PNG_Adam7_NumPasses; a++)
1825 {
1826 for(h = 0; h < PassHeight[a]; h++)
1827 {
1828 /*
1829 * Count the pixels on the scanline for those multipixel bytes
1830 */
1831
1832 uint32_t CurrPixel;
1833
1834 /*
1835 * skip FilterType
1836 * but only when the pass has a width bigger than zero
1837 */
1838
1839 if(BytesPerScanline[a])
1840 {
1841 DecompPtr++;
1842 }
1843
1844 /*
1845 * Reset the pixel count.
1846 */
1847
1848 CurrPixel = 0;
1849
1850 for(w = 0; w < (BytesPerScanline[a] / BytesPerPixel); w++)
1851 {
1852 if(PixelsPerByte > 1)
1853 {
1854 uint8_t Mask;
1855 uint32_t Shift;
1856 uint8_t SinglePixel;
1857
1858 for(p = 0; p < PixelsPerByte; p++)
1859 {
1860 if(CurrPixel < PassWidth[a])
1861 {
1862 Mask = (1 << IHDR->BitDepth) - 1;
1863 Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth;
1864
1865 SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift);
1866
1867 OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((CurrPixel * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL);
1868
1869 if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal))
1870 {
1871 return(qfalse);
1872 }
1873
1874 CurrPixel++;
1875 }
1876 }
1877
1878 }
1879 else
1880 {
1881 OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((w * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL);
1882
1883 if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal))
1884 {
1885 return(qfalse);
1886 }
1887 }
1888
1889 DecompPtr += BytesPerPixel;
1890 }
1891 }
1892 }
1893
1894 return(qtrue);
1895 }
1896
1897 /*
1898 * The PNG loader
1899 */
1900
R_LoadPNG(const char * name,byte ** pic,int * width,int * height,byte alphaByte)1901 void R_LoadPNG(const char *name, byte **pic, int *width, int *height, byte alphaByte)
1902 {
1903 struct BufferedFile *ThePNG;
1904 byte *OutBuffer;
1905 uint8_t *Signature;
1906 struct PNG_ChunkHeader *CH;
1907 uint32_t ChunkHeaderLength;
1908 uint32_t ChunkHeaderType;
1909 struct PNG_Chunk_IHDR *IHDR;
1910 uint32_t IHDR_Width;
1911 uint32_t IHDR_Height;
1912 PNG_ChunkCRC *CRC;
1913 uint8_t *InPal;
1914 uint8_t *DecompressedData;
1915 uint32_t DecompressedDataLength;
1916 uint32_t i;
1917
1918 /*
1919 * palette with 256 RGBA entries
1920 */
1921
1922 uint8_t OutPal[1024];
1923
1924 /*
1925 * transparent colour from the tRNS chunk
1926 */
1927
1928 qboolean HasTransparentColour = qfalse;
1929 uint8_t TransparentColour[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1930
1931 /*
1932 * input verification
1933 */
1934
1935 if(!(name && pic))
1936 {
1937 return;
1938 }
1939
1940 /*
1941 * Zero out return values.
1942 */
1943
1944 *pic = NULL;
1945
1946 if(width)
1947 {
1948 *width = 0;
1949 }
1950
1951 if(height)
1952 {
1953 *height = 0;
1954 }
1955
1956 /*
1957 * Read the file.
1958 */
1959
1960 ThePNG = ReadBufferedFile(name);
1961 if(!ThePNG)
1962 {
1963 return;
1964 }
1965
1966 /*
1967 * Read the siganture of the file.
1968 */
1969
1970 Signature = BufferedFileRead(ThePNG, PNG_Signature_Size);
1971 if(!Signature)
1972 {
1973 CloseBufferedFile(ThePNG);
1974
1975 return;
1976 }
1977
1978 /*
1979 * Is it a PNG?
1980 */
1981
1982 if(memcmp(Signature, PNG_Signature, PNG_Signature_Size))
1983 {
1984 CloseBufferedFile(ThePNG);
1985
1986 return;
1987 }
1988
1989 /*
1990 * Read the first chunk-header.
1991 */
1992
1993 CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
1994 if(!CH)
1995 {
1996 CloseBufferedFile(ThePNG);
1997
1998 return;
1999 }
2000
2001 /*
2002 * PNG multi-byte types are in Big Endian
2003 */
2004
2005 ChunkHeaderLength = BigLong(CH->Length);
2006 ChunkHeaderType = BigLong(CH->Type);
2007
2008 /*
2009 * Check if the first chunk is an IHDR.
2010 */
2011
2012 if(!((ChunkHeaderType == PNG_ChunkType_IHDR) && (ChunkHeaderLength == PNG_Chunk_IHDR_Size)))
2013 {
2014 CloseBufferedFile(ThePNG);
2015
2016 return;
2017 }
2018
2019 /*
2020 * Read the IHDR.
2021 */
2022
2023 IHDR = BufferedFileRead(ThePNG, PNG_Chunk_IHDR_Size);
2024 if(!IHDR)
2025 {
2026 CloseBufferedFile(ThePNG);
2027
2028 return;
2029 }
2030
2031 /*
2032 * Read the CRC for IHDR
2033 */
2034
2035 CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
2036 if(!CRC)
2037 {
2038 CloseBufferedFile(ThePNG);
2039
2040 return;
2041 }
2042
2043 /*
2044 * Here we could check the CRC if we wanted to.
2045 */
2046
2047 /*
2048 * multi-byte type swapping
2049 */
2050
2051 IHDR_Width = BigLong(IHDR->Width);
2052 IHDR_Height = BigLong(IHDR->Height);
2053
2054 /*
2055 * Check if Width and Height are valid.
2056 */
2057
2058 if(!((IHDR_Width > 0) && (IHDR_Height > 0))
2059 || IHDR_Width > INT_MAX / Q3IMAGE_BYTESPERPIXEL / IHDR_Height)
2060 {
2061 CloseBufferedFile(ThePNG);
2062
2063 Com_Printf(S_COLOR_YELLOW "%s: invalid image size\n", name);
2064
2065 return;
2066 }
2067
2068 /*
2069 * Do we need to check if the dimensions of the image are valid for Quake3?
2070 */
2071
2072 /*
2073 * Check if CompressionMethod and FilterMethod are valid.
2074 */
2075
2076 if(!((IHDR->CompressionMethod == PNG_CompressionMethod_0) && (IHDR->FilterMethod == PNG_FilterMethod_0)))
2077 {
2078 CloseBufferedFile(ThePNG);
2079
2080 return;
2081 }
2082
2083 /*
2084 * Check if InterlaceMethod is valid.
2085 */
2086
2087 if(!((IHDR->InterlaceMethod == PNG_InterlaceMethod_NonInterlaced) || (IHDR->InterlaceMethod == PNG_InterlaceMethod_Interlaced)))
2088 {
2089 CloseBufferedFile(ThePNG);
2090
2091 return;
2092 }
2093
2094 /*
2095 * Read palette for an indexed image.
2096 */
2097
2098 if(IHDR->ColourType == PNG_ColourType_Indexed)
2099 {
2100 /*
2101 * We need the palette first.
2102 */
2103
2104 if(!FindChunk(ThePNG, PNG_ChunkType_PLTE))
2105 {
2106 CloseBufferedFile(ThePNG);
2107
2108 return;
2109 }
2110
2111 /*
2112 * Read the chunk-header.
2113 */
2114
2115 CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
2116 if(!CH)
2117 {
2118 CloseBufferedFile(ThePNG);
2119
2120 return;
2121 }
2122
2123 /*
2124 * PNG multi-byte types are in Big Endian
2125 */
2126
2127 ChunkHeaderLength = BigLong(CH->Length);
2128 ChunkHeaderType = BigLong(CH->Type);
2129
2130 /*
2131 * Check if the chunk is an PLTE.
2132 */
2133
2134 if(!(ChunkHeaderType == PNG_ChunkType_PLTE))
2135 {
2136 CloseBufferedFile(ThePNG);
2137
2138 return;
2139 }
2140
2141 /*
2142 * Check if Length is divisible by 3
2143 */
2144
2145 if(ChunkHeaderLength % 3)
2146 {
2147 CloseBufferedFile(ThePNG);
2148
2149 return;
2150 }
2151
2152 /*
2153 * Read the raw palette data
2154 */
2155
2156 InPal = BufferedFileRead(ThePNG, ChunkHeaderLength);
2157 if(!InPal)
2158 {
2159 CloseBufferedFile(ThePNG);
2160
2161 return;
2162 }
2163
2164 /*
2165 * Read the CRC for the palette
2166 */
2167
2168 CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
2169 if(!CRC)
2170 {
2171 CloseBufferedFile(ThePNG);
2172
2173 return;
2174 }
2175
2176 /*
2177 * Set some default values.
2178 */
2179
2180 for(i = 0; i < 256; i++)
2181 {
2182 OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = 0x00;
2183 OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = 0x00;
2184 OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = 0x00;
2185 OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF;
2186 }
2187
2188 /*
2189 * Convert to the Quake3 RGBA-format.
2190 */
2191
2192 for(i = 0; i < (ChunkHeaderLength / 3); i++)
2193 {
2194 OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = InPal[i*3+0];
2195 OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = InPal[i*3+1];
2196 OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = InPal[i*3+2];
2197 OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF;
2198 }
2199 }
2200
2201 /*
2202 * transparency information is sometimes stored in an tRNS chunk
2203 */
2204
2205 /*
2206 * Let's see if there is a tRNS chunk
2207 */
2208
2209 if(FindChunk(ThePNG, PNG_ChunkType_tRNS))
2210 {
2211 uint8_t *Trans;
2212
2213 /*
2214 * Read the chunk-header.
2215 */
2216
2217 CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
2218 if(!CH)
2219 {
2220 CloseBufferedFile(ThePNG);
2221
2222 return;
2223 }
2224
2225 /*
2226 * PNG multi-byte types are in Big Endian
2227 */
2228
2229 ChunkHeaderLength = BigLong(CH->Length);
2230 ChunkHeaderType = BigLong(CH->Type);
2231
2232 /*
2233 * Check if the chunk is an tRNS.
2234 */
2235
2236 if(!(ChunkHeaderType == PNG_ChunkType_tRNS))
2237 {
2238 CloseBufferedFile(ThePNG);
2239
2240 return;
2241 }
2242
2243 /*
2244 * Read the transparency information.
2245 */
2246
2247 Trans = BufferedFileRead(ThePNG, ChunkHeaderLength);
2248 if(!Trans)
2249 {
2250 CloseBufferedFile(ThePNG);
2251
2252 return;
2253 }
2254
2255 /*
2256 * Read the CRC.
2257 */
2258
2259 CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
2260 if(!CRC)
2261 {
2262 CloseBufferedFile(ThePNG);
2263
2264 return;
2265 }
2266
2267 /*
2268 * Only for Grey, True and Indexed ColourType should tRNS exist.
2269 */
2270
2271 switch(IHDR->ColourType)
2272 {
2273 case PNG_ColourType_Grey :
2274 {
2275 if(!ChunkHeaderLength == 2)
2276 {
2277 CloseBufferedFile(ThePNG);
2278
2279 return;
2280 }
2281
2282 HasTransparentColour = qtrue;
2283
2284 /*
2285 * Grey can have one colour which is completely transparent.
2286 * This colour is always stored in 16 bits.
2287 */
2288
2289 TransparentColour[0] = Trans[0];
2290 TransparentColour[1] = Trans[1];
2291
2292 break;
2293 }
2294
2295 case PNG_ColourType_True :
2296 {
2297 if(!ChunkHeaderLength == 6)
2298 {
2299 CloseBufferedFile(ThePNG);
2300
2301 return;
2302 }
2303
2304 HasTransparentColour = qtrue;
2305
2306 /*
2307 * True can have one colour which is completely transparent.
2308 * This colour is always stored in 16 bits.
2309 */
2310
2311 TransparentColour[0] = Trans[0];
2312 TransparentColour[1] = Trans[1];
2313 TransparentColour[2] = Trans[2];
2314 TransparentColour[3] = Trans[3];
2315 TransparentColour[4] = Trans[4];
2316 TransparentColour[5] = Trans[5];
2317
2318 break;
2319 }
2320
2321 case PNG_ColourType_Indexed :
2322 {
2323 /*
2324 * Maximum of 256 one byte transparency entries.
2325 */
2326
2327 if(ChunkHeaderLength > 256)
2328 {
2329 CloseBufferedFile(ThePNG);
2330
2331 return;
2332 }
2333
2334 HasTransparentColour = qtrue;
2335
2336 /*
2337 * alpha values for palette entries
2338 */
2339
2340 for(i = 0; i < ChunkHeaderLength; i++)
2341 {
2342 OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = Trans[i];
2343 }
2344
2345 break;
2346 }
2347
2348 /*
2349 * All other ColourTypes should not have tRNS chunks
2350 */
2351
2352 default :
2353 {
2354 CloseBufferedFile(ThePNG);
2355
2356 return;
2357 }
2358 }
2359 }
2360
2361 /*
2362 * Rewind to the start of the file.
2363 */
2364
2365 if(!BufferedFileRewind(ThePNG, -1))
2366 {
2367 CloseBufferedFile(ThePNG);
2368
2369 return;
2370 }
2371
2372 /*
2373 * Skip the signature
2374 */
2375
2376 if(!BufferedFileSkip(ThePNG, PNG_Signature_Size))
2377 {
2378 CloseBufferedFile(ThePNG);
2379
2380 return;
2381 }
2382
2383 /*
2384 * Decompress all IDAT chunks
2385 */
2386
2387 DecompressedDataLength = DecompressIDATs(ThePNG, &DecompressedData);
2388 if(!(DecompressedDataLength && DecompressedData))
2389 {
2390 CloseBufferedFile(ThePNG);
2391
2392 return;
2393 }
2394
2395 /*
2396 * Allocate output buffer.
2397 */
2398
2399 OutBuffer = ri.Malloc(IHDR_Width * IHDR_Height * Q3IMAGE_BYTESPERPIXEL);
2400 if(!OutBuffer)
2401 {
2402 ri.Free(DecompressedData);
2403 CloseBufferedFile(ThePNG);
2404
2405 return;
2406 }
2407
2408 /*
2409 * Interlaced and Non-interlaced images need to be handled differently.
2410 */
2411
2412 switch(IHDR->InterlaceMethod)
2413 {
2414 case PNG_InterlaceMethod_NonInterlaced :
2415 {
2416 if(!DecodeImageNonInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal))
2417 {
2418 ri.Free(OutBuffer);
2419 ri.Free(DecompressedData);
2420 CloseBufferedFile(ThePNG);
2421
2422 return;
2423 }
2424
2425 break;
2426 }
2427
2428 case PNG_InterlaceMethod_Interlaced :
2429 {
2430 if(!DecodeImageInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal))
2431 {
2432 ri.Free(OutBuffer);
2433 ri.Free(DecompressedData);
2434 CloseBufferedFile(ThePNG);
2435
2436 return;
2437 }
2438
2439 break;
2440 }
2441
2442 default :
2443 {
2444 ri.Free(OutBuffer);
2445 ri.Free(DecompressedData);
2446 CloseBufferedFile(ThePNG);
2447
2448 return;
2449 }
2450 }
2451
2452 /*
2453 * update the pointer to the image data
2454 */
2455
2456 *pic = OutBuffer;
2457
2458 /*
2459 * Fill width and height.
2460 */
2461
2462 if(width)
2463 {
2464 *width = IHDR_Width;
2465 }
2466
2467 if(height)
2468 {
2469 *height = IHDR_Height;
2470 }
2471
2472 /*
2473 * DecompressedData is not needed anymore.
2474 */
2475
2476 ri.Free(DecompressedData);
2477
2478 /*
2479 * We have all data, so close the file.
2480 */
2481
2482 CloseBufferedFile(ThePNG);
2483 }
2484