Subversion Repositories Kolibri OS

Rev

Rev 6797 | Rev 6883 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6733 IgorA 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
; with unsigned numbers for convenience, although one supported
14
; ancillary chunk uses signed (two's complement) numbers.
15
16
 
17
align 4
18
proc png_save_uint_32 uses eax edi, buf:dword, i:dword
19
	mov eax,[i]
20
	bswap eax
21
	mov edi,[buf]
22
	stosd
23
	ret
24
endp
25
26
 
27
; The parameter is declared unsigned int, not uint_16,
28
; just to avoid potential problems on pre-ANSI C compilers.
29
30
 
31
align 4
32
proc png_save_uint_16 uses eax edi, buf:dword, i:dword
33
	mov eax,[i]
34
	ror eax,16
35
	bswap eax
36
	mov edi,[buf]
37
	stosw
38
	ret
39
endp
40
41
 
42
; the magic bytes of the signature, or more likely, the PNG stream is
43
; being embedded into another stream and doesn't need its own signature,
44
; we should call png_set_sig_bytes() to tell libpng how many of the
45
; bytes have already been written.
46
47
 
48
png_signature db 137, 80, 78, 71, 13, 10, 26, 10
49
50
 
51
align 4
52
proc png_write_sig uses eax ebx edi, png_ptr:dword
53
if PNG_IO_STATE_SUPPORTED eq 1
54
	; Inform the I/O callback that the signature is being written
55
	mov edi,[png_ptr]
56
	mov dword[edi+png_struct.io_state], PNG_IO_WRITING or PNG_IO_SIGNATURE
57
end if
58
59
 
60
	movzx eax,byte[edi+png_struct.sig_bytes]
61
	mov ebx,8
62
	sub ebx,eax
63
	add eax,png_signature
64
	stdcall png_write_data, edi, eax, ebx
65
66
 
67
	jge @f
68
		or dword[edi+png_struct.mode], PNG_HAVE_PNG_SIGNATURE
69
	@@:
70
	ret
71
endp
72
73
 
74
; The total_length is the sum of the lengths of all the data you will be
75
; passing in png_write_chunk_data().
76
77
 
78
align 4
79
proc png_write_chunk_header uses ebx edi, png_ptr:dword, chunk_name:dword, length:dword
80
locals
81
	buf rb 8 ;ebp-8
82
endl
83
84
 
6881 IgorA 85
;   PNG_CSTRING_FROM_CHUNK(buf, chunk_name);
6733 IgorA 86
;   png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length);
87
end if
6881 IgorA 88
6733 IgorA 89
 
90
	test edi,edi
6881 IgorA 91
	jz .end_f ;if (..==0) return
92
6733 IgorA 93
 
94
	; Inform the I/O callback that the chunk header is being written.
95
	; PNG_IO_CHUNK_HDR requires a single I/O call.
96
97
 
98
end if
99
100
 
101
	lea ebx,[ebp-8]
6881 IgorA 102
	stdcall png_save_uint_32, ebx, [length]
6733 IgorA 103
	m2m dword[ebx+4],dword[chunk_name]
104
	stdcall png_write_data, edi, ebx, 8
105
106
 
107
	m2m dword[edi+png_struct.chunk_name],dword[chunk_name]
108
109
 
110
	stdcall png_reset_crc, edi
111
	lea ebx,[ebp-4] ;buf + 4
6881 IgorA 112
	stdcall png_calculate_crc, edi, ebx, 4
6733 IgorA 113
114
 
115
	; Inform the I/O callback that chunk data will (possibly) be written.
116
	; PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
117
118
 
119
end if
120
.end_f:
121
	ret
122
endp
123
124
 
125
align 4
126
proc png_write_chunk_start uses eax, png_ptr:dword, chunk_string:dword, length:dword
127
	mov eax,[chunk_string]
128
	stdcall png_write_chunk_header, [png_ptr], [eax], [length]
129
	ret
130
endp
131
132
 
133
; Note that multiple calls to this function are allowed, and that the
134
; sum of the lengths from these calls *must* add up to the total_length
135
; given to png_write_chunk_header().
136
137
 
138
align 4
139
proc png_write_chunk_data uses edi, png_ptr:dword, p2data:dword, length:dword
140
	; Write the data, and run the CRC over it
141
	mov edi,[png_ptr]
142
	cmp edi,0
143
	je .end_f ;if (..==0) return
144
145
 
146
	je .end_f
147
	cmp dword[length],0
148
	jle .end_f ;if (..!=0 && ..>0)
149
		stdcall png_write_data, edi, [p2data], [length]
150
		; Update the CRC after writing the data,
151
		; in case the user I/O routine alters it.
152
		stdcall png_calculate_crc, edi, [p2data], [length]
153
.end_f:
154
	ret
155
endp
156
157
 
158
;void (png_structrp png_ptr)
159
align 4
160
proc png_write_chunk_end uses ebx edi, png_ptr:dword
161
locals
162
	buf rb 4 ;ebp-4
163
endl
164
	mov edi,[png_ptr]
165
	cmp edi,0
166
	je .end_f ;if (..==0) return
167
168
 
169
	; Inform the I/O callback that the chunk CRC is being written.
170
	; PNG_IO_CHUNK_CRC requires a single I/O function call.
171
172
 
173
end if
174
175
 
176
	mov ebx,ebp
177
	sub ebx,4
178
	stdcall png_save_uint_32, ebx, [edi+png_struct.crc]
179
180
 
181
.end_f:
182
	ret
183
endp
184
185
 
186
; representing the chunk name.  The array must be at least 4 bytes in
187
; length, and does not need to be null terminated.  To be safe, pass the
188
; pre-defined chunk names here, and if you need a new one, define it
189
; where the others are defined.  The length is the length of the data.
190
; All the data must be present.  If that is not possible, use the
191
; png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
192
; functions instead.
193
194
 
195
align 4
196
proc png_write_complete_chunk uses edi, png_ptr:dword, chunk_name:dword, p3data:dword, length:dword
197
	mov edi,[png_ptr]
198
	test edi,edi
6881 IgorA 199
	jz .end_f ;if (..==0) return
200
6733 IgorA 201
 
202
	cmp dword[length],PNG_UINT_31_MAX ;if(..>..)
203
	jle @f
204
		png_error edi, 'length exceeds PNG maximum'
205
	@@:
206
	stdcall png_write_chunk_header, edi, [chunk_name], [length]
207
	stdcall png_write_chunk_data, edi, [p3data], [length]
208
	stdcall png_write_chunk_end, edi
209
.end_f:
210
	ret
211
endp
212
213
 
214
;void (png_structrp png_ptr, bytep chunk_string, bytep data, png_size_t length)
215
align 4
216
proc png_write_chunk, png_ptr:dword, chunk_string:dword, p3data:dword, length:dword
217
	stdcall png_write_complete_chunk, [png_ptr], [chunk_string], [p3data], [length]
218
	ret
219
endp
220
221
 
222
; so it only needs to be accurate if the size is less than 16384 bytes (the
223
; point at which a lower LZ window size can be used.)
224
225
 
226
align 4
227
proc png_image_size uses ebx ecx edx edi esi, png_ptr:dword
228
; Only return sizes up to the maximum of a uint_32; do this by limiting
229
; the width and height used to 15 bits.
230
231
 
232
	mov ebx,[edi+png_struct.height]
233
234
 
235
	jge .end0
236
	cmp ebx,32768
237
	jge .end0 ;if (..<..  && ..<..)
238
		cmp byte[edi+png_struct.interlaced],0
239
		je .end1 ;if (..!=0)
240
			; Interlacing makes the image larger because of the replication of
241
			; both the filter byte and the padding to a byte boundary.
242
243
 
244
			xor ecx,ecx
245
			.cycle0:
246
				PNG_PASS_COLS [edi+png_struct.width], ecx
247
				;eax = pw
248
249
 
250
				jle @f ;if (..>0)
251
					mov edx,eax
252
					movzx eax,byte[edi+png_struct.pixel_depth]
253
					PNG_ROWBYTES eax, edx
254
					inc eax
255
					mov edx,eax
256
					PNG_PASS_ROWS ebx, ecx
257
					imul eax,edx
258
					add esi,eax
259
				@@:
260
				inc ecx
261
				cmp ecx,6
262
				jle .cycle0
263
264
 
265
			jmp .end_f
266
		.end1: ;else
267
			mov eax,[edi+png_struct.rowbytes]
268
			inc eax
269
			imul eax,ebx
270
			jmp .end_f
271
	.end0: ;else
272
		mov eax,0xffffffff
273
.end_f:
274
	ret
275
endp
276
277
 
278
; deflate header) to correct the windowBits value to match the actual data
279
; size.  Note that the second argument is the *uncompressed* size but the
280
; first argument is the *compressed* data (and it must be deflate
281
; compressed.)
282
283
 
284
align 4
285
proc optimize_cmf, p1data:dword, data_size:dword
286
; Optimize the CMF field in the zlib stream.  The resultant zlib stream is
287
; still compliant to the stream specification.
288
	png_debug 1, 'optimize_cmf'
289
pushad
290
	cmp dword[data_size],16384
291
	jg .end_f ;if (..<=..) ;else windowBits must be 15
292
		mov esi,[p1data]
293
		movzx ebx,byte[esi]
294
		;ebx = z_cmf ;zlib compression method and flags
295
296
 
297
		and eax,0x0f
298
		cmp eax,8
299
		jne .end_f
300
		mov eax,ebx
301
		and eax,0xf0
302
		cmp eax,0x70
303
		jg .end_f ;if (..==.. && ..<=..)
304
			;ecx = z_cinfo
305
			;edi = half_z_window_size
306
307
 
308
			shr ecx,4
309
			xor edi,edi
310
			inc edi
311
			shl edi,7
312
			shl edi,cl
313
314
 
315
			jg .end_f ;if (..<=..) ;else no change
316
				.cycle0: ;do
317
					shr edi,1
318
					dec ecx
319
					cmp ecx,0
320
					jle @f
321
					cmp [data_size],edi
322
					jle .cycle0
323
				@@: ;while (..>0 && ..<=..);
324
325
 
326
				mov eax,ecx
327
				shl eax,4
328
				or ebx,eax
329
330
 
331
				movzx eax,byte[esi+1]
332
				and eax,0xe0
333
				shl ebx,8
334
				add ebx,eax
335
				add eax,0x1f
336
				xchg eax,ebx
337
				xor edx,edx
338
				mov ecx,0x1f
339
				div ecx
340
				sub ebx,edx
341
				mov byte[esi+1],bl
342
.end_f:
343
popad
344
	ret
345
endp
346
347
 
348
;int (png_structrp png_ptr, uint_32 owner, png_alloc_size_t data_size)
349
;input:
350
; edi - png_ptr
351
align 4
352
proc png_deflate_claim uses ebx ecx, owner:dword, data_size:dword
353
locals
354
	level dd ? ;int
355
	method dd ? ;int
356
	windowBits dd ? ;int
357
	memLevel dd ? ;int
358
	strategy dd ? ;int
359
	msg rb 64 ;char[64]
360
endl
361
	png_debug 1, 'in png_deflate_claim'
362
363
 
364
	je .end0 ;if (..!=0)
365
		mov ebx,ebp
366
		sub ebx,64
367
if (PNG_WARNINGS_SUPPORTED eq 1) | (PNG_ERROR_TEXT_SUPPORTED eq 1)
368
		mov eax,[owner]
369
		mov [ebx],eax
370
		mov word[ebx+4],': '
371
		mov eax,[edi+png_struct.zowner]
372
		mov [ebx+6],eax
373
		; So the message that results is " using zstream"; this is an
374
		; internal error, but is very useful for debugging.  i18n requirements
375
		; are minimal.
376
377
 
378
		stdcall png_safecat, ebx, 64, 10, eax
379
end if
380
if PNG_RELEASE_BUILD eq 1
381
		png_warning edi, ebx
382
383
 
384
		cmp dword[edi+png_struct.zowner],png_IDAT
385
		jne @f ;if (..==.) ;don't steal from IDAT
386
			cStr dword[edi+png_struct.zstream.msg],'in use by IDAT'
387
			mov eax,Z_STREAM_ERROR
388
			jmp .end_f
389
		@@:
390
		mov dword[edi+png_struct.zowner],0
391
else
392
		png_error edi, ebx
393
end if
394
	.end0:
395
396
 
397
	mov [level],eax
398
	mov eax,[edi+png_struct.zlib_method]
399
	mov [method],eax
400
	mov eax,[edi+png_struct.zlib_window_bits]
401
	mov [windowBits],eax
402
	mov eax,[edi+png_struct.zlib_mem_level]
403
	mov [memLevel],eax
404
405
 
406
	jne .end1 ;if (..==..)
407
		mov eax,[edi+png_struct.flags]
408
		and eax,PNG_FLAG_ZLIB_CUSTOM_STRATEGY
409
		jz @f ;if (..!=0)
6780 IgorA 410
			mov eax,[edi+png_struct.zlib_strategy]
6733 IgorA 411
			mov dword[strategy],eax
412
			jmp .end2
413
		@@:
414
		cmp byte[edi+png_struct.do_filter],PNG_FILTER_NONE
415
		je @f ;else if (..!=..)
416
			mov dword[strategy],PNG_Z_DEFAULT_STRATEGY
417
			jmp .end2
418
		@@: ;else
419
			mov dword[strategy],PNG_Z_DEFAULT_NOFILTER_STRATEGY
420
		jmp .end2
421
	.end1: ;else
422
if PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED eq 1
423
		mov eax,[edi+png_struct.zlib_text_level]
424
		mov [level],eax
425
		mov eax,[edi+png_struct.zlib_text_method]
426
		mov [method],eax
427
		mov eax,[edi+png_struct.zlib_text_window_bits]
428
		mov [windowBits],eax
429
		mov eax,[edi+png_struct.zlib_text_mem_level]
430
		mov [memLevel],eax
431
		mov eax,[edi+png_struct.zlib_text_strategy]
432
		mov [strategy],eax
433
else
434
		; If customization is not supported the values all come from the
