Subversion Repositories Kolibri OS

Rev

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