Subversion Repositories Kolibri OS

Rev

Rev 8341 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8341 dunkaist 1
 
2
3
 
4
; Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
5
; (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
6
; (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
7
8
 
9
; For conditions of distribution and use, see the disclaimer
10
; and license in png.inc
11
12
 
13
14
 
15
include '../../../../../../fs/kfar/trunk/zlib/deflate.inc'
16
include 'pngtokos.inc' ;integrate png to kos
17
18
 
19
include 'pnglibconf.inc'
20
include 'pngpriv.inc'
21
include 'png.inc'
22
include 'pngstruct.inc'
23
include 'pnginfo.inc'
24
include 'pngerror.asm'
25
include 'pngtrans.asm'
26
include 'pngget.asm'
27
include 'pngwrite.asm'
28
include 'pngmem.asm'
29
include 'pngset.asm'
30
include 'pngwutil.asm'
31
include 'pngwio.asm'
32
include 'pngwtran.asm'
33
34
 
35
;typedef png_libpng_version_1_6_25 Your_png_h_is_not_version_1_6_25;
36
37
 
38
; of the PNG file signature.  If the PNG data is embedded into another
39
; stream we can set num_bytes = 8 so that libpng will not attempt to read
40
; or write any of the magic bytes before it starts on the IHDR.
41
42
 
43
 
44
;void (png_structrp png_ptr, int num_bytes)
45
align 4
46
proc png_set_sig_bytes uses eax edi, png_ptr:dword, num_bytes:dword
47
	png_debug 1, 'in png_set_sig_bytes'
48
49
 
50
	or edi,edi
8408 IgorA 51
	jz .end_f ;if (..==0) return
52
8341 dunkaist 53
 
54
	cmp eax,0
55
	jge @f
56
		xor eax,eax
57
	@@:
58
	cmp eax,8
59
	jle @f ;if (..>8)
60
		png_error edi, 'Too many bytes for PNG signature'
61
	@@:
62
	mov byte[edi+png_struct.sig_bytes],al
63
.end_f:
64
	ret
65
endp
66
67
 
68
; checking less than the full 8-byte signature so that those apps that
69
; already read the first few bytes of a file to determine the file type
70
; can simply check the remaining bytes for extra assurance.  Returns
71
; an integer less than, equal to, or greater than zero if sig is found,
72
; respectively, to be less than, to match, or be greater than the correct
73
; PNG signature (this is the same behavior as strcmp, memcmp, etc).
74
75
 
76
align 4
77
proc png_sig_cmp, sig:dword, start:dword, num_to_check:dword
78
;   byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
79
80
 
81
;      num_to_check = 8;
82
83
 
84
;      return (-1);
85
86
 
87
;      return (-1);
88
89
 
90
;      num_to_check = 8 - start;
91
92
 
93
	ret
94
endp
95
96
 
97
98
 
99
;voidpf (voidpf png_ptr, uInt items, uInt size)
100
align 4
101
proc png_zalloc uses edx ecx, png_ptr:dword, items:dword, size:dword
102
103
 
8408 IgorA 104
	cmp dword[png_ptr],eax
105
	je .end_f ;if (..==0) return 0
106
8341 dunkaist 107
 
108
	xor edx,edx
109
	mov ecx,[size]
110
	div ecx
111
	cmp [items],eax
112
	jl @f ;if (..>=..)
113
		png_warning [png_ptr], 'Potential overflow in png_zalloc()'
114
		xor eax,eax
115
		jmp .end_f
116
	@@:
117
118
 
119
	imul ecx,[items]
120
	stdcall png_malloc_warn, [png_ptr], ecx
121
.end_f:
122
	ret
123
endp
124
125
 
126
;void (voidpf png_ptr, voidpf ptr)
127
align 4
128
proc png_zfree, png_ptr:dword, p2ptr:dword
129
	stdcall png_free, [png_ptr], [p2ptr]
130
	ret
131
endp
132
133
 
134
; in case CRC is > 32 bits to leave the top bits 0.
135
136
 
137
align 4
138
proc png_reset_crc uses eax edi, png_ptr:dword
139
	; The cast is safe because the crc is a 32-bit value.
140
	mov edi,[png_ptr]
141
	stdcall [calc_crc32], 0, Z_NULL, 0
142
	mov dword[edi+png_struct.crc],eax
143
	ret
144
endp
145
146
 
147
; much data to this routine as the largest single buffer size.  We
148
; also check that this data will actually be used before going to the
149
; trouble of calculating it.
150
151
 
152
align 4
153
proc png_calculate_crc uses eax ebx edi, png_ptr:dword, ptr:dword, length:dword
154
locals
155
	need_crc dd 1
156
	safe_length dd ?
157
endl
158
	mov edi,[png_ptr]
159
	PNG_CHUNK_ANCILLARY [edi+png_struct.chunk_name]
160
	or eax,eax ;if (..!=0)
8408 IgorA 161
	jz @f
162
		mov eax,[edi+png_struct.flags]
8341 dunkaist 163
		and eax,PNG_FLAG_CRC_ANCILLARY_MASK
164
		cmp eax,PNG_FLAG_CRC_ANCILLARY_USE or PNG_FLAG_CRC_ANCILLARY_NOWARN
165
		jne .end0 ;if (..==..)
166
			mov dword[need_crc],0
167
		jmp .end0
168
	@@: ;else ;critical
169
		mov eax,[edi+png_struct.flags]
170
		and eax,PNG_FLAG_CRC_CRITICAL_IGNORE
171
		jz .end0 ;if (..!=0)
172
			mov dword[need_crc],0
173
	.end0:
174
175
 
176
	; systems it is a 64-bit value.  crc32, however, returns 32 bits so the
177
	; following cast is safe.  'uInt' may be no more than 16 bits, so it is
178
	; necessary to perform a loop here.
179
180
 
181
	je .end_f
182
	cmp dword[length],0
183
	jle .end_f ;if (..!=0 && ..>0)
184
		mov eax,[edi+png_struct.crc] ;Should never issue a warning
185
186
 
187
			mov ebx,[length]
188
			mov [safe_length],ebx
189
;#ifndef __COVERITY__
190
;         if (safe_length == 0)
191
;            safe_length = (uInt)-1 ;evil, but safe
192
;end if
193
			stdcall [calc_crc32], eax, [ptr], [safe_length]
194
195
 
196
			; target system has characteristics that will probably violate other
197
			; assumptions within the libpng code.
198
199
 
200
			add [ptr],ebx
201
			sub [length],ebx
202
			cmp dword[length],0
203
		jg .cycle0 ;while (..>0)
204
205
 
206
		mov [edi+png_struct.crc],eax
207
	.end_f:
208
	ret
209
endp
210
211
 
212
; functions that create a png_struct.
213
214
 
215
align 4
216
proc png_user_version_check, png_ptr:dword, user_png_ver:dword
217
	; Libpng versions 1.0.0 and later are binary compatible if the version
218
	; string matches through the second '.'; we must recompile any
219
	; applications that use any older library version.
220
221
 
222
;   {
223
;      int i = -1;
224
;      int found_dots = 0;
225
226
 
227
;      {
228
;         i++;
229
;         if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i])
230
;            png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
231
;         if (user_png_ver[i] == '.')
232
;            found_dots++;
233
;      } while (found_dots < 2 && user_png_ver[i] != 0 &&
234
;            PNG_LIBPNG_VER_STRING[i] != 0);
235
;   }
236
237
 
238
;      png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
239
240
 
241
;   {
242
if PNG_WARNINGS_SUPPORTED eq 1
243
;      size_t pos = 0;
244
;      char m[128];
245
246
 
247
;          "Application built with libpng-");
248
;      pos = png_safecat(m, (sizeof m), pos, user_png_ver);
249
;      pos = png_safecat(m, (sizeof m), pos, " but running with ");
250
;      pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING);
251
252
 
253
end if
254
255
 
256
;      png_ptr->flags = 0;
257
end if
258
259
 
260
;   }
261
262
 
263
	xor eax,eax
264
	inc eax
265
.end_f:
266
	ret
267
endp
268
269
 
270
; contains the common initialization.
271
272
 
273
;    png_error_ptr error_fn, png_error_ptr warn_fn, voidp mem_ptr,
274
;    png_malloc_ptr malloc_fn, png_free_ptr free_fn)
275
align 4
276
proc png_create_png_struct uses ebx ecx edi esi, user_png_ver:dword, error_ptr:dword, error_fn:dword, warn_fn:dword, mem_ptr:dword, malloc_fn:dword, free_fn:dword
277
locals
278
if PNG_SETJMP_SUPPORTED eq 1
279
	create_jmp_buf dd ? ;jmp_buf
280
end if
281
	create_struct png_struct
282
endl
283
	; This temporary stack-allocated structure is used to provide a place to
284
	; build enough context to allow the user provided memory allocator (if any)
285
	; to be called.
286
287
 
288
	mov ecx,sizeof.png_struct
289
	mov edi,ebp
290
	sub edi,ecx
291
	mov ebx,edi
292
	rep stosb
293
294
 
295
if PNG_USER_LIMITS_SUPPORTED eq 1
296
	mov dword[ebx+png_struct.user_width_max], PNG_USER_WIDTH_MAX
297
	mov dword[ebx+png_struct.user_height_max], PNG_USER_HEIGHT_MAX
298
299
 
300
	mov dword[ebx+png_struct.user_chunk_cache_max], PNG_USER_CHUNK_CACHE_MAX
301
302
 
303
	; in png_struct regardless.
304
305
 
306
end if
307
308
 
309
	; to do them now even though error handling is not yet set up.
310
311
 
312
	stdcall png_set_mem_fn, ebx, [mem_ptr], [malloc_fn], [free_fn]
313
end if
314
315
 
316
	; this will result in a memory leak unless the error_fn does something
317
	; extremely sophisticated.  The design lacks merit but is implicit in the
318
	; API.
319
320
 
321
322
 
323
	stdcall setjmp,... ;create_jmp_buf
324
	cmp eax,0
325
	j... .end0 ;if (!setjmp(create_jmp_buf))
326
327
 
328
		; successfully completed this function.  This only works if we have
329
		; setjmp() support compiled in, but it is safe - this stuff should
330
		; never happen.
331
332
 
333
		mov dword[ebx+png_struct.jmp_buf_size],0 ;stack allocation
334
;         create_struct.longjmp_fn = longjmp;
335
end if
336
	; Call the general version checker (shared with read and write code):
337
338
 
339
		or eax,eax
8408 IgorA 340
		jz .end0 ;if (..!=0)
341
			stdcall png_malloc_warn, ebx, sizeof.png_struct
8341 dunkaist 342
			;eax = png_ptr
343
			or eax,eax
8408 IgorA 344
			jz .end0 ;if (..!=0)
345
				; png_ptr->zstream holds a back-pointer to the png_struct, so
8341 dunkaist 346
				; this can only be done now:
347
348
 
349
				mov [ebx+png_struct.zstream.zfree], png_zfree
350
				mov [ebx+png_struct.zstream.opaque], eax
351
352
 
353
				; Eliminate the local error handling:
354
				mov [ebx+png_struct.jmp_buf_ptr], 0
355
				mov [ebx+png_struct.jmp_buf_size], 0
356
				mov [ebx+png_struct.longjmp_fn], 0
357
end if
358
				mov ecx,sizeof.png_struct
359
				mov edi,eax
360
				mov esi,ebx
361
				rep movsb ;*png_ptr = create_struct
362
363
 
364
				jmp .end_f
365
	.end0:
366
367
 
368
	; simple failure to allocate the png_struct.
369
370
 
371
.end_f:
372
	ret
373
endp
374
375
 
376
;png_infop (png_structrp png_ptr)
377
align 4
378
proc png_create_info_struct uses ecx edi, png_ptr:dword
8408 IgorA 379
	png_debug 1, 'in png_create_info_struct'
8341 dunkaist 380
381
 
8408 IgorA 382
	or eax,eax
383
	jz .end_f ;if (..==0) return 0
384
8341 dunkaist 385
 
386
	; that this call always returns ok.  The application typically sets up the
387
	; error handling *after* creating the info_struct because this is the way it
388
	; has always been done in 'example.asm'.
389
390
 
8408 IgorA 391
	or eax,eax
392
	jz .end_f
393
		push eax
394
		mov edi,eax
8341 dunkaist 395
		xor eax,eax
396
		mov ecx,sizeof.png_info_def
397
		rep stosb ;memset(...
398
		pop eax
8408 IgorA 399
.end_f:
8341 dunkaist 400
	ret
401
endp
402
403
 
404
; Normally, one would use either png_destroy_read_struct() or
405
; png_destroy_write_struct() to free an info struct, but this may be
406
; useful for some applications.  From libpng 1.6.0 this function is also used
407
; internally to implement the png_info release part of the 'struct' destroy
408
; APIs.  This ensures that all possible approaches free the same data (all of
409
; it).
410
411
 
412
align 4
413
proc png_destroy_info_struct uses eax ebx ecx edi, png_ptr:dword, info_ptr_ptr:dword
414
	png_debug 1, 'in png_destroy_info_struct'
415
416
 
417
	je .end_f ;if (..==0) return
418
419
 
420
	or edi,edi ;if (..!=0)
8408 IgorA 421
	jz .end_f
422
		; Do this first in case of an error below; if the app implements its own
8341 dunkaist 423
		; memory management this can lead to png_free calling png_error, which
424
		; will abort this routine and return control to the app error handler.
425
		; An infinite loop may result if it then tries to free the same info
426
		; ptr.
427
428
 
429
430
 
431
		mov ebx,edi
432
		xor eax,eax
433
		mov ecx,sizeof.png_info_def
434
		rep stosb
435
		stdcall png_free, [png_ptr], ebx
436
	.end_f:
437
	ret
438
endp
439
440
 
441
; and applications using it are urged to use png_create_info_struct()
442
; instead.  Use deprecated in 1.6.0, internal use removed (used internally it
443
; is just a memset).
444
445
 
446
; the user-memory mechanism and the user error handling/warning mechanisms in
447
; those cases where it does anything other than a memset.
448
449
 
450
align 4
451
proc png_info_init_3, ptr_ptr:dword, png_info_struct_size:dword
452
;   png_inforp info_ptr = *ptr_ptr;
453
454
 
455
456
 
457
;      return;
458
459
 
460
;   {
461
;      *ptr_ptr = NULL;
462
	; The following line is why this API should not be used:
463
;      free(info_ptr);
464
;      info_ptr = png_malloc_base(NULL, (sizeof *info_ptr));
465
;      if (info_ptr == NULL)
466
;         return;
467
;      *ptr_ptr = info_ptr;
468
;   }
469
470
 
471
;   memset(info_ptr, 0, (sizeof *info_ptr));
472
	ret
473
endp
474
475
 
476
;void (png_structrp png_ptr, png_inforp info_ptr, int freer, uint_32 mask)
477
align 4
478
proc png_data_freer uses edi esi, png_ptr:dword, info_ptr:dword, freer:dword, mask:dword
479
	png_debug 1, 'in png_data_freer'
480
481
 
482
	or edi,edi
8408 IgorA 483
	jz .end_f
484
	mov esi,[info_ptr]
8341 dunkaist 485
	or esi,esi
8408 IgorA 486
	jz .end_f ;if (..==0 || ..==0) return
487
8341 dunkaist 488
 
489
;      info_ptr->free_me |= mask;
490
491
 
492
;      info_ptr->free_me &= ~mask;
493
494
 
495
;      png_error(png_ptr, "Unknown freer parameter in png_data_freer");
496
.end_f
497
	ret
498
endp
499
500
 
501
align 4
502
proc png_free_data uses eax edi esi, png_ptr:dword, info_ptr:dword, mask:dword, num:dword
503
	png_debug 1, 'in png_free_data'
504
505
 
506
	or edi,edi
8408 IgorA 507
	jz .end_f
508
	mov esi,[info_ptr]
8341 dunkaist 509
	or esi,esi
8408 IgorA 510
	jz .end_f ;if (..==0 || ..==0) return
511
8341 dunkaist 512
 
513
	; Free text item num or (if num == -1) all text items
514
;   if (info_ptr->text != 0 &&
515
;       ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0)
516
;   {
517
;      if (num != -1)
518
;      {
519
;         png_free(png_ptr, info_ptr->text[num].key);
520
;         info_ptr->text[num].key = NULL;
521
;      }
522
523
 
524
;      {
525
;         int i;
526
527
 
528
;            png_free(png_ptr, info_ptr->text[i].key);
529
530
 
531
;         info_ptr->text = NULL;
532
;         info_ptr->num_text = 0;
533
;      }
534
;   }
535
end if
536
537
 
538
	; Free any tRNS entry
539
	mov eax,[mask]
540
	and eax,PNG_FREE_TRNS
541
	and eax,[esi+png_info_def.free_me]
542
	jz @f ;if (..!=0)
543
		and dword[esi+png_info_def.valid], not PNG_INFO_tRNS
544
		stdcall png_free, edi, [esi+png_info_def.trans_alpha]
545
		mov dword[esi+png_info_def.trans_alpha],0
546
		mov word[esi+png_info_def.num_trans],0
547
	@@:
548
end if
549
550
 
551
	; Free any sCAL entry
552
	mov eax,[mask]
553
	and eax,PNG_FREE_SCAL
554
	and eax,[esi+png_info_def.free_me]
555
	jz @f ;if (..!=0)
556
		stdcall png_free, edi, [esi+png_info_def.scal_s_width]
557
		stdcall png_free, edi, [esi+png_info_def.scal_s_height]
558
		mov dword[esi+png_info_def.scal_s_width],0
559
		mov dword[esi+png_info_def.scal_s_height],0
560
		and dword[esi+png_info_def.valid], not PNG_INFO_sCAL
561
	@@:
562
end if
563
564
 
565
	; Free any pCAL entry
566
;   if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0)
567
;   {
568
;      png_free(png_ptr, info_ptr->pcal_purpose);
569
;      png_free(png_ptr, info_ptr->pcal_units);
570
;      info_ptr->pcal_purpose = NULL;
571
;      info_ptr->pcal_units = NULL;
572
573
 
574
;         {
575
;            int i;
576
577
 
578
;               png_free(png_ptr, info_ptr->pcal_params[i]);
579
;
580
;            png_free(png_ptr, info_ptr->pcal_params);
581
;            info_ptr->pcal_params = NULL;
582
;         }
583
;      info_ptr->valid &= ~PNG_INFO_pCAL;
584
;   }
585
end if
586
587
 
588
	; Free any profile entry
589
	mov eax,[mask]
590
	and eax,PNG_FREE_ICCP
591
	and eax,[esi+png_info_def.free_me]
592
	jz @f ;if (..!=0)
593
		stdcall png_free, edi, [esi+png_info_def.iccp_name]
594
		stdcall png_free, edi, [esi+png_info_def.iccp_profile]
595
		mov dword[esi+png_info_def.iccp_name],0
596
		mov dword[esi+png_info_def.iccp_profile],0
597
		and dword[esi+png_info_def.valid], not PNG_INFO_iCCP
598
	@@:
599
end if
600
601
 
602
	; Free a given sPLT entry, or (if num == -1) all sPLT entries