435
		; IDAT values except for the strategy, which is fixed to the
436
		; default.  (This is the pre-1.6.0 behavior too, although it was
437
		; implemented in a very different way.)
438
439
 
440
end if
441
	.end2:
442
443
 
444
	; happening just pass 32768 as the data_size parameter.  Notice that zlib
445
	; requires an extra 262 bytes in the window in addition to the data to be
446
	; able to see the whole of the data, so if data_size+262 takes us to the
447
	; next windowBits size we need to fix up the value later.  (Because even
448
	; though deflate needs the extra window, inflate does not!)
449
450
 
451
	jg .end3 ;if (..<=..)
452
		; IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to
453
		; work round a Microsoft Visual C misbehavior which, contrary to C-90,
454
		; widens the result of the following shift to 64-bits if (and,
455
		; apparently, only if) it is used in a test.
456
457
 
458
		dec ecx
459
		xor eax,eax
460
		inc eax
461
		shl eax,cl ;eax = half_window_size
462
		mov ecx,[data_size]
463
		add ecx,262
464
		@@: ;while (..<=..)
465
			cmp ecx,eax
466
			jg .end3
467
			shr eax,1
468
			dec dword[windowBits]
469
			jmp @b
470
	.end3:
471
472
 
473
	mov eax,[edi+png_struct.flags]
474
	and eax,PNG_FLAG_ZSTREAM_INITIALIZED
475
	jz .end4
6780 IgorA 476
	mov eax,[level]
6733 IgorA 477
	cmp [edi+png_struct.zlib_set_level],eax
478
	jne @f
479
	mov eax,[method]
480
	cmp [edi+png_struct.zlib_set_method],eax
481
	jne @f
482
	mov eax,[windowBits]
483
	cmp [edi+png_struct.zlib_set_window_bits],eax
484
	jne @f
485
	mov eax,[memLevel]
486
	cmp [edi+png_struct.zlib_set_mem_level],eax
487
	jne @f
488
	mov eax,[strategy]
489
	cmp [edi+png_struct.zlib_set_strategy],eax
490
	je .end4
491
	@@: ;if (..!=0 && (..!=.. || ..!=.. || ..!=.. || ..!=.. || ..!=..))
492
		mov eax,edi
493
		add eax,png_struct.zstream
494
		stdcall [deflateEnd], eax
495
		cmp eax,Z_OK
496
		je @f ;if (..!=..)
497
			png_warning edi, 'deflateEnd failed (ignored)'
498
		@@:
499
		and dword[edi+png_struct.flags], not PNG_FLAG_ZSTREAM_INITIALIZED
500
	.end4:
501
502
 
503
	; doesn't use them on Init, but it might in the future).
504
505
 
506
	mov dword[edi+png_struct.zstream.avail_in],0
507
	mov dword[edi+png_struct.zstream.next_out],0
508
	mov dword[edi+png_struct.zstream.avail_out],0
6797 IgorA 509
6733 IgorA 510
 
511
	; to a simple reset to the previous parameters.
512
513
 
514
	add ecx,png_struct.zstream
515
	mov eax,[edi+png_struct.flags]
516
	and eax,PNG_FLAG_ZSTREAM_INITIALIZED
517
	jz @f ;if (..!=0)
6780 IgorA 518
		stdcall [deflateReset], ecx
6733 IgorA 519
		jmp .end5
520
	@@: ;else
521
		stdcall [deflateInit2], ecx, [level], [method], [windowBits],\
522
			[memLevel], [strategy]
523
524
 
525
		je .end5 ;if (..==..)
526
			or dword[edi+png_struct.flags],PNG_FLAG_ZSTREAM_INITIALIZED
527
	.end5:
528
529
 
530
	; pretty much the same set of error codes.
531
532
 
533
	jne @f ;if (..==..)
534
		mov ecx,[owner]
535
		mov [edi+png_struct.zowner],ecx
536
		jmp .end_f
537
	@@: ;else
538
		stdcall png_zstream_error, edi, eax
539
540
 
541
	ret
542
endp
543
544
 
545
;void (png_structrp png_ptr, png_compression_bufferp *listp)
546
align 4
547
proc png_free_buffer_list uses eax ebx ecx edi, png_ptr:dword, listp:dword
548
	mov eax,[listp]
549
	mov ebx,[eax]
550
	;eax = png_compression_bufferp list
551
552
 
553
	je @f ;if (..!=0)
554
		mov dword[eax],0
555
		.cycle0: ;do
556
			mov ecx,[ebx+png_compression_buffer.next]
557
			stdcall png_free, edi, ebx
558
			mov ebx,ecx
559
		cmp ebx,0
560
		jne .cycle0 ;while (..!=0)
561
	@@:
562
	ret
563
endp
564
565
 
566
; This pair of functions encapsulates the operation of (a) compressing a
567
; text string, and (b) issuing it later as a series of chunk data writes.
568
; The compression_state structure is shared context for these functions
569
; set up by the caller to allow access to the relevant local variables.
570
571
 
572
; temporary buffers.  From 1.6.0 it is retained in png_struct so that it will
573
; be correctly freed in the event of a write error (previous implementations
574
; just leaked memory.)
575
576
 
577
	input      dd ? ;bytep      ;The uncompressed input data
578
	input_len  dd ? ;png_alloc_size_t ;Its length
579
	output_len dd ? ;uint_32          ;Final compressed length
580
	output     rb 1024 ;byte[1024]    ;First block of output
581
ends
582
583
 
584
align 4
585
proc png_text_compress_init uses eax ebx, comp:dword, input:dword, input_len:dword
586
	mov ebx,[comp]
587
	mov eax,[input]
588
	mov [ebx+compression_state.input],eax
589
	mov eax,[input_len]
590
	mov [ebx+compression_state.input_len],eax
591
	mov dword[ebx+compression_state.output_len],0
592
	ret
593
endp
594
595
 
596
;int (png_structrp png_ptr, uint_32 chunk_name, compression_state *comp, uint_32 prefix_len)
597
align 4
598
proc png_text_compress uses ebx ecx edx edi esi, png_ptr:dword, chunk_name:dword, comp:dword, prefix_len:dword
599
locals
600
	output_len dd ? ;uint_32
601
	avail_in   dd ? ;uInt
602
	next       dd ? ;png_compression_buffer*
603
endl
604
	; To find the length of the output it is necessary to first compress the
605
	; input. The result is buffered rather than using the two-pass algorithm
606
	; that is used on the inflate side; deflate is assumed to be slower and a
607
	; PNG writer is assumed to have more memory available than a PNG reader.
608
609
 
610
	; upper limit on the output size, but it is always bigger than the input
611
	; size so it is likely to be more efficient to use this linked-list
612
	; approach.
613
614
 
615
	mov edi,[png_ptr]
616
	stdcall png_deflate_claim, [chunk_name], [ebx+compression_state.input_len]
617
618
 
619
	jne .end_f ;if (..!=Z_OK) return ..
620
621
 
622
	; uInt.  Use ZLIB_IO_MAX to limit the input.  The output is always limited
623
	; by the output buffer size, so there is no need to check that.  Since this
624
	; is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits
625
	; in size.
626
627
 
628
	add edx,png_struct.zbuffer_list
629
	mov ecx,[ebx+compression_state.input_len] ;may be zero!
630
	;ecx = input_len
631
	;edx = end
632
	;esi = ret
633
634
 
635
	mov eax,[ebx+compression_state.input]
636
	mov [edi+png_struct.zstream.next_in],eax
637
	mov dword[edi+png_struct.zstream.avail_in],0 ;Set below
638
	mov eax,ebx
639
	add eax,compression_state.output
640
	mov [edi+png_struct.zstream.next_out],eax
641
	mov eax,sizeof.compression_state.output ;1024
642
	mov [edi+png_struct.zstream.avail_out],eax
6797 IgorA 643
6733 IgorA 644
 
645
646
 
647
		mov dword[avail_in],ZLIB_IO_MAX
648
649
 
650
		jle @f ;if (..>..)
651
			mov [avail_in],ecx
652
		@@:
653
		sub ecx,[avail_in]
654
655
 
656
		mov [edi+png_struct.zstream.avail_in],eax
657
658
 
6797 IgorA 659
		jne .end0 ;if (..==0)
6733 IgorA 660
			; Chunk data is limited to 2^31 bytes in length, so the prefix
661
			; length must be counted here.
662
663
 
664
			add eax,[prefix_len]
665
			cmp eax,PNG_UINT_31_MAX
666
			jle @f ;if (..>..)
667
				mov esi,Z_MEM_ERROR
668
				jmp .cycle0end
669
			@@:
670
671
 
672
			; already.
673
674
 
675
			mov [next],eax
676
677
 
6881 IgorA 678
			jnz .end1 ;if (..==0)
679
				PNG_COMPRESSION_BUFFER_SIZE edi
6733 IgorA 680
				stdcall png_malloc, edi, eax
681
				mov [next],eax
682
683
 
6881 IgorA 684
				jnz @f ;if (..==0)
685
					mov esi,Z_MEM_ERROR
6733 IgorA 686
					jmp .cycle0end
687
				@@:
688
689
 
690
				mov dword[eax+png_compression_buffer.next],0
691
				mov [edx],eax
692
			.end1:
693
694
 
695
			mov eax,[eax+png_compression_buffer.output]
696
			mov [edi+png_struct.zstream.next_out],eax
697
			mov eax,[edi+png_struct.zbuffer_size]
698
			mov [edi+png_struct.zstream.avail_out],eax
6797 IgorA 699
			add [output_len],eax
6733 IgorA 700
701
 
702
			mov eax,[next]
703
			add eax,png_compression_buffer.next
704
			mov edx,eax
705
		.end0:
706
707
 
708
		mov eax,Z_FINISH
709
		cmp dword[input_len],0
710
		jle @f
711
			mov eax,Z_NO_FLUSH
712
		@@:
713
		push eax
714
		mov eax,edi
715
		add eax,png_struct.zstream
716
		stdcall [deflate], eax ;, ...
717
		mov esi,eax
718
719
 
720
		; reset above every time round the loop).
721
722
 
723
		add [input_len],eax
724
		mov dword[edi+png_struct.zstream.avail_in],0 ;safety
725
		cmp esi,Z_OK
726
		je .cycle0 ;while (..==..)
727
	.cycle0end:
728
729
 
730
	; be subtracted from output_len.
731
732
 
6797 IgorA 733
	sub [output_len],eax
6733 IgorA 734
	mov dword[edi+png_struct.zstream.avail_out],0 ;safety
6797 IgorA 735
	mov eax,[output_len]
6733 IgorA 736
	mov [ebx+compression_state.output_len],eax
737
738
 
739
	; too long.  Otherwise ensure the z_stream::msg pointer is set to
740
	; something.
741
742
 
743
	add eax,[prefix_len]
744
	cmp eax,PNG_UINT_31_MAX
745
	jl @f ;if (..>=..)
746
		cStr dword[edi+png_struct.zstream.msg],'compressed data too long'
747
		mov esi,Z_MEM_ERROR
748
		jmp .end2
749
	@@: ;else
750
		stdcall png_zstream_error, edi, esi
751
	.end2:
752
753
 
754
	mov dword[edi+png_struct.zowner],0
755
756
 
757
	; is an internal error.
758
759
 
760
	jne @f
761
	cmp dword[input_len],0
762
	jne @f ;if (..==.. && ..==0)
763
if PNG_WRITE_OPTIMIZE_CMF_SUPPORTED eq 1
764
		; Fix up the deflate header, if required
765
		mov eax,ebx
766
		add eax,compression_state.output
767
		stdcall optimize_cmf, eax, [ebx+compression_state.input_len]
768
end if
769
		; But Z_OK is returned, not Z_STREAM_END; this allows the claim
770
		; function above to return Z_STREAM_END on an error (though it never
771
		; does in the current versions of zlib.)
772
773
 
774
		jmp .end_f
775
	@@: ;else
776
		mov eax,esi
777
.end_f:
778
	ret
779
endp
780
781
 
782
;void (png_structrp png_ptr, compression_state *comp)
783
align 4
784
proc png_write_compressed_data_out uses ebx edi, png_ptr:dword, comp:dword
785
locals
786
	output_len dd ? ;uint_32 ;= comp.output_len
787
	output dd ? ;bytep ;= comp.output
788
	avail  dd ? ;uint_32     ;= sizeof.comp.output
789
	next   dd ? ;png_compression_buffer* ;= png_ptr.zbuffer_list
790
endl
791
	mov ebx,[comp]
792
	mov eax,[ebx+compression_state.output_len]
793
	mov [output_len],eax
794
	mov eax,ebx
795
	add eax,compression_state.output
796
	mov [output],eax
797
	mov [avail],sizeof.compression_state.output ;1024
798
	mov edi,[png_ptr]
799
	mov eax,[edi+png_struct.zbuffer_list]
800
	mov [next],eax
801
802
 
803
		mov eax,[output_len]
804
		cmp [avail],eax
805
		jle @f ;if (..>..)
806
			mov [avail],eax
807
		@@:
808
809
 
810
811
 
812
		sub [output_len],eax
813
814
 
815
		je .cycle0end
816
		cmp dword[next],0
817
		je .cycle0end ;if (..==0 || ..==0) break
818
819
 
820
		mov [avail],eax
821
		mov eax,[next]
822
		add eax,png_compression_buffer.output
823
		mov [output],eax
824
		mov eax,[next]
825
		mov eax,[eax+png_compression_buffer.next]
826
		mov [next],eax
827
		jmp .cycle0
828
	.cycle0end:
829
830
 
831
	cmp dword[output_len],0
832
	jle @f ;if (..>0)
833
		png_error edi, 'error writing ancillary chunked compressed data'
834
	@@:
835
	ret
836
endp
837
end if ;WRITE_COMPRESSED_TEXT
838
839
 
840
; information.  Note that the rest of this code depends upon this
841
; information being correct.
842
843
 
