Subversion Repositories Kolibri OS

Rev

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

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