Subversion Repositories Kolibri OS

Rev

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

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