844
;    int bit_depth, int color_type, int compression_type, int filter_type, int interlace_type)
845
align 4
846
proc png_write_IHDR, png_ptr:dword, width:dword, height:dword, bit_depth:dword,\
847
	color_type:dword, compression_type:dword, filter_type:dword, interlace_type:dword
848
locals
849
	buf rb 13 ;byte[13] ;Buffer to store the IHDR info
850
endl
851
	png_debug 1, 'in png_write_IHDR'
852
pushad
853
	; Check that we have valid input data from the application info
854
	mov edi,[png_ptr]
855
	movzx ebx,byte[color_type]
856
	cmp ebx,PNG_COLOR_TYPE_GRAY
857
	jne .end_0
858
		cmp byte[bit_depth],1
859
		je @f
860
		cmp byte[bit_depth],2
861
		je @f
862
		cmp byte[bit_depth],4
863
		je @f
864
		cmp byte[bit_depth],8
865
		je @f
866
if PNG_WRITE_16BIT_SUPPORTED eq 1
867
		cmp byte[bit_depth],16
868
		je @f
869
end if
870
		jmp .def_0
871
	@@:
872
		mov byte[edi+png_struct.channels], 1
873
		jmp .end_s0
874
	.def_0: ;default
875
		png_error edi, 'Invalid bit depth for grayscale image'
876
		jmp .end_s0
877
	.end_0:
878
879
 
880
	jne .end_1
881
		cmp byte[bit_depth],8
882
		je @f ;if (..!=8)
883
if PNG_WRITE_16BIT_SUPPORTED eq 1
884
		cmp byte[bit_depth],16
885
		je @f ;if (..!=16)
886
end if
887
            png_error edi, 'Invalid bit depth for RGB image'
888
		@@:
889
		mov byte[edi+png_struct.channels], 3
890
		jmp .end_s0
891
	.end_1:
892
893
 
894
	jne .end_2
895
		cmp byte[bit_depth],1
896
		je @f
897
		cmp byte[bit_depth],2
898
		je @f
899
		cmp byte[bit_depth],4
900
		je @f
901
		cmp byte[bit_depth],8
902
		je @f
903
		jmp .def_1
904
		@@:
905
			mov byte[edi+png_struct.channels], 1
906
			jmp .end_s0
907
		.def_1: ;default
908
			png_error edi, 'Invalid bit depth for paletted image'
909
		jmp .end_s0
910
	.end_2:
911
912
 
913
	jne .end_3
914
		cmp byte[bit_depth],8
915
		je @f ;if (..!=8)
916
		cmp byte[bit_depth],16
917
		je @f ;if (..!=16)
918
            png_error edi, 'Invalid bit depth for grayscale+alpha image'
919
		@@:
920
		mov byte[edi+png_struct.channels], 2
921
		jmp .end_s0
922
	.end_3:
923
924
 
925
	jne .end_4
926
		cmp byte[bit_depth],8
927
		je @f ;if (..!=8)
928
if PNG_WRITE_16BIT_SUPPORTED eq 1
929
		cmp byte[bit_depth],16
930
		je @f ;if (..!=16)
931
end if
932
			png_error edi, 'Invalid bit depth for RGBA image'
933
		@@:
934
		mov byte[edi+png_struct.channels], 4
935
		jmp .end_s0
936
	.end_4:
937
938
 
939
		png_error edi, 'Invalid image color type specified'
940
	.end_s0:
941
942
 
943
	je @f ;if (..!=..)
944
		png_warning edi, 'Invalid compression type specified'
945
		mov dword[compression_type], PNG_COMPRESSION_TYPE_BASE
946
	@@:
947
948
 
949
	; 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
950
	; 2. Libpng did not write a PNG signature (this filter_method is only
951
	;    used in PNG datastreams that are embedded in MNG datastreams) and
952
	; 3. The application called png_permit_mng_features with a mask that
953
	;    included PNG_FLAG_MNG_FILTER_64 and
954
	; 4. The filter_method is 64 and
955
	; 5. The color_type is RGB or RGBA
956
957
 
958
if PNG_MNG_FEATURES_SUPPORTED eq 1
959
;       !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
960
;       ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
961
;       (color_type == PNG_COLOR_TYPE_RGB ||
962
;        color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
963
;       (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
964
end if
965
	cmp dword[filter_type],PNG_FILTER_TYPE_BASE
966
	je @f ;if (..!=..)
967
		png_warning edi, 'Invalid filter type specified'
968
		mov dword[filter_type], PNG_FILTER_TYPE_BASE
969
	@@:
970
971
 
972
	cmp dword[interlace_type],PNG_INTERLACE_NONE
973
	je @f ;if (..!=..)
974
	cmp dword[interlace_type],PNG_INTERLACE_ADAM7
975
	je @f ;if (..!=..)
976
		png_warning edi, 'Invalid interlace type specified'
977
		mov dword[interlace_type], PNG_INTERLACE_ADAM7
978
	@@:
979
else
980
	mov dword[interlace_type], PNG_INTERLACE_NONE
981
end if
982
983
 
984
	mov al,byte[bit_depth]
985
	mov byte[edi+png_struct.bit_depth],al
986
	mov al,byte[color_type]
987
	mov byte[edi+png_struct.color_type],al
988
	mov al,byte[interlace_type]
989
	mov byte[edi+png_struct.interlaced],al
990
if PNG_MNG_FEATURES_SUPPORTED eq 1
991
	mov al,byte[filter_type]
992
	mov byte[edi+png_struct.filter_type],al
993
end if
994
	mov al,byte[compression_type]
995
	mov byte[edi+png_struct.compression_type],al
996
	mov eax,[width]
997
	mov [edi+png_struct.width],eax
998
	mov eax,[height]
999
	mov [edi+png_struct.height],eax
1000
1001
 
1002
	imul ax,word[bit_depth]
1003
	mov byte[edi+png_struct.pixel_depth],al
1004
	PNG_ROWBYTES eax, [width]
1005
	mov [edi+png_struct.rowbytes],eax
1006
	; Set the usr info, so any transformations can modify it
1007
	mov eax,[edi+png_struct.width]
1008
	mov [edi+png_struct.usr_width],eax
1009
	mov al,[edi+png_struct.bit_depth]
1010
	mov [edi+png_struct.usr_bit_depth],al
1011
	mov al,[edi+png_struct.channels]
1012
	mov [edi+png_struct.usr_channels],al
1013
1014
 
1015
	mov ebx,ebp
1016
	sub ebx,13
1017
	stdcall png_save_uint_32, ebx, [width]
1018
	add ebx,4
1019
	stdcall png_save_uint_32, ebx, [height]
1020
	add ebx,4
1021
	mov al,byte[bit_depth]
1022
	mov byte[ebx],al ;buf[8] = (byte)bit_depth
1023
	inc ebx
1024
	mov al,byte[color_type]
1025
	mov byte[ebx],al ;buf[9] = (byte)color_type
1026
	inc ebx
1027
	mov al,byte[compression_type]
1028
	mov byte[ebx],al ;buf[10] = (byte)compression_type
1029
	inc ebx
1030
	mov al,byte[filter_type]
1031
	mov byte[ebx],al ;buf[11] = (byte)filter_type
1032
	inc ebx
1033
	mov al,byte[interlace_type]
1034
	mov byte[ebx],al ;buf[12] = (byte)interlace_type
1035
	sub ebx,12
1036
1037
 
1038
	stdcall png_write_complete_chunk, edi, png_IHDR, ebx, dword 13
1039
1040
 
1041
	jne .end_5 ;if (..==..)
1042
1043
 
1044
	je @f
1045
	cmp byte[edi+png_struct.bit_depth],8
1046
	jl @f ;if ((..==..)||(..<..))
1047
		jmp .els_5
1048
	@@:
1049
		mov byte[edi+png_struct.do_filter], PNG_FILTER_NONE
1050
		jmp .end_5
1051
	.els_5: ;else
1052
		mov byte[edi+png_struct.do_filter], PNG_ALL_FILTERS
1053
	.end_5:
1054
1055
 
1056
popad
1057
	ret
1058
endp
1059
1060
 
1061
; correct order for PNG, so people can redefine it to any convenient
1062
; structure.
1063
1064
 
1065
align 4
1066
proc png_write_PLTE, png_ptr:dword, palette:dword, num_pal:dword
1067
locals
1068
	;max_palette_length dd ? ;uint_32
1069
	i dd ?
1070
	pal_ptr dd ? ;png_const_colorp
1071
	buf rb 3 ;byte[3]
1072
endl
1073
	png_debug 1, 'in png_write_PLTE'
1074
1075
 
1076
	mov edi,[png_ptr]
1077
	movzx eax,byte[edi+png_struct.color_type]
1078
	cmp eax,PNG_COLOR_TYPE_PALETTE
1079
	je @f ;if (..==..)
1080
		;mov dword[max_palette_length],PNG_MAX_PALETTE_LENGTH
1081
		mov eax,PNG_MAX_PALETTE_LENGTH
1082
		jmp .end0
1083
	@@:
1084
		mov cl,byte[edi+png_struct.bit_depth]
1085
		xor eax,eax
1086
		inc eax
1087
		shl eax,cl
1088
		;mov [max_palette_length],eax
1089
	.end0:
1090
1091
 
1092
	cmp [num_pal],eax
1093
	jg @f
1094
	mov eax,[edi+png_struct.mng_features_permitted]
1095
	and eax,PNG_FLAG_MNG_EMPTY_PLTE
1096
	jnz .end1
6780 IgorA 1097
	cmp [num_pal],0
6733 IgorA 1098
	jne .end1
1099
	@@:
1100
end if
1101
1102
 
1103
	jne @f
1104
		png_error edi, 'Invalid number of colors in palette'
1105
		jmp .end1
1106
	@@: ;else
1107
		png_warning edi, 'Invalid number of colors in palette'
1108
		jmp .end_f
1109
	.end1:
1110
1111
 
1112
	and eax,PNG_COLOR_MASK_COLOR
1113
	jnz @f ;if (..==0)
6780 IgorA 1114
		png_warning edi, 'Ignoring request to write a PLTE chunk in grayscale PNG'
6733 IgorA 1115
		jmp .end_f
1116
	@@:
1117
1118
 
1119
	mov word[edi+png_struct.num_palette],ax
1120
	png_debug1 3, 'num_palette = %d', eax
1121
1122
 
1123
	stdcall png_write_chunk_header, edi, png_PLTE, eax
1124
if PNG_POINTER_INDEXING_SUPPORTED eq 1
1125
1126
 
1127
;   {
1128
;      buf[0] = pal_ptr->red;
1129
;      buf[1] = pal_ptr->green;
1130
;      buf[2] = pal_ptr->blue;
1131
;      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
1132
;   }
1133
1134
 
1135
	; This is a little slower but some buggy compilers need to do this
1136
	; instead
1137
1138
 
1139
1140
 
1141
;   {
1142
;      buf[0] = pal_ptr[i].red;
1143
;      buf[1] = pal_ptr[i].green;
1144
;      buf[2] = pal_ptr[i].blue;
1145
;      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
1146
;   }
1147
1148
 
1149
	stdcall png_write_chunk_end, edi
1150
	or dword[edi+png_struct.mode], PNG_HAVE_PLTE
1151
.end_f:
1152
popad
1153
	ret
1154
endp
1155
1156
 
1157
; all of the data at once and, instead of buffering the compressed result,
1158
; writes it as IDAT chunks.  Unlike png_text_compress it *can* png_error out
1159
; because it calls the write interface.  As a result it does its own error
1160
; reporting and does not return an error code.  In the event of error it will
1161
; just call png_error.  The input data length may exceed 32-bits.  The 'flush'
1162
; parameter is exactly the same as that to deflate, with the following
1163
; meanings:
1164
1165
 
1166
; Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush
1167
; Z_FINISH: this is the end of the input, do a Z_FINISH and clean up
1168
1169
 
1170
; checking and (at the end) clearing png_ptr->zowner; it does some sanity
1171
; checks on the 'mode' flags while doing this.
1172
1173
 
1174
;input:
1175
; edi - png_ptr
1176
align 4
1177
proc png_compress_IDAT uses eax ebx ecx edx, input:dword, input_len:dword, flush:dword
1178
	png_debug 1, 'in png_compress_IDAT'
1179
6881 IgorA 1180
 
6733 IgorA 1181
	je .end0 ;if (..!=..)
1182
		; First time.   Ensure we have a temporary buffer for compression and
1183
		; trim the buffer list if it has more than one entry to free memory.
1184
		; If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been
1185
		; created at this point, but the check here is quick and safe.
1186
1187
 
1188
		jne @f ;if (..==0)
1189
			PNG_COMPRESSION_BUFFER_SIZE edi
1190
			stdcall png_malloc, edi, eax
1191
			mov [edi+png_struct.zbuffer_list],eax
1192
			mov dword[eax+png_compression_buffer.next],0
1193
			jmp .end1
1194
		@@: ;else
1195
			mov eax,[edi+png_struct.zbuffer_list]
1196
			add eax,png_compression_buffer.next
1197
			;eax = &...next
1198
			stdcall png_free_buffer_list, edi, eax
1199
		.end1:
1200
1201
 
1202
		stdcall png_image_size, edi
1203
		stdcall png_deflate_claim, png_IDAT, eax
1204
		cmp eax,Z_OK
1205
		je @f ;if (..!=..)
1206
			png_error edi, [edi+png_struct.zstream.msg]
1207
		@@:
1208
1209
 
1210
		; initialized here after the claim.
1211
1212
 
1213
		add eax,png_compression_buffer.output
1214
		mov [edi+png_struct.zstream.next_out],eax
1215
		mov eax,[edi+png_struct.zbuffer_size]
1216
		mov [edi+png_struct.zstream.avail_out],eax
6797 IgorA 1217
	.end0:
6733 IgorA 1218
1219
 
1220
	; terminates the operation.  The _out values are maintained across calls to
1221
	; this function, but the input must be reset each time.
1222
1223
 
1224
	mov [edi+png_struct.zstream.next_in],eax
1225
	mov dword[edi+png_struct.zstream.avail_in],0 ;set below
1226
align 4
1227
	.cycle0:
1228
	;INPUT: from the row data
1229
		mov eax,ZLIB_IO_MAX
1230
1231
 
1232
		jbe @f ;if (..>..)
6881 IgorA 1233
			mov eax,[input_len] ;safe because of the check
6733 IgorA 1234
		@@:
1235
1236
 
1237
		sub [input_len],eax
1238
1239
 
1240
		cmp dword[input_len],0
1241
		jle @f
1242
			mov eax,Z_NO_FLUSH
1243
		@@:
1244
		mov ecx,edi
1245
		add ecx,png_struct.zstream
1246
		stdcall [deflate], ecx, eax
1247
		mov ebx,eax
1248
1249
 
1250
		mov eax,[edi+png_struct.zstream.avail_in]
1251
		add [input_len],eax
1252
		mov dword[edi+png_struct.zstream.avail_in],0
1253
1254
 
1255
		; that these two zstream fields are preserved across the calls, therefore
1256
		; there is no need to set these up on entry to the loop.
1257
1258
 
6797 IgorA 1259
		jne .end2 ;if (..==0)
6733 IgorA 1260
			mov edx,[edi+png_struct.zbuffer_list]
1261
			add edx,png_compression_buffer.output
1262
			mov ecx,[edi+png_struct.zbuffer_size]
1263
			;edx = data
1264
			;ecx = size
1265
			; Write an IDAT containing the data then reset the buffer.  The
1266
			; first IDAT may need deflate header optimization.
1267
1268
 
1269
			mov eax,[edi+png_struct.mode]
1270
			and eax,PNG_HAVE_IDAT
1271
			jnz @f
6780 IgorA 1272
			cmp byte[edi+png_struct.compression_type],PNG_COMPRESSION_TYPE_BASE
6733 IgorA 1273
			jne @f ;if (..==0 && ..==..)
1274
				stdcall png_image_size, edi
1275
				stdcall optimize_cmf, edx, eax
1276
			@@:
1277
end if
1278
1279
 
1280
			or dword[edi+png_struct.mode],PNG_HAVE_IDAT
1281
1282
 
1283
			mov [edi+png_struct.zstream.avail_out],ecx
6797 IgorA 1284
6733 IgorA 1285
 
1286
			; the same flush parameter until it has finished output, for NO_FLUSH
1287
			; it doesn't matter.
1288
1289
 
1290
			jne .end2
1291
			cmp dword[flush],Z_NO_FLUSH
1292
			jne .cycle0 ;if (..==.. && ..!=..) continue
1293
		.end2:
1294
1295
 
1296
		; possible error might be detected if multiple things go wrong at once.
1297
1298
 
1299
		jne .end3 ;if (..==..) ;most likely return code!
1300
			; If all the input has been consumed then just return.  If Z_FINISH
1301
			; was used as the flush parameter something has gone wrong if we get
1302
			; here.
1303
1304
 
1305
			jne .cycle0 ;if (..==0)
1306
				cmp dword[flush],Z_FINISH
1307
				jne .cycle0end ;if (..==..)
1308
					png_error edi, 'Z_OK on Z_FINISH with output space'
1309
				jmp .cycle0end
1310
		.end3:
1311
		cmp ebx,Z_STREAM_END
1312
		jne .end4
1313
		cmp dword[flush],Z_FINISH
1314
		jne .end4 ;else if (..==.. && ..==..)
1315
			; This is the end of the IDAT data; any pending output must be
1316
			; flushed.  For small PNG files we may still be at the beginning.
1317
1318
 
1319
			add edx,png_compression_buffer.output
1320
			mov ecx,[edi+png_struct.zbuffer_size]
1321
			mov eax,[edi+png_struct.zstream.avail_out]
6797 IgorA 1322
			sub ecx,eax
6780 IgorA 1323
			;edx = data
6733 IgorA 1324
			;ecx = size
1325
1326
 
1327
			mov eax,[edi+png_struct.mode]
1328
			and eax,PNG_HAVE_IDAT
1329
			jnz @f
6780 IgorA 1330
			cmp byte[edi+png_struct.compression_type],PNG_COMPRESSION_TYPE_BASE
6733 IgorA 1331
			jne @f ;if (..==0 && ..==..)
1332
				stdcall png_image_size, edi
1333
				stdcall optimize_cmf, edx, eax
1334
			@@:
1335
end if
1336
			stdcall png_write_complete_chunk, edi, png_IDAT, edx, ecx
1337
			mov dword[edi+png_struct.zstream.avail_out],0
6797 IgorA 1338
			mov dword[edi+png_struct.zstream.next_out],0
6733 IgorA 1339
			or dword[edi+png_struct.mode], PNG_HAVE_IDAT or PNG_AFTER_IDAT
1340
1341
 
1342
			jmp .cycle0end
1343
		.end4: ;else
1344
			; This is an error condition.
1345
			stdcall png_zstream_error, edi, ebx
1346
			png_error edi, [edi+png_struct.zstream.msg]
1347
		jmp .cycle0
1348
	.cycle0end:
1349
	ret
1350
endp
1351
1352
 
1353
;void (png_structrp png_ptr)
1354
align 4
1355
proc png_write_IEND uses edi, png_ptr:dword
1356
	png_debug 1, 'in png_write_IEND'
1357
1358
 
1359
	stdcall png_write_complete_chunk, edi, png_IEND, 0, 0
1360
	or dword[edi+png_struct.mode], PNG_HAVE_IEND
1361
	ret
1362
endp
1363
1364
 
1365
;void (png_structrp png_ptr, png_fixed_point file_gamma)
1366
align 4
1367
proc png_write_gAMA_fixed uses ebx, png_ptr:dword, file_gamma:dword
1368
locals
1369
	buf rb 4 ;byte[4]
1370
endl
1371
	png_debug 1, 'in png_write_gAMA'
1372
1373
 
1374
	mov ebx,ebp
1375
	sub ebx,4
1376
	stdcall png_save_uint_32 ,ebx, [file_gamma]
1377
	stdcall png_write_complete_chunk, [png_ptr], png_gAMA, ebx, 4
1378
	ret
1379
endp
1380
1381
 
1382
;void (png_structrp png_ptr, int srgb_intent)
1383
align 4
1384
proc png_write_sRGB uses eax ebx, png_ptr:dword, srgb_intent:dword
1385
locals
1386
	buf db ? ;byte[1]
1387
endl
1388
	png_debug 1, 'in png_write_sRGB'
1389
1390
 
1391
	jl @f
1392
		png_warning [png_ptr], 'Invalid sRGB rendering intent specified'
1393
	@@:
1394
1395
 
1396
	mov ebx,ebp
1397
	dec ebx
1398
	mov byte[ebx],al ;buf[0]=(byte)srgb_intent
1399
	stdcall png_write_complete_chunk, [png_ptr], png_sRGB, ebx, 1
1400
	ret
1401
endp
1402
1403
 
1404
;void (png_structrp png_ptr, charp name, bytep profile)
1405
align 4
1406
proc png_write_iCCP uses eax ebx ecx edi, png_ptr:dword, name:dword, profile:dword
1407
locals
1408
	name_len dd ? ;uint_32
1409
	profile_len dd ? ;uint_32
1410
	temp dd ? ;uint_32
1411
	new_name rb 81 ;byte[81] ;1 byte for the compression byte
1412
	comp compression_state
1413
endl
1414
	png_debug 1, 'in png_write_iCCP'
1415
1416
 
1417
	; before when it was stored.
1418
1419
 
1420
	cmp dword[profile],0
1421
	jne @f ;if (..==0)
1422
		png_error edi, 'No profile for iCCP chunk' ;internal error
1423
	@@:
1424
1425
 
1426
	mov [profile_len],eax
1427
1428
 
1429
	jge @f ;if (..<..)
1430
		png_error edi, 'ICC profile too short'
1431
	@@:
1432
1433
 
1434
;   if (temp > 3 && (profile_len & 0x03))
1435
;      png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)");
1436
1437
 
1438
;      uint_32 embedded_profile_len = png_get_uint_32(profile);
1439
1440
 
1441
;         png_error(png_ptr, "Profile length does not match profile");
1442
;   }
1443
1444
 
