Subversion Repositories Kolibri OS

Rev

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