603
;   if (info_ptr->splt_palettes != 0 &&
604
;       ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0)
605
;   {
606
;      if (num != -1)
607
;      {
608
;         png_free(png_ptr, info_ptr->splt_palettes[num].name);
609
;         png_free(png_ptr, info_ptr->splt_palettes[num].entries);
610
;         info_ptr->splt_palettes[num].name = NULL;
611
;         info_ptr->splt_palettes[num].entries = NULL;
612
;      }
613
614
 
615
;      {
616
;         int i;
617
618
 
619
;         {
620
;            png_free(png_ptr, info_ptr->splt_palettes[i].name);
621
;            png_free(png_ptr, info_ptr->splt_palettes[i].entries);
622
;         }
623
624
 
625
;         info_ptr->splt_palettes = NULL;
626
;         info_ptr->splt_palettes_num = 0;
627
;         info_ptr->valid &= ~PNG_INFO_sPLT;
628
;      }
629
;   }
630
end if
631
632
 
633
;   if (info_ptr->unknown_chunks != 0 &&
634
;       ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0)
635
;   {
636
;      if (num != -1)
637
;      {
638
;          png_free(png_ptr, info_ptr->unknown_chunks[num].data);
639
;          info_ptr->unknown_chunks[num].data = NULL;
640
;      }
641
642
 
643
;      {
644
;         int i;
645
646
 
647
;            png_free(png_ptr, info_ptr->unknown_chunks[i].data);
648
649
 
650
;         info_ptr->unknown_chunks = NULL;
651
;         info_ptr->unknown_chunks_num = 0;
652
;      }
653
;   }
654
end if
655
656
 
657
	; Free any hIST entry
658
	mov eax,[mask]
659
	and eax,PNG_FREE_HIST
660
	and eax,[esi+png_info_def.free_me]
661
	jz @f ;if (..!=0)
662
		stdcall png_free, edi, [esi+png_info_def.hist]
663
		mov dword[esi+png_info_def.hist],0
664
		and dword[esi+png_info_def.valid], not PNG_INFO_hIST
665
	@@:
666
end if
667
668
 
669
	mov eax,[mask]
670
	and eax,PNG_FREE_PLTE
671
	and eax,[esi+png_info_def.free_me]
672
	jz @f ;if (..!=0)
673
		stdcall png_free, edi, [esi+png_info_def.palette]
674
		mov dword[esi+png_info_def.palette],0
675
		and dword[esi+png_info_def.valid],not PNG_INFO_PLTE
676
		mov dword[esi+png_info_def.num_palette],0
677
	@@:
678
679
 
680
	; Free any image bits attached to the info structure
681
;   if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0)
682
;   {
683
;      if (info_ptr->row_pointers != 0)
684
;      {
685
;         uint_32 row;
686
;         for (row = 0; row < info_ptr->height; row++)
687
;            png_free(png_ptr, info_ptr->row_pointers[row]);
688
689
 
690
;         info_ptr->row_pointers = NULL;
691
;      }
692
;      info_ptr->valid &= ~PNG_INFO_IDAT;
693
;   }
694
end if
695
696
 
697
;      mask &= ~PNG_FREE_MUL;
698
699
 
700
	not eax
701
	and [esi+png_info_def.free_me],eax
702
.end_f:
703
	ret
704
endp
705
706
 
707
; functions.  The application should free any memory associated with this
708
; pointer before png_write_destroy() or png_read_destroy() are called.
709
710
 
711
align 4
712
proc png_get_io_ptr, png_ptr:dword
713
	mov eax,[png_ptr]
714
	or eax,eax
8408 IgorA 715
	jz @f ;if (..==0) return 0
716
		mov eax,[eax+png_struct.io_ptr]
8341 dunkaist 717
	@@:
718
	ret
719
endp
720
721
 
722
; Initialize the default input/output functions for the PNG file.  If you
723
; use your own read or write routines, you can call either png_set_read_fn()
724
; or png_set_write_fn() instead of png_init_io().  If you have defined
725
; PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a
726
; function of your own because "FILE *" isn't necessarily available.
727
728
 
729
align 4
730
proc png_init_io uses eax edi, png_ptr:dword, fp:dword
731
	png_debug 1, 'in png_init_io'
732
733
 
734
	or edi,edi
8408 IgorA 735
	jz @f ;if (..==0) return
736
		mov eax,[fp]
8341 dunkaist 737
		mov [edi+png_struct.io_ptr],eax
738
	@@:
739
	ret
740
endp
741
742
 
743
; defines a cast of a signed integer to an unsigned integer either to preserve
744
; the value, if it is positive, or to calculate:
745
746
 
747
748
 
749
; negative integral value is added the result will be an unsigned value
750
; correspnding to the 2's complement representation.
751
752
 
753
align 4
754
proc png_save_int_32, buf:dword, i:dword
755
	stdcall png_save_uint_32, [buf], [i]
756
	ret
757
endp
758
759
 
760
; Convert the supplied time into an RFC 1123 string suitable for use in
761
; a "Creation Time" or other text-based time string.
762
763
 
764
align 4
765
short_months db 'Jan',0, 'Feb',0, 'Mar',0, 'Apr',0, 'May',0, 'Jun',0,\
766
	'Jul',0, 'Aug',0, 'Sep',0, 'Oct',0, 'Nov',0, 'Dec',0
767
768
 
769
proc png_convert_to_rfc1123_buffer, out_29:dword, ptime:dword
770
	cmp dword[out_29],0
771
	jne @f
772
		xor eax,eax
773
		jmp .end_f ;if (..==0) return 0
774
	@@:
775
776
 
777
;       ptime->month == 0    ||  ptime->month > 12  ||
778
;       ptime->day   == 0    ||  ptime->day   > 31  ||
779
;       ptime->hour  > 23    ||  ptime->minute > 59 ||
780
;       ptime->second > 60)
781
;      return 0;
782
783
 
784
;      size_t pos = 0;
785
;      char number_buf[5]; /* enough for a four-digit year */
786
787
 
788
;#     define APPEND_NUMBER(format, value)\
789
;         APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value)))
790
;#     define APPEND(ch) if (pos < 28) out_29[pos++] = (ch)
791
792
 
793
;      APPEND(' ');
794
;      APPEND_STRING(short_months[(ptime->month - 1)]);
795
;      APPEND(' ');
796
;      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year);
797
;      APPEND(' ');
798
;      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour);
799
;      APPEND(':');
800
;      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute);
801
;      APPEND(':');
802
;      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second);
803
;      APPEND_STRING(" +0000"); /* This reliably terminates the buffer */
804
805
 
806
;#     undef APPEND_NUMBER
807
;#     undef APPEND_STRING
808
;   }
809
810
 
811
	inc eax
812
.end_f:
813
	ret
814
endp
815
816
 
817
; To do: remove the following from libpng-1.7
818
; Original API that uses a private buffer in png_struct.
819
; Deprecated because it causes png_struct to carry a spurious temporary
820
; buffer (png_struct::time_buffer), better to have the caller pass this in.
821
822
 
823
align 4
824
proc png_convert_to_rfc1123, png_ptr:dword, ptime:dword
825
;   if (png_ptr != NULL)
826
;   {
827
	; The only failure above if png_ptr != NULL is from an invalid ptime
828
;      if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0)
829
;         png_warning(png_ptr, "Ignoring invalid time value");
830
831
 
832
;         return png_ptr->time_buffer;
833
;   }
834
835
 
836
	ret
837
endp
838
;#    endif /* LIBPNG_VER < 10700 */
839
;#  endif /* TIME_RFC1123 */
840
841
 
842
843
 
844
align 4
845
proc png_get_copyright, png_ptr:dword
846
jmp .end_0
847
@@: db 'libpng version 1.6.25 - September 1, 2016',13,10,\
848
	'      Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson',13,10,\
849
	'      Copyright (c) 1996-1997 Andreas Dilger',13,10,\
850
	'      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.',0
851
.end_0:
852
	mov eax,@b
853
	ret
854
endp
855
856
 
857
; format 1.0.0 through 99.99.99zz.  To get the version of *.inc files
858
; used with your application, print out PNG_LIBPNG_VER_STRING, which
859
; is defined in png.inc.
860
; Note: now there is no difference between png_get_libpng_ver() and
861
; png_get_header_ver().  Due to the version_nn_nn_nn typedef guard,
862
; it is guaranteed that png.asm uses the correct version of png.inc.
863
864
 
865
align 4
866
proc png_get_libpng_ver, png_ptr:dword
867
	; Version of *.asm files used when building libpng
868
;   return png_get_header_ver(png_ptr);
869
	ret
870
endp
871
872
 
873
align 4
874
proc png_get_header_ver, png_ptr:dword
875
	; Version of *.inc files used when building libpng
876
;   return PNG_LIBPNG_VER_STRING;
877
	ret
878
endp
879
880
 
881
align 4
882
proc png_get_header_version, png_ptr:dword
883
	; Returns longer string containing both version and date
884
;if __STDC__
885
;   return PNG_HEADER_VERSION_STRING
886
;#  ifndef PNG_READ_SUPPORTED
887
;      " (NO READ SUPPORT)"
888
;#  endif
889
;      PNG_STRING_NEWLINE;
890
;#else
891
;   return PNG_HEADER_VERSION_STRING;
892
;end if
893
	ret
894
endp
895
896
 
897
; Build a grayscale palette.  Palette is assumed to be 1 << bit_depth
898
; large of png_color.  This lets grayscale images be treated as
899
; paletted.  Most useful for gamma correction and simplification
900
; of code.  This API is not used internally.
901
902
 
903
align 4
904
proc png_build_grayscale_palette, bit_depth:dword, palette:dword
905
;   int num_palette;
906
;   int color_inc;
907
;   int i;
908
;   int v;
909
910
 
911
912
 
913
;      return;
914
915
 
916
;   {
917
;      case 1:
918
;         num_palette = 2;
919
;         color_inc = 0xff;
920
;         break;
921
;
922
;      case 2:
923
;         num_palette = 4;
924
;         color_inc = 0x55;
925
;         break;
926
;
927
;      case 4:
928
;         num_palette = 16;
929
;         color_inc = 0x11;
930
;         break;
931
;
932
;      case 8:
933
;         num_palette = 256;
934
;         color_inc = 1;
935
;         break;
936
;
937
;      default:
938
;         num_palette = 0;
939
;         color_inc = 0;
940
;         break;
941
;   }
942
;
943
;   for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
944
;   {
945
;      palette[i].red = (byte)(v & 0xff);
946
;      palette[i].green = (byte)(v & 0xff);
947
;      palette[i].blue = (byte)(v & 0xff);
948
;   }
949
	ret
950
endp
951
952
 
953
align 4
954
proc png_handle_as_unknown uses ecx edi esi, png_ptr:dword, chunk_name:dword
955
	; Check chunk_name and return "keep" value if it's on the list, else 0
956
;   bytep p, p_end;
957
958
 
959
	or edi,edi
8408 IgorA 960
	jz .end0
961
	cmp dword[chunk_name],0
8341 dunkaist 962
	je .end0
963
	cmp dword[edi+png_struct.num_chunk_list],0
964
	je .end0
965
		jmp @f
966
	.end0: ;if (..==0 || ..==0 || ..==0)
967
		mov eax,PNG_HANDLE_CHUNK_AS_DEFAULT
968
		jmp .end_f
969
	@@:
970
971
 
972
;   p = p_end + png_ptr->num_chunk_list*5; /* beyond end */
973
974
 
975
	; code was always searched from the end of the list, this is no longer
976
	; necessary because the 'set' routine handles duplicate entries correcty.
977
978
 
979
;   {
980
;      p -= 5;
981
982
 
983
;         return p[4];
984
;   }
985
;   while (p > p_end);
986
987
 
988
	; be handled according to the value of png_ptr->unknown_default; this can be
989
	; confusing because, as a result, there are two levels of defaulting for
990
	; unknown chunks.
991
992
 
993
.end_f:
994
	ret
995
endp
996
997
 
998
align 4
999
proc png_chunk_unknown_handling, png_ptr:dword, chunk_name:dword
1000
;   byte chunk_string[5];
1001
1002
 
1003
;   return png_handle_as_unknown(png_ptr, chunk_string);
1004
	ret
1005
endp
1006
1007
 
1008
;int (png_structrp png_ptr)
1009
align 4
1010
proc png_reset_zstream, png_ptr:dword
1011
	mov eax,[png_ptr]
1012
	or eax,eax
8408 IgorA 1013
	jnz @f ;if (..==0)
1014
		mov eax,Z_STREAM_ERROR
8341 dunkaist 1015
		jmp .end_f
1016
	@@:
1017
	; WARNING: this resets the window bits to the maximum!
1018
	add eax,png_struct.zstream
1019
	stdcall inflateReset,eax
1020
.end_f:
1021
	ret
1022
endp
1023
1024
 
1025
;uint_32 png_access_version_number(void)
1026
align 4
1027
png_access_version_number:
1028
	; Version of *.asm files used when building libpng
1029
	mov eax,PNG_LIBPNG_VER
1030
	ret
1031
1032
 
1033
; Ensure that png_ptr->zstream.msg holds some appropriate error message string.
1034
; If it doesn't 'ret' is used to set it to something appropriate, even in cases
1035
; like Z_OK or Z_STREAM_END where the error code is apparently a success code.
1036
1037
 
1038
align 4
1039
proc png_zstream_error uses eax edi, png_ptr:dword, p2ret:dword
1040
	; Translate 'p2ret' into an appropriate error string, priority is given to the
1041
	; one in zstream if set.  This always returns a string, even in cases like
1042
	; Z_OK or Z_STREAM_END where the error code is a success code.
1043
1044
 
1045
	cmp dword[edi+png_struct.zstream.msg],0
1046
	jne .end_f ;if (..==0) switch (p2ret)
1047
		mov eax,[p2ret]
1048
;      default:
1049
		cmp eax,Z_OK
1050
		jne @f
1051
			cStr dword[edi+png_struct.zstream.msg],'unexpected zlib return code'
1052
			jmp .end_f
1053
		@@:
1054
		cmp eax,Z_STREAM_END
1055
		jne @f
1056
			; Normal exit
1057
			cStr dword[edi+png_struct.zstream.msg],'unexpected end of LZ stream'
1058
			jmp .end_f
1059
		@@:
1060
		cmp eax,Z_NEED_DICT
1061
		jne @f
1062
			; This means the deflate stream did not have a dictionary; this
1063
			; indicates a bogus PNG.
1064
1065
 
1066
			jmp .end_f
1067
		@@:
1068
		cmp eax,Z_ERRNO
1069
		jne @f
1070
			; gz APIs only: should not happen
1071
			cStr dword[edi+png_struct.zstream.msg],'zlib IO error'
1072
			jmp .end_f
1073
		@@:
1074
		cmp eax,Z_STREAM_ERROR
1075
		jne @f
1076
			; internal libpng error
1077
			cStr dword[edi+png_struct.zstream.msg],'bad parameters to zlib'
1078
			jmp .end_f
1079
		@@:
1080
		cmp eax,Z_DATA_ERROR
1081
		jne @f
1082
			cStr dword[edi+png_struct.zstream.msg],'damaged LZ stream'
1083
			jmp .end_f
1084
		@@:
1085
		cmp eax,Z_MEM_ERROR
1086
		jne @f
1087
			cStr dword[edi+png_struct.zstream.msg],'insufficient memory'
1088
			jmp .end_f
1089
		@@:
1090
		cmp eax,Z_BUF_ERROR
1091
		jne @f
1092
			; End of input or output; not a problem if the caller is doing
1093
			; incremental read or write.
1094
1095
 
1096
			jmp .end_f
1097
		@@:
1098
		cmp eax,Z_VERSION_ERROR
1099
		jne @f
1100
			cStr dword[edi+png_struct.zstream.msg],'unsupported zlib version'
1101
			jmp .end_f
1102
		@@:
1103
		cmp eax,PNG_UNEXPECTED_ZLIB_RETURN
1104
		jne .end_f
1105
			; Compile errors here mean that zlib now uses the value co-opted in
1106
			; pngpriv.inc for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above
1107
			; and change pngpriv.inc.  Note that this message is "... return",
1108
			; whereas the default/Z_OK one is "... return code".
1109
1110
 
1111
;         break;
1112
.end_f:
1113
	ret
1114
endp
1115
1116
 
1117
; at libpng 1.5.5!
1118
1119
 
1120
 
1121
;if PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */
1122
;int (png_structrp png_ptr,
1123
;    png_colorspacerp colorspace, png_fixed_point gAMA, int from)
1124
	; This is called to check a new gamma value against an existing one.  The
1125
	; routine returns false if the new gamma value should not be written.
1126
	;
1127
	; 'from' says where the new gamma value comes from:
1128
	;
1129
	;    0: the new gamma value is the libpng estimate for an ICC profile
1130
	;    1: the new gamma value comes from a gAMA chunk
1131
	;    2: the new gamma value comes from an sRGB chunk
1132
1133
 
1134
proc png_colorspace_check_gamma, png_ptr:dword, colorspace:dword, gAMA:dword, from:dword
1135
;   png_fixed_point gtest;
1136
;
1137
;   if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
1138
;       (png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) == 0  ||
1139
;      png_gamma_significant(gtest) != 0))
1140
;   {
1141
	; Either this is an sRGB image, in which case the calculated gamma
1142
	; approximation should match, or this is an image with a profile and the
1143
	; value libpng calculates for the gamma of the profile does not match the
1144
	; value recorded in the file.  The former, sRGB, case is an error, the
1145
	; latter is just a warning.
1146
1147
 
1148
;      {
1149
;         png_chunk_report(png_ptr, "gamma value does not match sRGB",
1150
;             PNG_CHUNK_ERROR);
1151
;         /* Do not overwrite an sRGB value */
1152
;         return from == 2;
1153
;      }
1154
1155
 
1156
;      {
1157
;         png_chunk_report(png_ptr, "gamma value does not match libpng estimate",
1158
;             PNG_CHUNK_WARNING);
1159
;         return from == 1;
1160
;      }
1161
;   }
1162
1163
 
1164
	ret
1165
endp
1166
1167
 
1168
align 4
1169
proc png_colorspace_set_gamma, png_ptr:dword, colorspace:dword, gAMA:dword
1170
	; Changed in libpng-1.5.4 to limit the values to ensure overflow can't
1171
	; occur.  Since the fixed point representation is asymetrical it is
1172
	; possible for 1/gamma to overflow the limit of 21474 and this means the
1173
	; gamma value must be at least 5/100000 and hence at most 20000.0.  For
1174
	; safety the limits here are a little narrower.  The values are 0.00016 to
1175
	; 6250.0, which are truly ridiculous gamma values (and will produce
1176
	; displays that are all black or all white.)
1177
1178
 
1179
	; handling code, which only required the value to be >0.
1180
1181
 
1182
1183
 
1184
;      errmsg = "gamma value out of range";
1185
1186
 
1187
	; Allow the application to set the gamma value more than once
1188
;   else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
1189
;      (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0)
1190
;      errmsg = "duplicate";
1191
;#  endif
1192
1193
 