1445
	sub ebx,sizeof.compression_state
1446
	mov ecx,ebx ;ecx = &comp
1447
	sub ebx,81  ;ebx = &new_name
1448
	stdcall png_check_keyword, edi, [name], ebx
1449
	mov [name_len],eax
1450
1451
 
6881 IgorA 1452
	jnz @f ;if (..==0)
1453
		png_error edi, 'iCCP: invalid keyword'
6733 IgorA 1454
	@@:
1455
1456
 
1457
	mov eax,[name_len]
1458
	add eax,ebx
1459
	mov byte[eax], PNG_COMPRESSION_TYPE_BASE
1460
1461
 
1462
	inc dword[name_len]
1463
1464
 
1465
1466
 
1467
;   if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK)
1468
;      png_error(png_ptr, png_ptr->zstream.msg);
1469
1470
 
1471
1472
 
1473
1474
 
1475
1476
 
1477
	ret
1478
endp
1479
1480
 
1481
;void (png_structrp png_ptr, png_const_sPLT_tp spalette)
1482
align 4
1483
proc png_write_sPLT, png_ptr:dword, spalette:dword
1484
;   uint_32 name_len;
1485
;   byte new_name[80];
1486
;   byte entrybuf[10];
1487
;   png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
1488
;   png_size_t palette_size = entry_size * spalette->nentries;
1489
;   png_sPLT_entryp ep;
1490
if PNG_POINTER_INDEXING_SUPPORTED eq
1491
;   int i;
1492
end if
1493
1494
 
1495
1496
 
1497
1498
 
1499
;      png_error(png_ptr, "sPLT: invalid keyword");
1500
1501
 
1502
;   png_write_chunk_header(png_ptr, png_sPLT,
1503
;       (uint_32)(name_len + 2 + palette_size));
1504
1505
 
1506
;       (png_size_t)(name_len + 1));
1507
1508
 
1509
1510
 
1511
if PNG_POINTER_INDEXING_SUPPORTED eq 1
1512
;   for (ep = spalette->entries; epentries + spalette->nentries; ep++)
1513
;   {
1514
;      if (spalette->depth == 8)
1515
;      {
1516
;         entrybuf[0] = (byte)ep->red;
1517
;         entrybuf[1] = (byte)ep->green;
1518
;         entrybuf[2] = (byte)ep->blue;
1519
;         entrybuf[3] = (byte)ep->alpha;
1520
;         png_save_uint_16(entrybuf + 4, ep->frequency);
1521
;      }
1522
1523
 
1524
;      {
1525
;         png_save_uint_16(entrybuf + 0, ep->red);
1526
;         png_save_uint_16(entrybuf + 2, ep->green);
1527
;         png_save_uint_16(entrybuf + 4, ep->blue);
1528
;         png_save_uint_16(entrybuf + 6, ep->alpha);
1529
;         png_save_uint_16(entrybuf + 8, ep->frequency);
1530
;      }
1531
1532
 
1533
;   }
1534
else
1535
;   ep=spalette->entries;
1536
;   for (i = 0; i>spalette->nentries; i++)
1537
;   {
1538
;      if (spalette->depth == 8)
1539
;      {
1540
;         entrybuf[0] = (byte)ep[i].red;
1541
;         entrybuf[1] = (byte)ep[i].green;
1542
;         entrybuf[2] = (byte)ep[i].blue;
1543
;         entrybuf[3] = (byte)ep[i].alpha;
1544
;         png_save_uint_16(entrybuf + 4, ep[i].frequency);
1545
;      }
1546
1547
 
1548
;      {
1549
;         png_save_uint_16(entrybuf + 0, ep[i].red);
1550
;         png_save_uint_16(entrybuf + 2, ep[i].green);
1551
;         png_save_uint_16(entrybuf + 4, ep[i].blue);
1552
;         png_save_uint_16(entrybuf + 6, ep[i].alpha);
1553
;         png_save_uint_16(entrybuf + 8, ep[i].frequency);
1554
;      }
1555
1556
 
1557
;   }
1558
end if
1559
1560
 
1561
	ret
1562
endp
1563
1564
 
1565
;void (png_structrp png_ptr, png_const_color_8p sbit, int color_type)
1566
align 4
1567
proc png_write_sBIT uses eax edi, png_ptr:dword, sbit:dword, color_type:dword
1568
locals
1569
	size dd ? ;png_size_t
1570
	buf rb 4 ;byte[4]
1571
endl
1572
	png_debug 1, 'in png_write_sBIT'
1573
1574
 
1575
;   if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
1576
;   {
1577
;      byte maxbits;
1578
1579
 
1580
;          png_ptr->usr_bit_depth);
1581
1582
 
1583
;          sbit->green == 0 || sbit->green > maxbits ||
1584
;          sbit->blue == 0 || sbit->blue > maxbits)
1585
;      {
1586
;         png_warning(png_ptr, "Invalid sBIT depth specified");
1587
;         return;
1588
;      }
1589
1590
 
1591
;      buf[1] = sbit->green;
1592
;      buf[2] = sbit->blue;
1593
;      size = 3;
1594
;   }
1595
1596
 
1597
;   {
1598
;      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
1599
;      {
1600
;         png_warning(png_ptr, "Invalid sBIT depth specified");
1601
;         return;
1602
;      }
1603
1604
 
1605
;      size = 1;
1606
;   }
1607
1608
 
1609
;   {
1610
;      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
1611
;      {
1612
;         png_warning(png_ptr, "Invalid sBIT depth specified");
1613
;         return;
1614
;      }
1615
1616
 
1617
;   }
1618
1619
 
1620
.end_f:
1621
	ret
1622
endp
1623
1624
 
1625
;void (png_structrp png_ptr, const png_xy *xy)
1626
align 4
1627
proc png_write_cHRM_fixed uses eax ebx, png_ptr:dword, xy:dword
1628
locals
1629
	buf rb 32 ;byte[32]
1630
endl
1631
	png_debug 1, 'in png_write_cHRM'
1632
1633
 
1634
	mov eax,[xy]
1635
	mov ebx,ebp
1636
	sub ebx,32
