1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
|
libmng - Multiple-image Network Graphics (MNG) Reference Library 1.0.4
DESCRIPTION
The libmng library supports decoding, displaying, encoding, and various
other manipulations of the Multiple-image Network Graphics (MNG) format
image files. It uses the zlib compression library, and optionally the
JPEG library by the Independant JPEG Group (IJG) and/or
lcms (little cms), a color-management library by Marti Maria Saguer.
I. Introduction
This file describes how to use and modify the MNG reference library
(known as libmng) for your own use. There are seven sections to this
file: introduction, callbacks, housekeeping, reading, displaying,
writing, and modification and configuration notes for various special
platforms. We assume that libmng is already installed; see the
INSTALL.README file for instructions on how to install libmng.
Libmng was written to support and promote the MNG specification.
The latest MNG specification (currently 1.0) is available at
http://www.libpng.org/pub/mng
Other information about MNG can be found at the MNG home page at
http://www.libpng.org/pub/mng
The latest version of libmng can be found at its own homepage at
http://www.libmng.com
In most cases the library will not need to be changed.
For standardization purposes the library tqcontains both a Windows DLL
and a makefile for building a shared library (SO). The library is
written in C, but an interface for Borland Delphi is also available.
Libmng has been designed to handle multiple sessions at one time,
to be easily modifiable, to be portable to the vast majority of
machines (ANSI, K&R, 32-, and 64-bit) available, and to be easy
to use.
Libmng uses zlib for its compression and decompression of MNG files.
Further information about zlib, and the latest version of zlib, can be
found at the zlib home page, <http://www.info-zip.org/pub/infozip/zlib/>.
The zlib compression utility is a general purpose utility that is
useful for more than MNG/PNG files, and can be used without libmng.
See the documentation delivered with zlib for more details.
Libmng optionally uses the JPEG library by the Independant JPEG Group
(IJG). This library is used for the JNG sub-format, which is part of
the MNG specification, and allows for inclusion of JPEG decoded and
thus highly compressed (photographic) images.
Further information about the IJG JPEG library and the latest sources
can be found at <http://www.ijg.org>.
Libmng can also optionally use the lcms (little CMS) library by
Marti Maria Saguer. This library provides an excellent color-management
system (CMS), which gives libmng the ability to provide full
color-correction for images with the proper color-information encoded.
Further information and the latest sources can be found at
<http://www.littlecms.com/>.
Libmng is thread safe, provided the threads are using different
handles as returned by the initialization call.
Each thread should have its own handle and thus its own image.
Libmng does not protect itself against two threads using the
same instance of a handle.
The libmng.h header file is the single reference needed for programming
with libmng:
#include <libmng.h>
II. Callbacks
Libmng makes extensive use of callback functions. This is meant to
keep the library as platform-independant and flexible as possible.
Actually, the first call you will make to the library, already tqcontains
three parameters you can use to provide callback entry-points.
Most functions must return a mng_bool (boolean). Returning MNG_FALSE
indicates the library the callback failed in some way and the library
will immediately return from whatever it was doing back to the
application. Returning MNG_TRUE indicates there were no problems and
processing can continue.
Let's step through each of the possible callbacks. The sections on
reading, displaying and writing will also explain which callbacks are
needed when and where.
- mng_ptr mng_memalloc (mng_size_t iLen)
A very basic function which the library uses to allocate a memory-block
with the given size. A typical implementation would be:
mng_ptr my_alloc (mng_size_t iLen) {
return calloc (1, iSize);
}
Note that the library requires you to zero-out the memory-block!!!
- void mng_memfree (mng_ptr pPtr,
mng_size_t iLen)
Counterpart of the previous function. Typically:
void my_free (mng_ptr pPtr, mng_size_t iLen) {
free (pPtr);
}
- mng_bool mng_openstream (mng_handle hHandle)
- mng_bool mng_closestream (mng_handle hHandle)
These are called by the library just before it starts to process
(either read or write) a file and just after the processing stops.
This is the recommended place to do I/O initialization & finalization.
Whether you do or not, is up to you. The library does not put any
meaning into the calls. They are simply provided for your convenience.
- mng_bool mng_readdata (mng_handle hHandle,
mng_ptr pBuf,
mng_uint32 iBuflen,
mng_uint32p pRead)
This function is called when the library needs some more input while
reading an image. The reading process supports two modes:
Suspension-mode (SMOD) and non-suspension-mode (NSMOD).
See mng_set_suspensionmode() for a more detailed description.
In NSMOD, the library requires you to return exactly the amount of bytes
requested (= iBuflen). Any lesser amount indicates the input file
is exhausted and the library will return a MNG_UNEXPECTEDEOF errorcode.
In SMOD, you may return a smaller amount of bytes than requested.
This tells the library it should temporarily wait for more input to
arrive. The lib will return with MNG_NEEDMOREDATA, and will expect a
call to mng_read_resume() or mng_display_resume() next, as soon as
more input-data has arrived.
For NSMOD this function could be as simple as:
mng_bool my_read (mng_handle hHandle,
mng_ptr pBuf,
mng_uint32 iBuflen,
mng_uint32p pRead) {
*pRead = fread (pBuf, 1, iBuflen, myfile);
return MNG_TRUE;
}
- mng_bool mng_writedata (mng_handle hHandle,
mng_ptr pBuf,
mng_uint32 iBuflen,
mng_uint32p pWritten)
This function is called during the mng_write() function to actually
output data to the file. There is no suspension-mode during write,
so the application must return the exact number of bytes the library
requests to be written.
A typical implementation could be:
mng_bool my_write (mng_handle hHandle,
mng_ptr pBuf,
mng_uint32 iBuflen,
mng_uint32p pWritten) {
*pWritten = fwrite (pBuf, 1, iBuflen, myfile);
return MNG_TRUE;
}
- mng_bool mng_errorproc (mng_handle hHandle,
mng_int32 iErrorcode,
mng_int8 iSeverity,
mng_chunkid iChunkname,
mng_uint32 iChunkseq,
mng_int32 iExtra1,
mng_int32 iExtra2,
mng_pchar zErrortext)
This function is called whenever an error is detected inside the
library. This may be caused by invalid input, callbacks indicating
failure, or wrongfully calling functions out of place.
If you do not provide this callback the library will still return
an errorcode from the called function, and the mng_getlasterror()
function can be used to retrieve the other parameters.
This function is currently only provided for convenience, but may
at some point be used to indicate certain errors may be acceptable,
and processing should continue.
- mng_bool mng_traceproc (mng_handle hHandle,
mng_int32 iFuncnr,
mng_int32 iFuncseq,
mng_pchar zFuncname)
This function is provided to allow a functional analysis of the
library. This may be useful if you encounter certain errors and
cannot determine what the problem is.
Almost all functions inside the library will activate this
callback with an appropriate function-name at the start and end
of the function. Please note that large images may generate an
enormous amount of calls.
- mng_bool mng_processheader (mng_handle hHandle,
mng_uint32 iWidth,
mng_uint32 iHeight)
This function is called once the header information of an input-
image has been processed. At this point the image dimensions are
available and also some other properties depending on the type
of the image. Eg. for a MNG the frame-/layercount, playtime &
simplicity fields are known.
The primary purpose of this callback is to inform the application
of the size of the image, and for the application to initialize
the drawing canvas to be used by the library. This is also a good
point to set the canvas-style. Eg. mng_set_canvasstyle().
- mng_bool mng_processtext (mng_handle hHandle,
mng_uint8 iType,
mng_pchar zKeyword,
mng_pchar zText,
mng_pchar zLanguage,
mng_pchar zTranslation)
This callback is activated for each textual chunk in the input-
image. These are tEXt, zTXt & iTXt. It may be used to retain
specific comments for presentation to the user.
- mng_bool mng_processsave (mng_handle hHandle)
- mng_bool mng_processseek (mng_handle hHandle,
mng_pchar zName)
The purpose of these callbacks is to signal the processing of the
SAVE & SEEK chunks in a MNG input-file. This may be used in the
future to specify some special processing. At the moment these
functions are only provided as a signal.
- mng_ptr mng_getcanvasline (mng_handle hHandle,
mng_uint32 iLinenr)
- mng_ptr mng_getbkgdline (mng_handle hHandle,
mng_uint32 iLinenr)
- mng_ptr mng_getalphaline (mng_handle hHandle,
mng_uint32 iLinenr)
These callbacks are used to access the drawing canvas, background
canvas and an optional separate alpha-channel canvas. The latter is
used only with the MNG_CANVAS_RGB8_A8 canvas-style.
If the getbkgdline() callback is not supplied the library will
composite full or partially transtqparent pixels in the image against
a specified background color. See mng_set_bgcolor() for more details.
If a chosen canvas-style includes an alpha-channel, this callback
is very likely not needed.
The application is responsible for returning a pointer to a line of
pixels, which should be in the exact format as defined by the call
to mng_set_canvasstyle() and mng_set_bkgdstyle(), without gaps between
the representation of each pixel.
- mng_bool mng_refresh (mng_handle hHandle,
mng_uint32 iX,
mng_uint32 iY,
mng_uint32 iWidth,
mng_uint32 iHeight)
This callback is called when the library has drawn a complete frame
onto the drawing canvas, and it is ready to be displayed.
The application is responsible for transferring the drawing canvas
from memory onto the actual output tqdevice.
- mng_uint32 mng_gettickcount (mng_handle hHandle)
This function should return the number of milliseconds on some internal
clock. The entire animation timing depends heavily on this function,
1and the number returned should be as accurate as possible.
- mng_bool mng_settimer (mng_handle hHandle,
mng_uint32 iMsecs)
This callback is activated every time the library requires a "pause".
Note that the function itself should NOT execute the wait. It should
simply store the time-field and allow the library to return. Libmng
will return with the MNG_NEEDTIMERWAIT code, indicating the callback
was called and it is now time to execute the pause.
After the indicated number of milliseconds have elapsed, the application
should call mng_display_resume(), to resume the animation as planned.
This method allows for both a real timer or a simple wait command in the
application. Whichever method you select, both the gettickcount() and
settimer() callbacks are crucial for proper animation timing.
- mng_bool mng_processgamma (mng_handle hHandle,
mng_uint32 iGamma)
- mng_bool mng_processchroma (mng_handle hHandle,
mng_uint32 iWhitepointx,
mng_uint32 iWhitepointy,
mng_uint32 iRedx,
mng_uint32 iRedy,
mng_uint32 iGreenx,
mng_uint32 iGreeny,
mng_uint32 iBluex,
mng_uint32 iBluey)
- mng_bool mng_processsrgb (mng_handle hHandle,
mng_uint8 iRenderingintent)
- mng_bool mng_processiccp (mng_handle hHandle,
mng_uint32 iProfilesize,
mng_ptr pProfile)
- mng_bool mng_processarow (mng_handle hHandle,
mng_uint32 iRowsamples,
mng_bool bIsRGBA16,
mng_ptr pRow)
These callbacks are only required when you selected the MNG_APP_CMS
directive during compilation of the library. See the configuration
section for more details.
- mng_bool mng_iteratechunk (mng_handle hHandle,
mng_handle hChunk,
mng_chunkid iChunkid,
mng_uint32 iChunkseq)
This callback is only used for the mng_iterate_chunks() function.
It is called exactly once for each chunk stored.
III. Housekeeping
> Memory management
The library can use internal memory allocation/deallocation or use
provided callbacks for its memory management. The choice is made at
compilation time. See the section on customization for details.
If internal management has been selected, the memory callback functions
need not be supplied. Even if you do supply them they will not be used.
The actual code used is similar to the code discussed in the callback
section:
pPtr = calloc (1, iSize);
free (pPtr);
If your compiler does not support these functions, or you wish to monitor
the library's use of memory for certain reasons, you can choose to
compile the library with external memory management. In this case the
memory callback functions MUST be supplied, and should function as if the
above code was used.
> Initialization
The basic initialization of the library is short and swift:
myhandle = mng_initialize (myuserdata, my_alloc,
my_free, MNG_NULL);
if (myhandle == MNG_NULL)
/* process error */;
The first field is an application-only parameter. It is saved in
libmng's internal structures and available at all times through the
mng_get_userdata() function. This is especially handy in callback functions
if your program may be handling multiple files at the same time.
The second and third field supply the library with the memory callback
1function entry-points. These are described in more detail in the callback
section and the previous paragraph.
The fourth and last field may be used to supply the library with the
entry-point of a trace callback function. For regular use you will not
need this!
The function returns a handle which will be your ticket to MNG-heaven.
All other functions rely on this handle. It is the single fixed unique
reference-point between your application and the library.
You should call the initialization function for each image you wish to
process simultaneously. If you are processing images consecutively, you can
reset the internal status of the library with the mng_reset() function.
This function will clear all internal state variables, free any stored
chunks and/or objects, etc, etc. Your callbacks and other external parameters
will be retained.
After you successfully received the handle it is time to set the required
callbacks. The sections on reading, displaying & writing indicate which
callbacks are required and which are optional.
To set the callbacks simply do:
myretcode = mng_setcb_xxxxxx (myhandle, my_xxxxxx);
if (myretcode != MNG_NOERROR)
/* process error */;
Naturally you'd tqreplace the x's with the name of the callback.
> Cleanup
Once you've gotten hold of that precious mng_handle, you should always,
and I mean always, call the cleanup function when you're done.
Just do:
mng_cleanup (myhandle);
And you're done. There shouldn't be an ounce of memory spilled after
that call.
Note that if you would like to process multiple files consecutively
you do not need to do mng_cleanup() / mng_initialize() between each file
but simply
myretcode = mng_reset (myhandle);
if (myretcode != MNG_NOERROR)
/* process error */;
will suffice. Saves some time and effort, that.
> Error handling
From the examples in the previous paragraphs you may have noticed a
meticulous scheme for error handling. And yes, that's exactly what it is.
Practically each call simply returns an errorcode, indicating success,
eg. MNG_NOERROR or failure, anything else but MNG_NEEDMOREDATA and
MNG_NEEDTIMERWAIT. These latter two will be discussed in more detail in
their respective fields of interest: the reading section and displaying
section respectively.
It is the application's responsibility to check the returncode after
each call. You can call mng_getlasterror() to receive the details of
the last detected error. This even includes a discriptive error-message
if you enabled that option during compilation of the library.
Note that after receiving an error it is still possible to call the
library, but it's also very likely that any following call will fail.
The only functions deemed to work will be mng_reset() and mng_cleanup().
Yes, if you abort your program after an error, you should still call
mng_cleanup().
IV. Reading
Reading a MNG, JNG or PNG is fairly easy. It depends slightly on your
ultimate goal how certain specifics are to be handled, but the basics
are similar in all cases.
For the read functioins to work you must have compiled the library with
the MNG_READ_SUPPRT directive. The standard DLL and Shared Library
have this on by default!
> Setup
Naturally you must have initialized the library and be the owner of
a mng_handle. The following callbacks are essential:
mng_openstream, mng_readdata, mng_closestream
You may optionally define:
mng_errorproc, mng_traceproc
mng_processheader, mng_processtext
mng_processsave, mng_processseek
The reading bit will also fail if you are already creating or
displaying a file. Seems a bit obvious, but I thought I'd mention it,
just in case.
> To suspend or not to suspend
There is one choice you need to make before calling the read function.
Are you in need of suspension-mode or not?
If you're reading from a disk you most certainly do not need
suspension-mode. Even the oldest and slowest of disks will be fast
enough for straight reading.
However, if your input comes from a really slow tqdevice, such as a
dialup-line or the likes, you may opt for suspension-mode. This is done
by calling
myretcode = mng_set_suspensionmode (myhandle,
MNG_TRUE);
if (myretcode != MNG_NOERROR)
/* process error */;
Suspension-mode will force the library to use special buffering on the
input. This allows your application to receive data of arbitrarily length
and return this in the mng_readdata() callback, without disturbing the
chunk processing routines of the library.
Suspension-mode does require a little extra care in the main logic of the
1application. The read function may return with MNG_NEEDMOREDATA when the
mng_readdata() callback returns less data then it needs to process the
next chunk. This indicates the application to wait for more data to arrive
and then resume processing by calling mng_read_resume().
> The read HLAPI
The actual reading is just plain simple. Since all I/O is done
1outside the library through the callbacks, the library can focus on
its real task. Understanding, checking and labelling the input data!
All you really need to do is this:
myretcode = mng_read (myhandle);
if (myretcode != MNG_NOERROR)
/* process error */;
Of course, if you're on suspension-mode the code is a little more
complicated:
myretcode = mng_read (myhandle);
while (myretcode == MNG_NEEDMOREDATA) {
/* wait for input-data to arrive */
myretcode = mng_read_resume (myhandle);
}
if (myretcode != MNG_NOERROR)
/* process error */;
This is rather crude and more sophisticated programming methods may
dictate another approach. Whatever method you decide on, it should
act as if the above code was in its place.
There is also the mng_readdisplay() function, but this is discussed
in the displaying section. It functions pretty much as the mng_read()
function, but also immediately starts displaying the image.
mng_read_resume() should be tqreplaced by mng_display_resume() in that
case!
> What happens inside
What actually happens inside the library depends on the configuration
options set during the compilation of the library.
Basically the library will first read the 8-byte file header, to determine
its validity and the type of image it is about to process. Then it will
repeatedly read a 4-byte chunk-length and then the remainder of the chunk
until it either reaches EOF (indicated by the mng_readdata() callback) or
implicitly decides EOF as it processed the logically last chunk of the
image.
Applications that require strict conformity and do not allow superfluous
data after the ending chunk, will need to perform this check in their
mng_closestream() callback.
Each chunk is then checked on CRC, after which it is handed over to the
appropriate chunk processing routine. These routines will disect the
chunk, check the validity of its contents, check its position with respect
to other chunks, etc, etc.
If everything checks out, the chunk is further processed as follows:
If display support has been selected during compilation, certain pre-display
initialization will take place.
If chunk-storage support has been selected during compilation, the chunks
data may be stored in a special internal structure and held for future
reference.
> Storing and accessing chunks
One of the compilation options activates support for chunk storage.
This option may be useful if you want to examine an image. The directive
is MNG_STORE_CHUNKS. You must also turn on the MNG_ACCESS_CHUNKS
directive.
The actual storage facility can be turned on or off with the
mng_set_storechunks() function. If set to MNG_TRUE, chunks will be
stored as they are read.
At any point you can then call the mng_iterate_chunks() function
to iterate through the current list of chunks. This function requires
a callback which is called for each chunk and receives a specific
chunk-handle. This chunk-handle can be used to call the appropriate
mng_getchunk_xxxx() function, to access the chunks properties.
A typical implementation may look like this:
mng_bool my_iteratechunk (mng_handle hHandle,
mng_handle hChunk,
mng_chunkid iChunkid,
mng_uint32 iChunkseq) {
switch (iChunkid) {
case MNG_UINT_MHDR : { /* process MHDR */;
break; }
case MNG_UINT_FRAM : { /* process FRAM */;
break; }
...etc...
case MNG_UINT_HUH : { /* unknown chunk */;
break; }
default : { /* duh; forgot one */; }
}
return MNG_TRUE; /* keep'm coming */
}
To get to the actual chunk fields of lets say a SHOW chunk you would do:
mng_bool isempty;
mng_uint16 firstid, lastid;
mng_uint8 showmode;
myretcode mng_getchunk_show (hHandle, hChunk,
isempty, firstid,
lastid, showmode);
if (myretcode != MNG_NOERROR)
/* process error */;
V. Displaying
> Setup
Assuming you have initialized the library and are the owner of
a mng_handle. The following callbacks are essential:
mng_getcanvasline, mng_refresh
mng_gettickcount, mng_settimer
If you wish to use an application supplied background you must supply:
mng_getbkgdline
If you wish to use the MNG_CANVAS_RGB8_A8 canvas style you must supply:
mng_getalphaline
You may optionally define:
mng_errorproc, mng_traceproc
mng_processheader, mng_processtext
mng_processsave, mng_processseek
Note that the mng_processheader() callback is optional but will
be quite significant for proper operation!
Displaying an image will fail if you are creating a file or already
displaying one. Yes, you can't display it twice!
> A word on canvas styles
The canvas style describes how your drawing canvas is made up.
You must set this before the library actually starts drawing, so
the mng_processheader() callback is a pretty good place for it.
Currently only 8-bit RGB canvas styles are supported, either with
or without an alpha channel.
If you like to do alpha composition yourself you can select one of
the canvas styles that include an alpha channel. You can even have
a separate alpha canvas by selecting the MNG_CANVAS_RGB8_A8 style.
All styles require a compact model. Eg. MNG_CANVAS_BGR8 requires
your canvas lines in bgrbgrbgr... storage, where each letter
represents an 8-bit value of the corresponding color, and each
threesome makes up the values of one(1) pixel.
The library processes a line at a time, so the canvas lines do not
actually need to be consecutive in memory.
> Alpha composition and application backgrounds
All Network Graphics can be partially transtqparent. This requires
special processing if you need to display an image against some
background. Note that the MNG header (MHDR chunk) tqcontains a
simplicity field indicating whether transparency information in
the file is critical or not. This only applies to embedded images,
which means the full image-frame of the MNG may still contain fully
transtqparent pixels!
Depending on your needs you can supply a single background color,
a background canvas or tell the library to return the alpha-channel
and do alpha composition yourself.
This is different from the BACK chunk in a MNG, or the bKGD chunk
in an (embedded) PNG or JNG. The BACK chunk indicates an optional or
mandatory background color and/or image. The bKGD chunk only indicates
an optional background color. These chunks indicate the Authors
preferences. They may be absent in which case you need to supply
some sort of background yourself.
> Composing against a background color
This is the easiest method. Call the mng_set_bgcolor() function to
set the values of the red, green and blue component of your preferred
background color.
Use one of the canvas styles that do not have an alpha-channel, and
which matches your output requirements.
> Composing against a background canvas
This is somewhat more complicated. You will need to set the
mng_getbkgdline() callback. This will be called whenever the library
needs to compose a partially transtqparent line.
This canvas must hold the background against which the image should
be composed. Its size must match exactly with the image dimensions
and thus the drawing canvas!
Use one of the canvas styles that do not have an alpha-channel, and
which matches your output requirements. The canvas style of the
background canvas may even differ from the drawing canvas. The library's
composing will still function properly.
> Composing within the application
If you have the option in your application to draw a (partially)
transtqparent canvas to the output tqdevice, this option is preferred.
Select one of the canvas styles that do have an alpha-channel.
The library will now supply the appropriate alpha information,
allowing the application to compose the image as it sees fit.
> Color information and CMS
Network Graphics may, and usually will, contain color-correction
information. This information is intended to compensate for the
difference in recording and display tqdevices used.
This document does not address the specifics of color-management.
See the PNG specification for a more detailed description.
> Using little cms by Marti Maria Saguer
This is the easiest method, providing you can compile the lcms package.
Select the MNG_FULL_CMS directive during compilation, and sit back and
relax. The library will take care of all color-correction for you.
> Using an OS- or application-supplied CMS
If you are so lucky to have access to CMS functionality from within
your application, you may instruct the library to leave color-correction
to you.
Select the MNG_APP_CMS directive during compilation of the library.
You MUST also set the following callbacks:
mng_processgamma, mng_processchroma,
mng_processsrgb, mng_processiccp and
mng_processarow
The last callback is called when the library needs you to correct
an arbitrary line of pixels. The other callbacks are called when
the corresponding color-information is encountered in the file.
You must store this information somewhere for use in the
mng_processarow() callback.
> Using gamma-only correction
This isn't a preferred method, but it's better than no correction
at all. Gamma-only correction will at least compensate for
gamma-differences between the original recorder and your output tqdevice.
Select the MNG_GAMMA_ONLY directive during compilation
of the library. Your compiler MUST support fp operations.
> No color correction
Ouch. This is really bad. This is the least preferred method,
but may be necessary if your system cannot use lcms, doesn't
have its own CMS, and does not allow fp operations, ruling out
the gamma-only option.
Select the MNG_NO_CMS directive during compilation.
Images will definitely not be displayed as seen by the Author!!!
> Animations and timing
Animations require some form of timing support. The library relies
on two callbacks for this purpose. The mng_gettickcount() and
mng_settimer() callbacks. mng_gettickcount() is used to determine
the passing of time in milliseconds since the beginning of the
animation. This is also used to compensate during suspension-mode
if you are using the mng_readdisplay() function to read & display
the file simultaneously.
The callback may return an arbitrary number of milliseconds, but
this number must increase proportionaly between calls. Most modern
systems will have some tickcount() function which derives its
input from an internal clock. The value returned from this function
is more than adequate for libmng.
The mng_settimer() callback is called when the library determines
a little "pause" is required before rendering another frame of the
animation. The pause interval is also expressed in milliseconds.
Your application should store this value and return immediately.
The library will then make appropriate arrangements to store its
internal state and returns to your application with the
MNG_NEEDTIMERWAIT code.
At that point you should suspend processing and wait the given
interval. Please use your OS features for this. Do not engage some
sort of loop. That is real bad programming practice. Most modern
systems will have some timing functions. A simple wait() function
may suffice, but this may prevent your applications main-task from
running, and possibly prevent the actual update of your output tqdevice.
> The mng_refresh() callback
The mng_refresh() callback is called whenever the library has
"finished" drawing a new frame onto your canvas, and just before it
will call the mng_settimer() callback.
This allows you to perform some actions necessary to "refresh" the
canvas onto your output tqdevice. Please do NOT suspend processing
inside this callback. This must be handled after the mng_settimer()
callback!
> Displaying while reading
This method is preferred if you are reading from a slow input tqdevice
(such as a dialup-line) and you wish to start displaying something
as quickly as possible. This functionality is provided mainly for
browser-type applications but may be appropriate for other
applications as well.
The method is usually used in unison with the suspension-mode of
the read module. A typical implementation would look like this:
/* initiale library and set required callbacks */
/* activate suspension-mode */
myretcode = mng_set_suspensionmode (myhandle,
MNG_TRUE);
if (myretcode != MNG_NOERROR)
/* process error */;
myretcode = mng_readdisplay (myhandle);
while ((myretcode == MNG_NEEDMOREDATA) ||
(myretcode == MNG_NEEDTIMERWAIT)) {
if (myretcode == MNG_NEEDMOREDATA)
/* wait for more input-data */;
else
/* wait for timer interval */;
myretcode = mng_display_resume (myhandle);
}
if (myretcode != MNG_NOERROR)
/* process error */;
More advanced programming methods may require a different approach,
but the final result should function as in the code above.
> Displaying after reading
This method is used to display a file that was previously read.
It is primarily meant for viewers with direct file access, such as
1a local harddisk.
Once you have successfully read the file, all you need to do is:
myretcode = mng_display (myhandle);
while (myretcode == MNG_NEEDTIMERWAIT) {
/* wait for timer interval */;
myretcode = mng_display_resume (myhandle);
}
if (myretcode != MNG_NOERROR)
/* process error */;
Again, more advanced programming methods may require a different
approach, but the final result should function as in the code above.
> Display manipulation
Several HLAPI functions are provided to allow a user to manipulate
the normal flow of an animation.
- mng_display_freeze (mng_handle hHandle)
This will "freeze" the animation in place.
- mng_display_resume (mng_handle hHandle)
This function can be used to resume a frozen animation, or to force
the library to advance the animation to the next frame.
- mng_display_reset (mng_handle hHandle)
This function will "reset" the animation into its pristine state.
Calling mng_display_resume() afterwards will restart the animation
from the first frame.
- mng_display_golayer (mng_handle hHandle,
mng_uint32 iLayer)
- mng_display_goframe (mng_handle hHandle,
mng_uint32 iFrame)
- mng_display_goplaytime (mng_handle hHandle,
mng_uint32 iPlaytime)
These three functions can be used to "jump" to a specific layer, frame
or timeslot in the animation. You must "freeze" the animation before
using any of these functions.
All above functions may only be called during a timer interval!
It is the applications responsibility to cleanup any resources with
respect to the timer wait.
VI. Writing
The main focus of the library lies in its displaying capabilites.
But it does offer writing support as well.
You can create and write a file, or you can write a file you
have previously read, providing the storage of chunks was enabled
and active.
For this to work you must have compiled the library with the
MNG_WRITE_SUPPO1RT and MNG_ACCESS_CHUNKS directives. The standard DLL and
Shared Library have this on by default!
> Setup
As always you must have initialized the library and be the owner of
a mng_handle. The following callbacks are essential:
mng_openstream, mng_writedata, mng_closestream
You can optionally define:
mng_errorproc, mng_traceproc
The creation and writing functions will fail if you are in the middle
of reading, creating or writing a file.
> Creating a new file
To start a new file the library must be in its initial state.
First you need to tell the library your intentions:
myretcode = mng_create (myhandle);
if (myretcode != MNG_NOERROR)
/* process error */;
After that you start adding the appropriate chunks:
myretcode = mng_putchunk_mhdr (myhandle, ...);
if (myretcode != MNG_NOERROR)
/* process error */;
And so on, and so forth. Note that the library will automatically signal
the logical end of the file by the ending chunk. Also the first chunk
will indicate the library the filetype (eg. PNG, JNG or MNG) and force
the proper signature when writing the file.
The code above can be simplified, as you can always get the last errorcode
by using the mng_getlasterror() function:
if ( (mng_putchunk_xxxx (myhandle, ...)) or
(mng_putchunk_xxxx (myhandle, ...)) or
...etc... )
/* process error */;
Please note that you must have a pretty good understanding of the chunk
specification. Unlike the read functions, there are virtually no checks,
so it is quite possible to write completely wrong files.
It is a good practice to read back your file into the library to verify
its integrity.
Once you've got all the chunks added, all you do is:
myretcode mng_write (myhandle);
if (myretcode != MNG_NOERROR)
/* process error */;
And presto. You're done. The real work is of course carried out in
your callbacks. Note that this is a single operation as opposed to
the read & display functions that may return with MNG_NEEDMOREDATA
and/or MNG_NEEDTIMERWAIT. The write function just does the job, and
only returns after it's finished or if it encounters some
unrecoverable error.
> Writing a previously read file
If you have already successfully read a file, you can use the library to
write it out as a copy or something. You MUST have compiled the library
with the MNG_STORE_CHUNKS directive, and you must have done
mng_set_storechunks (myhandle, MNG_TRUE).
This doesn't require the MNG_ACCESS_CHUNKS directive, unless you want
to fiddle with the chunks as well.
Again all you need to do is:
myretcode mng_write (myhandle);
if (myretcode != MNG_NOERROR)
/* process error */;
VII. Modifying/Customizing libmng:
to do
> Compilation directives
to do
> Platform dependant modification
to do
References :
libmng :
http://www.libmng.com
zlib :
http://www.info-zip.org/pub/infozip/zlib/
IJG JPEG library :
http://www.ijg.org
lcms (little CMS) by Marti Maria Saguer :
http://www.littlecms.com/
MNG specification:
http://www.libpng.org/pub/mng
In the case of any inconsistency between the MNG specification
and this library, the specification takes precedence.
The contributing authors would like to thank all those who helped
with testing, bug fixes, and patience. This wouldn't have been
possible without all of you!!!
COPYRIGHT NOTICE:
Copyright (c) 2000,2001 Gerard Juyn
For the purposes of this copyright and license, "Contributing Authors"
is defined as the following set of individuals:
Gerard Juyn
The MNG Library is supplied "AS IS". The Contributing Authors
disclaim all warranties, expressed or implied, including, without
limitation, the warranties of merchantability and of fitness for any
purpose. The Contributing Authors assume no liability for direct,
indirect, incidental, special, exemplary, or consequential damages,
which may result from the use of the MNG Library, even if advised of
the possibility of such damage.
Permission is hereby granted to use, copy, modify, and distribute this
source code, or portions hereof, for any purpose, without fee, subject
to the following restrictions:
1. The origin of this source code must not be misrepresented;
you must not claim that you wrote the original software.
2. Altered versions must be plainly marked as such and must not be
misrepresented as being the original source.
3. This Copyright notice may not be removed or altered from any source
or altered source distribution.
The Contributing Authors specifically permit, without fee, and
encourage the use of this source code as a component to supporting
the MNG and JNG file format in commercial products. If you use this
source code in a product, acknowledgment would be highly appreciated.
Remarks :
Parts of this software have been adapted from the libpng library.
Although this library supports all features from the PNG specification
(as MNG descends from it) it does not require the libpng library.
It does require the zlib library and optionally the IJG JPEG library,
and/or the "little-cms" library by Marti Maria Saguer (depending on the
inclusion of support for JNG and Full-Color-Management respectively.
This library's function is primarily to read and display MNG
animations. It is not meant as a full-featured image-editing
component! It does however offer creation and editing functionality
at the chunk level. (future modifications may include some more
support for creation and or editing)
|