1194
;   else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
1195
;      return;
1196
1197
 
1198
;   {
1199
;      if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA,
1200
;          1/*from gAMA*/) != 0)
1201
;      {
1202
;         /* Store this gamma value. */
1203
;         colorspace->gamma = gAMA;
1204
;         colorspace->flags |=
1205
;            (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA);
1206
;      }
1207
1208
 
1209
	; not updated however the colorspace is not invalidated.  This
1210
	; corresponds to the case where the existing gamma comes from an sRGB
1211
	; chunk or profile.  An error message has already been output.
1212
1213
 
1214
;   }
1215
1216
 
1217
;   colorspace->flags |= PNG_COLORSPACE_INVALID;
1218
;   png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);
1219
.end_f:
1220
	ret
1221
endp
1222
1223
 
1224
align 4
1225
proc png_colorspace_sync_info uses eax esi, png_ptr:dword, info_ptr:dword
1226
	mov esi,[info_ptr]
1227
	mov ax,[esi+png_info_def.colorspace.flags]
1228
	and ax,PNG_COLORSPACE_INVALID
1229
	cmp ax,0
1230
	je @f ;if (..!=0)
1231
		; Everything is invalid
1232
		and dword[esi+png_info_def.valid], not (PNG_INFO_gAMA or PNG_INFO_cHRM or PNG_INFO_sRGB or PNG_INFO_iCCP)
1233
1234
 
1235
		; Clean up the iCCP profile now if it won't be used.
1236
		stdcall png_free_data, [png_ptr], esi, PNG_FREE_ICCP, -1 ;not used
1237
end if
1238
		jmp .end0
1239
	@@: ;else
1240
if PNG_COLORSPACE_SUPPORTED eq 1
1241
		; Leave the INFO_iCCP flag set if the pngset.c code has already set
1242
		; it; this allows a PNG to contain a profile which matches sRGB and
1243
		; yet still have that profile retrievable by the application.
1244
1245
 
1246
		and ax,PNG_COLORSPACE_MATCHES_sRGB
1247
		cmp ax,0
1248
		je @f ;if (..!=0)
1249
			or dword[esi+png_info_def.valid], PNG_INFO_sRGB
1250
			jmp .end1
1251
		@@: ;else
1252
			and dword[esi+png_info_def.valid], not PNG_INFO_sRGB
1253
		.end1:
1254
		mov ax,[esi+png_info_def.colorspace.flags]
1255
		and ax,PNG_COLORSPACE_HAVE_ENDPOINTS
1256
		cmp ax,0
1257
		je @f ;if (..!=0)
1258
			or dword[esi+png_info_def.valid], PNG_INFO_cHRM
1259
			jmp .end2
1260
		@@: ;else
1261
			and dword[esi+png_info_def.valid], not PNG_INFO_cHRM
1262
		.end2:
1263
end if
1264
1265
 
1266
		and ax,PNG_COLORSPACE_HAVE_GAMMA
1267
		cmp ax,0
1268
		je @f ;if (..!=0)
1269
			or dword[esi+png_info_def.valid], PNG_INFO_gAMA
1270
			jmp .end0
1271
		@@: ;else
1272
			and dword[esi+png_info_def.valid], not PNG_INFO_gAMA
1273
	.end0:
1274
	ret
1275
endp
1276
1277
 
1278
align 4
1279
proc png_colorspace_sync uses ecx edi esi, png_ptr:dword, info_ptr:dword
1280
	mov edi,[info_ptr]
1281
	or edi,edi
8408 IgorA 1282
	jz @f ;if (..==0) ;reduce code size; check here not in the caller
1283
		mov ecx,sizeof.png_colorspace
8341 dunkaist 1284
		mov esi,[png_ptr]
1285
		add esi,png_struct.colorspace
1286
		add edi,png_info_def.colorspace
1287
		rep movsb
1288
		stdcall png_colorspace_sync_info, [png_ptr], [info_ptr]
1289
	@@:
1290
	ret
1291
endp
1292
1293
 
1294
1295
 
1296
; Added at libpng-1.5.5 to support read and write of true CIEXYZ values for
1297
; cHRM, as opposed to using chromaticities.  These internal APIs return
1298
; non-zero on a parameter error.  The X, Y and Z values are required to be
1299
; positive and less than 1.0.
1300
1301
 
1302
align 4
1303
proc png_xy_from_XYZ, xy:dword, XYZ:dword
1304
;   int_32 d, dwhite, whiteX, whiteY;
1305
1306
 
1307
;   if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0)
1308
;      return 1;
1309
;   if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0)
1310
;      return 1;
1311
;   dwhite = d;
1312
;   whiteX = XYZ->red_X;
1313
;   whiteY = XYZ->red_Y;
1314
1315
 
1316
;   if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0)
1317
;      return 1;
1318
;   if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0)
1319
;      return 1;
1320
;   dwhite += d;
1321
;   whiteX += XYZ->green_X;
1322
;   whiteY += XYZ->green_Y;
1323
1324
 
1325
;   if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0)
1326
;      return 1;
1327
;   if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0)
1328
;      return 1;
1329
;   dwhite += d;
1330
;   whiteX += XYZ->blue_X;
1331
;   whiteY += XYZ->blue_Y;
1332
1333
 
1334
	; thus:
1335
1336
 
1337
;      return 1;
1338
;   if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0)
1339
;      return 1;
1340
1341
 
1342
	ret
1343
endp
1344
1345
 
1346
align 4
1347
proc png_XYZ_from_xy, XYZ:dword, xy:dword
1348
;   png_fixed_point red_inverse, green_inverse, blue_scale;
1349
;   png_fixed_point left, right, denominator;
1350
1351
 
1352
	; have end points with 0 tristimulus values (these are impossible end
1353
	; points, but they are used to cover the possible colors).  We check
1354
	; xy->whitey against 5, not 0, to avoid a possible integer overflow.
1355
1356
 
1357
;   if (xy->redy   < 0 || xy->redy > PNG_FP_1-xy->redx) return 1;
1358
;   if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1;
1359
;   if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1;
1360
;   if (xy->bluex  < 0 || xy->bluex > PNG_FP_1) return 1;
1361
;   if (xy->bluey  < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1;
1362
;   if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1;
1363
;   if (xy->whitey < 5 || xy->whitey > PNG_FP_1-xy->whitex) return 1;
1364
1365
 
1366
	; value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8
1367
	; derived values were recorded in the cHRM chunk;
1368
	; (red,green,blue,white)x(x,y).  This loses one degree of freedom and
1369
	; therefore an arbitrary ninth value has to be introduced to undo the
1370
	; original transformations.
1371
1372
 
1373
	; chromaticity values (c) have the property:
1374
1375
 
1376
	;   c = ---------
1377
	;       X + Y + Z
1378
1379
 
1380
	; three chromaticity values (x,y,z) for each end-point obey the
1381
	; relationship:
1382
1383
 
1384
1385
 
1386
	; value 1.0; call this the chromaticity plane.  Thus the chromaticity
1387
	; calculation has scaled each end-point so that it is on the x+y+z=1 plane
1388
	; and chromaticity is the intersection of the vector from the origin to the
1389
	; (X,Y,Z) value with the chromaticity plane.
1390
1391
 
1392
	; end-point scale factors, (red-scale, green-scale, blue-scale), but these
1393
	; were not recorded.  Instead we calculated the reference white (X,Y,Z) and
1394
	; recorded the chromaticity of this.  The reference white (X,Y,Z) would have
1395
	; given all three of the scale factors since:
1396
1397
 
1398
	;    white-C = red-C + green-C + blue-C
1399
	;            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
1400
1401
 
1402
	; factor:
1403
1404
 
1405
1406
 
1407
	; about white-scale:
1408
1409
 
1410
	;    Hence:  white-scale = 1/white-y
1411
	;    Or:     red-Y + green-Y + blue-Y = 1.0
1412
1413
 
1414
	; the nine values we want to calculate.  8 more equations come from the
1415
	; above routine as summarised at the top above (the chromaticity
1416
	; calculation):
1417
1418
 
1419
	;    Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0
1420
1421
 
1422
	; solved by Cramer's rule.  Cramer's rule requires calculating 10 9x9 matrix
1423
	; determinants, however this is not as bad as it seems because only 28 of
1424
	; the total of 90 terms in the various matrices are non-zero.  Nevertheless
1425
	; Cramer's rule is notoriously numerically unstable because the determinant
1426
	; calculation involves the difference of large, but similar, numbers.  It is
1427
	; difficult to be sure that the calculation is stable for real world values
1428
	; and it is certain that it becomes unstable where the end points are close
1429
	; together.
1430
1431
 
1432
	; understandable and totally obvious approach of calculating color-scale.
1433
1434
 
1435
	; (1/white-y), so we can immediately see that as white-y approaches 0 the
1436
	; accuracy inherent in the cHRM chunk drops off substantially.
1437
1438
 
1439
	; ------------------------------------------------------------
1440
1441
 
1442
	;    white-X = white-x * white-scale
1443
	;    white-Y = 1.0
1444
	;    white-Z = (1 - white-x - white-y) * white_scale
1445
1446
 
1447
	;            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
1448
1449
 
1450
	; all the coefficients are now known:
1451
1452
 
1453
	;       = white-x/white-y
1454
	;    red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1
1455
	;    red-z*red-scale + green-z*green-scale + blue-z*blue-scale
1456
	;       = (1 - white-x - white-y)/white-y
1457
1458
 
1459
	; three equations together to get an alternative third:
1460
1461
 
1462
1463
 
1464
	; 3x3 - far more tractible.  Unfortunately 3x3 determinants still involve
1465
	; multiplication of three coefficients so we can't guarantee to avoid
1466
	; overflow in the libpng fixed point representation.  Using Cramer's rule in
1467
	; floating point is probably a good choice here, but it's not an option for
1468
	; fixed point.  Instead proceed to simplify the first two equations by
1469
	; eliminating what is likely to be the largest value, blue-scale:
1470
1471
 
1472
1473
 
1474
1475
 
1476
	;                (white-x - blue-x)*white-scale
1477
1478
 
1479
	;                1 - blue-y*white-scale
1480
1481
 
1482
1483
 
1484
	;                (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale
1485
	;                -----------------------------------------------------------
1486
	;                                  green-x - blue-x
1487
1488
 
1489
	;                1 - blue-y*white-scale - (green-y - blue-y) * green-scale
1490
	;                ---------------------------------------------------------
1491
	;                                  red-y - blue-y
1492
1493
 
1494
1495
 
1496
	;          ( (green-x - blue-x) * (white-y - blue-y) -
1497
	;            (green-y - blue-y) * (white-x - blue-x) ) / white-y
1498
	; -------------------------------------------------------------------------
1499
	;  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
1500
1501
 
1502
	;          ( (red-y - blue-y) * (white-x - blue-x) -
1503
	;            (red-x - blue-x) * (white-y - blue-y) ) / white-y
1504
	; -------------------------------------------------------------------------
1505
	;  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
1506
1507
 
1508
	; The input values have 5 decimal digits of accuracy.  The values are all in
1509
	; the range 0 < value < 1, so simple products are in the same range but may
1510
	; need up to 10 decimal digits to preserve the original precision and avoid
1511
	; underflow.  Because we are using a 32-bit signed representation we cannot
1512
	; match this; the best is a little over 9 decimal digits, less than 10.
1513
1514
 
1515
	; signed representation.  Because the red-scale calculation above uses the
1516
	; difference between two products of values that must be in the range -1..+1
1517
	; it is sufficient to divide the product by 7; ceil(100,000/32767*2).  The
1518
	; factor is irrelevant in the calculation because it is applied to both
1519
	; numerator and denominator.
1520
1521
 
1522
	; chromaticities in the above equations tend to be small, for example for
1523
	; the sRGB chromaticities they are:
1524
1525
 
1526
	; green numerator:  -0.08788
1527
	; denominator:      -0.2241 (without white-y multiplication)
1528
1529
 
1530
	;  color space definitions are (to 15 decimal places):
1531
1532
 
1533
	;    0.212639005871510 0.715168678767756 0.072192315360734
1534
	;  Kodak ProPhoto
1535
	;    0.288071128229293 0.711843217810102 0.000085653960605
1536
	;  Adobe RGB
1537
	;    0.297344975250536 0.627363566255466 0.075291458493998
1538
	;  Adobe Wide Gamut RGB
1539
	;    0.258728243040113 0.724682314948566 0.016589442011321
1540
1541
 
1542
	; value of 2 indicates an internal error to the caller.
1543
1544
 
1545
;      return 2;
1546
;   if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0)
1547
;      return 2;
1548
;   denominator = left - right;
1549
1550
 
1551
;   if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
1552
;      return 2;
1553
;   if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
1554
;      return 2;
1555
1556
 
1557
	; chunk values.  This calculation actually returns the reciprocal of the
1558
	; scale value because this allows us to delay the multiplication of white-y
1559
	; into the denominator, which tends to produce a small number.
1560
1561
 
1562
;       red_inverse <= xy->whitey /* r+g+b scales = white scale */)
1563
;      return 1;
1564
1565
 
1566
;   if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
1567
;      return 2;
1568
;   if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
1569
;      return 2;
1570
;   if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 ||
1571
;       green_inverse <= xy->whitey)
1572
;      return 1;
1573
1574
 
1575
	; can still produce 0 for extreme cHRM values.
1576
1577
 
1578
;       png_reciprocal(green_inverse);
1579
;   if (blue_scale <= 0)
1580
;      return 1;
1581
1582
 
1583
 
1584
;   if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0)
1585
;      return 1;
1586
;   if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0)
1587
;      return 1;
1588
;   if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1,
1589
;       red_inverse) == 0)
1590
;      return 1;
1591
1592
 
1593
;      return 1;
1594
;   if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0)
1595
;      return 1;
1596
;   if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1,
1597
;       green_inverse) == 0)
1598
;      return 1;
1599
1600
 
1601
;      return 1;
1602
;   if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0)
1603
;      return 1;
1604
;   if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale,
1605
;       PNG_FP_1) == 0)
1606
;      return 1;
1607
1608
 
1609
	ret
1610
endp
1611
1612
 
1613
align 4
1614
proc png_XYZ_normalize, XYZ:dword
1615
;   int_32 Y;
1616
1617
 
1618
;      XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 ||
1619
;      XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0)
1620
;      return 1;
1621
1622
 
1623
	; IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore
1624
	; relying on addition of two positive values producing a negative one is not
1625
	; safe.
1626
1627
 
1628
;   if (0x7fffffff - Y < XYZ->green_X)
1629
;      return 1;
1630
;   Y += XYZ->green_Y;
1631
;   if (0x7fffffff - Y < XYZ->blue_X)
1632
;      return 1;
1633
;   Y += XYZ->blue_Y;
1634
1635
 
1636
;   {
1637
;      if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0)
1638
;         return 1;
1639
;      if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0)
1640
;         return 1;
1641
;      if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0)
1642
;         return 1;
1643
1644
 
1645
;         return 1;
1646
;      if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0)
1647
;         return 1;
1648
;      if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0)
1649
;         return 1;
1650
1651
 
1652
;         return 1;
1653
;      if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0)
1654
;         return 1;
1655
;      if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0)
1656
;         return 1;
1657
;   }
1658
1659
 
1660
	ret
1661
endp
1662
1663
 
1664
align 4
1665
proc png_colorspace_endpoints_match, xy1:dword, xy2:dword, delta:dword
1666
	; Allow an error of +/-0.01 (absolute value) on each chromaticity
1667
;   if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) ||
1668
;       PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) ||
1669
;       PNG_OUT_OF_RANGE(xy1->redx,   xy2->redx,  delta) ||
1670
;       PNG_OUT_OF_RANGE(xy1->redy,   xy2->redy,  delta) ||
1671
;       PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) ||
1672
;       PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) ||
1673
;       PNG_OUT_OF_RANGE(xy1->bluex,  xy2->bluex, delta) ||
1674
;       PNG_OUT_OF_RANGE(xy1->bluey,  xy2->bluey, delta))
1675
;      return 0;
1676
;   return 1;
1677
	ret
1678
endp
1679
1680
 
1681
; chunk chromaticities.  Earlier checks used to simply look for the overflow
1682
; condition (where the determinant of the matrix to solve for XYZ ends up zero
1683
; because the chromaticity values are not all distinct.)  Despite this it is
1684
; theoretically possible to produce chromaticities that are apparently valid
1685
; but that rapidly degrade to invalid, potentially crashing, sets because of
1686
; arithmetic inaccuracies when calculations are performed on them.  The new
1687
; check is to round-trip xy -> XYZ -> xy and then check that the result is
1688
; within a small percentage of the original.
1689
1690
 
1691
align 4
1692
proc png_colorspace_check_xy, XYZ:dword, xy:dword
1693
;   int result;
1694
;   png_xy xy_test;
1695
1696
 
1697
;   result = png_XYZ_from_xy(XYZ, xy);
1698
;   if (result != 0)
1699
;      return result;
1700
1701
 
1702
;   if (result != 0)
1703
;      return result;
1704
1705
 
1706
;       5/*actually, the math is pretty accurate*/) != 0)
1707
;      return 0;
1708
1709
 
1710
;   return 1;
1711
	ret
1712
endp
1713
1714
 
1715
; (another side-effect) and the xy chromaticities are returned.
1716
1717
 
1718
align 4
1719
proc png_colorspace_check_XYZ, xy:dword, XYZ:dword
1720
;   int result;
1721
;   png_XYZ XYZtemp;
1722
1723
 
1724
;   if (result != 0)
1725
;      return result;
1726
1727
 
1728
;   if (result != 0)
1729
;      return result;
1730
1731
 
1732
;   return png_colorspace_check_xy(&XYZtemp, xy);
1733
	ret
1734
endp
1735
1736
 
1737
;const png_xy sRGB_xy = /* From ITU-R BT.709-3 */
1738
;   /* color      x       y */
1739
;   /* red   */ 64000, 33000,
1740
;   /* green */ 30000, 60000,
1741
;   /* blue  */ 15000,  6000,
1742
;   /* white */ 31270, 32900
1743
1744
 
1745
;    png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ,
1746
;    int preferred)
1747
align 4
1748
proc png_colorspace_set_xy_and_XYZ, png_ptr:dword, colorspace:dword, xy:dword, XYZ:dword, preferred:dword
1749
;   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
1750
;      return 0;
1751
1752
 
1753
	; variations because of the normalization (or not) of the end point Y
1754
	; values.
1755
1756
 
1757
;       (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
1758
;   {
1759
	; The end points must be reasonably close to any we already have.  The
1760
	; following allows an error of up to +/-.001
1761
1762
 
1763
;          100) == 0)
1764
;      {
1765
;         colorspace->flags |= PNG_COLORSPACE_INVALID;
1766
;         png_benign_error(png_ptr, "inconsistent chromaticities");
1767
;         return 0; /* failed */
1768
;      }
1769
1770
 
1771
;      if (preferred == 0)
1772
;         return 1; /* ok, but no change */
1773
;   }
1774
1775
 
1776
;   colorspace->end_points_XYZ = *XYZ;
1777
;   colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS;
1778
1779
 