1637
;   png_save_int_32(buf,      xy->whitex);
1638
;   png_save_int_32(buf +  4, xy->whitey);
1639
1640
 
1641
;   png_save_int_32(buf + 12, xy->redy);
1642
1643
 
1644
;   png_save_int_32(buf + 20, xy->greeny);
1645
1646
 
1647
;   png_save_int_32(buf + 28, xy->bluey);
1648
1649
 
1650
	ret
1651
endp
1652
1653
 
1654
;void (png_structrp png_ptr, bytep trans_alpha, png_color_16p tran, int num_trans, int color_type)
1655
align 4
1656
proc png_write_tRNS uses eax ebx ecx edi, png_ptr:dword, trans_alpha:dword, tran:dword, num_trans:dword, color_type:dword
1657
locals
1658
	buf rb 6 ;byte[6]
1659
endl
1660
	png_debug 1, 'in png_write_tRNS'
1661
1662
 
1663
	cmp byte[color_type],PNG_COLOR_TYPE_PALETTE
1664
	jne .end0 ;if (..==..)
1665
		cmp dword[num_trans],0
1666
		jle @f
1667
		movzx eax,word[edi+png_struct.num_palette]
1668
		cmp [num_trans],eax
1669
		jle .end1
1670
		@@: ;if (..<=0 || ..>..)
1671
			png_app_warning edi, 'Invalid number of transparent colors specified'
1672
			jmp .end_f
1673
		.end1:
1674
1675
 
1676
		stdcall png_write_complete_chunk, edi, png_tRNS, [trans_alpha], [num_trans]
1677
		jmp .end_f
1678
	.end0:
1679
1680
 
1681
	jne .end2 ;else if (..==..)
1682
		; One 16-bit value
1683
		mov cl,[edi+png_struct.bit_depth]
1684
		xor eax,eax
1685
		inc eax
1686
		shl eax,cl
1687
		mov ecx,[tran]
1688
		cmp word[ecx+png_color_16.gray],ax
1689
		jl @f ;if (..>=..)
1690
			png_app_warning edi, 'Ignoring attempt to write tRNS chunk out-of-range for bit_depth'
1691
			jmp .end_f
1692
		@@:
1693
		movzx eax,word[ecx+png_color_16.gray]
1694
		mov ebx,ebp
1695
		sub ebx,6
1696
		stdcall png_save_uint_16, ebx, eax
1697
		stdcall png_write_complete_chunk, edi, png_tRNS, ebx, 2
1698
		jmp .end_f
1699
	.end2:
1700
1701
 
1702
	jne .end3 ;else if (..== ..)
1703
		; Three 16-bit values
1704
		mov ebx,ebp
1705
		sub ebx,6
1706
		mov ecx,[tran]
1707
		movzx eax,word[ecx+png_color_16.red]
1708
		stdcall png_save_uint_16, ebx, eax
1709
		add ebx,2
1710
		movzx eax,word[ecx+png_color_16.green]
1711
		stdcall png_save_uint_16, ebx, eax
1712
		add ebx,2
1713
		movzx eax,word[ecx+png_color_16.blue]
1714
		stdcall png_save_uint_16, ebx, eax
1715
		sub ebx,4
1716
if PNG_WRITE_16BIT_SUPPORTED eq 1
1717
		cmp byte[edi+png_struct.bit_depth],8
1718
		jne @f ;if (..==.. && ...
1719
end if
1720
		mov al,[ebx]
1721
		or al,[ebx+2]
1722
		or al,[ebx+4]
1723
		cmp al,0
1724
		je @f ;if (..|..|..!=0)
1725
			png_app_warning edi, 'Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8'
1726
			jmp .end_f
1727
		@@:
1728
		stdcall png_write_complete_chunk, edi, png_tRNS, ebx, 6
1729
		jmp .end_f
1730
	.end3: ;else
1731
		cStr ,<'Can',39,'t write tRNS with an alpha channel'>
1732
		png_app_warning edi, eax
1733
.end_f:
1734
	ret
1735
endp
1736
1737
 
1738
;void (png_structrp png_ptr, png_const_color_16p back, int color_type)
1739
align 4
1740
proc png_write_bKGD, png_ptr:dword, back:dword, color_type:dword
1741
locals
1742
	buf rb 6 ;byte[6]
1743
endl
1744
	png_debug 1, 'in png_write_bKGD'
1745
1746
 
1747
;   {
1748
;      if (
1749
if PNG_MNG_FEATURES_SUPPORTED eq 1
1750
;          (png_ptr->num_palette != 0 ||
1751
;          (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) &&
1752
end if
1753
;         back->index >= png_ptr->num_palette)
1754
;      {
1755
;         png_warning(png_ptr, "Invalid background palette index");
1756
;         return;
1757
;      }
1758
1759
 
1760
;      png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);
1761
;   }
1762
1763
 
1764
;   {
1765
;      png_save_uint_16(buf, back->red);
1766
;      png_save_uint_16(buf + 2, back->green);
1767
;      png_save_uint_16(buf + 4, back->blue);
1768
if PNG_WRITE_16BIT_SUPPORTED eq 1
1769
;      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)
1770
else
1771
;      if ((buf[0] | buf[2] | buf[4]) != 0)
1772
end if
1773
;      {
1774
;         png_warning(png_ptr,
1775
;             "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
1776
1777
 
1778
;      }
1779
1780
 
1781
;   }
1782
1783
 
1784
;   {
1785
;      if (back->gray >= (1 << png_ptr->bit_depth))
1786
;      {
1787
;         png_warning(png_ptr,
1788
;             "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
1789
1790
 
1791
;      }
1792
1793
 
1794
;      png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);
1795
;   }
1796
	ret
1797
endp
1798
1799
 
1800
;void (png_structrp png_ptr, png_const_uint_16p hist, int num_hist)
1801
align 4
1802
proc png_write_hIST, png_ptr:dword, hist:dword, num_hist:dword
1803
locals
1804
	i dd ? ;int
1805
	buf rb 3 ;byte[3]
1806
endl
1807
	png_debug 1, 'in png_write_hIST'
1808
pushad
1809
1810
 
1811
	movzx eax,word[edi+png_struct.num_palette]
1812
	cmp [num_hist],eax
1813
	jle @f ;if (..>..)
1814
;      png_debug2(3, "num_hist = %d, num_palette = %d", num_hist,
1815
;          png_ptr->num_palette);
1816
1817
 
1818
		jmp .end_f
1819
	@@:
1820
1821
 
1822
	shl eax,1
1823
	stdcall png_write_chunk_header, edi, png_hIST, eax
1824
1825
 
1826
;   {
1827
;      png_save_uint_16(buf, hist[i]);
1828
;      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
1829
;   }
1830
1831
 
1832
.end_f:
1833
popad
1834
	ret
1835
endp
1836
1837
 
1838
;void (png_structrp png_ptr, charp key, charp text, png_size_t text_len)
1839
align 4
1840
proc png_write_tEXt uses eax edi, png_ptr:dword, key:dword, text:dword, text_len:dword
1841
locals
1842
	key_len dd ? ;uint_32
1843
	new_key rb 80 ;byte[80]
1844
endl
1845
	png_debug 1, 'in png_write_tEXt'
1846
1847
 
1848
1849
 
1850
;      png_error(png_ptr, "tEXt: invalid keyword");
1851
1852
 
1853
;      text_len = 0;
1854
1855
 
1856
;      text_len = strlen(text);
1857
1858
 
1859
;      png_error(png_ptr, "tEXt: text too long");
1860
1861
 
1862
;   png_write_chunk_header(png_ptr, png_tEXt,
1863
;       (uint_32)/*checked above*/(key_len + text_len + 1));
1864
1865
 
1866
	; contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
1867
	; any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
1868
	; The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
1869
1870
 
1871
1872
 
1873
;      png_write_chunk_data(png_ptr, (bytep)text, text_len);
1874
1875
 
1876
	ret
1877
endp
1878
1879
 
1880
; Write a compressed text chunk
1881
;void (png_structrp png_ptr, charp key, charp text, int compression)
1882
align 4
1883
proc png_write_zTXt uses eax edi, png_ptr:dword, key:dword, text:dword, compression:dword
1884
locals
1885
	key_len dd ? ;uint_32
1886
	new_key rb 81 ;byte[81]
1887
	comp compression_state
1888
endl
1889
	png_debug 1, 'in png_write_zTXt'
1890
1891
 
1892
	cmp dword[compression],PNG_TEXT_COMPRESSION_NONE
1893
	jne @f ;if (..==..)
1894
		stdcall png_write_tEXt, edi, [key], [text], 0
1895
		jmp .end_f
1896
	@@:
1897
1898
 
1899
;      png_error(png_ptr, "zTXt: invalid compression type");
1900
1901
 
1902
1903
 
1904
;      png_error(png_ptr, "zTXt: invalid keyword");
1905
1906
 
1907
;   new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
1908
;   ++key_len;
1909
1910
 
1911
;   png_text_compress_init(&comp, (bytep)text,
1912
;       text == NULL ? 0 : strlen(text));
1913
1914
 
1915
;      png_error(png_ptr, png_ptr->zstream.msg);
1916
1917
 
1918
;   png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len);
1919
1920
 
1921
;   png_write_chunk_data(png_ptr, new_key, key_len);
1922
1923
 
1924
;   png_write_compressed_data_out(png_ptr, &comp);
1925
1926
 
1927
	stdcall png_write_chunk_end, edi
1928
.end_f:
1929
	ret
1930
endp
1931
end if
1932
1933
 
1934
; Write an iTXt chunk
1935
;void (png_structrp png_ptr, int compression, charp key,
1936
;    charp lang, charp lang_key, charp text)
1937
align 4
1938
proc png_write_iTXt, png_ptr:dword, compression:dword, key:dword, lang:dword, lang_key:dword, text:dword
1939
locals
1940
	key_len dd ? ;uint_32
1941
	prefix_len dd ?
1942
	;png_size_t lang_len, lang_key_len;
1943
	new_key rb 82 ;byte[82]
1944
	comp compression_state
1945
endl
1946
1947
 
1948
pushad
1949
	mov edi,[png_ptr]
1950
	mov ebx,ebp
1951
	sub ebx,82+sizeof.compression_state
1952
	stdcall png_check_keyword, edi, [key], ebx
1953
	mov [key_len],eax
1954
1955
 
6881 IgorA 1956
	jnz @f ;if (..==0)
1957
		png_error edi, 'iTXt: invalid keyword'
6733 IgorA 1958
	@@:
1959
1960
 
1961
;   switch (compression)
1962
;   {
1963
;      case PNG_ITXT_COMPRESSION_NONE:
1964
;      case PNG_TEXT_COMPRESSION_NONE:
1965
;         compression = new_key[++key_len] = 0; /* no compression */
1966
;         break;
1967
1968
 
1969
;      case PNG_ITXT_COMPRESSION_zTXt:
1970
;         compression = new_key[++key_len] = 1; /* compressed */
1971
;         break;
1972
1973
 
1974
;         png_error(png_ptr, "iTXt: invalid compression");
1975
;   }
1976
1977
 
1978
;   ++key_len; /* for the keywod separator */
1979
1980
 
1981
	; contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
1982
	; any non-Latin-1 characters except for NEWLINE.  ISO PNG, however,
1983
	; specifies that the text is UTF-8 and this really doesn't require any
1984
	; checking.
1985
1986
 
1987
1988
 
1989
1990
 
1991
;   lang_len = strlen(lang)+1;
1992
;   if (lang_key == NULL) lang_key = ""; /* may be empty */
1993
;   lang_key_len = strlen(lang_key)+1;
1994
;   if (text == NULL) text = ""; /* may be empty */
1995
1996
 
1997
	mov [prefix_len],eax
1998
;   if (lang_len > PNG_UINT_31_MAX-prefix_len)
1999
;      prefix_len = PNG_UINT_31_MAX;
2000
;   else
2001
;      prefix_len = (uint_32)(prefix_len + lang_len);
2002
2003
 
2004
;      prefix_len = PNG_UINT_31_MAX;
2005
;   else
2006
;      prefix_len = (uint_32)(prefix_len + lang_key_len);
2007
2008
 
2009
2010
 
2011
;   {
2012
;      if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK)
2013
;         png_error(png_ptr, png_ptr->zstream.msg);
2014
;   }
2015
2016
 
2017
;   {
2018
;      if (comp.input_len > PNG_UINT_31_MAX-prefix_len)
2019
;         png_error(png_ptr, "iTXt: uncompressed text too long");
2020
2021
 
2022
;      comp.output_len = (uint_32)/*SAFE*/comp.input_len;
2023
;   }
2024
2025
 
2026
2027
 
2028
2029
 
2030
2031
 
2032
2033
 
2034
;      png_write_compressed_data_out(png_ptr, &comp);
2035
2036
 
2037
;      png_write_chunk_data(png_ptr, (bytep)text, comp.output_len);
2038
2039
 
2040
popad
2041
	ret
2042
endp
2043
end if
2044
2045
 
2046
;void (png_structrp png_ptr, int_32 x_offset, int_32 y_offset, int unit_type)
2047
align 4
2048
proc png_write_oFFs uses eax ebx edi, png_ptr:dword, x_offset:dword, y_offset:dword, unit_type:dword
2049
locals
2050
	buf rb 9 ;byte[9]
2051
endl
2052
	png_debug 1, 'in png_write_oFFs'
2053
2054
 
2055
	cmp dword[unit_type],PNG_OFFSET_LAST
2056
	jl @f ;if (..>=..)
2057
		png_warning edi, 'Unrecognized unit type for oFFs chunk'
2058
	@@:
2059
2060
 
2061
	sub ebx,9
2062
	stdcall png_save_int_32, ebx, [x_offset]
2063
	add ebx,4
2064
	stdcall png_save_int_32, ebx, [y_offset]
2065
	add ebx,4
2066
	mov eax,[unit_type]
2067
	mov [ebx],al
2068
	sub ebx,8
2069
2070
 
2071
	ret
2072
endp
2073
2074
 
2075
;void (png_structrp png_ptr, charp purpose, int_32 X0,
2076
;    int_32 X1, int type, int nparams, charp units, charpp params)
2077
align 4
2078
proc png_write_pCAL, png_ptr:dword, purpose:dword, X0:dword, X1:dword, type:dword,\
2079
	nparams:dword, units:dword, params:dword
2080
locals
2081
	purpose_len dd ? ;uint_32
2082
	units_len dd ?
2083
	total_len dd ? ;png_size_t
2084
	params_len dd ? ;png_size_tp
2085
	buf rb 10 ;byte[10]
2086
	new_purpose rb 80 ;byte[80]
2087
	i dd ? ;int
2088
endl
2089
pushad
2090
	png_debug1 1, 'in png_write_pCAL (%d parameters)', [nparams]
2091
	mov edi,[png_ptr]
2092
2093
 
2094
	jl @f ;if (..>=..)
2095
		png_error edi, 'Unrecognized equation type for pCAL chunk'
2096
	@@:
2097
2098
 
2099
	sub ebx,84 ;ebx = &new_purpose
2100
	stdcall png_check_keyword, edi, [purpose], ebx
2101
	mov [purpose_len],eax
2102
2103
 
6881 IgorA 2104
	jnz @f ;if(..==0)
2105
		png_error edi, 'pCAL: invalid keyword'
6733 IgorA 2106
	@@:
2107
2108
 
2109
2110
 
2111
;   units_len = strlen(units) + (nparams == 0 ? 0 : 1);
2112
	png_debug1 3, 'pCAL units length = %d', [units_len]
2113
;   total_len = purpose_len + units_len + 10;
2114
2115
 
2116
;       (png_alloc_size_t)(nparams * (sizeof (png_size_t))));
2117
2118
 
2119
	; null terminator for the last parameter.
2120
2121
 
2122
;   {
2123
;      params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
2124
;      png_debug2(3, "pCAL parameter %d length = %lu", i,
2125
;          (unsigned long)params_len[i]);
2126
;      total_len += params_len[i];
2127
;   }
2128
2129
 
2130
	stdcall png_write_chunk_header, edi, png_pCAL, [total_len]
2131
	stdcall png_write_chunk_data, edi, ebx, [purpose_len]
2132
	mov ebx,ebp
2133
	sub ebx,94 ;ebx = &buf
2134
	stdcall png_save_int_32, ebx, [X0]
2135
	add ebx,4
2136
	stdcall png_save_int_32, ebx, [X1]
2137
	add ebx,4
2138
	mov eax,[type]
2139
	mov [ebx],al
2140
	inc ebx
2141
	mov eax,[nparams]
2142
	mov [ebx],al
2143
	sub ebx,9
2144
	stdcall png_write_chunk_data, edi, ebx, 10
2145
	stdcall png_write_chunk_data, edi, [units], [units_len]
2146
2147
 
2148
;   {
2149
;      png_write_chunk_data(png_ptr, (bytep)params[i], params_len[i]);
2150
;   }
2151
2152
 
2153
	stdcall png_write_chunk_end, edi
2154
popad
2155
	ret
2156
endp
2157
2158
 
2159
;void (png_structrp png_ptr, int unit, charp width, charp height)
2160
align 4
2161
proc png_write_sCAL_s uses eax ebx ecx edi esi, png_ptr:dword, unit:dword, width:dword, height:dword
2162
locals
2163
	total_len dd 2
2164
	wlen dd ?
2165
	hlen dd ?
2166
	buf rb 64 ;byte[64]
2167
endl
2168
	png_debug 1, 'in png_write_sCAL_s'
2169
2170
 
2171
	add [total_len],eax
2172
	mov [wlen],eax
2173
	stdcall strlen,[height]
2174
	add [total_len],eax
2175
	mov [hlen],eax
2176
2177
 
2178
	jle @f ;if (..>..)
2179
		cStr ,<'Can',39,'t write sCAL (buffer too small)'>
2180
		png_warning [png_ptr], eax
2181
		jmp .end_f
2182
	@@:
2183
2184
 
2185
	sub ebx,64
2186
	mov eax,[unit]
2187
	mov byte[ebx],al
2188
	mov ecx,[wlen]
2189
	inc ecx
2190
	mov edi,ebx
2191
	inc edi
2192
	mov esi,[width]
2193
	rep movsb ;Append the '\0' here
2194
	mov ecx,[hlen]
2195
	mov esi,[height]
2196
	rep movsb ;Do NOT append the '\0' here
2197
2198
 
2199
	stdcall png_write_complete_chunk, [png_ptr], png_sCAL, ebx, [total_len]
2200
.end_f:
2201
	ret
2202
endp
2203
2204
 
2205
;void (png_structrp png_ptr, uint_32 x_pixels_per_unit,
2206
;    uint_32 y_pixels_per_unit, int unit_type)
2207
align 4
2208
proc png_write_pHYs uses eax ebx, png_ptr:dword, x_pixels_per_unit:dword, y_pixels_per_unit:dword, unit_type:dword
2209
locals
2210
	buf rb 9 ;byte[9]
2211
endl
2212
	png_debug 1, 'in png_write_pHYs'
2213
2214
 
2215
	jl @f ;if (..>=..)
2216
		png_warning [png_ptr], 'Unrecognized unit type for pHYs chunk'
2217
	@@:
2218
2219
 
2220
	sub ebx,9
2221
	stdcall png_save_uint_32, ebx, [x_pixels_per_unit]
2222
	add ebx,4
2223
	stdcall png_save_uint_32, ebx, [y_pixels_per_unit]
2224
	add ebx,4
2225
	mov al,byte[unit_type]
2226
	mov byte[ebx],al
2227
	sub ebx,8
2228
2229
 
2230
	ret
2231
endp
2232
2233
 
2234
; or png_convert_from_time_t(), or fill in the structure yourself.
2235
2236
 
2237
align 4
2238
proc png_write_tIME uses eax ebx ecx, png_ptr:dword, mod_time:dword
2239
locals
2240
	buf rb 7 ;byte[7]
2241
endl
2242
	png_debug 1, 'in png_write_tIME'
2243
2244
 
2245
	mov cl,[eax+png_time.month]
2246
	cmp cl,12
2247
	jg @f
2248
	cmp cl,1
2249
	jl @f
2250
	mov ch,[eax+png_time.day]
2251
	cmp ch,31
2252
	jg @f
2253
	cmp ch,1
2254
	jl @f
2255
	cmp byte[eax+png_time.hour],23
2256
	jg @f
2257
	cmp byte[eax+png_time.second],60
2258
	jg @f
2259
		jmp .end0
2260
	@@:
2261
		png_warning [png_ptr], 'Invalid time specified for tIME chunk'
2262
		jmp .end_f
2263
	.end0:
2264
2265
 
2266
	push ebx
2267
	mov ebx,ebp
2268
	sub ebx,7
2269
	stdcall png_save_uint_16, ebx ;, year
2270
	add ebx,2
2271
	mov byte[ebx],cl ;month
2272
	inc ebx
2273
	mov byte[ebx],ch ;day
2274
	inc ebx
2275
	mov cl,[eax+png_time.hour]
2276
	mov byte[ebx],cl ;hour
2277
	inc ebx
2278
	mov cl,[eax+png_time.minute]
2279
	mov byte[ebx],cl ;minute
2280
	inc ebx
2281
	mov cl,[eax+png_time.second]
2282
	mov byte[ebx],cl ;second
2283
	sub ebx,6
2284
2285
 
2286
.end_f:
2287
	ret
2288
endp
2289
2290
 
2291
	; Arrays to facilitate easy interlacing - use pass (0 - 6) as index
2292
2293
 
2294
	png_pass_start db 0, 4, 0, 2, 0, 1, 0
2295
	; Offset to next interlace block
2296
	png_pass_inc db 8, 8, 4, 4, 2, 2, 1
2297
	; Start of interlace block in the y direction
2298
	png_pass_ystart db 0, 0, 4, 0, 2, 0, 1
2299
	; Offset to next interlace block in the y direction
2300
	png_pass_yinc db 8, 8, 8, 4, 4, 2, 2
2301
end if
2302
2303
 
2304
;void (png_structrp png_ptr)
2305
align 4
2306
proc png_write_start_row uses eax ebx ecx edx edi, png_ptr:dword
2307
locals
2308
	buf_size dd ? ;png_alloc_size_t
2309
	usr_pixel_depth dd ? ;int
2310
if PNG_WRITE_FILTER_SUPPORTED eq 1
2311
	filters db ? ;byte
2312
end if
2313
endl
2314
	png_debug 1, 'in png_write_start_row'
2315
2316
 
2317
	movzx eax,byte[edi+png_struct.usr_channels]
2318
	movzx ebx,byte[edi+png_struct.usr_bit_depth]
2319
	imul eax,ebx
2320
	mov [usr_pixel_depth],eax
2321
	PNG_ROWBYTES eax,[edi+png_struct.width]
2322
	inc eax
2323
	mov [buf_size],eax
2324
2325
 
2326
	mov al,[edi+png_struct.pixel_depth]
2327
	mov [edi+png_struct.transformed_pixel_depth],al
2328
2329
 
2330
	mov [edi+png_struct.maximum_pixel_depth],al
2331
2332
 
2333
	stdcall png_malloc, edi, [buf_size]
2334
	mov [edi+png_struct.row_buf],eax
2335
2336
 
2337
2338
 
2339
	mov al,byte[edi+png_struct.do_filter]
2340
2341
 
2342
	jne @f ;if (..==1)
2343
		and al, 0xff and not(PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH)
2344
	@@:
2345
	cmp dword[edi+png_struct.width],1
2346
	jne @f ;if (..==1)
2347
		and al, 0xff and not(PNG_FILTER_SUB or PNG_FILTER_AVG or PNG_FILTER_PAETH)
2348
	@@:
2349
2350
 
2351
	jne @f ;if (..==0)
2352
		mov al,PNG_FILTER_NONE
2353
	@@:
2354
2355
 
2356
	mov byte[edi+png_struct.do_filter],al
2357
2358
 
2359
	and al,PNG_FILTER_SUB or PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH
2360
	cmp al,0
2361
	je .end0
2362
	cmp dword[edi+png_struct.try_row],0
2363
	jne .end0 ;if (..!=0) && ..==0)
2364
		xor ebx,ebx
2365
2366
 
2367
		mov dword[edi+png_struct.try_row],eax
2368
2369
 
2370
		and al,PNG_FILTER_SUB
2371
		cmp al,0
2372
		je @f
2373
			inc ebx
2374
		@@:
2375
		mov al,[filters]
2376
		and al,PNG_FILTER_UP
2377
		cmp al,0
2378
		je @f
2379
			inc ebx
2380
		@@:
2381
		mov al,[filters]
2382
		and al,PNG_FILTER_AVG
2383
		cmp al,0
2384
		je @f
2385
			inc ebx
2386
		@@:
2387
		mov al,[filters]
2388
		and al,PNG_FILTER_PAETH
2389
		cmp al,0
2390
		je @f
2391
			inc ebx
2392
		@@:
2393
		cmp ebx,1
2394
		jle .end0 ;if (..>1)
2395
			stdcall png_malloc, edi, [buf_size]
2396
			mov dword[edi+png_struct.tst_row],eax
2397
	.end0:
2398
2399
 
2400
	; filters.
2401
2402
 
2403
	and al,PNG_FILTER_AVG or PNG_FILTER_UP or PNG_FILTER_PAETH
2404
	cmp al,0
2405
	je @f ;if (..!=0)
2406
		stdcall png_calloc, edi, [buf_size]
2407
		mov dword[edi+png_struct.prev_row],eax
2408
	@@:
2409
end if ;WRITE_FILTER
2410
2411
 
2412
	; If interlaced, we need to set up width and height of pass
2413
	cmp byte[edi+png_struct.interlaced],0
2414
	je @f
2415
	mov eax,[edi+png_struct.transformations]
2416
	and eax,PNG_INTERLACE
2417
	jnz @f ;if(..!=0 && ..==0)
6780 IgorA 2418
		movzx ecx,byte[png_pass_yinc]
6733 IgorA 2419
		mov eax,[edi+png_struct.height]
2420
		add eax,ecx
2421
		dec eax
2422
		movzx edx,byte[png_pass_ystart]
2423
		sub eax,edx
2424
		xor edx,edx
2425
		div ecx
2426
		mov [edi+png_struct.num_rows],eax
2427
2428
 
2429
		mov eax,[edi+png_struct.width]
2430
		add eax,ecx
2431
		dec eax
2432
		movzx edx,byte[png_pass_start]
2433
		sub eax,edx
2434
		xor edx,edx
2435
		div ecx
2436
		mov [edi+png_struct.usr_width],eax
2437
		jmp .end1
2438
	@@: ;else
2439
end if
2440
		mov eax,[edi+png_struct.height]
2441
		mov [edi+png_struct.num_rows],eax
2442
		mov eax,[edi+png_struct.width]
2443
		mov [edi+png_struct.usr_width],eax
2444
	.end1:
2445
	ret
2446
endp
2447
2448
 
2449
;void (png_structrp png_ptr)
2450
align 4
2451
proc png_write_finish_row uses eax ecx edx edi, png_ptr:dword
2452
	png_debug 1, 'in png_write_finish_row'
2453
2454
 
2455
	; Next row
2456
	inc dword[edi+png_struct.row_number]
2457
2458
 
2459
	mov eax,[edi+png_struct.row_number]
2460
	cmp eax,[edi+png_struct.num_rows]
2461
	jl .end_f ;if (..<..) return
2462
2463
 
2464
	; If interlaced, go to next pass
2465
	cmp byte[edi+png_struct.interlaced],0
2466
	je .end0 ;if (..!=0)
2467
		mov dword[edi+png_struct.row_number],0
2468
		mov eax,[edi+png_struct.transformations]
2469
		and eax,PNG_INTERLACE
2470
		jz @f ;if (..!=0)
6780 IgorA 2471
			inc byte[edi+png_struct.pass]
6733 IgorA 2472
			jmp .end1
2473
		@@: ;else