1780
	; on this test.
1781
1782
 
1783
;      colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB;
1784
;
1785
;   else
1786
;      colorspace->flags &= PNG_COLORSPACE_CANCEL(
1787
;         PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);
1788
1789
 
1790
	ret
1791
endp
1792
1793
 
1794
;    png_colorspacerp colorspace, const png_xy *xy, int preferred)
1795
align 4
1796
proc png_colorspace_set_chromaticities, png_ptr:dword, colorspace:dword, xy:dword, preferred:dword
1797
	; We must check the end points to ensure they are reasonable - in the past
1798
	; color management systems have crashed as a result of getting bogus
1799
	; colorant values, while this isn't the fault of libpng it is the
1800
	; responsibility of libpng because PNG carries the bomb and libpng is in a
1801
	; position to protect against it.
1802
1803
 
1804
1805
 
1806
;   {
1807
;      case 0: /* success */
1808
;         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ,
1809
;             preferred);
1810
1811
 
1812
	; We can't invert the chromaticities so we can't produce value XYZ
1813
	; values.  Likely as not a color management system will fail too.
1814
1815
 
1816
;         png_benign_error(png_ptr, "invalid chromaticities");
1817
;         break;
1818
;
1819
;      default:
1820
	; libpng is broken; this should be a warning but if it happens we
1821
	; want error reports so for the moment it is an error.
1822
1823
 
1824
;         png_error(png_ptr, "internal error checking chromaticities");
1825
;   }
1826
1827
 
1828
.end_f:
1829
	ret
1830
endp
1831
1832
 
1833
;    png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred)
1834
align 4
1835
proc png_colorspace_set_endpoints, png_ptr:dword, colorspace:dword, XYZ_in:dword, preferred:dword
1836
;   png_XYZ XYZ = *XYZ_in;
1837
;   png_xy xy;
1838
1839
 
1840
;   {
1841
;      case 0:
1842
;         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ,
1843
;             preferred);
1844
1845
 
1846
	; End points are invalid.
1847
;         colorspace->flags |= PNG_COLORSPACE_INVALID;
1848
;         png_benign_error(png_ptr, "invalid end points");
1849
;         break;
1850
1851
 
1852
;         colorspace->flags |= PNG_COLORSPACE_INVALID;
1853
;         png_error(png_ptr, "internal error checking chromaticities");
1854
;   }
1855
1856
 
1857
.end_f:
1858
	ret
1859
endp
1860
1861
 
1862
;char (uint_32 byte)
1863
align 4
1864
proc png_icc_tag_char, p1byte:dword
1865
	mov eax,[p1byte]
1866
	cmp al,32
1867
	jl @f
1868
	cmp al,126
1869
	jg @f ;if (..>=.. && ..<=..) return
1870
		mov al,'?'
1871
	@@:
1872
	and eax,0xff
1873
	ret
1874
endp
1875
1876
 
1877
align 4
1878
proc png_icc_tag_name uses eax edi, name:dword, tag:dword
1879
	mov edi,[name]
1880
	mov byte[edi],39
1881
	mov byte[edi+5],39
1882
	inc edi
1883
	mov eax,[tag]
1884
	shr eax,24
1885
	stdcall png_icc_tag_char,eax
1886
	stosb
1887
	mov eax,[tag]
1888
	shr eax,16
1889
	stdcall png_icc_tag_char,eax
1890
	stosb
1891
	mov eax,[tag]
1892
	shr eax,8
1893
	stdcall png_icc_tag_char,eax
1894
	stosb
1895
	stdcall png_icc_tag_char,[tag]
1896
	stosb
1897
	ret
1898
endp
1899
1900
 
1901
align 4
1902
proc is_ICC_signature_char, it:dword
1903
;   return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) ||
1904
;      (it >= 97 && it <= 122);
1905
	ret
1906
endp
1907
1908
 
1909
align 4
1910
proc is_ICC_signature, it:dword
1911
;   return is_ICC_signature_char(it >> 24) /* checks all the top bits */ &&
1912
;      is_ICC_signature_char((it >> 16) & 0xff) &&
1913
;      is_ICC_signature_char((it >> 8) & 0xff) &&
1914
;      is_ICC_signature_char(it & 0xff);
1915
	ret
1916
endp
1917
1918
 
1919
;    charp name, png_alloc_size_t value, charp reason)
1920
align 4
1921
proc png_icc_profile_error, png_ptr:dword, colorspace:dword, name:dword, value:dword, reason:dword
1922
locals
1923
	pos dd ? ;size_t
1924
	message rb 196 ;char[] ;see below for calculation
1925
endl
1926
	mov eax,[colorspace]
1927
	or eax,eax
8408 IgorA 1928
	jz @f ;if (..!=0)
1929
		or word[eax+png_colorspace.flags], PNG_COLORSPACE_INVALID
8341 dunkaist 1930
	@@:
1931
1932
 
1933
;   pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */
1934
;   pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */
1935
;   if (is_ICC_signature(value) != 0)
1936
;   {
1937
	; So 'value' is at most 4 bytes and the following cast is safe
1938
;      png_icc_tag_name(message+pos, (uint_32)value);
1939
;      pos += 6; /* total +8; less than the else clause */
1940
;      message[pos++] = ':';
1941
;      message[pos++] = ' ';
1942
;   }
1943
if PNG_WARNINGS_SUPPORTED eq 1
1944
;   else
1945
;      {
1946
;         char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/
1947
1948
 
1949
;             png_format_number(number, number+(sizeof number),
1950
;             PNG_NUMBER_FORMAT_x, value));
1951
;         pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/
1952
;      }
1953
end if
1954
	; The 'reason' is an arbitrary message, allow +79 maximum 195
1955
;   pos = png_safecat(message, (sizeof message), pos, reason);
1956
1957
 
1958
	; avoid writing invalid ICC profiles into PNG files (i.e., we handle them
1959
	; on read, with a warning, but on write unless the app turns off
1960
	; application errors the PNG won't be written.)
1961
1962
 
1963
;       (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR);
1964
1965
 
1966
	ret
1967
endp
1968
1969
 
1970
;color      X      Y      Z
1971
sRGB_XYZ dd 41239, 21264,  1933,\ ;red
1972
	35758, 71517, 11919,\ ;green
1973
	18048,  7219, 95053  ;blue
1974
end if
1975
1976
 
1977
align 4
1978
proc png_colorspace_set_sRGB uses ebx ecx edi esi, png_ptr:dword, colorspace:dword, intent:dword
1979
	; sRGB sets known gamma, end points and (from the chunk) intent.
1980
	; IMPORTANT: these are not necessarily the values found in an ICC profile
1981
	; because ICC profiles store values adapted to a D50 environment; it is
1982
	; expected that the ICC profile mediaWhitePointTag will be D50; see the
1983
	; checks and code elsewhere to understand this better.
1984
1985
 
1986
	; coefficients of (6968,23435,2366), which are reduced (because they add up
1987
	; to 32769 not 32768) to (6968,23434,2366).  These are the values that
1988
	; libpng has traditionally used (and are the best values given the 15bit
1989
	; algorithm used by the rgb to gray code.)
1990
1991
 
1992
	mov ebx,[colorspace]
1993
	mov ax,[ebx+png_colorspace.flags]
1994
	and ax,PNG_COLORSPACE_INVALID
1995
	cmp ax,0
1996
	je @f ;if (..!=0)
1997
		xor eax,eax
1998
		jmp .end_f
1999
	@@:
2000
2001
 
2002
	; PNG file to have cHRM or gAMA chunks along with sRGB, but the values must
2003
	; be consistent with the correct values.  If, however, this function is
2004
	; called below because an iCCP chunk matches sRGB then it is quite
2005
	; conceivable that an older app recorded incorrect gAMA and cHRM because of
2006
	; an incorrect calculation based on the values in the profile - this does
2007
	; *not* invalidate the profile (though it still produces an error, which can
2008
	; be ignored.)
2009
2010
 
2011
	cmp dword[intent],0
2012
	jl @f
2013
	cmp dword[intent],PNG_sRGB_INTENT_LAST
2014
	jge @f
2015
		jmp .end0
2016
	@@: ;if (..<0 || ..>=..)
2017
		cStr ,'sRGB'
2018
		cStr ecx,'invalid sRGB rendering intent'
2019
		stdcall png_icc_profile_error, edi, ebx, eax, [intent], ecx
2020
		jmp .end_f
2021
	.end0:
2022
2023
 
2024
	and ax,PNG_COLORSPACE_HAVE_INTENT
2025
	cmp ax,0
2026
	je @f
2027
	movzx eax,word[ebx+png_colorspace.rendering_intent]
2028
	cmp eax,[intent]
2029
	je @f ;if (..!=0 && ..!=..)
2030
		cStr ,'sRGB'
2031
		cStr ecx,'inconsistent rendering intents'
2032
		stdcall png_icc_profile_error, edi, ebx, eax, [intent], ecx
2033
		jmp .end_f
2034
	@@:
2035
2036
 
2037
	and ax,PNG_COLORSPACE_FROM_sRGB
2038
	cmp ax,0
2039
	je @f ;if (..!=0)
2040
		png_benign_error edi, 'duplicate sRGB information ignored'
2041
		xor eax,eax
2042
		jmp .end_f
2043
	@@:
2044
2045
 
2046
	; warn but overwrite the value with the correct one.
2047
2048
 
2049
	and ax,PNG_COLORSPACE_HAVE_ENDPOINTS
2050
	cmp ax,0
2051
	je @f ;if (..!=0 &&
2052
;       !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy,
2053
;       100))
2054
		cStr ,'cHRM chunk does not match sRGB'
2055
		stdcall png_chunk_report, edi, eax, PNG_CHUNK_ERROR
2056
	@@:
2057
2058
 
2059
	; returns true when the 'from' argument corresponds to sRGB (2).
2060
2061
 
2062
2063
 
2064
	mov eax,[intent]
2065
	mov [ebx+png_colorspace.rendering_intent],ax
2066
	or word[ebx+png_colorspace.flags], PNG_COLORSPACE_HAVE_INTENT
2067
2068
 
2069
;   colorspace->end_points_xy = sRGB_xy;
2070
;   colorspace->end_points_XYZ = sRGB_XYZ;
2071
	or word[ebx+png_colorspace.flags], (PNG_COLORSPACE_HAVE_ENDPOINTS or PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB)
2072
2073
 
2074
	mov dword[ebx+png_colorspace.gamma], PNG_GAMMA_sRGB_INVERSE
2075
	or word[ebx+png_colorspace.flags], PNG_COLORSPACE_HAVE_GAMMA
2076
2077
 
2078
	or word[ebx+png_colorspace.flags], (PNG_COLORSPACE_MATCHES_sRGB or PNG_COLORSPACE_FROM_sRGB)
2079
2080
 
2081
	inc eax ;set
2082
.end_f:
2083
	ret
2084
endp
2085
2086
 
2087
; Encoded value of D50 as an ICC XYZNumber.  From the ICC 2010 spec the value
2088
; is XYZ(0.9642,1.0,0.8249), which scales to:
2089
2090
 
2091
2092
 
2093
	0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d
2094
2095
 
2096
;(png_structrp png_ptr, png_colorspacerp colorspace, charp name, uint_32 profile_length)
2097
align 4
2098
proc icc_check_length, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword
2099
	cmp dword[profile_length],132
2100
	jge @f ;if (..<..)
2101
;      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2102
;          "too short");
2103
		jmp .end_f
2104
	@@:
2105
	xor eax,eax
2106
	inc eax
2107
.end_f:
2108
	ret
2109
endp
2110
2111
 
2112
;    charp name, uint_32 profile_length)
2113
align 4
2114
proc png_icc_check_length, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword
2115
;   if (!icc_check_length(png_ptr, colorspace, name, profile_length))
2116
;      return 0;
2117
2118
 
2119
	; png_decompress_chunk, yet this happens after the attempt to
2120
	; png_malloc_base the required data.  We only need this on read; on write
2121
	; the caller supplies the profile buffer so libpng doesn't allocate it.  See
2122
	; the call to icc_check_length below (the write case).
2123
2124
 
2125
;      else if (png_ptr->user_chunk_malloc_max > 0 &&
2126
;               png_ptr->user_chunk_malloc_max < profile_length)
2127
;         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2128
;             "exceeds application limits");
2129
elseif PNG_USER_CHUNK_MALLOC_MAX > 0
2130
;      else if (PNG_USER_CHUNK_MALLOC_MAX < profile_length)
2131
;         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2132
;             "exceeds libpng limits");
2133
else ;!SET_USER_LIMITS
2134
	; This will get compiled out on all 32-bit and better systems.
2135
;      else if (PNG_SIZE_MAX < profile_length)
2136
;         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2137
;             "exceeds system limits");
2138
end if ;!SET_USER_LIMITS
2139
	xor eax,eax
2140
	inc eax
2141
.end_f:
2142
	ret
2143
endp
2144
2145
 
2146
;    charp name, uint_32 profile_length,
2147
;    bytep profile/* first 132 bytes only */, int color_type)
2148
align 4
2149
proc png_icc_check_header, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword, profile:dword, color_type:dword
2150
;   uint_32 temp;
2151
2152
 
2153
	; is used later to check the tag table, so even if the profile seems over
2154
	; long profile_length from the caller must be correct.  The caller can fix
2155
	; this up on read or write by just passing in the profile header length.
2156
2157
 
2158
;   if (temp != profile_length)
2159
;      return png_icc_profile_error(png_ptr, colorspace, name, temp,
2160
;          "length does not match profile");
2161
2162
 
2163
;   if (temp > 3 && (profile_length & 3))
2164
;      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2165
;          "invalid length");
2166
2167
 
2168
;   if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */
2169
;      profile_length < 132+12*temp) /* truncated tag table */
2170
;      return png_icc_profile_error(png_ptr, colorspace, name, temp,
2171
;          "tag count too large");
2172
2173
 
2174
	; 16 bits.
2175
2176
 
2177
;   if (temp >= 0xffff) /* The ICC limit */
2178
;      return png_icc_profile_error(png_ptr, colorspace, name, temp,
2179
;          "invalid rendering intent");
2180
2181
 
2182
	; versions.
2183
2184
 
2185
;      (void)png_icc_profile_error(png_ptr, NULL, name, temp,
2186
;          "intent outside defined range");
2187
2188
 
2189
	; been loaded; however, various header fields can be checked.  These checks
2190
	; are for values permitted by the PNG spec in an ICC profile; the PNG spec
2191
	; restricts the profiles that can be passed in an iCCP chunk (they must be
2192
	; appropriate to processing PNG data!)
2193
2194
 
2195
	; version number; however, the version number doesn't accomodate changes in
2196
	; the header fields (just the known tags and the interpretation of the
2197
	; data.)
2198
2199
 
2200
;   if (temp != 0x61637370)
2201
;      return png_icc_profile_error(png_ptr, colorspace, name, temp,
2202
;          "invalid signature");
2203
2204
 
2205
	; white point) are required to be D50,
2206
	; however the profile contains a record of the illuminant so perhaps ICC
2207
	; expects to be able to change this in the future (despite the rationale in
2208
	; the introduction for using a fixed PCS adopted white.)  Consequently the
2209
	; following is just a warning.
2210
2211
 
2212
;      (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/,
2213
;          "PCS illuminant is not D50");
2214
2215
 
2216
	; "If the iCCP chunk is present, the image samples conform to the colour
2217
	; space represented by the embedded ICC profile as defined by the
2218
	; International Color Consortium [ICC]. The colour space of the ICC profile
2219
	; shall be an RGB colour space for colour images (PNG colour types 2, 3, and
2220
	; 6), or a greyscale colour space for greyscale images (PNG colour types 0
2221
	; and 4)."
2222
2223
 
2224
	; conforms to the specification requirements.  Notice that an ICC 'gray'
2225
	; color-space profile contains the information to transform the monochrome
2226
	; data to XYZ or L*a*b (according to which PCS the profile uses) and this
2227
	; should be used in preference to the standard libpng K channel replication
2228
	; into R, G and B channels.
2229
2230
 
2231
	; handled.  However it it is clear that using an RGB profile in this context
2232
	; must be an error - there is no specification of what it means.  Thus it is
2233
	; almost certainly more correct to ignore the profile.
2234
2235
 
2236
;   switch (temp)
2237
;   {
2238
;      case 0x52474220: /* 'RGB ' */
2239
;         if ((color_type & PNG_COLOR_MASK_COLOR) == 0)
2240
;            return png_icc_profile_error(png_ptr, colorspace, name, temp,
2241
;                "RGB color space not permitted on grayscale PNG");
2242
;         break;
2243
2244
 
2245
;         if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
2246
;            return png_icc_profile_error(png_ptr, colorspace, name, temp,
2247
;                "Gray color space not permitted on RGB PNG");
2248
;         break;
2249
2250
 
2251
;         return png_icc_profile_error(png_ptr, colorspace, name, temp,
2252
;             "invalid ICC profile color space");
2253
;   }
2254
2255
 
2256
	; application requirements; the spec provides no guidance, but it's pretty
2257
	; weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer
2258
	; ('prtr') or 'spac' (for generic color spaces).  Issue a warning in these
2259
	; cases.  Issue an error for device link or abstract profiles - these don't
2260
	; contain the records necessary to transform the color-space to anything
2261
	; other than the target device (and not even that for an abstract profile).
2262
	; Profiles of these classes may not be embedded in images.
2263
2264
 
2265
;   switch (temp)
2266
;   {
2267
;      case 0x73636e72: /* 'scnr' */
2268
;      case 0x6d6e7472: /* 'mntr' */
2269
;      case 0x70727472: /* 'prtr' */
2270
;      case 0x73706163: /* 'spac' */
2271
;         /* All supported */
2272
;         break;
2273
2274
 
2275
;         /* May not be embedded in an image */
2276
;         return png_icc_profile_error(png_ptr, colorspace, name, temp,
2277
;             "invalid embedded Abstract ICC profile");
2278
2279
 
2280
;         /* DeviceLink profiles cannot be interpreted in a non-device specific
2281
	; fashion, if an app uses the AToB0Tag in the profile the results are
2282
	; undefined unless the result is sent to the intended device,
2283
	; therefore a DeviceLink profile should not be found embedded in a
2284
	; PNG.
2285
2286
 
2287
;             "unexpected DeviceLink ICC profile class");
2288
2289
 
2290
;         /* A NamedColor profile is also device specific, however it doesn't
2291
	; contain an AToB0 tag that is open to misinterpretation.  Almost
2292
	; certainly it will fail the tests below.
2293
2294
 
2295
;             "unexpected NamedColor ICC profile class");
2296
;         break;
2297
2298
 
2299
;         /* To allow for future enhancements to the profile accept unrecognized
2300
	; profile classes with a warning, these then hit the test below on the
2301
	; tag content to ensure they are backward compatible with one of the
2302
	; understood profiles.
2303
2304
 
2305
;             "unrecognized ICC profile class");
2306
;         break;
2307
;   }
2308
2309
 
2310
	; either in XYZ or Lab.
2311
2312
 
2313
;   switch (temp)
2314
;   {
2315
;      case 0x58595a20: /* 'XYZ ' */
2316
;      case 0x4c616220: /* 'Lab ' */
2317
;         break;
2318
2319
 
2320
;         return png_icc_profile_error(png_ptr, colorspace, name, temp,
2321
;             "unexpected ICC PCS encoding");
2322
;   }
2323
2324
 
2325
	ret
2326
endp
2327
2328
 
2329
;    charp name, uint_32 profile_length,
2330
;    bytep profile /* header plus whole tag table */)
2331
align 4
2332
proc png_icc_check_tag_table, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword, profile:dword
2333
;   uint_32 tag_count = png_get_uint_32(profile+128);
2334
;   uint_32 itag;
2335
;   bytep tag = profile+132; /* The first tag */
2336
2337
 
2338
	; (temporarily in 'tags').
2339
2340
 
2341
;   {
2342
;      uint_32 tag_id = png_get_uint_32(tag+0);
2343
;      uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */
2344
;      uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */
2345
2346
 
2347
	; start might actually be anywhere if there is no data, but this would be
2348
	; a clear abuse of the intent of the standard so the start is checked for
2349
	; being in range.  All defined tag types have an 8 byte header - a 4 byte
2350
	; type signature then 0.
2351
2352
 
2353
;      {
2354
	; CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is
2355
	; only a warning here because libpng does not care about the
2356
	; alignment.
2357
2358
 
2359
;             "ICC profile tag start not a multiple of 4");
2360
;      }
2361
2362
 
2363
	; profile.
2364
2365
 
2366
;         return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
2367
;             "ICC profile tag outside profile");
2368
;   }
2369
	xor eax,eax
2370
	inc eax ;success, maybe with warnings
2371
.end_f:
2372
	ret
2373
endp
2374
2375
 
2376
;#if PNG_sRGB_PROFILE_CHECKS >= 0
2377
; Information about the known ICC sRGB profiles
2378
struct png_sRGB_checks
2379
	adler dd ? ;uint_32
2380
	crc dd ?
2381
	length dd ?
2382
	md5 rd 4 ;uint_32[4]
2383
	have_md5 db ? ;byte
2384
	is_broken db ? ;byte
2385
	intent dw ? ;uint_16
2386
ends
2387
;#  define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0)
2388
;#  define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\
2389
;      { adler, crc, length, md5, broke, intent },
2390
2391
 
2392
	; This data comes from contrib/tools/checksum-icc run on downloads of
2393
	; all four ICC sRGB profiles from www.color.org.
2394
2395
 
2396
;   PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9,
2397
;       PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0,
2398
;       "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc")
2399
2400
 
2401
;   PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21,
2402
;       PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0,
2403
;       "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc")
2404
2405
 
2406
;       PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0,
2407
;       "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc")
2408
2409
 
2410
;   PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812,
2411
;       PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0,
2412
;       "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc")
2413
2414
 
2415
	; on the (empty) MD5 the other fields are used to attempt a match and
2416
	; a warning is produced.  The first two of these profiles have a 'cprt' tag
2417
	; which suggests that they were also made by Hewlett Packard.
2418
2419
 
2420
;       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0,
2421
;       "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc")
2422
2423
 
2424
	; match the D50 PCS illuminant in the header (it is in fact the D65 values,
2425
	; so the white point is recorded as the un-adapted value.)  The profiles
2426
	; below only differ in one byte - the intent - and are basically the same as
2427
	; the previous profile except for the mediaWhitePointTag error and a missing
2428
	; chromaticAdaptationTag.
2429
2430
 
2431
;       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/,
2432
;       "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual")
2433
2434
 
2435
;       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/,
2436
;       "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative")
2437
;
2438
2439
 
2440
align 4
2441
proc png_compare_ICC_profile_with_sRGB, png_ptr:dword, profile:dword, adler:dword
2442
	; The quick check is to verify just the MD5 signature and trust the
2443
	; rest of the data.  Because the profile has already been verified for
2444
	; correctness this is safe.  png_colorspace_set_sRGB will check the 'intent'
2445
	; field too, so if the profile has been edited with an intent not defined
2446
	; by sRGB (but maybe defined by a later ICC specification) the read of
2447
	; the profile will fail at that point.
2448
2449
 
2450
;   uint_32 intent = 0x10000; /* invalid */
2451
if PNG_sRGB_PROFILE_CHECKS > 1
2452
;   uLong crc = 0; /* the value for 0 length data */
2453
end if
2454
;   uint i;
2455
2456
 
2457
	; First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on"
2458
;   if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) ==
2459
;               PNG_OPTION_ON)
2460
;      return 0;
2461
end if
2462
2463
 
2464
;   {
2465
;      if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] &&
2466
;         png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&
2467
;         png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&
2468
;         png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3])
2469
;      {
2470
	; This may be one of the old HP profiles without an MD5, in that
2471
	; case we can only use the length and Adler32 (note that these
2472
	; are not used by default if there is an MD5!)
2473
2474
 
2475
;            if (png_sRGB_checks[i].have_md5 != 0)
2476
;               return 1+png_sRGB_checks[i].is_broken;
2477
;#        endif
2478
2479
 
2480
;         if (length == 0)
2481
;         {
2482
;            length = png_get_uint_32(profile);
2483
;            intent = png_get_uint_32(profile+64);
2484
;         }
2485
2486
 
2487
;         if (length == (uint_32) png_sRGB_checks[i].length &&
2488
;            intent == (uint_32) png_sRGB_checks[i].intent)
2489
;         {
2490
	; Now calculate the adler32 if not done already.
2491
;            if (adler == 0)
2492
;            {
2493
;               adler = adler32(0, NULL, 0);
2494
;               adler = adler32(adler, profile, length);
2495
;            }
2496
2497
 
2498
;            {
2499
	; These basic checks suggest that the data has not been
2500
	; modified, but if the check level is more than 1 perform
2501
	; our own crc32 checksum on the data.
2502
2503
 
2504
;                  if (crc == 0)
2505
;                  {
2506
;                     crc = calc_crc32(0, NULL, 0);
2507
;                     crc = calc_crc32(crc, profile, length);
2508
;                  }
2509
2510
 
2511
2512
 
2513
;#              endif
2514
;               {
2515
;                  if (png_sRGB_checks[i].is_broken != 0)
2516
;                  {
2517
	; These profiles are known to have bad data that may cause
2518
	; problems if they are used, therefore attempt to
2519
	; discourage their use, skip the 'have_md5' warning below,
2520
	; which is made irrelevant by this error.
2521
2522
 
2523
;                         PNG_CHUNK_ERROR);
2524
;                  }
2525
2526
 
2527
	; the profile is perfectly valid, but it would be nice if
2528
	; people used the up-to-date ones.
2529
2530
 
2531
;                  {
2532
;                     png_chunk_report(png_ptr,
2533
;                         "out-of-date sRGB profile with no signature",
2534
;                         PNG_CHUNK_WARNING);
2535
;                  }
2536
2537
 
2538
;               }
2539
;            }
2540
2541
 
2542
	; The signature matched, but the profile had been changed in some
2543
	; way.  This probably indicates a data error or uninformed hacking.
2544
	; Fall through to "no match".
2545
2546
 
2547
;             "Not recognizing known sRGB profile that has been edited",
2548
;             PNG_CHUNK_WARNING);
2549
;         break;
2550
;# endif
2551
;         }
2552
;      }
2553
;   }
2554
2555
 
2556
	ret
2557
endp
2558
2559
 
2560
;    png_colorspacerp colorspace, bytep profile, uLong adler)
2561
align 4
2562
proc png_icc_set_sRGB uses eax, png_ptr:dword, colorspace:dword, profile:dword, adler:dword
2563
	; Is this profile one of the known ICC sRGB profiles?  If it is, just set
2564
	; the sRGB information.
2565
2566
 
2567
;      (void)png_colorspace_set_sRGB(png_ptr, colorspace,
2568
;         (int)/*already checked*/png_get_uint_32(profile+64));
2569
	ret
2570
endp
2571
;end if /* PNG_sRGB_PROFILE_CHECKS >= 0 */
2572
;end if /* sRGB */
2573
2574
 
2575
;    charp name, uint_32 profile_length, bytep profile,
2576
;    int color_type)
2577
align 4
2578
proc png_colorspace_set_ICC, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword, profile:dword, color_type:dword
2579
;   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
2580
;      return 0;
2581
2582
 
2583
;       png_icc_check_header(png_ptr, colorspace, name, profile_length, profile,
2584
;           color_type) != 0 &&
2585
;       png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,
2586
;           profile) != 0)
2587
;   {
2588
;#     if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0
2589
	; If no sRGB support, don't try storing sRGB information
2590
;         png_icc_set_sRGB(png_ptr, colorspace, profile, 0);
2591
;#     endif
2592
;      return 1;
2593
;   }
2594
2595
 
2596
	xor eax,eax
2597
.end_f:
2598
	ret
2599
endp
2600
;end if /* iCCP */
2601
2602
 
2603
align 4
2604
proc png_colorspace_set_rgb_coefficients, png_ptr:dword
2605
	; Set the rgb_to_gray coefficients from the colorspace.
2606
;   if (png_ptr->rgb_to_gray_coefficients_set == 0 &&
2607
;      (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
2608
;   {
2609
	; png_set_background has not been called, get the coefficients from the Y
2610
	; values of the colorspace colorants.
2611
2612
 
2613
;      png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y;
2614
;      png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y;
2615
;      png_fixed_point total = r+g+b;
2616
2617
 
2618
;         r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&
2619
;         g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&
2620
;         b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&
2621
;         r+g+b <= 32769)
2622
;      {
2623
	; We allow 0 coefficients here.  r+g+b may be 32769 if two or
2624
	; all of the coefficients were rounded up.  Handle this by
2625
	; reducing the *largest* coefficient by 1; this matches the
2626
	; approach used for the default coefficients in pngrtran.c
2627
2628
 
2629
;
2630
;         if (r+g+b > 32768)
2631
;            add = -1;
2632
;         else if (r+g+b < 32768)
2633
;            add = 1;
2634
2635
 
2636
;         {
2637
;            if (g >= r && g >= b)
2638
;               g += add;
2639
;            else if (r >= g && r >= b)
2640
;               r += add;
2641
;            else
2642
;               b += add;
2643
;         }
2644
2645
 
2646
;         if (r+g+b != 32768)
2647
;            png_error(png_ptr,
2648
;                "internal error handling cHRM coefficients");
2649
2650
 
2651
;         {
2652
;            png_ptr->rgb_to_gray_red_coeff   = (uint_16)r;
2653
;            png_ptr->rgb_to_gray_green_coeff = (uint_16)g;
2654
;         }
2655
;      }
2656
2657
 
2658
	; it should never happen, but it is important that if it does, the
2659
	; bug is fixed.
2660
2661
 
2662
;         png_error(png_ptr, "internal error handling cHRM->XYZ");
2663
;   }
2664
	ret
2665
endp
2666
2667
 
2668
2669
 
2670
;    uint_32 width, uint_32 height, int bit_depth,
2671
;    int color_type, int interlace_type, int compression_type, int filter_type)
2672
align 4
2673
proc png_check_IHDR uses eax ebx edi, png_ptr:dword, width:dword, height:dword, bit_depth:dword, color_type:dword, interlace_type:dword, compression_type:dword, filter_type:dword
2674
	mov edi,[png_ptr]
2675
	xor ebx,ebx
2676
2677
 
2678
	cmp dword[width],0
2679
	jne @f ;if (..==0)
2680
		png_warning edi, 'Image width is zero in IHDR'
2681
		inc ebx
2682
	@@:
2683
2684
 
2685
	jle @f ;if (..>..)
2686
		png_warning edi, 'Invalid image width in IHDR'
2687
		inc ebx
2688
	@@:
2689
2690
 
2691
	;  1 - filter byte
2692
	;  8 - 8-byte RGBA pixels
2693
	;  1 - extra max_pixel_depth pad
2694
	mov eax,[width]
2695
	add eax,7
2696
	and eax,not 7
2697
	cmp eax,((PNG_SIZE_MAX -48 -1) / 8) -1
2698
	jle @f ;if (..>..)
2699
		; The size of the row must be within the limits of this architecture.
2700
		; Because the read code can perform arbitrary transformations the
2701
		; maximum size is checked here.  Because the code in png_read_start_row
2702
		; adds extra space "for safety's sake" in several places a conservative
2703
		; limit is used here.
2704
2705
 
2706
		; but the effect in the real world is minor and the changes are more
2707
		; extensive, therefore much more dangerous and much more difficult to
2708
		; write in a way that avoids compiler warnings.
2709
2710
 
2711
		inc ebx
2712
	@@:
2713
2714
 
2715
	mov eax,[edi+png_struct.user_width_max]
2716
	cmp dword[width],eax
2717
else
2718
	cmp dword[width],PNG_USER_WIDTH_MAX
2719
end if
2720
	jle @f ;if (..>..)
2721
		png_warning edi, 'Image width exceeds user limit in IHDR'
2722
		inc ebx
2723
	@@:
2724
2725
 
2726
	jne @f ;if (..==0)
2727
		png_warning edi, 'Image height is zero in IHDR'
2728
		inc ebx
2729
	@@:
2730
2731
 
2732
	jle @f ;if (..>..)
2733
		png_warning edi, 'Invalid image height in IHDR'
2734
		inc ebx
2735
	@@:
2736
2737
 
2738
	mov eax,[edi+png_struct.user_height_max]
2739
	cmp dword[height],eax
2740
else
2741
	cmp dword[height],PNG_USER_HEIGHT_MAX
2742
end if
2743
	jle @f ;if (..>..)
2744
		png_warning edi, 'Image height exceeds user limit in IHDR'
2745
		inc ebx
2746
	@@:
2747
2748
 
2749
	cmp dword[bit_depth],1
2750
	je @f
2751
	cmp dword[bit_depth],2
2752
	je @f
2753
	cmp dword[bit_depth],4
2754
	je @f
2755
	cmp dword[bit_depth],8
2756
	je @f
2757
	cmp dword[bit_depth],16
2758
	je @f ;if (..!=.. && ...)
2759
		png_warning edi, 'Invalid bit depth in IHDR'
2760
		inc ebx
2761
	@@:
2762
2763
 
2764
	jl @f
2765
	cmp dword[color_type],1
2766
	je @f
2767
	cmp dword[color_type],5
2768
	je @f
2769
	cmp dword[color_type],6
2770
	jg @f
2771
		jmp .end0
2772
	@@: ;if (..<0 || ..==1 || ..==5 || ..>6)
2773
		png_warning edi, 'Invalid color type in IHDR'
2774
		inc ebx
2775
	.end0:
2776
2777
 
2778
	jne @f
2779
	cmp dword[bit_depth],8
2780
	jg .beg1
2781
	@@:
2782
	cmp dword[color_type],PNG_COLOR_TYPE_RGB
2783
	je @f
2784
	cmp dword[color_type],PNG_COLOR_TYPE_GRAY_ALPHA
2785
	je @f
2786
	cmp dword[color_type],PNG_COLOR_TYPE_RGB_ALPHA
2787
	jne .end1
2788
	@@:
2789
	cmp dword[bit_depth],8
2790
	jge .end1
2791
	.beg1: ;if (((..==..) && ..>..) || ((..==.. || ..==.. || ..==..) && ..<..))
2792
		png_warning edi, 'Invalid color type/bit depth combination in IHDR'
2793
		inc ebx
2794
	.end1:
2795
2796
 
2797
	jl @f ;if (..>=..)
2798
		png_warning edi, 'Unknown interlace method in IHDR'
2799
		inc ebx
2800
	@@:
2801
2802
 
2803
	je @f ;if (..!=..)
2804
		png_warning edi, 'Unknown compression method in IHDR'
2805
		inc ebx
2806
	@@:
2807
2808
 
2809
	; Accept filter_method 64 (intrapixel differencing) only if
2810
	; 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
2811
	; 2. Libpng did not read a PNG signature (this filter_method is only
2812
	;    used in PNG datastreams that are embedded in MNG datastreams) and
2813
	; 3. The application called png_permit_mng_features with a mask that
2814
	;    included PNG_FLAG_MNG_FILTER_64 and
2815
	; 4. The filter_method is 64 and
2816
	; 5. The color_type is RGB or RGBA
2817
2818
 
2819
;       png_ptr->mng_features_permitted != 0)
2820
		png_warning edi, 'MNG features are not allowed in a PNG datastream'
2821
2822
 