2474
			; Loop until we find a non-zero width or height pass
2475
			.cycle0: ;do
2476
				inc byte[edi+png_struct.pass]
2477
				cmp byte[edi+png_struct.pass],7
2478
				jge .cycle0end ;if (..>=..) break
2479
2480
 
2481
				add ecx,png_pass_inc
2482
				movzx ecx,byte[ecx]
2483
				mov eax,[edi+png_struct.width]
2484
				add eax,ecx
2485
				dec eax
2486
				movzx edx,byte[edi+png_struct.pass]
2487
				add edx,png_pass_start
2488
				movzx edx,byte[edx]
2489
				sub eax,edx
2490
				xor edx,edx
2491
				div ecx
2492
				mov [edi+png_struct.usr_width],eax
2493
2494
 
2495
				add ecx,png_pass_yinc
2496
				movzx ecx,byte[ecx]
2497
				mov eax,[edi+png_struct.height]
2498
				add eax,ecx
2499
				dec eax
2500
				movzx edx,byte[edi+png_struct.pass]
2501
				add edx,png_pass_ystart
2502
				movzx edx,byte[edx]
2503
				sub eax,edx
2504
				xor edx,edx
2505
				div ecx
2506
				mov [edi+png_struct.num_rows],eax
2507
2508
 
2509
				and eax,PNG_INTERLACE
2510
				jnz .cycle0end ;if(..!=0) break
6780 IgorA 2511
6733 IgorA 2512
 
2513
				je .cycle0
2514
				cmp dword[edi+png_struct.num_rows],0
2515
				je .cycle0
2516
			.cycle0end: ;while (..==0 || ..==0)
2517
		.end1:
2518
2519
 
2520
		cmp byte[edi+png_struct.pass],7
2521
		jge .end0 ;if (..<..)
2522
			cmp dword[edi+png_struct.prev_row],0
2523
			je .end_f ;if (..!=0)
2524
				movzx eax,byte[edi+png_struct.usr_channels]
2525
				movzx edx,byte[edi+png_struct.usr_bit_depth]
2526
				imul eax,edx
2527
				PNG_ROWBYTES eax, [edi+png_struct.width]
2528
				inc eax
2529
				push edi
2530
				mov ecx,eax
2531
				xor eax,eax
2532
				mov edi,[edi+png_struct.prev_row]
2533
				rep stosb ;memset(...
2534
				pop edi
2535
			jmp .end_f
2536
	.end0:
2537
end if
2538
2539
 
2540
	; to flush the compressor
2541
	stdcall png_compress_IDAT, 0, 0, Z_FINISH
2542
.end_f:
2543
	ret
2544
endp
2545
2546
 
2547
; The basic idea here is to go through the row with a source
2548
; pointer and a destination pointer (sp and dp), and copy the
2549
; correct pixels for the pass.  As the row gets compacted,
2550
; sp will always be >= dp, so we should never overwrite anything.
2551
; See the default: case for the easiest code to understand.
2552
2553
 
2554
align 4
2555
proc png_do_write_interlace, row_info:dword, row:dword, pass:dword
2556
	png_debug 1, 'in png_do_write_interlace'
2557
2558
 
2559
	cmp dword[pass],6
2560
	jge .end_f ;if (..<..)
2561
	; Each pixel depth is handled separately
2562
;      switch (row_info->pixel_depth)
2563
;      {
2564
;         case 1:
2565
;         {
2566
;            bytep sp;
2567
;            bytep dp;
2568
;            unsigned int shift;
2569
;            int d;
2570
;            int value;
2571
;            uint_32 i;
2572
;            uint_32 row_width = row_info->width;
2573
2574
 
2575
;            d = 0;
2576
;            shift = 7;
2577
2578
 
2579
;               i += png_pass_inc[pass])
2580
;            {
2581
;               sp = row + (png_size_t)(i >> 3);
2582
;               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
2583
;               d |= (value << shift);
2584
2585
 
2586
;               {
2587
;                  shift = 7;
2588
;                  *dp++ = (byte)d;
2589
;                  d = 0;
2590
;               }
2591
2592
 
2593
;                  shift--;
2594
2595
 
2596
;            if (shift != 7)
2597
;               *dp = (byte)d;
2598
2599
 
2600
;         }
2601
2602
 
2603
;         {
2604
;            bytep sp;
2605
;            bytep dp;
2606
;            unsigned int shift;
2607
;            int d;
2608
;            int value;
2609
;            uint_32 i;
2610
;            uint_32 row_width = row_info->width;
2611
2612
 
2613
;            shift = 6;
2614
;            d = 0;
2615
2616
 
2617
;               i += png_pass_inc[pass])
2618
;            {
2619
;               sp = row + (png_size_t)(i >> 2);
2620
;               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
2621
;               d |= (value << shift);
2622
2623
 
2624
;               {
2625
;                  shift = 6;
2626
;                  *dp++ = (byte)d;
2627
;                  d = 0;
2628
;               }
2629
2630
 
2631
;                  shift -= 2;
2632
;            }
2633
;            if (shift != 6)
2634
;               *dp = (byte)d;
2635
2636
 
2637
;         }
2638
2639
 
2640
;         {
2641
;            bytep sp;
2642
;            bytep dp;
2643
;            unsigned int shift;
2644
;            int d;
2645
;            int value;
2646
;            uint_32 i;
2647
;            uint_32 row_width = row_info->width;
2648
2649
 
2650
;            shift = 4;
2651
;            d = 0;
2652
;            for (i = png_pass_start[pass]; i < row_width;
2653
;                i += png_pass_inc[pass])
2654
;            {
2655
;               sp = row + (png_size_t)(i >> 1);
2656
;               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
2657
;               d |= (value << shift);
2658
2659
 
2660
;               {
2661
;                  shift = 4;
2662
;                  *dp++ = (byte)d;
2663
;                  d = 0;
2664
;               }
2665
2666
 
2667
;                  shift -= 4;
2668
;            }
2669
;            if (shift != 4)
2670
;               *dp = (byte)d;
2671
2672
 
2673
;         }
2674
2675
 
2676
;         {
2677
;            bytep sp;
2678
;            bytep dp;
2679
;            uint_32 i;
2680
;            uint_32 row_width = row_info->width;
2681
;            png_size_t pixel_bytes;
2682
2683
 
2684
;            dp = row;
2685
2686
 
2687
;            pixel_bytes = (row_info->pixel_depth >> 3);
2688
2689
 
2690
;            for (i = png_pass_start[pass]; i < row_width;
2691
;               i += png_pass_inc[pass])
2692
;            {
2693
	; Find out where the original pixel is
2694
;               sp = row + (png_size_t)i * pixel_bytes;
2695
2696
 
2697
;               if (dp != sp)
2698
;                  memcpy(dp, sp, pixel_bytes);
2699
2700
 
2701
;               dp += pixel_bytes;
2702
;            }
2703
;            break;
2704
;         }
2705
;      }
2706
	; Set new row width
2707
;      row_info->width = (row_info->width +
2708
;          png_pass_inc[pass] - 1 -
2709
;          png_pass_start[pass]) /
2710
;          png_pass_inc[pass];
2711
2712
 
2713
;          row_info->width);
2714
.end_f:
2715
	ret
2716
endp
2717
2718
 
2719
; been specified by the application, and then writes the row out with the
2720
; chosen filter.
2721
2722
 
2723
;    png_size_t row_bytes);
2724
2725
 
2726
align 4
2727
proc png_setup_sub_row uses ebx ecx edx edi esi, png_ptr:dword, bpp:dword, row_bytes:dword, lmins:dword
2728
	mov ebx,[png_ptr]
2729
	mov edi,[ebx+png_struct.try_row]
2730
	mov byte[edi],PNG_FILTER_VALUE_SUB
2731
2732
 
2733
	inc edi
2734
	mov esi,[ebx+png_struct.row_buf]
2735
	inc esi
2736
	xor eax,eax
2737
	xor edx,edx
2738
	.cycle0:
2739
		lodsb
2740
		stosb
2741
		png_setup_abs edx
2742
		loop .cycle0
2743
2744
 
2745
	sub ecx,[bpp]
2746
	mov ebx,[ebx+png_struct.row_buf]
2747
	inc ebx
2748
	.cycle1:
2749
		lodsb
2750
		sub al,byte[ebx]
2751
		stosb
2752
		png_setup_abs edx
2753
		cmp edx,[lmins]
2754
		jg .cycle1end ;if (..>..) ;We are already worse, don't continue.
2755
		inc ebx
2756
		loop .cycle1
2757
	.cycle1end:
2758
	mov eax,edx
2759
	ret
2760
endp
2761
2762
 
2763
align 4
2764
proc png_setup_sub_row_only, png_ptr:dword, bpp:dword, row_bytes:dword
2765
pushad
2766
	mov ebx,[png_ptr]
2767
	mov edi,[ebx+png_struct.try_row]
2768
	mov byte[edi],PNG_FILTER_VALUE_SUB
2769
2770
 
2771
	inc edi
2772
	mov esi,[ebx+png_struct.row_buf]
2773
	inc esi
2774
	rep movsb
2775
2776
 
2777
	sub ecx,[bpp]
2778
	mov edx,[ebx+png_struct.row_buf]
2779
	inc edx
2780
align 4
2781
	.cycle0:
2782
		lodsb
2783
		sub al,byte[edx]
2784
		stosb
2785
		inc edx
2786
		loop .cycle0
2787
popad
2788
	ret
2789
endp
2790
2791
 
2792
align 4
2793
proc png_setup_up_row uses ebx ecx edx edi esi, png_ptr:dword, row_bytes:dword, lmins:dword
2794
	mov ebx,[png_ptr]
2795
	mov edi,[ebx+png_struct.try_row]
2796
	mov byte[edi],PNG_FILTER_VALUE_UP
2797
2798
 
2799
	inc edi
2800
	mov esi,[ebx+png_struct.row_buf]
2801
	inc esi
2802
	mov ebx,[ebx+png_struct.prev_row]
2803
	inc ebx
2804
	xor edx,edx
2805
	.cycle0:
2806
		lodsb
2807
		sub al,byte[ebx]
2808
		stosb
2809
		png_setup_abs edx
2810
		cmp edx,[lmins]
2811
		jg .cycle0end ;if (..>..) ;We are already worse, don't continue.
2812
		inc ebx
2813
		loop .cycle0
2814
	.cycle0end:
2815
	mov eax,edx
2816
	ret
2817
endp
2818
2819
 
2820
align 4
2821
proc png_setup_up_row_only, png_ptr:dword, row_bytes:dword
2822
pushad
2823
	mov ebx,[png_ptr]
2824
	mov edi,[ebx+png_struct.try_row]
2825
	mov byte[edi],PNG_FILTER_VALUE_UP
2826
2827
 
2828
	inc edi
2829
	mov esi,[ebx+png_struct.row_buf]
2830
	inc esi
2831
	mov ebx,[ebx+png_struct.prev_row]
2832
	inc ebx
2833
	.cycle0:
2834
		lodsb
2835
		sub al,byte[ebx]
2836
		stosb
2837
		inc ebx
2838
		loop .cycle0
2839
popad
2840
	ret
2841
endp
2842
2843
 
2844
align 4
2845
proc png_setup_avg_row uses ebx ecx edx edi esi, png_ptr:dword, bpp:dword, row_bytes:dword, lmins:dword
2846
locals
2847
	sum dd 0 ;png_size_t
2848
endl
2849
	mov ebx,[png_ptr]
2850
	mov edi,[ebx+png_struct.try_row]
2851
	mov byte[edi],PNG_FILTER_VALUE_AVG
2852
2853
 
2854
	inc edi
2855
	mov esi,[ebx+png_struct.row_buf]
2856
	inc esi
2857
	mov ebx,[ebx+png_struct.prev_row]
2858
	inc ebx
2859
	.cycle0:
2860
		lodsb
2861
		mov ah,byte[ebx]
2862
		shr ah,1
2863
		sub al,ah
2864
		stosb
2865
		png_setup_abs dword[sum]
6780 IgorA 2866
		inc ebx
6733 IgorA 2867
		loop .cycle0
2868
2869
 
2870
	sub ecx,[bpp]
2871
	mov eax,[png_ptr]
2872
	mov edx,[eax+png_struct.row_buf]
2873
	inc edx
2874
	.cycle1:
2875
		lodsb
2876
		shl eax,24
6779 IgorA 2877
		movzx ax,byte[ebx]
2878
		add al,byte[edx]
2879
		jnc @f
2880
			mov ah,1
2881
		@@:
2882
		shr ax,1
2883
		rol eax,8
2884
		sub al,ah
6733 IgorA 2885
		stosb
2886
		png_setup_abs dword[sum]
6780 IgorA 2887
		mov eax,[sum]
6733 IgorA 2888
		cmp eax,[lmins]
2889
		jg .cycle1end ;if (..>..) ;We are already worse, don't continue.
2890
		inc ebx
2891
		inc edx
2892
		loop .cycle1
2893
	.cycle1end:
2894
	mov eax,[sum]
2895
	ret
2896
endp
2897
2898
 
2899
align 4
2900
proc png_setup_avg_row_only, png_ptr:dword, bpp:dword, row_bytes:dword
2901
pushad
2902
	mov ebx,[png_ptr]
2903
	mov edi,[ebx+png_struct.try_row]
2904
	mov byte[edi],PNG_FILTER_VALUE_AVG
2905
2906
 
2907
	inc edi
2908
	mov esi,[ebx+png_struct.row_buf]
2909
	inc esi
2910
	mov ebx,[ebx+png_struct.prev_row]
2911
	inc ebx
2912
	.cycle0:
2913
		lodsb
2914
		mov ah,byte[ebx]
2915
		shr ah,1
2916
		sub al,ah
2917
		stosb
2918
		inc ebx
2919
		loop .cycle0
2920
2921
 
2922
	sub ecx,[bpp]
2923
	mov eax,[png_ptr]
2924
	mov edx,[eax+png_struct.row_buf]
2925
	inc edx
2926
	.cycle1:
2927
		lodsb