2823
;   {
2824
;      if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
2825
;          (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
2826
;          ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
2827
;          (color_type == PNG_COLOR_TYPE_RGB ||
2828
;          color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
2829
;      {
2830
		png_warning edi, 'Unknown filter method in IHDR'
2831
		inc ebx
2832
;      }
2833
2834
 
2835
;      {
2836
		png_warning edi, 'Invalid filter method in IHDR'
2837
		inc ebx
2838
;      }
2839
;   }
2840
2841
 
2842
	cmp dword[filter_type],PNG_FILTER_TYPE_BASE
2843
	je @f ;if (..!=..)
2844
		png_warning edi, 'Unknown filter method in IHDR'
2845
		inc ebx
2846
	@@:
2847
end if
2848
2849
 
8408 IgorA 2850
	jz @f
2851
		png_error edi, 'Invalid IHDR data'
8341 dunkaist 2852
	@@:
2853
	ret
2854
endp
2855
2856
 
2857
; ASCII to fp functions
2858
; Check an ASCII formated floating point value, see the more detailed
2859
; comments in pngpriv.inc
2860
2861
 
2862
;#define png_fp_add(state, flags) ((state) |= (flags))
2863
;#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY))
2864
2865
 
2866
align 4
2867
proc png_check_fp_number, string:dword, size:dword, statep:dword, whereami:dword
2868
;   int state = *statep;
2869
;   png_size_t i = *whereami;
2870
2871
 
2872
;   {
2873
;      int type;
2874
	; First find the type of the next character
2875
;      switch (string[i])
2876
;      {
2877
;      case 43:  type = PNG_FP_SAW_SIGN;                   break;
2878
;      case 45:  type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break;
2879
;      case 46:  type = PNG_FP_SAW_DOT;                    break;
2880
;      case 48:  type = PNG_FP_SAW_DIGIT;                  break;
2881
;      case 49: case 50: case 51: case 52:
2882
;      case 53: case 54: case 55: case 56:
2883
;      case 57:  type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break;
2884
;      case 69:
2885
;      case 101: type = PNG_FP_SAW_E;                      break;
2886
;      default:  goto PNG_FP_End;
2887
;      }
2888
2889
 
2890
	; state, the type is arranged to not overlap the
2891
	; bits of the PNG_FP_STATE.
2892
2893
 
2894
;      {
2895
;      case PNG_FP_INTEGER + PNG_FP_SAW_SIGN:
2896
;         if ((state & PNG_FP_SAW_ANY) != 0)
2897
;            goto PNG_FP_End; /* not a part of the number */
2898
2899
 
2900
;         break;
2901
2902
 
2903
	; Ok as trailer, ok as lead of fraction.
2904
;         if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */
2905
;            goto PNG_FP_End;
2906
2907
 
2908
;            png_fp_add(state, type);
2909
2910
 
2911
;            png_fp_set(state, PNG_FP_FRACTION | type);
2912
2913
 
2914
2915
 
2916
;         if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */
2917
;            png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
2918
2919
 
2920
2921
 
2922
2923
 
2924
;         if ((state & PNG_FP_SAW_DIGIT) == 0)
2925
;            goto PNG_FP_End;
2926
2927
 
2928
2929
 
2930
2931
 
2932
2933
 
2934
2935
 
2936
;         png_fp_add(state, type | PNG_FP_WAS_VALID);
2937
;         break;
2938
2939
 
2940
	; This is correct because the trailing '.' on an
2941
	; integer is handled above - so we can only get here
2942
	; with the sequence ".E" (with no preceding digits).
2943
2944
 
2945
;            goto PNG_FP_End;
2946
2947
 
2948
2949
 
2950
2951
 
2952
;         if ((state & PNG_FP_SAW_ANY) != 0)
2953
;            goto PNG_FP_End; /* not a part of the number */
2954
2955
 
2956
2957
 
2958
2959
 
2960
2961
 
2962
;         png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID);
2963
2964
 
2965
2966
 
2967
2968
 
2969
;      }
2970
2971
 
2972
;      ++i;
2973
;   }
2974
;
2975
;PNG_FP_End:
2976
	; Here at the end, update the state and return the correct
2977
	; return code.
2978
2979
 
2980
;   *whereami = i;
2981
2982
 
2983
	ret
2984
endp
2985
2986
 
2987
 
2988
;int (charp string, png_size_t size)
2989
align 4
2990
proc png_check_fp_string, string:dword, size:dword
2991
;   int        state=0;
2992
;   png_size_t char_index=0;
2993
;
2994
;   if (png_check_fp_number(string, size, &state, &char_index) != 0 &&
2995
;      (char_index == size || string[char_index] == 0))
2996
;      return state /* must be non-zero - see above */;
2997
2998
 
2999
	ret
3000
endp
3001
;end if /* pCAL || sCAL */
3002
3003
 
3004
;#  ifdef PNG_FLOATING_POINT_SUPPORTED
3005
; Utility used below - a simple accurate power of ten from an integral
3006
; exponent.
3007
3008
 
3009
align 4
3010
proc png_pow10, power:dword
3011
;   int recip = 0;
3012
;   double d = 1;
3013
3014
 
3015
	; 10 is exact whereas .1 is inexact in base 2
3016
3017
 
3018
;   {
3019
;      if (power < DBL_MIN_10_EXP) return 0;
3020
;      recip = 1, power = -power;
3021
;   }
3022
3023
 
3024
;   {
3025
	; Decompose power bitwise.
3026
;      double mult = 10;
3027
;      do
3028
;      {
3029
;         if (power & 1) d *= mult;
3030
;         mult *= mult;
3031
;         power >>= 1;
3032
;      }
3033
;      while (power > 0);
3034
3035
 
3036
;   }
3037
	; else power is 0 and d is 1
3038
3039
 
3040
	ret
3041
endp
3042
3043
 
3044
; precision.
3045
3046
 
3047
;    double fp, uint precision)
3048
align 4
3049
proc png_ascii_from_fp, png_ptr:dword, ascii:dword, size:dword, fp:dword, precision:dword
3050
	; We use standard functions from math.h, but not printf because
3051
	; that would require stdio.  The caller must supply a buffer of
3052
	; sufficient size or we will png_error.  The tests on size and
3053
	; the space in ascii[] consumed are indicated below.
3054
3055
 
3056
;      precision = DBL_DIG;
3057
3058
 
3059
;   if (precision > DBL_DIG+1)
3060
;      precision = DBL_DIG+1;
3061
3062
 
3063
;   if (size >= precision+5) /* See the requirements below. */
3064
;   {
3065
;      if (fp < 0)
3066
;      {
3067
;         fp = -fp;
3068
;         *ascii++ = 45; /* '-'  PLUS 1 TOTAL 1 */
3069
;         --size;
3070
;      }
3071
3072
 
3073
;      {
3074
;         int exp_b10;   /* A base 10 exponent */
3075
;         double base;   /* 10^exp_b10 */
3076
3077
 
3078
	; the calculation below rounds down when converting
3079
	; from base 2 to base 10 (multiply by log10(2) -
3080
	; 0.3010, but 77/256 is 0.3008, so exp_b10 needs to
3081
	; be increased.  Note that the arithmetic shift
3082
	; performs a floor() unlike C arithmetic - using a
3083
	; C multiply would break the following for negative
3084
	; exponents.
3085
3086
 
3087
3088
 
3089
3090
 
3091
;         base = png_pow10(exp_b10); /* May underflow */
3092
3093
 
3094
;         {
3095
;            /* And this may overflow. */
3096
;            double test = png_pow10(exp_b10+1);
3097
3098
 
3099
;               ++exp_b10, base = test;
3100
3101
 
3102
;               break;
3103
;         }
3104
3105
 
3106
	; range [.1,1) and exp_b10 is both the exponent and the digit
3107
	; *before* which the decimal point should be inserted
3108
	; (starting with 0 for the first digit).  Note that this
3109
	; works even if 10^exp_b10 is out of range because of the
3110
	; test on DBL_MAX above.
3111
3112
 
3113
;         while (fp >= 1) fp /= 10, ++exp_b10;
3114
3115
 
3116
	; less than .1, this is ok because the code below can
3117
	; handle the leading zeros this generates, so no attempt
3118
	; is made to correct that here.
3119
3120
 
3121
;            uint czero, clead, cdigits;
3122
;            char exponent[10];
3123
3124
 
3125
	; the number compared to using E-n.
3126
3127
 
3128
;            {
3129
;               czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */
3130
;               exp_b10 = 0;      /* Dot added below before first output. */
3131
;            }
3132
;            else
3133
;               czero = 0;    /* No zeros to add */
3134
3135
 
3136
	; inserting a '.' before a digit if the exponent is 0.
3137
3138
 
3139
;            cdigits = 0;   /* Count of digits in list. */
3140
3141
 
3142
;            {
3143
;               double d;
3144
3145
 
3146
	; Use modf here, not floor and subtract, so that
3147
	; the separation is done in one step.  At the end
3148
	; of the loop don't break the number into parts so
3149
	; that the final digit is rounded.
3150
3151
 
3152
;                  fp = modf(fp, &d);
3153
3154
 
3155
;               {
3156
;                  d = floor(fp + .5);
3157
3158
 
3159
;                  {
3160
;                     /* Rounding up to 10, handle that here. */
3161
;                     if (czero > 0)
3162
;                     {
3163
;                        --czero, d = 1;
3164
;                        if (cdigits == 0) --clead;
3165
;                     }
3166
;                     else
3167
;                     {
3168
;                        while (cdigits > 0 && d > 9)
3169
;                        {
3170
;                           int ch = *--ascii;
3171
3172
 
3173
;                              ++exp_b10;
3174
3175
 
3176
;                           {
3177
;                              ch = *--ascii, ++size;
3178
;                              /* Advance exp_b10 to '1', so that the
3179
;                               * decimal point happens after the
3180
;                               * previous digit.
3181
3182
 
3183
;                           }
3184
3185
 
3186
;                           d = ch - 47;  /* I.e. 1+(ch-48) */
3187
;                        }
3188
3189
 
3190
;                         * exponent but take into account the leading
3191
;                         * decimal point.
3192
3193
 
3194
;                        {
3195
;                           if (exp_b10 == (-1))
3196
;                           {
3197
		; Leading decimal point (plus zeros?), if
3198
		; we lose the decimal point here it must
3199
		; be reentered below.
3200
3201
 
3202
3203
 
3204
;                                 ++size, exp_b10 = 1;
3205
3206
 
3207
;                               * still ok at (-1)
3208
3209
 
3210
;                           else
3211
;                              ++exp_b10;
3212
3213
 
3214
;                           d = 1;
3215
;                        }
3216
;                     }
3217
;                  }
3218
;                  fp = 0; /* Guarantees termination below. */
3219
;               }
3220
3221
 
3222
;               {
3223
;                  ++czero;
3224
;                  if (cdigits == 0) ++clead;
3225
;               }
3226
;               else
3227
;               {
3228
;                  /* Included embedded zeros in the digit count. */
3229
;                  cdigits += czero - clead;
3230
;                  clead = 0;
3231
3232
 
3233
;                  {
3234
		; exp_b10 == (-1) means we just output the decimal
3235
		; place - after the DP don't adjust 'exp_b10' any
3236
		; more!
3237
3238
 
3239
;                     {
3240
;                        if (exp_b10 == 0) *ascii++ = 46, --size;
3241
;                        /* PLUS 1: TOTAL 4 */
3242
;                        --exp_b10;
3243
;                     }
3244
;                     *ascii++ = 48, --czero;
3245
;                  }
3246
3247
 
3248
;                  {
3249
;                     if (exp_b10 == 0)
3250
;                        *ascii++ = 46, --size; /* counted above */
3251
3252
 
3253
;                  }
3254
;                  *ascii++ = (char)(48 + (int)d), ++cdigits;
3255
;               }
3256
;            }
3257
;            while (cdigits+czero < precision+clead && fp > DBL_MIN);
3258
3259
 
3260
3261
 
3262
	; done and just need to terminate the string.  At
3263
	; this point exp_b10==(-1) is effectively if flag - it got
3264
	; to '-1' because of the decrement after outputting
3265
	; the decimal point above (the exponent required is
3266
	; *not* -1!)
3267
3268
 
3269
;            {
3270
		; The following only happens if we didn't output the
3271
		; leading zeros above for negative exponent, so this
3272
		; doesn't add to the digit requirement.  Note that the
3273
		; two zeros here can only be output if the two leading
3274
		; zeros were *not* output, so this doesn't increase
3275
		; the output count.
3276
3277
 
3278
3279
 
3280
3281
 
3282
		; 5+precision - see check at the start.
3283
3284
 
3285
;            }
3286
3287
 
3288
	; the digits we output but did not count.  The total
3289
	; digit output here so far is at most 1+precision - no
3290
	; decimal point and no leading or trailing zeros have
3291
	; been output.
3292
3293
 
3294
;
3295
;            *ascii++ = 69, --size;    /* 'E': PLUS 1 TOTAL 2+precision */
3296
3297
 
3298
	; the signed arithmetic on exp_b10 and permits GCC at least to do
3299
	; better optimization.
3300
3301
 
3302
;               uint uexp_b10;
3303
3304
 
3305
;               {
3306
;                  *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
3307
;                  uexp_b10 = -exp_b10;
3308
;               }
3309
3310
 
3311
;                  uexp_b10 = exp_b10;
3312
3313
 
3314
3315
 
3316
;               {
3317
;                  exponent[cdigits++] = (char)(48 + uexp_b10 % 10);
3318
;                  uexp_b10 /= 10;
3319
;               }
3320
;            }
3321
3322
 
3323
	; this need not be considered above.
3324
3325
 
3326
;            {
3327
;               while (cdigits > 0) *ascii++ = exponent[--cdigits];
3328
3329
 
3330
3331
 
3332
;            }
3333
;         }
3334
;      }
3335
;      else if (!(fp >= DBL_MIN))
3336
;      {
3337
;         *ascii++ = 48; /* '0' */
3338
;         *ascii = 0;
3339
;         return;
3340
;      }
3341
;      else
3342
;      {
3343
;         *ascii++ = 105; /* 'i' */
3344
;         *ascii++ = 110; /* 'n' */
3345
;         *ascii++ = 102; /* 'f' */
3346
;         *ascii = 0;
3347
;         return;
3348
;      }
3349
;   }
3350
3351
 
3352
;   png_error(png_ptr, "ASCII conversion buffer too small");
3353
	ret
3354
endp
3355
3356
 
3357
3358
 
3359
3360
 
3361
align 4
3362
proc png_ascii_from_fixed, png_ptr:dword, ascii:dword, size:dword, fp:dword
3363
	; Require space for 10 decimal digits, a decimal point, a minus sign and a
3364
	; trailing \0, 13 characters:
3365
3366
 
3367
	jle .end0 ;if (..>..)
3368
;      uint_32 num;
3369
3370
 
3371
;      if (fp < 0)
3372
;         *ascii++ = 45, num = -fp;
3373
;      else
3374
;         num = fp;
3375
3376
 
3377
;      {
3378
;         uint ndigits = 0, first = 16 /* flag value */;
3379
;         char digits[10];
3380
3381
 
3382
;         {
3383
	; Split the low digit off num:
3384
;            uint tmp = num/10;
3385
;            num -= tmp*10;
3386
;            digits[ndigits++] = (char)(48 + num);
3387
	; Record the first non-zero digit, note that this is a number
3388
	; starting at 1, it's not actually the array index.
3389
3390
 
3391
;               first = ndigits;
3392
;            num = tmp;
3393
;         }
3394
3395
 
3396
;         {
3397
;            while (ndigits > 5) *ascii++ = digits[--ndigits];
3398
	; The remaining digits are fractional digits, ndigits is '5' or
3399
	; smaller at this point.  It is certainly not zero.  Check for a
3400
	; non-zero fractional digit:
3401
3402
 
3403
;            {
3404
;               uint i;
3405
;               *ascii++ = 46; /* decimal point */
3406
	; ndigits may be <5 for small numbers, output leading zeros
3407
	; then ndigits digits to first:
3408
3409
 
3410
;               while (ndigits < i) *ascii++ = 48, --i;
3411
;               while (ndigits >= first) *ascii++ = digits[--ndigits];
3412
	; Don't output the trailing zeros!
3413
;            }
3414
;         }
3415
;         else
3416
;            *ascii++ = 48;
3417
3418
 
3419
;         *ascii = 0;
3420
;         return;
3421
;      }
3422
	.end0:
3423
3424
 
3425
	png_error [png_ptr], 'ASCII conversion buffer too small'
3426
	ret
3427
endp
3428
;end if /* SCAL */
3429
3430
 
3431
align 4
3432
proc png_fixed, png_ptr:dword, fp:dword, text:dword
3433
;   double r = floor(100000 * fp + .5);
3434
3435
 
3436
;      png_fixed_error(png_ptr, text);
3437
3438
 
3439
	ret
3440
endp
3441
3442
 
3443
; This API takes signed arguments and rounds the result to the nearest
3444
; integer (or, for a fixed point number - the standard argument - to
3445
; the nearest .00001).  Overflow and divide by zero are signalled in
3446
; the result, a boolean - true on success, false on overflow.
3447
3448
 
3449
align 4
3450
proc png_muldiv, res:dword, a:dword, p3times:dword, divisor:dword
3451
	; Return a * times / divisor, rounded.
3452
;   if (divisor != 0)
3453
;   {
3454
;      if (a == 0 || p3times == 0)
3455
;      {
3456
;         *res = 0;
3457
;         return 1;
3458
;      }
3459
;      else
3460
;      {
3461
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3462
;         double r = a;
3463
;         r *= p3times;
3464
;         r /= divisor;
3465
;         r = floor(r+.5);
3466
3467
 
3468
;         if (r <= 2147483647. && r >= -2147483648.)
3469
;         {
3470
;            *res = (png_fixed_point)r;
3471
;            return 1;
3472
;         }
3473
else
3474
;         int negative = 0;
3475
;         uint_32 A, T, D;
3476
;         uint_32 s16, s32, s00;
3477
3478
 
3479
;            negative = 1, A = -a;
3480
;         else
3481
;            A = a;
3482
3483
 
3484
;            negative = !negative, T = -p3times;
3485
;         else
3486
;            T = p3times;
3487
3488
 
3489
;            negative = !negative, D = -divisor;
3490
;         else
3491
;            D = divisor;
3492
3493
 
3494
	; have 31 bits each, however the result may be 32 bits.
3495
3496
 
3497
;                           (A & 0xffff) * (T >> 16);
3498
	; Can't overflow because the a*times bit is only 30
3499
	; bits at most.
3500
3501
 
3502
;         s00 = (A & 0xffff) * (T & 0xffff);
3503
3504
 
3505
;         s00 += s16;
3506
3507
 
3508
;            ++s32; /* carry */
3509
3510
 
3511
;         {
3512
	; s32.s00 is now the 64-bit product, do a standard
3513
	; division, we know that s32 < D, so the maximum
3514
	; required shift is 31.
3515
3516
 
3517
;            png_fixed_point result = 0; /* NOTE: signed */
3518
3519
 
3520
;            {
3521
;               uint_32 d32, d00;
3522
3523
 
3524
;                  d32 = D >> (32-bitshift), d00 = D << bitshift;
3525
3526
 
3527
;                  d32 = 0, d00 = D;
3528
3529
 
3530
;               {
3531
;                  if (s00 < d00) --s32; /* carry */
3532
;                  s32 -= d32, s00 -= d00, result += 1<
3533
;               }
3534
3535
 
3536
;                  if (s32 == d32 && s00 >= d00)
3537
;                     s32 = 0, s00 -= d00, result += 1<
3538
;            }
3539
3540
 
3541
;            if (s00 >= (D >> 1))
3542
;               ++result;
3543
3544
 
3545
;               result = -result;
3546
3547
 
3548
;            if ((negative != 0 && result <= 0) ||
3549
;                (negative == 0 && result >= 0))
3550
;            {
3551
;               *res = result;
3552
;               return 1;
3553
;            }
3554
;         }
3555
end if
3556
;      }
3557
;   }
3558
3559
 
3560
	ret
3561
endp
3562
3563
 
3564
; result.
3565
3566
 
3567
;    int_32 divisor)
3568
align 4
3569
proc png_muldiv_warn, png_ptr:dword, a:dword, p3times:dword, divisor:dword
3570
;   png_fixed_point result;
3571
3572
 
3573
;      return result;
3574
3575
 
3576
	xor eax,eax
3577
	ret
3578
endp
3579
3580
 
3581
;png_fixed_point (png_fixed_point a)
3582
align 4
3583
proc png_reciprocal, a:dword
3584
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3585
;   double r = floor(1E10/a+.5);
3586
3587
 
3588
;      return (png_fixed_point)r;
3589
else
3590
;   png_fixed_point res;
3591
3592
 
3593
;      return res;
3594
end if
3595
3596
 
3597
	ret
3598
endp
3599
3600
 
3601
; it is worth doing gamma correction.
3602
3603
 
3604
align 4
3605
proc png_gamma_significant, gamma_val:dword
3606
;   return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||
3607
;       gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
3608
	ret
3609
endp
3610
3611
 
3612
; A local convenience routine.
3613
;png_fixed_point (png_fixed_point a, png_fixed_point b)
3614
align 4
3615
proc png_product2, a:dword, b:dword
3616
	; The required result is 1/a * 1/b; the following preserves accuracy.
3617
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3618
;   double r = a * 1E-5;
3619
;   r *= b;
3620
;   r = floor(r+.5);
3621
3622
 
3623
;      return (png_fixed_point)r;
3624
else
3625
;   png_fixed_point res;
3626
3627
 
3628
;      return res;
3629
end if
3630
3631
 
3632
	ret
3633
endp
3634
3635
 
3636
;png_fixed_point (png_fixed_point a, png_fixed_point b)
3637
align 4
3638
proc png_reciprocal2, a:dword, b:dword
3639
	; The required result is 1/a * 1/b; the following preserves accuracy.
3640
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3641
;   if (a != 0 && b != 0)
3642
;   {
3643
;      double r = 1E15/a;
3644
;      r /= b;
3645
;      r = floor(r+.5);
3646
;
3647
;      if (r <= 2147483647. && r >= -2147483648.)
3648
;         return (png_fixed_point)r;
3649
;   }
3650
else
3651
	; This may overflow because the range of png_fixed_point isn't symmetric,
3652
	; but this API is only used for the product of file and screen gamma so it
3653
	; doesn't matter that the smallest number it can produce is 1/21474, not
3654
	; 1/100000
3655
3656
 
3657
3658
 
3659
;      return png_reciprocal(res);
3660
end if
3661
3662
 
3663
	ret
3664
endp
3665
;end if /* READ_GAMMA */
3666
3667
 
3668
;#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
3669
; Fixed point gamma.
3670
3671
 
3672
; contrib/tools/intgamma.sh
3673
3674
 
3675
; fixed point arithmetic.  This code has sufficient precision for either 8-bit
3676
; or 16-bit sample values.
3677
3678
 
3679
; precision floating point arithmetic would work fine.
3680
3681
 
3682
;   This is a table of -log(value/255)/log(2) for 'value' in the range 128 to
3683
;   255, so it's the base 2 logarithm of a normalized 8-bit floating point
3684
;   mantissa.  The numbers are 32-bit fractions.
3685
3686
 
3687
;png_8bit_l2[128] =
3688
;   4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,
3689
;   3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,
3690
;   3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,
3691
;   3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,
3692
;   3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,
3693
;   2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,
3694
;   2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,
3695
;   2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,
3696
;   2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,
3697
;   2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,
3698
;   1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,
3699
;   1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,
3700
;   1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,
3701
;   1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,
3702
;   1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,
3703
;   971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,
3704
;   803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,
3705
;   639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,
3706
;   479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,
3707
;   324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,
3708
;   172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
3709
;   24347096U, 0U
3710
3711
 
3712
	; The following are the values for 16-bit tables - these work fine for the
3713
	; 8-bit conversions but produce very slightly larger errors in the 16-bit
3714
	; log (about 1.2 as opposed to 0.7 absolute error in the final value).  To
3715
	; use these all the shifts below must be adjusted appropriately.
3716
3717
 
3718
;   57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
3719
;   50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,
3720
;   43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,
3721
;   37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,
3722
;   31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,
3723
;   25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,
3724
;   20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,
3725
;   15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,
3726
;   10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,
3727
;   6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,
3728
;   1119, 744, 372
3729
end if
3730
3731
 
3732
align 4
3733
proc png_log8bit, x:dword
3734
;   uint lg2 = 0;
3735
	; Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,
3736
	; because the log is actually negate that means adding 1.  The final
3737
	; returned value thus has the range 0 (for 255 input) to 7.994 (for 1
3738
	; input), return -1 for the overflow (log 0) case, - so the result is
3739
	; always at most 19 bits.
3740
3741
 
3742
;      return -1;
3743
3744
 
3745
;      lg2  = 4, x <<= 4;
3746
3747
 
3748
;      lg2 += 2, x <<= 2;
3749
3750
 
3751
;      lg2 += 1, x <<= 1;
3752
3753
 
3754
;   return (int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));
3755
	ret
3756
endp
3757
3758
 
3759
; for 16-bit images we use the most significant 8 bits of the 16-bit value to
3760
; get an approximation then multiply the approximation by a correction factor
3761
; determined by the remaining up to 8 bits.  This requires an additional step
3762
; in the 16-bit case.
3763
3764
 
3765
3766
 
3767
;          = v' * f
3768
3769
 
3770
; to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less
3771
; than 258.  The final factor also needs to correct for the fact that our 8-bit
3772
; value is scaled by 255, whereas the 16-bit values must be scaled by 65535.
3773
3774
 
3775
; scaling by 65536 to match the above table:
3776
3777
 
3778
3779
 
3780
; interpolation between the two end values 256/257 (result -368.61) and 258/257
3781
; (result 367.179).  The values used below are scaled by a further 64 to give
3782
; 16-bit precision in the interpolation:
3783
3784
 
3785
; Zero  (257):      0
3786
; End   (258):  23499
3787
3788
 
3789
align 4
3790
proc png_log16bit, x:dword
3791
;   uint lg2 = 0;
3792
3793
 
3794
;   if ((x &= 0xffff) == 0)
3795
;      return -1;
3796
3797
 
3798
;      lg2  = 8, x <<= 8;
3799
3800
 
3801
;      lg2 += 4, x <<= 4;
3802
3803
 
3804
;      lg2 += 2, x <<= 2;
3805
3806
 
3807
;      lg2 += 1, x <<= 1;
3808
3809
 
3810
	; value.
3811
3812
 
3813
;   lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4;
3814
3815
 
3816
	; 8 bits.  Do this with maximum precision.
3817
3818
 
3819
3820
 
3821
	; the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly
3822
	; 16 bits to interpolate to get the low bits of the result.  Round the
3823
	; answer.  Note that the end point values are scaled by 64 to retain overall
3824
	; precision and that 'lg2' is current scaled by an extra 12 bits, so adjust
3825
	; the overall scaling by 6-12.  Round at every step.
3826
3827
 
3828
3829
 
3830
;      lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);
3831
3832
 
3833
;      lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);
3834
3835
 
3836
;   return (int_32)((lg2 + 2048) >> 12);
3837
	ret
3838
endp
3839
3840
 
3841
; logarithmic value and returning a 16 or 8-bit number as appropriate.  In
3842
; each case only the low 16 bits are relevant - the fraction - since the
3843
; integer bits (the top 4) simply determine a shift.
3844
3845
 
3846
; requires perhaps spurious accuracy in the decoding of the logarithm to
3847
; distinguish log2(65535/65534.5) - 10^-5 or 17 bits.  There is little chance
3848
; of getting this accuracy in practice.
3849
3850
 
3851
; frational part of the logarithm by using an accurate 32-bit value from the
3852
; top four fractional bits then multiplying in the remaining bits.
3853
3854
 
3855
align 4
3856
png_32bit_exp dd 4294967295, 4112874773, 3938502376, 3771522796, 3611622603, 3458501653,\
3857
	3311872529, 3171459999, 3037000500, 2908241642, 2784941738, 2666869345,\
3858
	2553802834, 2445529972, 2341847524, 2242560872
3859
3860
 
3861
;#if 0
3862
;for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
3863
;   11 44937.64284865548751208448
3864
;   10 45180.98734845585101160448
3865
;    9 45303.31936980687359311872
3866
;    8 45364.65110595323018870784
3867
;    7 45395.35850361789624614912
3868
;    6 45410.72259715102037508096
3869
;    5 45418.40724413220722311168
3870
;    4 45422.25021786898173001728
3871
;    3 45424.17186732298419044352
3872
;    2 45425.13273269940811464704
3873
;    1 45425.61317555035558641664
3874
;    0 45425.85339951654943850496
3875
;end if
3876
3877
 
3878
align 4
3879
proc png_exp, x:dword
3880
;   if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */
3881
;   {
3882
	; Obtain a 4-bit approximation
3883
;      uint_32 e = png_32bit_exp[(x >> 12) & 0x0f];
3884
3885
 
3886
	; multiplying by a number less than 1 if the bit is set.  The multiplier
3887
	; is determined by the above table and the shift. Notice that the values
3888
	; converge on 45426 and this is used to allow linear interpolation of the
3889
	; low bits.
3890
3891
 
3892
;         e -= (((e >> 16) * 44938U) +  16U) >> 5;
3893
3894
 
3895
;         e -= (((e >> 16) * 45181U) +  32U) >> 6;
3896
3897
 
3898
;         e -= (((e >> 16) * 45303U) +  64U) >> 7;
3899
3900
 
3901
;         e -= (((e >> 16) * 45365U) + 128U) >> 8;
3902
3903
 
3904
;         e -= (((e >> 16) * 45395U) + 256U) >> 9;
3905
3906
 
3907
;         e -= (((e >> 16) * 45410U) + 512U) >> 10;
3908
3909
 
3910
;      e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;
3911
3912
 
3913
;      e >>= x >> 16;
3914
;      return e;
3915
;   }
3916
3917
 
3918
;   if (x <= 0)
3919
;      return png_32bit_exp[0];
3920
3921
 
3922
;   return 0;
3923
	ret
3924
endp
3925
3926
 
3927
align 4
3928
proc png_exp8bit, lg2:dword
3929
	; Get a 32-bit value:
3930
;   uint_32 x = png_exp(lg2);
3931
3932
 
3933
	; second, rounding, step can't overflow because of the first, subtraction,
3934
	; step.
3935
3936
 
3937
;   return (byte)(((x + 0x7fffffU) >> 24) & 0xff);
3938
	ret
3939
endp
3940
3941
 
3942
align 4
3943
proc png_exp16bit, lg2:dword
3944
	; Get a 32-bit value:
3945
;   uint_32 x = png_exp(lg2);
3946
3947
 
3948
;   x -= x >> 16;
3949
;   return (uint_16)((x + 32767U) >> 16);
3950
	ret
3951
endp
3952
;end if /* FLOATING_ARITHMETIC */
3953
3954
 
3955
align 4
3956
proc png_gamma_8bit_correct, value:dword, gamma_val:dword
3957
;   if (value > 0 && value < 255)
3958
;   {
3959
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3960
	; 'value' is unsigned, ANSI-C90 requires the compiler to correctly
3961
	; convert this to a floating point value.  This includes values that
3962
	; would overflow if 'value' were to be converted to 'int'.
3963
3964
 
3965
	; on some (ARM) but not all (x86) platforms, possibly because of
3966
	; hardware FP limitations.  (E.g. if the hardware conversion always
3967
	; assumes the integer register contains a signed value.)  This results
3968
	; in ANSI-C undefined behavior for large values.
3969
3970
 
3971
	; conformant and therefore compile spurious extra code for the large
3972
	; values.
3973
3974
 
3975
	; won't be faster than an int to float one.  Therefore this code
3976
	; assumes responsibility for the undefined behavior, which it knows
3977
	; can't happen because of the check above.
3978
3979
 
3980
	; 16-bit platforms, it is assigned a value which might be out of
3981
	; range for an (int); that would result in undefined behavior in the
3982
	; caller if the *argument* ('value') were to be declared (int).
3983
3984
 
3985
;         return (byte)r;
3986
else
3987
;         int_32 lg2 = png_log8bit(value);
3988
;         png_fixed_point res;
3989
3990
 
3991
;            return png_exp8bit(res);
3992
3993
 
3994
;         value = 0;
3995
end if
3996
;   }
3997
3998
 
3999
	ret
4000
endp
4001
4002
 
4003
align 4
4004
proc png_gamma_16bit_correct, value:dword, gamma_val:dword
4005
;   if (value > 0 && value < 65535)
4006
;   {
4007
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
4008
	; The same (uint)->(double) constraints apply here as above,
4009
	; however in this case the (uint) to (int) conversion can
4010
	; overflow on an ANSI-C90 compliant system so the cast needs to ensure
4011
	; that this is not possible.
4012
4013
 
4014
;          gamma_val*.00001)+.5);
4015
;      return (uint_16)r;
4016
else
4017
;      int_32 lg2 = png_log16bit(value);
4018
;      png_fixed_point res;
4019
4020
 
4021
;         return png_exp16bit(res);
4022
4023
 
4024
;      value = 0;
4025
end if
4026
;   }
4027
4028
 
4029
	ret
4030
endp
4031
4032
 
4033
; png_struct, interpreting values as 8-bit or 16-bit.  While the result
4034
; is nominally a 16-bit value if bit depth is 8 then the result is
4035
; 8-bit (as are the arguments.)
4036
4037
 
4038
align 4
4039
proc png_gamma_correct, png_ptr:dword, value:dword, gamma_val:dword
4040
;   if (png_ptr->bit_depth == 8)
4041
;      return png_gamma_8bit_correct(value, gamma_val);
4042
;
4043
if PNG_16BIT_SUPPORTED eq 1
4044
;   else
4045
;      return png_gamma_16bit_correct(value, gamma_val);
4046
else
4047
	; should not reach this
4048
	xor eax,eax
4049
end if ;16BIT
4050
.end_f:
4051
	ret
4052
endp
4053
4054
 
4055
; Internal function to build a single 16-bit table - the table consists of
4056
; 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
4057
; to shift the input values right (or 16-number_of_signifiant_bits).
4058
4059
 
4060
; png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument
4061
; should be somewhere that will be cleaned.
4062
4063
 
4064
align 4
4065
proc png_build_16bit_table, png_ptr:dword, ptable:dword, shift:dword, gamma_val:dword
4066
	; Various values derived from 'shift':
4067
;    uint num = 1U << (8U - shift);
4068
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
4069
	; CSE the division and work round wacky GCC warnings (see the comments
4070
	; in png_gamma_8bit_correct for where these come from.)
4071
4072
 
4073
end if
4074
;    uint max = (1U << (16U - shift))-1U;
4075
;    uint max_by_2 = 1U << (15U-shift);
4076
;   uint i;
4077
4078
 
4079
;       (uint_16pp)png_calloc(png_ptr, num * (sizeof (uint_16p)));
4080
4081
 
4082
;   {
4083
;      uint_16p sub_table = table[i] =
4084
;          (uint_16p)png_malloc(png_ptr, 256 * (sizeof (uint_16)));
4085
4086
 
4087
	; the 16-bit tables even if the others don't hit it.
4088
4089
 
4090
;      {
4091
	; The old code would overflow at the end and this would cause the
4092
	; 'pow' function to return a result >1, resulting in an
4093
	; arithmetic error.  This code follows the spec exactly; ig is
4094
	; the recovered input sample, it always has 8-16 bits.
4095
4096
 
4097
	; bits (unsigned) so long as max <= 32767.
4098
4099
 
4100
;         for (j = 0; j < 256; j++)
4101
;         {
4102
;            uint_32 ig = (j << (8-shift)) + i;
4103
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
4104
		; Inline the 'max' scaling operation:
4105
		; See png_gamma_8bit_correct for why the cast to (int) is
4106
		; required here.
4107
4108
 
4109
;               sub_table[j] = (uint_16)d;
4110
else
4111
;               if (shift != 0)
4112
;                  ig = (ig * 65535U + max_by_2)/max;
4113
;
4114
;               sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);
4115
end if
4116
;         }
4117
;      }
4118
;      else
4119
;      {
4120
		; We must still build a table, but do it the fast way.
4121
;         uint j;
4122
;
4123
;         for (j = 0; j < 256; j++)
4124
;         {
4125
;            uint_32 ig = (j << (8-shift)) + i;
4126
;
4127
;            if (shift != 0)
4128
;               ig = (ig * 65535U + max_by_2)/max;
4129
;
4130
;            sub_table[j] = (uint_16)ig;
4131
;         }
4132
;      }
4133
;   }
4134
	ret
4135
endp
4136
4137
 
4138
; required.
4139
4140
 
4141
align 4
4142
proc png_build_16to8_table, png_ptr:dword, ptable:dword, shift:dword, gamma_val:dword
4143
;   uint num = 1U << (8U - shift);
4144
;   uint max = (1U << (16U - shift))-1U;
4145
;   uint i;
4146
;   uint_32 last;
4147
4148
 
4149
;       (uint_16pp)png_calloc(png_ptr, num * (sizeof (uint_16p)));
4150
4151
 
4152
	; bits of the input 16-bit value used to select a table.  Each table is
4153
	; itself indexed by the high 8 bits of the value.
4154
4155
 
4156
;      table[i] = (uint_16p)png_malloc(png_ptr,
4157
;          256 * (sizeof (uint_16)));
4158
4159
 
4160
	; pow(out,g) is an *input* value.  'last' is the last input value set.
4161
	;
4162
	; In the loop 'i' is used to find output values.  Since the output is
4163
	; 8-bit there are only 256 possible values.  The tables are set up to
4164
	; select the closest possible output value for each input by finding
4165
	; the input value at the boundary between each pair of output values
4166
	; and filling the table up to that boundary with the lower output
4167
	; value.
4168
4169
 
4170
	; values the code below uses a 16-bit value in i; the values start at
4171
	; 128.5 (for 0.5) and step by 257, for a total of 254 values (the last
4172
	; entries are filled with 255).  Start i at 128 and fill all 'last'
4173
	; table entries <= 'max'
4174
4175
 
4176
;   for (i = 0; i < 255; ++i) /* 8-bit output value */
4177
;   {
4178
	; Find the corresponding maximum input value
4179
;      uint_16 out = (uint_16)(i * 257U); /* 16-bit output value */
4180
4181
 
4182
;      uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);
4183
4184
 
4185
;      bound = (bound * max + 32768U)/65535U + 1U;
4186
;
4187
;      while (last < bound)
4188
;      {
4189
;         table[last & (0xffU >> shift)][last >> (8U - shift)] = out;
4190
;         last++;
4191
;      }
4192
;   }
4193
4194
 
4195
;   while (last < (num << 8))
4196
;   {
4197
;      table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;
4198
;      last++;
4199
;   }
4200
	ret
4201
endp
4202
;end if /* 16BIT */
4203
4204
 
4205
; typically much faster).  Note that libpng currently does no sBIT processing
4206
; (apparently contrary to the spec) so a 256-entry table is always generated.
4207
4208
 
4209
align 4
4210
proc png_build_8bit_table, png_ptr:dword, ptable:dword, gamma_val:dword
4211
;   uint i;
4212
;   bytep table = *ptable = (bytep)png_malloc(png_ptr, 256);
4213
4214
 
4215
;      for (i=0; i<256; i++)
4216
;         table[i] = png_gamma_8bit_correct(i, gamma_val);
4217
4218
 
4219
;      for (i=0; i<256; ++i)
4220
;         table[i] = (byte)(i & 0xff);
4221
	ret
4222
endp
4223
4224
 
4225
; tables.
4226
4227
 
4228
align 4
4229
proc png_destroy_gamma_table, png_ptr:dword
4230
;   png_free(png_ptr, png_ptr->gamma_table);
4231
;   png_ptr->gamma_table = NULL;
4232
4233
 
4234
;   if (png_ptr->gamma_16_table != NULL)
4235
;   {
4236
;      int i;
4237
;      int istop = (1 << (8 - png_ptr->gamma_shift));
4238
;      for (i = 0; i < istop; i++)
4239
;      {
4240
;         png_free(png_ptr, png_ptr->gamma_16_table[i]);
4241
;      }
4242
;   png_free(png_ptr, png_ptr->gamma_16_table);
4243
;   png_ptr->gamma_16_table = NULL;
4244
;   }
4245
end if ;16BIT
4246
4247
 
4248
;   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
4249
;   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4250
;   png_free(png_ptr, png_ptr->gamma_from_1);
4251
;   png_ptr->gamma_from_1 = NULL;
4252
;   png_free(png_ptr, png_ptr->gamma_to_1);
4253
;   png_ptr->gamma_to_1 = NULL;
4254
4255
 