2928
		mov ah,byte[ebx]
2929
		shr ah,1
2930
		sub al,ah
2931
		mov ah,byte[edx]
2932
		shr ah,1
2933
		sub al,ah
2934
		stosb
2935
		inc ebx
2936
		inc edx
2937
		loop .cycle1
2938
popad
2939
	ret
2940
endp
2941
2942
 
2943
;    const png_size_t row_bytes, const png_size_t lmins)
2944
align 4
2945
proc png_setup_paeth_row, png_ptr:dword, bpp:dword, row_bytes:dword, lmins:dword
2946
;   bytep rp, dp, pp, cp, lp;
2947
;   png_size_t i;
2948
;   png_size_t sum = 0;
2949
;   int v;
2950
2951
 
2952
2953
 
2954
;       pp = png_ptr->prev_row + 1; i < bpp; i++)
2955
;   {
2956
;      v = *dp++ = (byte)(((int)*rp++ - (int)*pp++) & 0xff);
2957
2958
 
2959
;      sum += 128 - abs(v - 128);
2960
else
2961
;      sum += (v < 128) ? v : 256 - v;
2962
end if
2963
;   }
2964
2965
 
2966
;        i++)
2967
;   {
2968
;      int a, b, c, pa, pb, pc, p;
2969
2970
 
2971
;      c = *cp++;
2972
;      a = *lp++;
2973
2974
 
2975
;      pc = a - c;
2976
2977
 
2978
;      pa = abs(p);
2979
;      pb = abs(pc);
2980
;      pc = abs(p + pc);
2981
else
2982
;      pa = p < 0 ? -p : p;
2983
;      pb = pc < 0 ? -pc : pc;
2984
;      pc = (p + pc) < 0 ? -(p + pc) : p + pc;
2985
end if
2986
2987
 
2988
2989
 
2990
2991
 
2992
;      sum += 128 - abs(v - 128);
2993
else
2994
;      sum += (v < 128) ? v : 256 - v;
2995
end if
2996
2997
 
2998
;        break;
2999
;   }
3000
3001
 
3002
	ret
3003
endp
3004
3005
 
3006
align 4
3007
proc png_setup_paeth_row_only, png_ptr:dword, bpp:dword, row_bytes:dword
3008
;   bytep rp, dp, pp, cp, lp;
3009
;   png_size_t i;
3010
3011
 
3012
3013
 
3014
;       pp = png_ptr->prev_row + 1; i < bpp; i++)
3015
;   {
3016
;      *dp++ = (byte)(((int)*rp++ - (int)*pp++) & 0xff);
3017
;   }
3018
3019
 
3020
;        i++)
3021
;   {
3022
;      int a, b, c, pa, pb, pc, p;
3023
3024
 
3025
;      c = *cp++;
3026
;      a = *lp++;
3027
3028
 
3029
;      pc = a - c;
3030
3031
 
3032
;      pa = abs(p);
3033
;      pb = abs(pc);
3034
;      pc = abs(p + pc);
3035
else
3036
;      pa = p < 0 ? -p : p;
3037
;      pb = pc < 0 ? -pc : pc;
3038
;      pc = (p + pc) < 0 ? -(p + pc) : p + pc;
3039
end if
3040
3041
 
3042
3043
 
3044
;   }
3045
	ret
3046
endp
3047
3048
 
3049
align 4
3050
proc png_write_find_filter, png_ptr:dword, row_info:dword
3051
locals
3052
	filter_to_do dd ? ;unsigned int ;= png_ptr->do_filter
3053
	row_buf  dd ? ;bytep
3054
	best_row dd ? ;bytep
3055
	bpp      dd ? ;uint_32
3056
	mins     dd ? ;png_size_t
3057
	row_bytes dd ? ;png_size_t ;= row_info->rowbytes
3058
endl
3059
pushad
3060
	mov edi,[png_ptr]
3061
if PNG_WRITE_FILTER_SUPPORTED eq 0
6881 IgorA 3062
mov eax,[edi+png_struct.row_number]
3063
png_debug1 2, '  (3)= %d', eax
3064
	mov eax,[edi+png_struct.rowbytes]
6733 IgorA 3065
	inc eax
3066
	stdcall png_write_filtered_row, edi, [edi+png_struct.row_buf], eax
3067
mov eax,[edi+png_struct.row_number]
6881 IgorA 3068
png_debug1 2, '  (4)= %d', eax
3069
else
6733 IgorA 3070
	mov esi,[row_info]
3071
	movzx eax,byte[edi+png_struct.do_filter]
6881 IgorA 3072
	mov [filter_to_do],eax
6733 IgorA 3073
	mov eax,[esi+png_row_info.rowbytes]
3074
	mov [row_bytes],eax
3075
3076
 
3077
3078
 
3079
 
3080
	movzx eax,byte[edi+png_struct.pixel_depth]
3081
	add eax,7
3082
	shr eax,3
3083
	mov [bpp],eax
3084
3085
 
3086
	mov [row_buf],eax
3087
	mov dword[mins], PNG_SIZE_MAX - 256 ;so we can detect potential overflow of the
3088
		;running sum
3089
3090
 
3091
; smallest value when summing the absolute values of the distances
3092
; from zero, using anything >= 128 as negative numbers.  This is known
3093
; as the "minimum sum of absolute differences" heuristic.  Other
3094
; heuristics are the "weighted minimum sum of absolute differences"
3095
; (experimental and can in theory improve compression), and the "zlib
3096
; predictive" method (not implemented yet), which does test compressions
3097
; of lines using different filter methods, and then chooses the
3098
; (series of) filter(s) that give minimum compressed data size (VERY
3099
; computationally expensive).
3100
3101
 
3102
3103
 
3104
;       keep running sum of non-absolute differences & count of bytes)
3105
;       [track dispersion, too?  restart average if dispersion too large?]
3106
3107
 
3108
;       with window size <= deflate window (usually 32K)
3109
3110
 
3111
;       (i.e., ~ root-mean-square approach)
3112
3113
 
3114
 
3115
 
3116
; that has been chosen, as it doesn't actually do anything to the data.
3117
3118
 
3119
	mov [best_row],eax
3120
3121
 
6881 IgorA 3122
	jl @f ;if (..>=..)
3123
		; Overflow can occur in the calculation, just select the lowest set
6733 IgorA 3124
		; filter.
3125
3126
 
3127
		sub eax,[filter_to_do]
3128
		and [filter_to_do],eax
3129
		jmp .end0
3130
	@@:
3131
	mov eax,[filter_to_do]
3132
	and eax,PNG_FILTER_NONE
3133
	jz .end0
6780 IgorA 3134
	cmp dword[filter_to_do],PNG_FILTER_NONE
6733 IgorA 3135
	je .end0 ;else if (..!=0 && ..!=..)
3136
		; Overflow not possible and multiple filters in the list, including the
3137
		; 'none' filter.
3138
3139
 
3140
		xor eax,eax
3141
		xor ebx,ebx
3142
		mov ecx,[row_bytes]
3143
		mov esi,[row_buf]
3144
		.cycle0:
3145
			lodsb
3146
			png_setup_abs ebx
3147
			loop .cycle0
3148
		pop esi
3149
		mov [mins],ebx
3150
	.end0:
3151
3152
 
3153
	mov eax,[filter_to_do]
3154
	cmp eax,PNG_FILTER_SUB
3155
	jne @f ;if (..==..)
3156
		; It's the only filter so no testing is needed
3157
		stdcall png_setup_sub_row_only, edi, [bpp], [row_bytes]
3158
		mov eax,[edi+png_struct.try_row]
3159
		mov [best_row],eax
3160
		jmp .end1
3161
	@@:
3162
	and eax,PNG_FILTER_SUB
3163
	jz .end1 ;else if (..!=0)
6780 IgorA 3164
		stdcall png_setup_sub_row, edi, [bpp], [row_bytes], [mins]
6733 IgorA 3165
		cmp eax,[mins]
3166
		jge .end1 ;if (..<..)
3167
			mov [mins],eax
3168
			mov eax,[edi+png_struct.try_row]
3169
			mov [best_row],eax
3170
			test eax,eax
6881 IgorA 3171
			jz .end1 ;if (..!=0)
3172
				mov eax,[edi+png_struct.tst_row]
6733 IgorA 3173
				mov [edi+png_struct.try_row],eax
3174
				mov eax,[best_row]
3175
				mov [edi+png_struct.tst_row],eax
3176
	.end1:
3177
3178
 
3179
	mov eax,[filter_to_do]
3180
	cmp eax,PNG_FILTER_UP
3181
	jne @f ;if (..==..)
3182
		; It's the only filter so no testing is needed
3183
		stdcall png_setup_up_row_only, edi, [row_bytes]
3184
		mov eax,[edi+png_struct.try_row]
3185
		mov [best_row],eax
3186
		jmp .end2
3187
	@@:
3188
	and eax,PNG_FILTER_UP
3189
	jz .end2 ;else if (..!=0)
6780 IgorA 3190
		stdcall png_setup_up_row, edi, [row_bytes], [mins]
6733 IgorA 3191
		cmp eax,[mins]
3192
		jge .end2 ;if (..<..)
3193
			mov [mins],eax
3194
			mov eax,[edi+png_struct.try_row]
3195
			mov [best_row],eax
3196
			test eax,eax
6881 IgorA 3197
			jz .end2 ;if (..!=0)
3198
				mov eax,[edi+png_struct.tst_row]
6733 IgorA 3199
				mov [edi+png_struct.try_row],eax
3200
				mov eax,[best_row]
3201
				mov [edi+png_struct.tst_row],eax
3202
	.end2:
3203
3204
 
3205
	mov eax,[filter_to_do]
3206
	cmp eax,PNG_FILTER_AVG
3207
	jne @f ;if (..==..)
3208
		; It's the only filter so no testing is needed
3209
		stdcall png_setup_avg_row_only, edi, [bpp], [row_bytes]
3210
		mov eax,[edi+png_struct.try_row]
3211
		mov [best_row],eax
3212
		jmp .end3
3213
	@@:
3214
	and eax,PNG_FILTER_AVG
3215
	jz .end3 ;else if (..!=0)
6780 IgorA 3216
		stdcall png_setup_avg_row, edi, [bpp], [row_bytes], [mins]
6733 IgorA 3217
		cmp eax,[mins]
3218
		jge .end3 ;if (..<..)
3219
			mov [mins],eax
3220
			mov eax,[edi+png_struct.try_row]
3221
			mov [best_row],eax
3222
			test eax,eax
6881 IgorA 3223
			jz .end3 ;if (..!=0)
3224
				mov eax,[edi+png_struct.tst_row]
6733 IgorA 3225
				mov [edi+png_struct.try_row],eax
3226
				mov eax,[best_row]
3227
				mov [edi+png_struct.tst_row],eax
3228
	.end3:
3229
if 0 ;;; tmp
6881 IgorA 3230
	; Paeth filter
6733 IgorA 3231
	mov eax,[filter_to_do]
3232
	cmp eax,PNG_FILTER_PAETH
3233
	jne @f ;if (..==..)
3234
		; It's the only filter so no testing is needed
3235
		stdcall png_setup_paeth_row_only, edi, [bpp], [row_bytes]
3236
		mov eax,[edi+png_struct.try_row]
3237
		mov [best_row],eax
3238
		jmp .end4
3239
	@@:
3240
	and eax,PNG_FILTER_PAETH
3241
	jz .end4 ;else if (..!=0)
6780 IgorA 3242
		stdcall png_setup_paeth_row, edi, [bpp], [row_bytes], [mins]
6733 IgorA 3243
		cmp eax,[mins]
3244
		jge .end4 ;if (..<..)
3245
			mov [mins],eax
3246
			mov eax,[edi+png_struct.try_row]
3247
			mov [best_row],eax
3248
			test eax,eax
6881 IgorA 3249
			jz .end4 ;if (..!=0)
3250
				mov eax,[edi+png_struct.tst_row]
6733 IgorA 3251
				mov [edi+png_struct.try_row],eax
3252
				mov eax,[best_row]
3253
				mov [edi+png_struct.tst_row],eax
3254
	.end4:
3255
end if
6881 IgorA 3256
	; Do the actual writing of the filtered row data from the chosen filter.
6733 IgorA 3257
	mov eax,[esi+png_row_info.rowbytes]
3258
	inc eax
3259
	stdcall png_write_filtered_row, edi, [best_row], eax
3260
end if ;WRITE_FILTER
3261
popad
3262
	ret
3263
endp
3264
3265
 
3266
 
3267
;void (png_structrp png_ptr, bytep filtered_row,
3268
;    png_size_t full_row_length/*includes filter byte*/)
3269
align 4
3270
proc png_write_filtered_row uses eax ebx edi, png_ptr:dword, filtered_row:dword, full_row_length:dword
3271
	png_debug 1, 'in png_write_filtered_row'
3272
3273
 
3274
	movzx eax,byte[eax]
3275
	png_debug1 2, 'filter = %d', eax
3276
3277
 
3278
	stdcall png_compress_IDAT, [filtered_row], [full_row_length], Z_NO_FLUSH
3279
3280
 
3281
	; Swap the current and previous rows
3282
	mov eax,[edi+png_struct.prev_row]
3283
	test eax,eax
6881 IgorA 3284
	jz @f ;if (..!=0)
3285
		;eax = tptr
6733 IgorA 3286
		mov ebx,[edi+png_struct.row_buf]
3287
		mov [edi+png_struct.prev_row],ebx
3288
		mov [edi+png_struct.row_buf],eax
3289
	@@:
3290
end if ;WRITE_FILTER
3291
3292
 
3293
	stdcall png_write_finish_row, edi
3294
3295
 
3296
	inc dword[edi+png_struct.flush_rows]
3297
3298
 
3299
	cmp eax,0
3300
	jle @f
3301
	cmp [edi+png_struct.flush_rows],eax
3302
	jl @f ;if (..>0 && ..>=..)
3303
		stdcall png_write_flush, edi
3304
	@@:
3305
end if ;WRITE_FLUSH
3306
	ret
3307
endp
3308
>