4256
;   if (png_ptr->gamma_16_from_1 != NULL)
4257
;   {
4258
;      int i;
4259
;      int istop = (1 << (8 - png_ptr->gamma_shift));
4260
;      for (i = 0; i < istop; i++)
4261
;      {
4262
;         png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
4263
;      }
4264
;   png_free(png_ptr, png_ptr->gamma_16_from_1);
4265
;   png_ptr->gamma_16_from_1 = NULL;
4266
;   }
4267
;   if (png_ptr->gamma_16_to_1 != NULL)
4268
;   {
4269
;      int i;
4270
;      int istop = (1 << (8 - png_ptr->gamma_shift));
4271
;      for (i = 0; i < istop; i++)
4272
;      {
4273
;         png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
4274
;      }
4275
;   png_free(png_ptr, png_ptr->gamma_16_to_1);
4276
;   png_ptr->gamma_16_to_1 = NULL;
4277
;   }
4278
end if ;16BIT
4279
;end if /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
4280
	ret
4281
endp
4282
4283
 
4284
; tables, we don't make a full table if we are reducing to 8-bit in
4285
; the future.  Note also how the gamma_16 tables are segmented so that
4286
; we don't need to allocate > 64K chunks for a full 16-bit table.
4287
4288
 
4289
align 4
4290
proc png_build_gamma_table, png_ptr:dword, bit_depth:dword
4291
	png_debug 1, 'in png_build_gamma_table'
4292
4293
 
4294
	; png_read_update_info. The warning is because building the gamma tables
4295
	; multiple times is a performance hit - it's harmless but the ability to
4296
	; call png_read_update_info() multiple times is new in 1.5.6 so it seems
4297
	; sensible to warn if the app introduces such a hit.
4298
4299
 
4300
;   {
4301
;      png_warning(png_ptr, "gamma table being rebuilt");
4302
;      png_destroy_gamma_table(png_ptr);
4303
;   }
4304
4305
 
4306
;   {
4307
;      png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
4308
;          png_ptr->screen_gamma > 0 ?
4309
;          png_reciprocal2(png_ptr->colorspace.gamma,
4310
;          png_ptr->screen_gamma) : PNG_FP_1);
4311
;
4312
if (PNG_READ_BACKGROUND_SUPPORTED eq 1) | (PNG_READ_ALPHA_MODE_SUPPORTED eq 1) | (PNG_READ_RGB_TO_GRAY_SUPPORTED eq 1)
4313
;      if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
4314
;      {
4315
;         png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
4316
;             png_reciprocal(png_ptr->colorspace.gamma));
4317
;
4318
;         png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
4319
;             png_ptr->screen_gamma > 0 ?
4320
;             png_reciprocal(png_ptr->screen_gamma) :
4321
;             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
4322
;      }
4323
end if ;READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY
4324
;   }
4325
if PNG_16BIT_SUPPORTED eq 1
4326
;   else
4327
;   {
4328
;      byte shift, sig_bit;
4329
;
4330
;      if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
4331
;      {
4332
;         sig_bit = png_ptr->sig_bit.red;
4333
;
4334
;         if (png_ptr->sig_bit.green > sig_bit)
4335
;            sig_bit = png_ptr->sig_bit.green;
4336
;
4337
;         if (png_ptr->sig_bit.blue > sig_bit)
4338
;            sig_bit = png_ptr->sig_bit.blue;
4339
;      }
4340
;      else
4341
;         sig_bit = png_ptr->sig_bit.gray;
4342
4343
 
4344
4345
 
4346
4347
 
4348
	; pow(iv, gamma).
4349
4350
 
4351
	; is selected by the (8-gamma_shift) most significant of the low 8 bits
4352
	; of the color value then indexed by the upper 8 bits:
4353
	;
4354
	;   table[low bits][high 8 bits]
4355
4356
 
4357
4358
 
4359
4360
 
4361
 
4362
;         /* shift == insignificant bits */
4363
;         shift = (byte)((16U - sig_bit) & 0xff);
4364
4365
 
4366
;         shift = 0; /* keep all 16 bits */
4367
4368
 
4369
;      {
4370
	; PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
4371
	; the significant bits in the *input* when the output will
4372
	; eventually be 8 bits.  By default it is 11.
4373
4374
 
4375
;            shift = (16U - PNG_MAX_GAMMA_8);
4376
;      }
4377
4378
 
4379
;         shift = 8U; /* Guarantees at least one table! */
4380
4381
 
4382
4383
 
4384
	; PNG_COMPOSE).  This effectively smashed the background calculation for
4385
	; 16-bit output because the 8-bit table assumes the result will be
4386
	; reduced to 8 bits.
4387
4388
 
4389
;          png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
4390
;          png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma,
4391
;          png_ptr->screen_gamma) : PNG_FP_1);
4392
;
4393
;      else
4394
;          png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
4395
;          png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma,
4396
;          png_ptr->screen_gamma) : PNG_FP_1);
4397
;
4398
if (PNG_READ_BACKGROUND_SUPPORTED eq 1) | (PNG_READ_ALPHA_MODE_SUPPORTED eq 1) | (PNG_READ_RGB_TO_GRAY_SUPPORTED eq 1)
4399
;      if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
4400
;      {
4401
;         png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
4402
;             png_reciprocal(png_ptr->colorspace.gamma));
4403
4404
 
4405
	; the lookup on this table still uses gamma_shift, so it can't be.
4406
	; TODO: fix this.
4407
4408
 
4409
;             png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
4410
;             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
4411
;      }
4412
end if ;READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY
4413
;   }
4414
end if ;16BIT
4415
	ret
4416
endp
4417
;end if /* READ_GAMMA */
4418
4419
 
4420
;int (png_structrp png_ptr, int option, int onoff)
4421
align 4
4422
proc png_set_option uses ecx, png_ptr:dword, option:dword, onoff:dword
4423
	mov eax,[png_ptr]
4424
	or eax,eax
8408 IgorA 4425
	jz @f
4426
	mov ecx,[option]
8341 dunkaist 4427
	cmp ecx,0
4428
	jl @f
4429
	cmp ecx,PNG_OPTION_NEXT
4430
	jge @f
4431
	bt ecx,0 ;cmp (ecx & 1), 0
4432
	jc @f ;if (..!=0 && ..>=0 && ..<.. && ..==0)
4433
;      int mask = 3 << option;
4434
;      int setting = (2 + (onoff != 0)) << option;
4435
;      int current = png_ptr->options;
4436
4437
 
4438
4439
 
4440
		jmp .end_f
4441
	@@:
4442
	mov eax,PNG_OPTION_INVALID
4443
.end_f:
4444
	ret
4445
endp
4446
4447
 
4448
if (PNG_SIMPLIFIED_READ_SUPPORTED eq 1) | (PNG_SIMPLIFIED_WRITE_SUPPORTED eq 1)
4449
; sRGB conversion tables; these are machine generated with the code in
4450
; contrib/tools/makesRGB.c.  The actual sRGB transfer curve defined in the
4451
; specification (see the article at http://en.wikipedia.org/wiki/SRGB)
4452
; is used, not the gamma=1/2.2 approximation use elsewhere in libpng.
4453
; The sRGB to linear table is exact (to the nearest 16-bit linear fraction).
4454
; The inverse (linear to sRGB) table has accuracies as follows:
4455
4456
 
4457
;    error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact
4458
4459
 
4460
;    error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact
4461
4462
 
4463
4464
 
4465
 
4466
; The convert-to-sRGB table is only currently required for read.
4467
align 4
4468
png_sRGB_table dw 0,20,40,60,80,99,119,139,\
4469
	159,179,199,219,241,264,288,313,\
4470
	340,367,396,427,458,491,526,562,\
4471
	599,637,677,718,761,805,851,898,\
4472
	947,997,1048,1101,1156,1212,1270,1330,\
4473
	1391,1453,1517,1583,1651,1720,1790,1863,\
4474
	1937,2013,2090,2170,2250,2333,2418,2504,\
4475
	2592,2681,2773,2866,2961,3058,3157,3258,\
4476
	3360,3464,3570,3678,3788,3900,4014,4129,\
4477
	4247,4366,4488,4611,4736,4864,4993,5124,\
4478
	5257,5392,5530,5669,5810,5953,6099,6246,\
4479
	6395,6547,6700,6856,7014,7174,7335,7500,\
4480
	7666,7834,8004,8177,8352,8528,8708,8889,\
4481
	9072,9258,9445,9635,9828,10022,10219,10417,\
4482
	10619,10822,11028,11235,11446,11658,11873,12090,\
4483
	12309,12530,12754,12980,13209,13440,13673,13909,\
4484
	14146,14387,14629,14874,15122,15371,15623,15878,\
4485
	16135,16394,16656,16920,17187,17456,17727,18001,\
4486
	18277,18556,18837,19121,19407,19696,19987,20281,\
4487
	20577,20876,21177,21481,21787,22096,22407,22721,\
4488
	23038,23357,23678,24002,24329,24658,24990,25325,\
4489
	25662,26001,26344,26688,27036,27386,27739,28094,\
4490
	28452,28813,29176,29542,29911,30282,30656,31033,\
4491
	31412,31794,32179,32567,32957,33350,33745,34143,\
4492
	34544,34948,35355,35764,36176,36591,37008,37429,\
4493
	37852,38278,38706,39138,39572,40009,40449,40891,\
4494
	41337,41785,42236,42690,43147,43606,44069,44534,\
4495
	45002,45473,45947,46423,46903,47385,47871,48359,\
4496
	48850,49344,49841,50341,50844,51349,51858,52369,\
4497
	52884,53401,53921,54445,54971,55500,56032,56567,\
4498
	57105,57646,58190,58737,59287,59840,60396,60955,\
4499
	61517,62082,62650,63221,63795,64372,64952,65535
4500
end if ;SIMPLIFIED_READ
4501
4502
 
4503
; only the simplified versions.)
4504
align 4
4505
png_sRGB_base dw 128,1782,3383,4644,5675,6564,7357,8074,\
4506
	8732,9346,9921,10463,10977,11466,11935,12384,\
4507
	12816,13233,13634,14024,14402,14769,15125,15473,\
4508
	15812,16142,16466,16781,17090,17393,17690,17981,\
4509
	18266,18546,18822,19093,19359,19621,19879,20133,\
4510
	20383,20630,20873,21113,21349,21583,21813,22041,\
4511
	22265,22487,22707,22923,23138,23350,23559,23767,\
4512
	23972,24175,24376,24575,24772,24967,25160,25352,\
4513
	25542,25730,25916,26101,26284,26465,26645,26823,\
4514
	27000,27176,27350,27523,27695,27865,28034,28201,\
4515
	28368,28533,28697,28860,29021,29182,29341,29500,\
4516
	29657,29813,29969,30123,30276,30429,30580,30730,\
4517
	30880,31028,31176,31323,31469,31614,31758,31902,\
4518
	32045,32186,32327,32468,32607,32746,32884,33021,\
4519
	33158,33294,33429,33564,33697,33831,33963,34095,\
4520
	34226,34357,34486,34616,34744,34873,35000,35127,\
4521
	35253,35379,35504,35629,35753,35876,35999,36122,\
4522
	36244,36365,36486,36606,36726,36845,36964,37083,\
4523
	37201,37318,37435,37551,37668,37783,37898,38013,\
4524
	38127,38241,38354,38467,38580,38692,38803,38915,\
4525
	39026,39136,39246,39356,39465,39574,39682,39790,\
4526
	39898,40005,40112,40219,40325,40431,40537,40642,\
4527
	40747,40851,40955,41059,41163,41266,41369,41471,\
4528
	41573,41675,41777,41878,41979,42079,42179,42279,\
4529
	42379,42478,42577,42676,42775,42873,42971,43068,\
4530
	43165,43262,43359,43456,43552,43648,43743,43839,\
4531
	43934,44028,44123,44217,44311,44405,44499,44592,\
4532
	44685,44778,44870,44962,45054,45146,45238,45329,\
4533
	45420,45511,45601,45692,45782,45872,45961,46051,\
4534
	46140,46229,46318,46406,46494,46583,46670,46758,\
4535
	46846,46933,47020,47107,47193,47280,47366,47452,\
4536
	47538,47623,47709,47794,47879,47964,48048,48133,\
4537
	48217,48301,48385,48468,48552,48635,48718,48801,\
4538
	48884,48966,49048,49131,49213,49294,49376,49458,\
4539
	49539,49620,49701,49782,49862,49943,50023,50103,\
4540
	50183,50263,50342,50422,50501,50580,50659,50738,\
4541
	50816,50895,50973,51051,51129,51207,51285,51362,\
4542
	51439,51517,51594,51671,51747,51824,51900,51977,\
4543
	52053,52129,52205,52280,52356,52432,52507,52582,\
4544
	52657,52732,52807,52881,52956,53030,53104,53178,\
4545
	53252,53326,53400,53473,53546,53620,53693,53766,\
4546
	53839,53911,53984,54056,54129,54201,54273,54345,\
4547
	54417,54489,54560,54632,54703,54774,54845,54916,\
4548
	54987,55058,55129,55199,55269,55340,55410,55480,\
4549
	55550,55620,55689,55759,55828,55898,55967,56036,\
4550
	56105,56174,56243,56311,56380,56448,56517,56585,\
4551
	56653,56721,56789,56857,56924,56992,57059,57127,\
4552
	57194,57261,57328,57395,57462,57529,57595,57662,\
4553
	57728,57795,57861,57927,57993,58059,58125,58191,\
4554
	58256,58322,58387,58453,58518,58583,58648,58713,\
4555
	58778,58843,58908,58972,59037,59101,59165,59230,\
4556
	59294,59358,59422,59486,59549,59613,59677,59740,\
4557
	59804,59867,59930,59993,60056,60119,60182,60245,\
4558
	60308,60370,60433,60495,60558,60620,60682,60744,\
4559
	60806,60868,60930,60992,61054,61115,61177,61238,\
4560
	61300,61361,61422,61483,61544,61605,61666,61727,\
4561
	61788,61848,61909,61969,62030,62090,62150,62211,\
4562
	62271,62331,62391,62450,62510,62570,62630,62689,\
4563
	62749,62808,62867,62927,62986,63045,63104,63163,\
4564
	63222,63281,63340,63398,63457,63515,63574,63632,\
4565
	63691,63749,63807,63865,63923,63981,64039,64097,\
4566
	64155,64212,64270,64328,64385,64443,64500,64557,\
4567
	64614,64672,64729,64786,64843,64900,64956,65013,\
4568
	65070,65126,65183,65239,65296,65352,65409,65465
4569
align 4
4570
png_sRGB_delta db 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54,\
4571
	52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36,\
4572
	35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28,\
4573
	28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24,\
4574
	23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21,\
4575
	21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,\
4576
	19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,\
4577
	17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,\
4578
	16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,\
4579
	15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,\
4580
	14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,\
4581
	13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,\
4582
	12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,\
4583
	12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,\
4584
	11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,\
4585
	11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,\
4586
	11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,\
4587
	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,\
4588
	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,\
4589
	10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\
4590
	9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\
4591
	9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\
4592
	9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\
4593
	9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4594
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4595
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4596
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4597
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4598
	8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,\
4599
	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\
4600
	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\
4601
	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
4602
4603
 
4604
4605
 
4606
;int (voidp argument)
4607
align 4
4608
proc png_image_free_function uses ebx ecx edi esi, argument:dword
4609
locals
4610
;   png_imagep image = argument;
4611
;   png_controlp cp = image->opaque;
4612
	c png_control
4613
endl
4614
	; Double check that we have a png_ptr - it should be impossible to get here
4615
	; without one.
4616
4617
 
4618
	mov esi,[ebx+png_image.opaque] ;esi = cp
4619
	cmp dword[esi+png_control.png_ptr],0
4620
	jne @f ;if (..==0)
4621
		xor eax,eax
4622
		jmp .end_f
4623
	@@:
4624
4625
 
4626
if PNG_STDIO_SUPPORTED eq 1
4627
;      if (cp->owned_file != 0)
4628
;      {
4629
;         FILE *fp = cp->png_ptr->io_ptr;
4630
;         cp->owned_file = 0;
4631
4632
 
4633
;         if (fp != NULL)
4634
;         {
4635
;            cp->png_ptr->io_ptr = NULL;
4636
;            (void)fclose(fp);
4637
;         }
4638
;      }
4639
end if
4640
4641
 
4642
	; safely freed.  Notice that a png_error here stops the remainder of the
4643
	; cleanup, but this is probably fine because that would indicate bad memory
4644
	; problems anyway.
4645
4646
 
4647
	mov edi,ebp
4648
	sub edi,ecx ;edi = &c
4649
	rep movsb
4650
	sub edi,sizeof.png_control
4651
	sub esi,sizeof.png_control
4652
	mov dword[ebx+png_image.opaque],edi
4653
	stdcall png_free, [edi+png_control.png_ptr], esi
4654
4655
 
4656
;   if (c.for_write != 0)
4657
;   {
4658
if PNG_SIMPLIFIED_WRITE_SUPPORTED eq 1
4659
;         png_destroy_write_struct(&c.png_ptr, &c.info_ptr);
4660
else
4661
;         png_error(c.png_ptr, "simplified write not supported");
4662
end if
4663
		jmp .end2
4664
	.end1: ;else
4665
if PNG_SIMPLIFIED_READ_SUPPORTED eq 1
4666
;         png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL);
4667
else
4668
;         png_error(c.png_ptr, "simplified read not supported");
4669
end if
4670
	.end2:
4671
4672
 
4673
	xor eax,eax
4674
	inc eax
4675
.end_f:
4676
	ret
4677
endp
4678
4679
 
4680
align 4
4681
proc png_image_free uses eax ebx, image:dword
4682
	; Safely call the real function, but only if doing so is safe at this point
4683
	; (if not inside an error handling context).  Otherwise assume
4684
	; png_safe_execute will call this API after the return.
4685
4686
 
4687
	or ebx,ebx
8408 IgorA 4688
	jz @f
4689
	cmp dword[ebx+png_image.opaque],0
8341 dunkaist 4690
	je @f
4691
	mov eax,[ebx+png_image.opaque]
4692
	cmp dword[eax+png_control.error_buf],0
4693
	jne @f ;if (..!=0 && ..!=0 && ..==0)
4694
		; Ignore errors here:
4695
		stdcall png_safe_execute, ebx, png_image_free_function, ebx
4696
		mov dword[ebx+png_image.opaque],0
4697
	@@:
4698
	ret
4699
endp
4700
4701
 
4702
align 4
4703
proc png_image_error uses ebx, image:dword, error_message:dword
4704
	; Utility to log an error.
4705
	mov ebx,[image]
4706
	mov eax,ebx
4707
	add eax,png_image.message
4708
	stdcall png_safecat, eax, sizeof.png_image.message, 0, [error_message]
4709
	or dword[ebx+png_image.warning_or_error], PNG_IMAGE_ERROR
4710
	stdcall png_image_free, ebx
4711
	xor eax,eax
4712
	ret
4713
endp
4714
4715
 
4716
>