summaryrefslogtreecommitdiffstats
path: root/src
ModeNameSize
-rw-r--r--.indent.pro4406logstatsplain
-rwxr-xr-xCOPYING773logstatsplain
-rw-r--r--H5.c24899logstatsplain
-rw-r--r--H5A.c81216logstatsplain
-rw-r--r--H5AC.c146518logstatsplain
-rw-r--r--H5ACpkg.h12998logstatsplain
-rw-r--r--H5ACprivate.h13936logstatsplain
-rw-r--r--H5ACpublic.h15848logstatsplain
-rw-r--r--H5Abtree2.c20467logstatsplain
-rw-r--r--H5Adense.c72527logstatsplain
-rw-r--r--H5Adeprec.c18261logstatsplain
-rw-r--r--H5Aint.c21118logstatsplain
-rw-r--r--H5Apkg.h11195logstatsplain
-rw-r--r--H5Aprivate.h2209logstatsplain
-rw-r--r--H5Apublic.h4978logstatsplain
-rw-r--r--H5Atest.c4506logstatsplain
-rw-r--r--H5B.c73823logstatsplain
-rw-r--r--H5B2.c47279logstatsplain
-rw-r--r--H5B2cache.c36970logstatsplain
-rw-r--r--H5B2dbg.c16194logstatsplain
-rw-r--r--H5B2int.c145129logstatsplain
-rw-r--r--H5B2pkg.h15384logstatsplain
-rw-r--r--H5B2private.h7453logstatsplain
-rw-r--r--H5B2public.h1926logstatsplain
-rw-r--r--H5B2stat.c3671logstatsplain
-rw-r--r--H5B2test.c15492logstatsplain
-rw-r--r--H5Bcache.c13024logstatsplain
-rw-r--r--H5Bpkg.h3072logstatsplain
-rw-r--r--H5Bprivate.h6816logstatsplain
-rw-r--r--H5Bpublic.h2184logstatsplain
-rw-r--r--H5C.c383885logstatsplain
-rw-r--r--H5CS.c9756logstatsplain
-rw-r--r--H5CSprivate.h1914logstatsplain
-rw-r--r--H5Cpkg.h38541logstatsplain
-rw-r--r--H5Cprivate.h37593logstatsplain
-rw-r--r--H5Cpublic.h1823logstatsplain
-rw-r--r--H5D.c136735logstatsplain
-rw-r--r--H5Dcompact.c14672logstatsplain
-rw-r--r--H5Dcontig.c55219logstatsplain
-rw-r--r--H5Defl.c12949logstatsplain
-rw-r--r--H5Dio.c134159logstatsplain
-rw-r--r--H5Distore.c152529logstatsplain
-rw-r--r--H5Dmpio.c75884logstatsplain
-rw-r--r--H5Doh.c8557logstatsplain
-rw-r--r--H5Dpkg.h18349logstatsplain
-rw-r--r--H5Dprivate.h9183logstatsplain
-rw-r--r--H5Dpublic.h4742logstatsplain
-rw-r--r--H5Dselect.c29492logstatsplain
-rw-r--r--H5Dtest.c4572logstatsplain
-rw-r--r--H5E.c94249logstatsplain
-rw-r--r--H5Edefin.h11780logstatsplain
-rw-r--r--H5Einit.h49791logstatsplain
-rw-r--r--H5Eprivate.h6506logstatsplain
-rw-r--r--H5Epubgen.h19106logstatsplain
-rw-r--r--H5Epublic.h8878logstatsplain
-rw-r--r--H5Eterm.h4818logstatsplain
-rw-r--r--H5F.c120997logstatsplain
-rw-r--r--H5FD.c139589logstatsplain
-rw-r--r--H5FDcore.c27328logstatsplain
-rw-r--r--H5FDcore.h1705logstatsplain
-rw-r--r--H5FDdirect.c41753logstatsplain
-rw-r--r--H5FDdirect.h2174logstatsplain
-rw-r--r--H5FDfamily.c45627logstatsplain
-rw-r--r--H5FDfamily.h1723logstatsplain
-rw-r--r--H5FDlog.c44595logstatsplain
-rw-r--r--H5FDlog.h3285logstatsplain
-rw-r--r--H5FDmpi.c16178logstatsplain
-rw-r--r--H5FDmpi.h5036logstatsplain
-rw-r--r--H5FDmpio.c74221logstatsplain
-rw-r--r--H5FDmpio.h2588logstatsplain
-rw-r--r--H5FDmpiposix.c52658logstatsplain
-rw-r--r--H5FDmpiposix.h1994logstatsplain
-rw-r--r--H5FDmulti.c64120logstatsplain
-rw-r--r--H5FDmulti.h2241logstatsplain
-rw-r--r--H5FDprivate.h4097logstatsplain
-rw-r--r--H5FDpublic.h13840logstatsplain
-rw-r--r--H5FDsec2.c28320logstatsplain
-rw-r--r--H5FDsec2.h1554logstatsplain
-rw-r--r--H5FDstdio.c30032logstatsplain
-rw-r--r--H5FDstdio.h1561logstatsplain
-rw-r--r--H5FDstream.c40115logstatsplain
-rw-r--r--H5FDstream.h3777logstatsplain
-rw-r--r--H5FL.c72889logstatsplain
-rw-r--r--H5FLprivate.h18062logstatsplain
-rw-r--r--H5FO.c18910logstatsplain
-rw-r--r--H5FOprivate.h2366logstatsplain
-rw-r--r--H5FS.c17948logstatsplain
-rw-r--r--H5FScache.c40097logstatsplain
-rw-r--r--H5FSdbg.c9567logstatsplain
-rw-r--r--H5FSpkg.h10649logstatsplain
-rw-r--r--H5FSprivate.h9390logstatsplain
-rw-r--r--H5FSpublic.h1932logstatsplain
-rw-r--r--H5FSsection.c74542logstatsplain
-rw-r--r--H5Fdbg.c7285logstatsplain
-rw-r--r--H5Ffake.c4373logstatsplain
-rw-r--r--H5Fmount.c22368logstatsplain
-rw-r--r--H5Fpkg.h8274logstatsplain
-rw-r--r--H5Fprivate.h21354logstatsplain
-rw-r--r--H5Fpublic.h6266logstatsplain
-rw-r--r--H5Fsfile.c7000logstatsplain
-rw-r--r--H5Fsuper.c35049logstatsplain
-rw-r--r--H5Ftest.c3644logstatsplain
-rw-r--r--H5G.c60133logstatsplain
-rw-r--r--H5Gbtree2.c20448logstatsplain
-rw-r--r--H5Gcompact.c22349logstatsplain
-rw-r--r--H5Gdense.c69384logstatsplain
-rw-r--r--H5Gdeprec.c36675logstatsplain
-rw-r--r--H5Gent.c16233logstatsplain
-rw-r--r--H5Glink.c27253logstatsplain
-rw-r--r--H5Gloc.c21779logstatsplain
-rw-r--r--H5Gname.c47042logstatsplain
-rw-r--r--H5Gnode.c72949logstatsplain
-rw-r--r--H5Gobj.c47266logstatsplain
-rw-r--r--H5Goh.c6014logstatsplain
-rw-r--r--H5Gpkg.h25380logstatsplain
-rw-r--r--H5Gprivate.h8992logstatsplain
-rw-r--r--H5Gpublic.h7113logstatsplain
-rw-r--r--H5Gstab.c34135logstatsplain
-rw-r--r--H5Gtest.c20092logstatsplain
-rw-r--r--H5Gtraverse.c33936logstatsplain
-rw-r--r--H5HF.c30314logstatsplain
-rw-r--r--H5HFbtree2.c39367logstatsplain
-rw-r--r--H5HFcache.c64255logstatsplain
-rw-r--r--H5HFdbg.c28648logstatsplain
-rw-r--r--H5HFdblock.c27783logstatsplain
-rw-r--r--H5HFdtable.c12343logstatsplain
-rw-r--r--H5HFhdr.c59600logstatsplain
-rw-r--r--H5HFhuge.c39650logstatsplain
-rw-r--r--H5HFiblock.c63175logstatsplain
-rw-r--r--H5HFiter.c21242logstatsplain
-rw-r--r--H5HFman.c25894logstatsplain
-rw-r--r--H5HFpkg.h40749logstatsplain
-rw-r--r--H5HFprivate.h6504logstatsplain
-rw-r--r--H5HFpublic.h1929logstatsplain
-rw-r--r--H5HFsection.c185132logstatsplain
-rw-r--r--H5HFspace.c12092logstatsplain
-rw-r--r--H5HFstat.c3225logstatsplain
-rw-r--r--H5HFtest.c16091logstatsplain
-rw-r--r--H5HFtiny.c11888logstatsplain
-rw-r--r--H5HG.c44929logstatsplain
-rw-r--r--H5HGdbg.c5042logstatsplain
-rw-r--r--H5HGpkg.h3841logstatsplain
-rw-r--r--H5HGprivate.h2295logstatsplain
-rw-r--r--H5HGpublic.h1384logstatsplain
-rw-r--r--H5HL.c50905logstatsplain
-rw-r--r--H5HLdbg.c5201logstatsplain
-rw-r--r--H5HLpkg.h3045logstatsplain
-rw-r--r--H5HLprivate.h3240logstatsplain
-rw-r--r--H5HLpublic.h1684logstatsplain
-rw-r--r--H5HP.c30225logstatsplain
-rw-r--r--H5HPprivate.h2796logstatsplain
-rw-r--r--H5I.c65294logstatsplain
-rw-r--r--H5Ipkg.h2598logstatsplain
-rw-r--r--H5Iprivate.h3223logstatsplain
-rw-r--r--H5Ipublic.h4598logstatsplain
-rw-r--r--H5L.c96884logstatsplain
-rw-r--r--H5Lexternal.c13472logstatsplain
-rw-r--r--H5Lpkg.h2231logstatsplain
-rw-r--r--H5Lprivate.h3665logstatsplain
-rw-r--r--H5Lpublic.h8605logstatsplain
-rw-r--r--H5MF.c11741logstatsplain
-rw-r--r--H5MFprivate.h2484logstatsplain
-rw-r--r--H5MM.c6977logstatsplain
-rw-r--r--H5MMprivate.h2091logstatsplain
-rw-r--r--H5MMpublic.h1907logstatsplain
-rw-r--r--H5MP.c15406logstatsplain
-rw-r--r--H5MPpkg.h4432logstatsplain
-rw-r--r--H5MPprivate.h2378logstatsplain
-rw-r--r--H5MPtest.c7160logstatsplain
-rw-r--r--H5O.c67981logstatsplain
-rw-r--r--H5Oalloc.c60420logstatsplain
-rw-r--r--H5Oattr.c43682logstatsplain
-rw-r--r--H5Oattribute.c60232logstatsplain
-rw-r--r--H5Obogus.c7601logstatsplain
-rw-r--r--H5Ocache.c31638logstatsplain
-rw-r--r--H5Ocont.c9624logstatsplain
-rw-r--r--H5Ocopy.c46198logstatsplain
-rw-r--r--H5Odbg.c17834logstatsplain
-rw-r--r--H5Odtype.c70508logstatsplain
-rw-r--r--H5Oefl.c17166logstatsplain
-rw-r--r--H5Ofill.c27651logstatsplain
-rw-r--r--H5Oginfo.c11610logstatsplain
-rw-r--r--H5Olayout.c26996logstatsplain
-rw-r--r--H5Olinfo.c21400logstatsplain
-rw-r--r--H5Olink.c27039logstatsplain
-rw-r--r--H5Omessage.c64749logstatsplain
-rw-r--r--H5Omtime.c16777logstatsplain
-rw-r--r--H5Oname.c9398logstatsplain
-rw-r--r--H5Onull.c2826logstatsplain
-rw-r--r--H5Opkg.h21658logstatsplain
-rw-r--r--H5Opline.c24873logstatsplain
-rw-r--r--H5Oprivate.h20811logstatsplain
-rw-r--r--H5Opublic.h6974logstatsplain
-rw-r--r--H5Osdspace.c20224logstatsplain
-rw-r--r--H5Oshared.c21325logstatsplain
-rw-r--r--H5Oshared.h15216logstatsplain
-rw-r--r--H5Oshmesg.c8870logstatsplain
-rw-r--r--H5Ostab.c14165logstatsplain
-rw-r--r--H5Otest.c11890logstatsplain
-rw-r--r--H5P.c236672logstatsplain
-rw-r--r--H5Pacpl.c2927logstatsplain
-rw-r--r--H5Pdcpl.c92496logstatsplain
-rw-r--r--H5Pdxpl.c53964logstatsplain
-rw-r--r--H5Pfapl.c69884logstatsplain
-rw-r--r--H5Pfcpl.c37954logstatsplain
-rw-r--r--H5Pfmpl.c4272logstatsplain
-rw-r--r--H5Pgcpl.c18549logstatsplain
-rw-r--r--H5Plapl.c14308logstatsplain
-rw-r--r--H5Plcpl.c7079logstatsplain
-rwxr-xr-xH5Pocpl.c12855logstatsplain
-rwxr-xr-xH5Pocpypl.c7364logstatsplain
-rw-r--r--H5Ppkg.h8373logstatsplain
-rw-r--r--H5Pprivate.h4629logstatsplain
-rw-r--r--H5Ppublic.h20518logstatsplain
-rw-r--r--H5Pstrcpl.c6795logstatsplain
-rw-r--r--H5Ptest.c4730logstatsplain
-rw-r--r--H5R.c35191logstatsplain
-rw-r--r--H5RC.c4160logstatsplain
-rw-r--r--H5RCprivate.h2389logstatsplain
-rw-r--r--H5RS.c14412logstatsplain
-rw-r--r--H5RSprivate.h2364logstatsplain
-rw-r--r--H5Rprivate.h1376logstatsplain
-rw-r--r--H5Rpublic.h3708logstatsplain
-rw-r--r--H5S.c71754logstatsplain
-rw-r--r--H5SL.c52784logstatsplain
-rw-r--r--H5SLprivate.h3675logstatsplain
-rwxr-xr-xH5SM.c76877logstatsplain
-rwxr-xr-xH5SMbtree2.c12720logstatsplain
-rw-r--r--H5SMcache.c22804logstatsplain
-rwxr-xr-xH5SMpkg.h9211logstatsplain
-rwxr-xr-xH5SMprivate.h3111logstatsplain
-rw-r--r--H5SMtest.c4206logstatsplain
-rw-r--r--H5ST.c22139logstatsplain
-rw-r--r--H5STprivate.h2911logstatsplain
-rw-r--r--H5Sall.c26666logstatsplain
-rw-r--r--H5Shyper.c326826logstatsplain
-rw-r--r--H5Smpio.c27976logstatsplain
-rw-r--r--H5Snone.c24799logstatsplain
-rw-r--r--H5Spkg.h11852logstatsplain
-rw-r--r--H5Spoint.c49165logstatsplain
-rw-r--r--H5Sprivate.h14980logstatsplain
-rw-r--r--H5Spublic.h7428logstatsplain
-rw-r--r--H5Sselect.c54625logstatsplain
-rw-r--r--H5Stest.c4400logstatsplain
-rw-r--r--H5T.c202230logstatsplain
-rw-r--r--H5TS.c9756logstatsplain
-rw-r--r--H5TSprivate.h2550logstatsplain
-rw-r--r--H5Tarray.c10606logstatsplain
-rw-r--r--H5Tbit.c19099logstatsplain
-rw-r--r--H5Tcommit.c30419logstatsplain
-rw-r--r--H5Tcompound.c20216logstatsplain
-rw-r--r--H5Tconv.c396357logstatsplain
-rw-r--r--H5Tcset.c5194logstatsplain
-rw-r--r--H5Tenum.c20022logstatsplain
-rw-r--r--H5Tfields.c15195logstatsplain
-rw-r--r--H5Tfixed.c5582logstatsplain
-rw-r--r--H5Tfloat.c14504logstatsplain
-rw-r--r--H5Tnative.c36219logstatsplain
-rw-r--r--H5Toffset.c9431logstatsplain
-rw-r--r--H5Toh.c5626logstatsplain
-rw-r--r--H5Topaque.c4750logstatsplain
-rw-r--r--H5Torder.c4899logstatsplain
-rw-r--r--H5Tpad.c5185logstatsplain
-rw-r--r--H5Tpkg.h68076logstatsplain
-rw-r--r--H5Tprecis.c9589logstatsplain
-rw-r--r--H5Tprivate.h4736logstatsplain
-rw-r--r--H5Tpublic.h26693logstatsplain
-rw-r--r--H5Tstrpad.c5812logstatsplain
-rw-r--r--H5Tvlen.c39690logstatsplain
-rw-r--r--H5V.c45790logstatsplain
-rw-r--r--H5Vprivate.h14588logstatsplain
-rw-r--r--H5Z.c44968logstatsplain
-rw-r--r--H5Zdeflate.c7291logstatsplain
-rw-r--r--H5Zfletcher32.c6814logstatsplain
-rw-r--r--H5Znbit.c52600logstatsplain
-rw-r--r--H5Zpkg.h2289logstatsplain
-rw-r--r--H5Zprivate.h4712logstatsplain
-rw-r--r--H5Zpublic.h9482logstatsplain
-rw-r--r--H5Zscaleoffset.c82189logstatsplain
-rw-r--r--H5Zshuffle.c10880logstatsplain
-rw-r--r--H5Zszip.c15300logstatsplain
-rw-r--r--H5Ztrans.c58637logstatsplain
-rw-r--r--H5api_adpt.h4364logstatsplain
-rw-r--r--H5checksum.c15542logstatsplain
-rw-r--r--H5config.h.in17402logstatsplain
-rw-r--r--H5dbg.c3822logstatsplain
-rw-r--r--H5detect.c46630logstatsplain
-rw-r--r--H5err.txt10493logstatsplain
-rw-r--r--H5private.h50691logstatsplain
-rw-r--r--H5public.h11176logstatsplain
-rw-r--r--H5system.c16010logstatsplain
-rw-r--r--H5timer.c7566logstatsplain
-rw-r--r--H5trace.c66788logstatsplain
-rwxr-xr-xMakefile.am6401logstatsplain
-rw-r--r--Makefile.in57924logstatsplain
-rw-r--r--hdf5-lin.lnt696logstatsplain
-rw-r--r--hdf5-win.lnt1315logstatsplain
-rw-r--r--hdf5.h2634logstatsplain
-rwxr-xr-xhdf5.lnt2690logstatsplain
-rw-r--r--libhdf5.settings.in559logstatsplain
ef='#n4493'>4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941
/*
 * tkImgPhoto.c --
 *
 *	Implements images of type "photo" for Tk.  Photo images are
 *	stored in full color (32 bits per pixel including alpha channel)
 *	and displayed using dithering if necessary.
 *
 * Copyright (c) 1994 The Australian National University.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 2002 Donal K. Fellows
 * Copyright (c) 2003 ActiveState Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * Author: Paul Mackerras (paulus@cs.anu.edu.au),
 *	   Department of Computer Science,
 *	   Australian National University.
 *
 * RCS: @(#) $Id: tkImgPhoto.c,v 1.36.2.8 2004/05/03 18:01:32 hobbs Exp $
 */

#include "tkInt.h"
#include "tkPort.h"
#include "tclMath.h"
#include <ctype.h>

#ifdef __WIN32__
#include "tkWinInt.h"
#endif

/*
 * Declaration for internal Xlib function used here:
 */

extern int _XInitImageFuncPtrs _ANSI_ARGS_((XImage *image));

/*
 * A signed 8-bit integral type.  If chars are unsigned and the compiler
 * isn't an ANSI one, then we have to use short instead (which wastes
 * space) to get signed behavior.
 */

#if defined(__STDC__) || defined(_AIX)
    typedef signed char schar;
#else
#   ifndef __CHAR_UNSIGNED__
	typedef char schar;
#   else
	typedef short schar;
#   endif
#endif

/*
 * An unsigned 32-bit integral type, used for pixel values.
 * We use int rather than long here to accommodate those systems
 * where longs are 64 bits.
 */

typedef unsigned int pixel;

/*
 * The maximum number of pixels to transmit to the server in a
 * single XPutImage call.
 */

#define MAX_PIXELS 65536

/*
 * The set of colors required to display a photo image in a window depends on:
 *	- the visual used by the window
 *	- the palette, which specifies how many levels of each primary
 *	  color to use, and
 *	- the gamma value for the image.
 *
 * Pixel values allocated for specific colors are valid only for the
 * colormap in which they were allocated.  Sets of pixel values
 * allocated for displaying photos are re-used in other windows if
 * possible, that is, if the display, colormap, palette and gamma
 * values match.  A hash table is used to locate these sets of pixel
 * values, using the following data structure as key:
 */

typedef struct {
    Display *display;		/* Qualifies the colormap resource ID */
    Colormap colormap;		/* Colormap that the windows are using. */
    double gamma;		/* Gamma exponent value for images. */
    Tk_Uid palette;		/* Specifies how many shades of each primary
				 * we want to allocate. */
} ColorTableId;

/*
 * For a particular (display, colormap, palette, gamma) combination,
 * a data structure of the following type is used to store the allocated
 * pixel values and other information:
 */

typedef struct ColorTable {
    ColorTableId id;		/* Information used in selecting this
				 * color table. */
    int	flags;			/* See below. */
    int	refCount;		/* Number of instances using this map. */
    int liveRefCount;		/* Number of instances which are actually
				 * in use, using this map. */
    int	numColors;		/* Number of colors allocated for this map. */

    XVisualInfo	visualInfo;	/* Information about the visual for windows
				 * using this color table. */

    pixel redValues[256];	/* Maps 8-bit values of red intensity
				 * to a pixel value or index in pixelMap. */
    pixel greenValues[256];	/* Ditto for green intensity */
    pixel blueValues[256];	/* Ditto for blue intensity */
    unsigned long *pixelMap;	/* Actual pixel values allocated. */

    unsigned char colorQuant[3][256];
				/* Maps 8-bit intensities to quantized
				 * intensities.  The first index is 0 for
				 * red, 1 for green, 2 for blue. */
} ColorTable;

/*
 * Bit definitions for the flags field of a ColorTable.
 * BLACK_AND_WHITE:		1 means only black and white colors are
 *				available.
 * COLOR_WINDOW:		1 means a full 3-D color cube has been
 *				allocated.
 * DISPOSE_PENDING:		1 means a call to DisposeColorTable has
 *				been scheduled as an idle handler, but it
 *				hasn't been invoked yet.
 * MAP_COLORS:			1 means pixel values should be mapped
 *				through pixelMap.
 */
#ifdef COLOR_WINDOW
#undef COLOR_WINDOW
#endif

#define BLACK_AND_WHITE		1
#define COLOR_WINDOW		2
#define DISPOSE_PENDING		4
#define MAP_COLORS		8

/*
 * Definition of the data associated with each photo image master.
 */

typedef struct PhotoMaster {
    Tk_ImageMaster tkMaster;	/* Tk's token for image master.  NULL means
				 * the image is being deleted. */
    Tcl_Interp *interp;		/* Interpreter associated with the
				 * application using this image. */
    Tcl_Command imageCmd;	/* Token for image command (used to delete
				 * it when the image goes away).  NULL means
				 * the image command has already been
				 * deleted. */
    int	flags;			/* Sundry flags, defined below. */
    int	width, height;		/* Dimensions of image. */
    int userWidth, userHeight;	/* User-declared image dimensions. */
    Tk_Uid palette;		/* User-specified default palette for
				 * instances of this image. */
    double gamma;		/* Display gamma value to correct for. */
    char *fileString;		/* Name of file to read into image. */
    Tcl_Obj *dataString;	/* Object to use as contents of image. */
    Tcl_Obj *format;		/* User-specified format of data in image
				 * file or string value. */
    unsigned char *pix32;	/* Local storage for 32-bit image. */
    int ditherX, ditherY;	/* Location of first incorrectly
				 * dithered pixel in image. */
    TkRegion validRegion;	/* Tk region indicating which parts of
				 * the image have valid image data. */
    struct PhotoInstance *instancePtr;
				/* First in the list of instances
				 * associated with this master. */
} PhotoMaster;

/*
 * Bit definitions for the flags field of a PhotoMaster.
 * COLOR_IMAGE:			1 means that the image has different color
 *				components.
 * IMAGE_CHANGED:		1 means that the instances of this image
 *				need to be redithered.
 * COMPLEX_ALPHA:		1 means that the instances of this image
 *				have alpha values that aren't 0 or 255.
 */

#define COLOR_IMAGE		1
#define IMAGE_CHANGED		2
#define COMPLEX_ALPHA		4

/*
 * The following data structure represents all of the instances of
 * a photo image in windows on a given screen that are using the
 * same colormap.
 */

typedef struct PhotoInstance {
    PhotoMaster *masterPtr;	/* Pointer to master for image. */
    Display *display;		/* Display for windows using this instance. */
    Colormap colormap;		/* The image may only be used in windows with
				 * this particular colormap. */
    struct PhotoInstance *nextPtr;
				/* Pointer to the next instance in the list
				 * of instances associated with this master. */
    int refCount;		/* Number of instances using this structure. */
    Tk_Uid palette;		/* Palette for these particular instances. */
    double gamma;		/* Gamma value for these instances. */
    Tk_Uid defaultPalette;	/* Default palette to use if a palette
				 * is not specified for the master. */
    ColorTable *colorTablePtr;	/* Pointer to information about colors
				 * allocated for image display in windows
				 * like this one. */
    Pixmap pixels;		/* X pixmap containing dithered image. */
    int width, height;		/* Dimensions of the pixmap. */
    schar *error;		/* Error image, used in dithering. */
    XImage *imagePtr;		/* Image structure for converted pixels. */
    XVisualInfo visualInfo;	/* Information about the visual that these
				 * windows are using. */
    GC gc;			/* Graphics context for writing images
				 * to the pixmap. */
} PhotoInstance;

/*
 * The following data structure is used to return information
 * from ParseSubcommandOptions:
 */

struct SubcommandOptions {
    int options;		/* Individual bits indicate which
				 * options were specified - see below. */
    Tcl_Obj *name;		/* Name specified without an option. */
    int fromX, fromY;		/* Values specified for -from option. */
    int fromX2, fromY2;		/* Second coordinate pair for -from option. */
    int toX, toY;		/* Values specified for -to option. */
    int toX2, toY2;		/* Second coordinate pair for -to option. */
    int zoomX, zoomY;		/* Values specified for -zoom option. */
    int subsampleX, subsampleY;	/* Values specified for -subsample option. */
    Tcl_Obj *format;		/* Value specified for -format option. */
    XColor *background;		/* Value specified for -background option. */
    int compositingRule;	/* Value specified for -compositingrule opt */
};

/*
 * Bit definitions for use with ParseSubcommandOptions:
 * Each bit is set in the allowedOptions parameter on a call to
 * ParseSubcommandOptions if that option is allowed for the current
 * photo image subcommand.  On return, the bit is set in the options
 * field of the SubcommandOptions structure if that option was specified.
 *
 * OPT_BACKGROUND:		Set if -format option allowed/specified.
 * OPT_COMPOSITE:		Set if -compositingrule option allowed/spec'd.
 * OPT_FORMAT:			Set if -format option allowed/specified.
 * OPT_FROM:			Set if -from option allowed/specified.
 * OPT_GRAYSCALE:		Set if -grayscale option allowed/specified.
 * OPT_SHRINK:			Set if -shrink option allowed/specified.
 * OPT_SUBSAMPLE:		Set if -subsample option allowed/spec'd.
 * OPT_TO:			Set if -to option allowed/specified.
 * OPT_ZOOM:			Set if -zoom option allowed/specified.
 */

#define OPT_BACKGROUND	1
#define OPT_COMPOSITE	2
#define OPT_FORMAT	4
#define OPT_FROM	8
#define OPT_GRAYSCALE	0x10
#define OPT_SHRINK	0x20
#define OPT_SUBSAMPLE	0x40
#define OPT_TO		0x80
#define OPT_ZOOM	0x100

/*
 * List of option names.  The order here must match the order of
 * declarations of the OPT_* constants above.
 */

static char *optionNames[] = {
    "-background",
    "-compositingrule",
    "-format",
    "-from",
    "-grayscale",
    "-shrink",
    "-subsample",
    "-to",
    "-zoom",
    (char *) NULL
};

/*
 * Message to generate when an attempt to resize an image fails due
 * to memory problems.
 */
#define TK_PHOTO_ALLOC_FAILURE_MESSAGE \
	"not enough free memory for image buffer"

/*
 * Functions used in the type record for photo images.
 */

static int		ImgPhotoCreate _ANSI_ARGS_((Tcl_Interp *interp,
			    char *name, int objc, Tcl_Obj *CONST objv[],
			    Tk_ImageType *typePtr, Tk_ImageMaster master,
			    ClientData *clientDataPtr));
static ClientData	ImgPhotoGet _ANSI_ARGS_((Tk_Window tkwin,
			    ClientData clientData));
static void		ImgPhotoDisplay _ANSI_ARGS_((ClientData clientData,
			    Display *display, Drawable drawable,
			    int imageX, int imageY, int width, int height,
			    int drawableX, int drawableY));
static void		ImgPhotoFree _ANSI_ARGS_((ClientData clientData,
			    Display *display));
static void		ImgPhotoDelete _ANSI_ARGS_((ClientData clientData));
static int		ImgPhotoPostscript _ANSI_ARGS_((ClientData clientData,
			    Tcl_Interp *interp, Tk_Window tkwin,
			    Tk_PostscriptInfo psInfo, int x, int y, int width,
			    int height, int prepass));

/*
 * The type record itself for photo images:
 */

Tk_ImageType tkPhotoImageType = {
    "photo",			/* name */
    ImgPhotoCreate,		/* createProc */
    ImgPhotoGet,		/* getProc */
    ImgPhotoDisplay,		/* displayProc */
    ImgPhotoFree,		/* freeProc */
    ImgPhotoDelete,		/* deleteProc */
    ImgPhotoPostscript,		/* postscriptProc */
    (Tk_ImageType *) NULL	/* nextPtr */
};

typedef struct ThreadSpecificData {
    Tk_PhotoImageFormat *formatList;  /* Pointer to the first in the 
				       * list of known photo image formats.*/
    Tk_PhotoImageFormat *oldFormatList;  /* Pointer to the first in the 
				       * list of known photo image formats.*/
    int initialized;	/* set to 1 if we've initialized the strucuture */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;

/*
 * Default configuration
 */

#define DEF_PHOTO_GAMMA		"1"
#define DEF_PHOTO_HEIGHT	"0"
#define DEF_PHOTO_PALETTE	""
#define DEF_PHOTO_WIDTH		"0"

/*
 * Information used for parsing configuration specifications:
 */
static Tk_ConfigSpec configSpecs[] = {
    {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
	 (char *) NULL, Tk_Offset(PhotoMaster, fileString), TK_CONFIG_NULL_OK},
    {TK_CONFIG_DOUBLE, "-gamma", (char *) NULL, (char *) NULL,
	 DEF_PHOTO_GAMMA, Tk_Offset(PhotoMaster, gamma), 0},
    {TK_CONFIG_INT, "-height", (char *) NULL, (char *) NULL,
	 DEF_PHOTO_HEIGHT, Tk_Offset(PhotoMaster, userHeight), 0},
    {TK_CONFIG_UID, "-palette", (char *) NULL, (char *) NULL,
	 DEF_PHOTO_PALETTE, Tk_Offset(PhotoMaster, palette), 0},
    {TK_CONFIG_INT, "-width", (char *) NULL, (char *) NULL,
	 DEF_PHOTO_WIDTH, Tk_Offset(PhotoMaster, userWidth), 0},
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
	 (char *) NULL, 0, 0}
};

/*
 * Hash table used to hash from (display, colormap, palette, gamma)
 * to ColorTable address.
 */

static Tcl_HashTable imgPhotoColorHash;
static int imgPhotoColorHashInitialized;
#define N_COLOR_HASH	(sizeof(ColorTableId) / sizeof(int))

/*
 * Forward declarations
 */

static void		PhotoFormatThreadExitProc _ANSI_ARGS_((
			    ClientData clientData));
static int		ImgPhotoCmd _ANSI_ARGS_((ClientData clientData,
			    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
static int		ParseSubcommandOptions _ANSI_ARGS_((
			    struct SubcommandOptions *optPtr,
			    Tcl_Interp *interp, int allowedOptions,
			    int *indexPtr, int objc, Tcl_Obj *CONST objv[]));
static void		ImgPhotoCmdDeletedProc _ANSI_ARGS_((
			    ClientData clientData));
static int		ImgPhotoConfigureMaster _ANSI_ARGS_((
			    Tcl_Interp *interp, PhotoMaster *masterPtr,
			    int objc, Tcl_Obj *CONST objv[], int flags));
static void		ImgPhotoConfigureInstance _ANSI_ARGS_((
			    PhotoInstance *instancePtr));
static int              ToggleComplexAlphaIfNeeded _ANSI_ARGS_((
                            PhotoMaster *mPtr));
static void             ImgPhotoBlendComplexAlpha _ANSI_ARGS_((
			    XImage *bgImg, PhotoInstance *iPtr,
			    int xOffset, int yOffset, int width, int height));
static int		ImgPhotoSetSize _ANSI_ARGS_((PhotoMaster *masterPtr,
			    int width, int height));
static void		ImgPhotoInstanceSetSize _ANSI_ARGS_((
			    PhotoInstance *instancePtr));
static int		ImgStringWrite _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *formatString,
			    Tk_PhotoImageBlock *blockPtr));
static char *		ImgGetPhoto _ANSI_ARGS_((PhotoMaster *masterPtr,
			    Tk_PhotoImageBlock *blockPtr,
			    struct SubcommandOptions *optPtr));
static int		IsValidPalette _ANSI_ARGS_((PhotoInstance *instancePtr,
			    CONST char *palette));
static int		CountBits _ANSI_ARGS_((pixel mask));
static void		GetColorTable _ANSI_ARGS_((PhotoInstance *instancePtr));
static void		FreeColorTable _ANSI_ARGS_((ColorTable *colorPtr,
			    int force));
static void		AllocateColors _ANSI_ARGS_((ColorTable *colorPtr));
static void		DisposeColorTable _ANSI_ARGS_((ClientData clientData));
static void		DisposeInstance _ANSI_ARGS_((ClientData clientData));
static int		ReclaimColors _ANSI_ARGS_((ColorTableId *id,
			    int numColors));
static int		MatchFileFormat _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Channel chan, char *fileName, Tcl_Obj *formatString,
			    Tk_PhotoImageFormat **imageFormatPtr,
			    int *widthPtr, int *heightPtr, int *oldformat));
static int		MatchStringFormat _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *data, Tcl_Obj *formatString,
			    Tk_PhotoImageFormat **imageFormatPtr,
			    int *widthPtr, int *heightPtr, int *oldformat));
static Tcl_ObjCmdProc *	PhotoOptionFind _ANSI_ARGS_((Tcl_Interp * interp,
			    Tcl_Obj *obj));
static void		DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr,
			    int x, int y, int width, int height));
static void		PhotoOptionCleanupProc _ANSI_ARGS_((
			    ClientData clientData, Tcl_Interp *interp));

#undef MIN
#define MIN(a, b)	((a) < (b)? (a): (b))
#undef MAX
#define MAX(a, b)	((a) > (b)? (a): (b))

/*
 *----------------------------------------------------------------------
 *
 * Tk_CreateOldPhotoImageFormat, Tk_CreatePhotoImageFormat --
 *
 *	This procedure is invoked by an image file handler to register
 *	a new photo image format and the procedures that handle the
 *	new format.  The procedure is typically invoked during
 *	Tcl_AppInit.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The new image file format is entered into a table used in the
 *	photo image "read" and "write" subcommands.
 *
 *----------------------------------------------------------------------
 */

static void
PhotoFormatThreadExitProc(clientData)
    ClientData clientData;	/* not used */
{
    Tk_PhotoImageFormat *freePtr;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    while (tsdPtr->oldFormatList != NULL) {
	freePtr = tsdPtr->oldFormatList;
	tsdPtr->oldFormatList = tsdPtr->oldFormatList->nextPtr;
	ckfree((char *) freePtr->name);
	ckfree((char *) freePtr);
    }
    while (tsdPtr->formatList != NULL) {
	freePtr = tsdPtr->formatList;
	tsdPtr->formatList = tsdPtr->formatList->nextPtr;
	ckfree((char *) freePtr->name);
	ckfree((char *) freePtr);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_CreateOldPhotoImageFormat, Tk_CreatePhotoImageFormat --
 *
 *	This procedure is invoked by an image file handler to register
 *	a new photo image format and the procedures that handle the
 *	new format.  The procedure is typically invoked during
 *	Tcl_AppInit.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The new image file format is entered into a table used in the
 *	photo image "read" and "write" subcommands.
 *
 *----------------------------------------------------------------------
 */
void
Tk_CreateOldPhotoImageFormat(formatPtr)
    Tk_PhotoImageFormat *formatPtr;
				/* Structure describing the format.  All of
				 * the fields except "nextPtr" must be filled
				 * in by caller.  Must not have been passed
				 * to Tk_CreatePhotoImageFormat previously. */
{
    Tk_PhotoImageFormat *copyPtr;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    if (!tsdPtr->initialized) {
	tsdPtr->initialized = 1;
	Tcl_CreateThreadExitHandler(PhotoFormatThreadExitProc, NULL);
    }
    copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
    *copyPtr = *formatPtr;
    copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1));
    strcpy(copyPtr->name, formatPtr->name);
    copyPtr->nextPtr = tsdPtr->oldFormatList;
    tsdPtr->oldFormatList = copyPtr;
}

void
Tk_CreatePhotoImageFormat(formatPtr)
    Tk_PhotoImageFormat *formatPtr;
				/* Structure describing the format.  All of
				 * the fields except "nextPtr" must be filled
				 * in by caller.  Must not have been passed
				 * to Tk_CreatePhotoImageFormat previously. */
{
    Tk_PhotoImageFormat *copyPtr;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    if (!tsdPtr->initialized) {
	tsdPtr->initialized = 1;
	Tcl_CreateThreadExitHandler(PhotoFormatThreadExitProc, NULL);
    }
    copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
    *copyPtr = *formatPtr;
    copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1));
    strcpy(copyPtr->name, formatPtr->name);
    if (isupper((unsigned char) *formatPtr->name)) {
	copyPtr->nextPtr = tsdPtr->oldFormatList;
	tsdPtr->oldFormatList = copyPtr;
    } else {
	copyPtr->nextPtr = tsdPtr->formatList;
	tsdPtr->formatList = copyPtr;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoCreate --
 *
 *	This procedure is called by the Tk image code to create
 *	a new photo image.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	The data structure for a new photo image is allocated and
 *	initialized.
 *
 *----------------------------------------------------------------------
 */

static int
ImgPhotoCreate(interp, name, objc, objv, typePtr, master, clientDataPtr)
    Tcl_Interp *interp;		/* Interpreter for application containing
				 * image. */
    char *name;			/* Name to use for image. */
    int objc;			/* Number of arguments. */
    Tcl_Obj *CONST objv[];	/* Argument objects for options (doesn't
				 * include image name or type). */
    Tk_ImageType *typePtr;	/* Pointer to our type record (not used). */
    Tk_ImageMaster master;	/* Token for image, to be used by us in
				 * later callbacks. */
    ClientData *clientDataPtr;	/* Store manager's token for image here;
				 * it will be returned in later callbacks. */
{
    PhotoMaster *masterPtr;

    /*
     * Allocate and initialize the photo image master record.
     */

    masterPtr = (PhotoMaster *) ckalloc(sizeof(PhotoMaster));
    memset((void *) masterPtr, 0, sizeof(PhotoMaster));
    masterPtr->tkMaster = master;
    masterPtr->interp = interp;
    masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgPhotoCmd,
	    (ClientData) masterPtr, ImgPhotoCmdDeletedProc);
    masterPtr->palette = NULL;
    masterPtr->pix32 = NULL;
    masterPtr->instancePtr = NULL;
    masterPtr->validRegion = TkCreateRegion();

    /*
     * Process configuration options given in the image create command.
     */

    if (ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, 0) != TCL_OK) {
	ImgPhotoDelete((ClientData) masterPtr);
	return TCL_ERROR;
    }

    *clientDataPtr = (ClientData) masterPtr;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoCmd --
 *
 *	This procedure is invoked to process the Tcl command that
 *	corresponds to a photo image.  See the user documentation
 *	for details on what it does.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

static int
ImgPhotoCmd(clientData, interp, objc, objv)
    ClientData clientData;	/* Information about photo master. */
    Tcl_Interp *interp;		/* Current interpreter. */
    int objc;			/* Number of arguments. */
    Tcl_Obj *CONST objv[];	/* Argument objects. */
{
    int oldformat = 0;
    static CONST char *photoOptions[] = {
	"blank", "cget", "configure", "copy", "data", "get", "put",
	"read", "redither", "transparency", "write", (char *) NULL
    };
    enum options {
	PHOTO_BLANK, PHOTO_CGET, PHOTO_CONFIGURE, PHOTO_COPY, PHOTO_DATA,
	PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_TRANS,
	PHOTO_WRITE
    };

    PhotoMaster *masterPtr = (PhotoMaster *) clientData;
    int result, index;
    int x, y, width, height;
    int dataWidth, dataHeight;
    struct SubcommandOptions options;
    int listArgc;
    CONST char **listArgv;
    CONST char **srcArgv;
    unsigned char *pixelPtr;
    Tk_PhotoImageBlock block;
    Tk_Window tkwin;
    XColor color;
    Tk_PhotoImageFormat *imageFormat;
    int imageWidth, imageHeight;
    int matched;
    Tcl_Channel chan;
    Tk_PhotoHandle srcHandle;
    size_t length;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
	return TCL_ERROR;
    }

    if (Tcl_GetIndexFromObj(interp, objv[1], photoOptions, "option", 0,
	    &index) != TCL_OK) {
	Tcl_ObjCmdProc *proc;
	proc = PhotoOptionFind(interp, objv[1]);
	if (proc == (Tcl_ObjCmdProc *) NULL) {
	    return TCL_ERROR;
	}
	return proc(clientData, interp, objc, objv);
    }

    switch ((enum options) index) {
    case PHOTO_BLANK:
	/*
	 * photo blank command - just call Tk_PhotoBlank.
	 */

	if (objc == 2) {
	    Tk_PhotoBlank(masterPtr);
	    return TCL_OK;
	} else {
	    Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
	    return TCL_ERROR;
	}

    case PHOTO_CGET: {
	char *arg;

	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "option");
	    return TCL_ERROR;
	}
	arg = Tcl_GetStringFromObj(objv[2], (int *) &length);
	if (strncmp(arg,"-data", length) == 0) {
	    if (masterPtr->dataString) {
		Tcl_SetObjResult(interp, masterPtr->dataString);
	    }
	} else if (strncmp(arg,"-format", length) == 0) {
	    if (masterPtr->format) {
		Tcl_SetObjResult(interp, masterPtr->format);
	    }
	} else {
	    Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
		    (char *) masterPtr, Tcl_GetString(objv[2]), 0);
	}
	return TCL_OK;
    }

    case PHOTO_CONFIGURE:
	/*
	 * photo configure command - handle this in the standard way.
	 */

	if (objc == 2) {
	    Tcl_Obj *obj, *subobj;
	    result = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
		    configSpecs, (char *) masterPtr, (char *) NULL, 0);
	    if (result != TCL_OK) {
		return result;
	    }
	    obj = Tcl_NewObj();
	    subobj = Tcl_NewStringObj("-data {} {} {}", 14);
	    if (masterPtr->dataString) {
		Tcl_ListObjAppendElement(interp, subobj, masterPtr->dataString);
	    } else {
		Tcl_AppendStringsToObj(subobj, " {}", (char *) NULL);
	    }
	    Tcl_ListObjAppendElement(interp, obj, subobj);
	    subobj = Tcl_NewStringObj("-format {} {} {}", 16);
	    if (masterPtr->format) {
		Tcl_ListObjAppendElement(interp, subobj, masterPtr->format);
	    } else {
		Tcl_AppendStringsToObj(subobj, " {}", (char *) NULL);
	    }
	    Tcl_ListObjAppendElement(interp, obj, subobj);
	    Tcl_ListObjAppendList(interp, obj, Tcl_GetObjResult(interp));
	    Tcl_SetObjResult(interp, obj);
	    return TCL_OK;
	}
	if (objc == 3) {
	    char *arg = Tcl_GetStringFromObj(objv[2], (int *) &length);
	    if (!strncmp(arg, "-data", length)) {
		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			"-data {} {} {}", (char *) NULL);
		if (masterPtr->dataString) {
		    Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
			    masterPtr->dataString);
		} else {
		    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			    " {}", (char *) NULL);
		}
		return TCL_OK;
	    } else if (!strncmp(arg, "-format", length)) {
		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			"-format {} {} {}", (char *) NULL);
		if (masterPtr->format) {
		    Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
			    masterPtr->format);
		} else {
		    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			    " {}", (char *) NULL);
		}
		return TCL_OK;
	    } else {
		return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
			configSpecs, (char *) masterPtr, arg, 0);
	    }
	}
	return ImgPhotoConfigureMaster(interp, masterPtr, objc-2, objv+2,
		TK_CONFIG_ARGV_ONLY);

    case PHOTO_COPY:
	/*
	 * photo copy command - first parse options.
	 */

	index = 2;
	memset((VOID *) &options, 0, sizeof(options));
	options.zoomX = options.zoomY = 1;
	options.subsampleX = options.subsampleY = 1;
	options.name = NULL;
	options.compositingRule = TK_PHOTO_COMPOSITE_OVERLAY;
	if (ParseSubcommandOptions(&options, interp,
		OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK |
		OPT_COMPOSITE, &index, objc, objv) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (options.name == NULL || index < objc) {
	    Tcl_WrongNumArgs(interp, 2, objv,
		    "source-image ?-compositingrule rule? ?-from x1 y1 x2 y2? ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?");
	    return TCL_ERROR;
	}

	/*
	 * Look for the source image and get a pointer to its image data.
	 * Check the values given for the -from option.
	 */

	srcHandle = Tk_FindPhoto(interp, Tcl_GetString(options.name));
	if (srcHandle == NULL) {
	    Tcl_AppendResult(interp, "image \"",
		    Tcl_GetString(options.name), "\" doesn't",
		    " exist or is not a photo image", (char *) NULL);
	    return TCL_ERROR;
	}
	Tk_PhotoGetImage(srcHandle, &block);
	if ((options.fromX2 > block.width) || (options.fromY2 > block.height)
		|| (options.fromX2 > block.width)
		|| (options.fromY2 > block.height)) {
	    Tcl_AppendResult(interp, "coordinates for -from option extend ",
		    "outside source image", (char *) NULL);
	    return TCL_ERROR;
	}

	/*
	 * Fill in default values for unspecified parameters.
	 */

	if (!(options.options & OPT_FROM) || (options.fromX2 < 0)) {
	    options.fromX2 = block.width;
	    options.fromY2 = block.height;
	}
	if (!(options.options & OPT_TO) || (options.toX2 < 0)) {
	    width = options.fromX2 - options.fromX;
	    if (options.subsampleX > 0) {
		width = (width + options.subsampleX - 1) / options.subsampleX;
	    } else if (options.subsampleX == 0) {
		width = 0;
	    } else {
		width = (width - options.subsampleX - 1) / -options.subsampleX;
	    }
	    options.toX2 = options.toX + width * options.zoomX;

	    height = options.fromY2 - options.fromY;
	    if (options.subsampleY > 0) {
		height = (height + options.subsampleY - 1)
			/ options.subsampleY;
	    } else if (options.subsampleY == 0) {
		height = 0;
	    } else {
		height = (height - options.subsampleY - 1)
			/ -options.subsampleY;
	    }
	    options.toY2 = options.toY + height * options.zoomY;
	}

	/*
	 * Set the destination image size if the -shrink option was specified.
	 */

	if (options.options & OPT_SHRINK) {
	    if (ImgPhotoSetSize(masterPtr, options.toX2,
		    options.toY2) != TCL_OK) {
		Tcl_ResetResult(interp);
		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
		return TCL_ERROR;
	    }
	}

	/*
	 * Copy the image data over using Tk_PhotoPutZoomedBlock.
	 */

	block.pixelPtr += options.fromX * block.pixelSize
		+ options.fromY * block.pitch;
	block.width = options.fromX2 - options.fromX;
	block.height = options.fromY2 - options.fromY;
	Tk_PhotoPutZoomedBlock((Tk_PhotoHandle) masterPtr, &block,
		options.toX, options.toY, options.toX2 - options.toX,
		options.toY2 - options.toY, options.zoomX, options.zoomY,
		options.subsampleX, options.subsampleY,
		options.compositingRule);
	return TCL_OK;

    case PHOTO_DATA: {
	char *data;

	/*
	 * photo data command - first parse and check any options given.
	 */
	Tk_ImageStringWriteProc *stringWriteProc = NULL;

	index = 2;
	memset((VOID *) &options, 0, sizeof(options));
	options.name = NULL;
	options.format = NULL;
	options.fromX = 0;
	options.fromY = 0;
	if (ParseSubcommandOptions(&options, interp,
		OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
		&index, objc, objv) != TCL_OK) {
	    return TCL_ERROR;
	}
	if ((options.name != NULL) || (index < objc)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?options?");
	    return TCL_ERROR;
	}
	if ((options.fromX > masterPtr->width)
		|| (options.fromY > masterPtr->height)
		|| (options.fromX2 > masterPtr->width)
		|| (options.fromY2 > masterPtr->height)) {
	    Tcl_AppendResult(interp, "coordinates for -from option extend ",
		    "outside image", (char *) NULL);
	    return TCL_ERROR;
	}

	/*
	 * Fill in default values for unspecified parameters.
	 */

	if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
	    options.fromX2 = masterPtr->width;
	    options.fromY2 = masterPtr->height;
	}

	/*
	 * Search for an appropriate image string format handler.
	 */

	if (options.options & OPT_FORMAT) {
	    matched = 0;
	    for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
	 	imageFormat = imageFormat->nextPtr) {
		if ((strncasecmp(Tcl_GetString(options.format),
			imageFormat->name, strlen(imageFormat->name)) == 0)) {
		    matched = 1;
		    if (imageFormat->stringWriteProc != NULL) {
			stringWriteProc = imageFormat->stringWriteProc;
			break;
		    }
		}
	    }
	    if (stringWriteProc == NULL) {
		oldformat = 1;
		for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
			imageFormat = imageFormat->nextPtr) {
		    if ((strncasecmp(Tcl_GetString(options.format),
			    imageFormat->name,
			    strlen(imageFormat->name)) == 0)) {
			matched = 1;
			if (imageFormat->stringWriteProc != NULL) {
			    stringWriteProc = imageFormat->stringWriteProc;
			    break;
			}
		    }
		}
	    }
	    if (stringWriteProc == NULL) {
		Tcl_AppendResult(interp, "image string format \"",
			Tcl_GetString(options.format), "\" is ",
			(matched ? "not supported" : "unknown"),
			(char *) NULL);
		return TCL_ERROR;
	    }
	} else {
	    stringWriteProc = ImgStringWrite;
	}

	/*
	 * Call the handler's string write procedure to write out
	 * the image.
	 */

	data = ImgGetPhoto(masterPtr, &block, &options);

	if (oldformat) {
	    Tcl_DString buffer;

	    Tcl_DStringInit(&buffer);
	    result = ((int (*) _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_DString *buffer, char *formatString,
		    Tk_PhotoImageBlock *blockPtr))) stringWriteProc)
		    (interp, &buffer, Tcl_GetString(options.format), &block);
	    if (result == TCL_OK) {
		Tcl_DStringResult(interp, &buffer);
	    } else {
		Tcl_DStringFree(&buffer);
	    }
	} else {
	    result = ((int (*) _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Obj *formatString, Tk_PhotoImageBlock *blockPtr,
		    VOID *dummy))) stringWriteProc)
		    (interp, options.format, &block, (VOID *) NULL);
	}
	if (options.background) {
	    Tk_FreeColor(options.background);
	}
	if (data) {
	    ckfree(data);
	}
	return result;
    }

    case PHOTO_GET: {
	/*
	 * photo get command - first parse and check parameters.
	 */

	char string[TCL_INTEGER_SPACE * 3];

	if (objc != 4) {
	    Tcl_WrongNumArgs(interp, 2, objv, "x y");
	    return TCL_ERROR;
	}
	if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK)
		|| (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) {
	    return TCL_ERROR;
	}
	if ((x < 0) || (x >= masterPtr->width)
		|| (y < 0) || (y >= masterPtr->height)) {
	    Tcl_AppendResult(interp, Tcl_GetString(objv[0]), " get: ",
		    "coordinates out of range", (char *) NULL);
	    return TCL_ERROR;
	}

	/*
	 * Extract the value of the desired pixel and format it as a string.
	 */

	pixelPtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
	sprintf(string, "%d %d %d", pixelPtr[0], pixelPtr[1],
		pixelPtr[2]);
	Tcl_AppendResult(interp, string, (char *) NULL);
	return TCL_OK;
    }

    case PHOTO_PUT:
	/*
	 * photo put command - first parse the options and colors specified.
	 */

	index = 2;
	memset((VOID *) &options, 0, sizeof(options));
	options.name = NULL;
	if (ParseSubcommandOptions(&options, interp, OPT_TO|OPT_FORMAT,
		&index, objc, objv) != TCL_OK) {
	    return TCL_ERROR;
	}
	if ((options.name == NULL) || (index < objc)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "data ?options?");
	    return TCL_ERROR;
	}

	if (MatchStringFormat(interp, options.name ? objv[2]:NULL, 
		options.format, &imageFormat, &imageWidth,
		&imageHeight, &oldformat) == TCL_OK) {
	    Tcl_Obj *format, *data;

	    if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
		options.toX2 = options.toX + imageWidth;
		options.toY2 = options.toY + imageHeight;
	    }
	    if (imageWidth > options.toX2 - options.toX) {
		imageWidth = options.toX2 - options.toX;
	    }
	    if (imageHeight > options.toY2 - options.toY) {
		imageHeight = options.toY2 - options.toY;
	    }
	    format = options.format;
	    data = objv[2];
	    if (oldformat) {
		if (format) {
		    format = (Tcl_Obj *) Tcl_GetString(format);
		}
		data = (Tcl_Obj *) Tcl_GetString(data);
	    }
	    if ((*imageFormat->stringReadProc)(interp, data,
		    format, (Tk_PhotoHandle) masterPtr,
		    options.toX, options.toY, imageWidth, imageHeight,
		    0, 0) != TCL_OK) {
		return TCL_ERROR;
	    }
	    masterPtr->flags |= IMAGE_CHANGED;
	    return TCL_OK;
	}
	if (options.options & OPT_FORMAT) {
	    return TCL_ERROR;
	}
	Tcl_ResetResult(interp);
	if (Tcl_SplitList(interp, Tcl_GetString(options.name),
		&dataHeight, &srcArgv) != TCL_OK) {
	    return TCL_ERROR;
	}
	tkwin = Tk_MainWindow(interp);
	block.pixelPtr = NULL;
	dataWidth = 0;
	pixelPtr = NULL;
	for (y = 0; y < dataHeight; ++y) {
	    if (Tcl_SplitList(interp, srcArgv[y], &listArgc, &listArgv)
		    != TCL_OK) {
		break;
	    }
	    if (y == 0) {
		if (listArgc == 0) {
		    /*
		     * Lines must be non-empty...
		     */
		    break;
		}
		dataWidth = listArgc;
		pixelPtr = (unsigned char *)
			ckalloc((unsigned) dataWidth * dataHeight * 3);
		block.pixelPtr = pixelPtr;
	    } else if (listArgc != dataWidth) {
		Tcl_AppendResult(interp, "all elements of color list must",
			" have the same number of elements", (char *) NULL);
		ckfree((char *) listArgv);
		break;
	    }
	    for (x = 0; x < dataWidth; ++x) {
		if (!XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
			listArgv[x], &color)) {
		    Tcl_AppendResult(interp, "can't parse color \"",
			    listArgv[x], "\"", (char *) NULL);
		    break;
		}
		*pixelPtr++ = color.red >> 8;
		*pixelPtr++ = color.green >> 8;
		*pixelPtr++ = color.blue >> 8;
	    }
	    ckfree((char *) listArgv);
	    if (x < dataWidth) {
		break;
	    }
	}
	ckfree((char *) srcArgv);
	if (y < dataHeight || dataHeight == 0 || dataWidth == 0) {
	    if (block.pixelPtr != NULL) {
		ckfree((char *) block.pixelPtr);
	    }
	    if (y < dataHeight) {
		return TCL_ERROR;
	    }
	    return TCL_OK;
	}

	/*
	 * Fill in default values for the -to option, then
	 * copy the block in using Tk_PhotoPutBlock.
	 */

	if (!(options.options & OPT_TO) || (options.toX2 < 0)) {
	    options.toX2 = options.toX + dataWidth;
	    options.toY2 = options.toY + dataHeight;
	}
	block.width = dataWidth;
	block.height = dataHeight;
	block.pitch = dataWidth * 3;
	block.pixelSize = 3;
	block.offset[0] = 0;
	block.offset[1] = 1;
	block.offset[2] = 2;
	block.offset[3] = 0;
	Tk_PhotoPutBlock((ClientData)masterPtr, &block,
		options.toX, options.toY, options.toX2 - options.toX,
		options.toY2 - options.toY, TK_PHOTO_COMPOSITE_SET);
	ckfree((char *) block.pixelPtr);
	return TCL_OK;

    case PHOTO_READ: {
	Tcl_Obj *format;

	/*
	 * photo read command - first parse the options specified.
	 */

	index = 2;
	memset((VOID *) &options, 0, sizeof(options));
	options.name = NULL;
	options.format = NULL;
	if (ParseSubcommandOptions(&options, interp,
		OPT_FORMAT | OPT_FROM | OPT_TO | OPT_SHRINK,
		&index, objc, objv) != TCL_OK) {
	    return TCL_ERROR;
	}
	if ((options.name == NULL) || (index < objc)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?");
	    return TCL_ERROR;
	}

        /*
         * Prevent file system access in safe interpreters.
         */

        if (Tcl_IsSafe(interp)) {
            Tcl_AppendResult(interp, "can't get image from a file in a",
		    " safe interpreter", (char *) NULL);
            return TCL_ERROR;
        }
        
	/*
	 * Open the image file and look for a handler for it.
	 */

	chan = Tcl_OpenFileChannel(interp,
		Tcl_GetString(options.name), "r", 0);
	if (chan == NULL) {
	    return TCL_ERROR;
	}
        if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
		!= TCL_OK) {
	    Tcl_Close(NULL, chan);
            return TCL_ERROR;
        }
        if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
		!= TCL_OK) {
	    Tcl_Close(NULL, chan);
            return TCL_ERROR;
        }
    
	if (MatchFileFormat(interp, chan,
		Tcl_GetString(options.name), options.format, &imageFormat,
		&imageWidth, &imageHeight, &oldformat) != TCL_OK) {
	    Tcl_Close(NULL, chan);
	    return TCL_ERROR;
	}

	/*
	 * Check the values given for the -from option.
	 */

	if ((options.fromX > imageWidth) || (options.fromY > imageHeight)
		|| (options.fromX2 > imageWidth)
		|| (options.fromY2 > imageHeight)) {
	    Tcl_AppendResult(interp, "coordinates for -from option extend ",
		    "outside source image", (char *) NULL);
	    Tcl_Close(NULL, chan);
	    return TCL_ERROR;
	}
	if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
	    width = imageWidth - options.fromX;
	    height = imageHeight - options.fromY;
	} else {
	    width = options.fromX2 - options.fromX;
	    height = options.fromY2 - options.fromY;
	}

	/*
	 * If the -shrink option was specified, set the size of the image.
	 */

	if (options.options & OPT_SHRINK) {
	    if (ImgPhotoSetSize(masterPtr, options.toX + width,
		    options.toY + height) != TCL_OK) {
		Tcl_ResetResult(interp);
		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
		return TCL_ERROR;
	    }
	}

	/*
	 * Call the handler's file read procedure to read the data
	 * into the image.
	 */

	format = options.format;
	if (oldformat && format) {
	    format = (Tcl_Obj *) Tcl_GetString(format);
	}
	result = (*imageFormat->fileReadProc)(interp, chan,
		Tcl_GetString(options.name),
		format, (Tk_PhotoHandle) masterPtr, options.toX,
		options.toY, width, height, options.fromX, options.fromY);
	if (chan != NULL) {
	    Tcl_Close(NULL, chan);
	}
	return result;
    }

    case PHOTO_REDITHER:
	if (objc != 2) {
	    Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
	    return TCL_ERROR;
	}

	/*
	 * Call Dither if any part of the image is not correctly
	 * dithered at present.
	 */

	x = masterPtr->ditherX;
	y = masterPtr->ditherY;
	if (masterPtr->ditherX != 0) {
	    Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y,
		    masterPtr->width - x, 1);
	}
	if (masterPtr->ditherY < masterPtr->height) {
	    x = 0;
	    Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, 0,
		    masterPtr->ditherY, masterPtr->width,
		    masterPtr->height - masterPtr->ditherY);
	}

	if (y < masterPtr->height) {
	    /*
	     * Tell the core image code that part of the image has changed.
	     */

	    Tk_ImageChanged(masterPtr->tkMaster, x, y,
		    (masterPtr->width - x), (masterPtr->height - y),
		    masterPtr->width, masterPtr->height);
	}
	return TCL_OK;

    case PHOTO_TRANS: {
	static CONST char *photoTransOptions[] = {
	    "get", "set", (char *) NULL
	};
	enum transOptions {
	    PHOTO_TRANS_GET, PHOTO_TRANS_SET
	};

	if (objc < 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?");
	    return TCL_ERROR;
	}
	if (Tcl_GetIndexFromObj(interp, objv[2], photoTransOptions, "option",
		0, &index) != TCL_OK) {
	    return TCL_ERROR;
	}

	switch ((enum transOptions) index) {
	case PHOTO_TRANS_GET: {
	    XRectangle testBox;
	    TkRegion testRegion;

	    if (objc != 5) {
		Tcl_WrongNumArgs(interp, 3, objv, "x y");
		return TCL_ERROR;
	    }
	    if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
		    || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)) {
		return TCL_ERROR;
	    }
	    if ((x < 0) || (x >= masterPtr->width)
		|| (y < 0) || (y >= masterPtr->height)) {
		Tcl_AppendResult(interp, Tcl_GetString(objv[0]),
			" transparency get: coordinates out of range",
			(char *) NULL);
		return TCL_ERROR;
	    }

	    testBox.x = x;
	    testBox.y = y;
	    testBox.width = 1;
	    testBox.height = 1;
	    /* What a way to do a test! */
	    testRegion = TkCreateRegion();
	    TkUnionRectWithRegion(&testBox, testRegion, testRegion);
	    TkIntersectRegion(testRegion, masterPtr->validRegion, testRegion);
	    TkClipBox(testRegion, &testBox);
	    TkDestroyRegion(testRegion);

	    Tcl_SetBooleanObj(Tcl_GetObjResult(interp),
		    (testBox.width==0 && testBox.height==0));
	    return TCL_OK;
	}

	case PHOTO_TRANS_SET: {
	    int transFlag;
	    XRectangle setBox;

	    if (objc != 6) {
		Tcl_WrongNumArgs(interp, 3, objv, "x y boolean");
		return TCL_ERROR;
	    }
	    if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
		    || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)
		    || (Tcl_GetBooleanFromObj(interp, objv[5],
		    &transFlag) != TCL_OK)) {
		return TCL_ERROR;
	    }
	    if ((x < 0) || (x >= masterPtr->width)
		|| (y < 0) || (y >= masterPtr->height)) {
		Tcl_AppendResult(interp, Tcl_GetString(objv[0]),
			" transparency set: coordinates out of range",
			(char *) NULL);
		return TCL_ERROR;
	    }

	    setBox.x = x;
	    setBox.y = y;
	    setBox.width = 1;
	    setBox.height = 1;
	    pixelPtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;

	    if (transFlag) {
		/*
		 * Make pixel transparent.
		 */
		TkRegion clearRegion = TkCreateRegion();

		TkUnionRectWithRegion(&setBox, clearRegion, clearRegion);
		TkSubtractRegion(masterPtr->validRegion, clearRegion,
			masterPtr->validRegion);
		TkDestroyRegion(clearRegion);
		/*
		 * Set the alpha value correctly.
		 */
		pixelPtr[3] = 0;
	    } else {
		/*
		 * Make pixel opaque.
		 */
		TkUnionRectWithRegion(&setBox, masterPtr->validRegion,
			masterPtr->validRegion);
		pixelPtr[3] = 255;
	    }

	    /*
	     * Inform the generic image code that the image
	     * has (potentially) changed.
	     */

	    Tk_ImageChanged(masterPtr->tkMaster, x, y, 1, 1,
		    masterPtr->width, masterPtr->height);
	    masterPtr->flags &= ~IMAGE_CHANGED;
	    return TCL_OK;
	}
	}

	panic("unexpected fallthrough");
    }

    case PHOTO_WRITE: {
	char *data;
	Tcl_Obj *format;

        /*
         * Prevent file system access in safe interpreters.
         */

        if (Tcl_IsSafe(interp)) {
            Tcl_AppendResult(interp, "can't write image to a file in a",
		    " safe interpreter", (char *) NULL);
            return TCL_ERROR;
        }
        
	/*
	 * photo write command - first parse and check any options given.
	 */

	index = 2;
	memset((VOID *) &options, 0, sizeof(options));
	options.name = NULL;
	options.format = NULL;
	if (ParseSubcommandOptions(&options, interp,
		OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
		&index, objc, objv) != TCL_OK) {
	    return TCL_ERROR;
	}
	if ((options.name == NULL) || (index < objc)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?");
	    return TCL_ERROR;
	}
	if ((options.fromX > masterPtr->width)
		|| (options.fromY > masterPtr->height)
		|| (options.fromX2 > masterPtr->width)
		|| (options.fromY2 > masterPtr->height)) {
	    Tcl_AppendResult(interp, "coordinates for -from option extend ",
		    "outside image", (char *) NULL);
	    return TCL_ERROR;
	}

	/*
	 * Fill in default values for unspecified parameters.
	 */

	if (!(options.options & OPT_FROM) || (options.fromX2 < 0)) {
	    options.fromX2 = masterPtr->width;
	    options.fromY2 = masterPtr->height;
	}

	/*
	 * Search for an appropriate image file format handler,
	 * and give an error if none is found.
	 */

	matched = 0;
	for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
		imageFormat = imageFormat->nextPtr) {
	    if ((options.format == NULL)
		    || (strncasecmp(Tcl_GetString(options.format),
		    imageFormat->name, strlen(imageFormat->name)) == 0)) {
		matched = 1;
		if (imageFormat->fileWriteProc != NULL) {
		    break;
		}
	    }
	}
	if (imageFormat == NULL) {
	    oldformat = 1;
	    for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
		    imageFormat = imageFormat->nextPtr) {
		if ((options.format == NULL)
			|| (strncasecmp(Tcl_GetString(options.format),
			imageFormat->name, strlen(imageFormat->name)) == 0)) {
		    matched = 1;
		    if (imageFormat->fileWriteProc != NULL) {
			break;
		    }
		}
	    }
	}
	if (imageFormat == NULL) {
	    if (options.format == NULL) {
		Tcl_AppendResult(interp, "no available image file format ",
			"has file writing capability", (char *) NULL);
	    } else if (!matched) {
		Tcl_AppendResult(interp, "image file format \"",
			Tcl_GetString(options.format),
			"\" is unknown", (char *) NULL);
	    } else {
		Tcl_AppendResult(interp, "image file format \"",
			Tcl_GetString(options.format),
			"\" has no file writing capability",
			(char *) NULL);
	    }
	    return TCL_ERROR;
	}

	/*
	 * Call the handler's file write procedure to write out
	 * the image.
	 */

	data = ImgGetPhoto(masterPtr, &block, &options);
	format = options.format;
	if (oldformat && format) {
	    format = (Tcl_Obj *) Tcl_GetString(options.format);
	}
	result = (*imageFormat->fileWriteProc)(interp,
		Tcl_GetString(options.name), format, &block);
	if (options.background) {
	    Tk_FreeColor(options.background);
	}
	if (data) {
	    ckfree(data);
	}
	return result;
    }

    }
    panic("unexpected fallthrough");
    return TCL_ERROR; /* NOT REACHED */
}

/*
 *----------------------------------------------------------------------
 *
 * ParseSubcommandOptions --
 *
 *	This procedure is invoked to process one of the options
 *	which may be specified for the photo image subcommands,
 *	namely, -from, -to, -zoom, -subsample, -format, -shrink,
 *	and -compositingrule.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	Fields in *optPtr get filled in.
 *
 *----------------------------------------------------------------------
 */

static int
ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, objc, objv)
    struct SubcommandOptions *optPtr;
				/* Information about the options specified
				 * and the values given is returned here. */
    Tcl_Interp *interp;		/* Interpreter to use for reporting errors. */
    int allowedOptions;		/* Indicates which options are valid for
				 * the current command. */
    int *optIndexPtr;		/* Points to a variable containing the
				 * current index in objv; this variable is
				 * updated by this procedure. */
    int objc;			/* Number of arguments in objv[]. */
    Tcl_Obj *CONST objv[];	/* Arguments to be parsed. */
{
    int index, c, bit, currentBit;
    int length;
    char *option, **listPtr;
    int values[4];
    int numValues, maxValues, argIndex;

    for (index = *optIndexPtr; index < objc; *optIndexPtr = ++index) {
	/*
	 * We can have one value specified without an option;
	 * it goes into optPtr->name.
	 */

	option = Tcl_GetStringFromObj(objv[index], &length);
	if (option[0] != '-') {
	    if (optPtr->name == NULL) {
		optPtr->name = objv[index];
		continue;
	    }
	    break;
	}

	/*
	 * Work out which option this is.
	 */

	c = option[0];
	bit = 0;
	currentBit = 1;
	for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
	    if ((c == *listPtr[0])
		    && (strncmp(option, *listPtr, (size_t) length) == 0)) {
		if (bit != 0) {
		    bit = 0;	/* An ambiguous option. */
		    break;
		}
		bit = currentBit;
	    }
	    currentBit <<= 1;
	}

	/*
	 * If this option is not recognized and allowed, put
	 * an error message in the interpreter and return.
	 */

	if ((allowedOptions & bit) == 0) {
	    Tcl_AppendResult(interp, "unrecognized option \"",
	    	    Tcl_GetString(objv[index]),
		    "\": must be ", (char *)NULL);
	    bit = 1;
	    for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
		if ((allowedOptions & bit) != 0) {
		    if ((allowedOptions & (bit - 1)) != 0) {
			Tcl_AppendResult(interp, ", ", (char *) NULL);
			if ((allowedOptions & ~((bit << 1) - 1)) == 0) {
			    Tcl_AppendResult(interp, "or ", (char *) NULL);
			}
		    }
		    Tcl_AppendResult(interp, *listPtr, (char *) NULL);
		}
		bit <<= 1;
	    }
	    return TCL_ERROR;
	}

	/*
	 * For the -from, -to, -zoom and -subsample options,
	 * parse the values given.  Report an error if too few
	 * or too many values are given.
	 */

	if (bit == OPT_BACKGROUND) {
	    /*
	     * The -background option takes a single XColor value.
	     */

	    if (index + 1 < objc) {
		*optIndexPtr = ++index;
		optPtr->background = Tk_GetColor(interp, Tk_MainWindow(interp),
			Tk_GetUid(Tcl_GetString(objv[index])));
		if (!optPtr->background) {
		    return TCL_ERROR;
		}
	    } else {
		Tcl_AppendResult(interp, "the \"-background\" option ",
			"requires a value", (char *) NULL);
		return TCL_ERROR;
	    }
	} else if (bit == OPT_FORMAT) {
	    /*
	     * The -format option takes a single string value.  Note
	     * that parsing this is outside the scope of this
	     * function.
	     */

	    if (index + 1 < objc) {
		*optIndexPtr = ++index;
		optPtr->format = objv[index];
	    } else {
		Tcl_AppendResult(interp, "the \"-format\" option ",
			"requires a value", (char *) NULL);
		return TCL_ERROR;
	    }
	} else if (bit == OPT_COMPOSITE) {
	    /*
	     * The -compositingrule option takes a single value from
	     * a well-known set.
	     */

	    if (index + 1 < objc) {
		/*
		 * Note that these must match the TK_PHOTO_COMPOSITE_*
		 * constants.
		 */
		static CONST char *compositingRules[] = {
		    "overlay", "set",
		    NULL
		};

		index++;
		if (Tcl_GetIndexFromObj(interp, objv[index], compositingRules,
			"compositing rule", 0, &optPtr->compositingRule)
			!= TCL_OK) {
		    return TCL_ERROR;
		}
		*optIndexPtr = index;
	    } else {
		Tcl_AppendResult(interp, "the \"-compositingrule\" option ",
			"requires a value", (char *) NULL);
		return TCL_ERROR;
	    }
	} else if ((bit != OPT_SHRINK) && (bit != OPT_GRAYSCALE)) {
	    char *val;
	    maxValues = ((bit == OPT_FROM) || (bit == OPT_TO))? 4: 2;
	    argIndex = index + 1;
	    for (numValues = 0; numValues < maxValues; ++numValues) {
		if (argIndex >= objc) {
		    break;
		}
	        val = Tcl_GetString(objv[argIndex]);
		if ((argIndex < objc) && (isdigit(UCHAR(val[0]))
			|| ((val[0] == '-') && isdigit(UCHAR(val[1]))))) {
		    if (Tcl_GetInt(interp, val, &values[numValues])
			    != TCL_OK) {
			return TCL_ERROR;
		    }
		} else {
		    break;
		}
		++argIndex;
	    }

	    if (numValues == 0) {
		Tcl_AppendResult(interp, "the \"", option, "\" option ",
			 "requires one ", maxValues == 2? "or two": "to four",
			 " integer values", (char *) NULL);
		return TCL_ERROR;
	    }
	    *optIndexPtr = (index += numValues);

	    /*
	     * Y values default to the corresponding X value if not specified.
	     */

	    if (numValues == 1) {
		values[1] = values[0];
	    }
	    if (numValues == 3) {
		values[3] = values[2];
	    }

	    /*
	     * Check the values given and put them in the appropriate
	     * field of the SubcommandOptions structure.
	     */

	    switch (bit) {
		case OPT_FROM:
		    if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
			    && ((values[2] < 0) || (values[3] < 0)))) {
			Tcl_AppendResult(interp, "value(s) for the -from",
				" option must be non-negative", (char *) NULL);
			return TCL_ERROR;
		    }
		    if (numValues <= 2) {
			optPtr->fromX = values[0];
			optPtr->fromY = values[1];
			optPtr->fromX2 = -1;
			optPtr->fromY2 = -1;
		    } else {
			optPtr->fromX = MIN(values[0], values[2]);
			optPtr->fromY = MIN(values[1], values[3]);
			optPtr->fromX2 = MAX(values[0], values[2]);
			optPtr->fromY2 = MAX(values[1], values[3]);
		    }
		    break;
		case OPT_SUBSAMPLE:
		    optPtr->subsampleX = values[0];
		    optPtr->subsampleY = values[1];
		    break;
		case OPT_TO:
		    if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
			    && ((values[2] < 0) || (values[3] < 0)))) {
			Tcl_AppendResult(interp, "value(s) for the -to",
				" option must be non-negative", (char *) NULL);
			return TCL_ERROR;
		    }
		    if (numValues <= 2) {
			optPtr->toX = values[0];
			optPtr->toY = values[1];
			optPtr->toX2 = -1;
			optPtr->toY2 = -1;
		    } else {
			optPtr->toX = MIN(values[0], values[2]);
			optPtr->toY = MIN(values[1], values[3]);
			optPtr->toX2 = MAX(values[0], values[2]);
			optPtr->toY2 = MAX(values[1], values[3]);
		    }
		    break;
		case OPT_ZOOM:
		    if ((values[0] <= 0) || (values[1] <= 0)) {
			Tcl_AppendResult(interp, "value(s) for the -zoom",
				" option must be positive", (char *) NULL);
			return TCL_ERROR;
		    }
		    optPtr->zoomX = values[0];
		    optPtr->zoomY = values[1];
		    break;
	    }
	}

	/*
	 * Remember that we saw this option.
	 */

	optPtr->options |= bit;
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoConfigureMaster --
 *
 *	This procedure is called when a photo image is created or
 *	reconfigured.  It processes configuration options and resets
 *	any instances of the image.
 *
 * Results:
 *	A standard Tcl return value.  If TCL_ERROR is returned then
 *	an error message is left in the masterPtr->interp's result.
 *
 * Side effects:
 *	Existing instances of the image will be redisplayed to match
 *	the new configuration options.
 *
 *----------------------------------------------------------------------
 */

static int
ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
    Tcl_Interp *interp;		/* Interpreter to use for reporting errors. */
    PhotoMaster *masterPtr;	/* Pointer to data structure describing
				 * overall photo image to (re)configure. */
    int objc;			/* Number of entries in objv. */
    Tcl_Obj *CONST objv[];	/* Pairs of configuration options for image. */
    int flags;			/* Flags to pass to Tk_ConfigureWidget,
				 * such as TK_CONFIG_ARGV_ONLY. */
{
    PhotoInstance *instancePtr;
    CONST char *oldFileString, *oldPaletteString;
    Tcl_Obj *oldData, *data = NULL, *oldFormat, *format = NULL;
    int length, i, j;
    double oldGamma;
    int result;
    Tcl_Channel chan;
    Tk_PhotoImageFormat *imageFormat;
    int imageWidth, imageHeight;
    CONST char **args;
    int oldformat;
    Tcl_Obj *tempdata, *tempformat;

    args = (CONST char **) ckalloc((objc + 1) * sizeof(char *));
    for (i = 0, j = 0; i < objc; i++,j++) {
	args[j] = Tcl_GetStringFromObj(objv[i], &length);
	if ((length > 1) && (args[j][0] == '-')) {
	    if ((args[j][1] == 'd') &&
		    !strncmp(args[j], "-data", (size_t) length)) {
		if (++i < objc) {
		    data = objv[i];
		    j--;
		} else {
		    Tcl_AppendResult(interp,
			    "value for \"-data\" missing", (char *) NULL);
		    return TCL_ERROR;
		}
	    } else if ((args[j][1] == 'f') &&
		    !strncmp(args[j], "-format", (size_t) length)) {
		if (++i < objc) {
		    format = objv[i];
		    j--;
		} else {
		    Tcl_AppendResult(interp,
			    "value for \"-format\" missing", (char *) NULL);
		    return TCL_ERROR;
		}
	    }
	}
    }

    /*
     * Save the current values for fileString and dataString, so we
     * can tell if the user specifies them anew.
     * IMPORTANT: if the format changes we have to interpret
     * "-file" and "-data" again as well!!!!!!! It might be
     * that the format string influences how "-data" or "-file"
     * is interpreted.
     */

    oldFileString = masterPtr->fileString;
    if (oldFileString == NULL) {
	oldData = masterPtr->dataString;
	if (oldData != NULL) {
	    Tcl_IncrRefCount(oldData);
	}
    } else {
	oldData = NULL;
    }
    oldFormat = masterPtr->format;
    if (oldFormat != NULL) {
	Tcl_IncrRefCount(oldFormat);
    }
    oldPaletteString = masterPtr->palette;
    oldGamma = masterPtr->gamma;

    /*
     * Process the configuration options specified.
     */

    if (Tk_ConfigureWidget(interp, Tk_MainWindow(interp), configSpecs,
	    j, args, (char *) masterPtr, flags) != TCL_OK) {
	ckfree((char *) args);
	goto errorExit;
    }
    ckfree((char *) args);

    /*
     * Regard the empty string for -file, -data or -format as the null
     * value.
     */

    if ((masterPtr->fileString != NULL) && (masterPtr->fileString[0] == 0)) {
	ckfree(masterPtr->fileString);
	masterPtr->fileString = NULL;
    }
    if (data) {
	/*
	 * Force into ByteArray format, which most (all) image handlers
	 * will use anyway.  Empty length means ignore the -data option.
	 */
	(void) Tcl_GetByteArrayFromObj(data, &length);
	if (length) {
	    Tcl_IncrRefCount(data);
	} else {
	    data = NULL;
	}
	if (masterPtr->dataString) {
	    Tcl_DecrRefCount(masterPtr->dataString);
	}
	masterPtr->dataString = data;
    }
    if (format) {
	/*
	 * Stringify to ignore -format "".  It may come in as a list or
	 * other object.
	 */
	(void) Tcl_GetStringFromObj(format, &length);
	if (length) {
	    Tcl_IncrRefCount(format);
	} else {
	    format = NULL;
	}
	if (masterPtr->format) {
	    Tcl_DecrRefCount(masterPtr->format);
	}
	masterPtr->format = format;
    }
    /*
     * Set the image to the user-requested size, if any,
     * and make sure storage is correctly allocated for this image.
     */

    if (ImgPhotoSetSize(masterPtr, masterPtr->width,
	    masterPtr->height) != TCL_OK) {
	Tcl_ResetResult(interp);
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
	goto errorExit;
    }

    /*
     * Read in the image from the file or string if the user has
     * specified the -file or -data option.
     */

    if ((masterPtr->fileString != NULL)
	    && ((masterPtr->fileString != oldFileString)
	    || (masterPtr->format != oldFormat))) {

        /*
         * Prevent file system access in a safe interpreter.
         */

        if (Tcl_IsSafe(interp)) {
	    Tcl_ResetResult(interp);
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		    "can't get image from a file in a safe interpreter",
		    (char *) NULL);
	    goto errorExit;
        }
        
	chan = Tcl_OpenFileChannel(interp, masterPtr->fileString, "r", 0);
	if (chan == NULL) {
	    goto errorExit;
	}
	/*
	 * -translation binary also sets -encoding binary
	 */
        if ((Tcl_SetChannelOption(interp, chan,
		"-translation", "binary") != TCL_OK) ||
		(MatchFileFormat(interp, chan, masterPtr->fileString,
			masterPtr->format, &imageFormat, &imageWidth,
			&imageHeight, &oldformat) != TCL_OK)) {
	    Tcl_Close(NULL, chan);
	    goto errorExit;
	}
	result = ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
	if (result != TCL_OK) {
	    Tcl_Close(NULL, chan);
	    Tcl_ResetResult(interp);
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		    TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
	    goto errorExit;
	}
	tempformat = masterPtr->format;
	if (oldformat && tempformat) {
	    tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
	}
	result = (*imageFormat->fileReadProc)(interp, chan,
		masterPtr->fileString, tempformat,
		(Tk_PhotoHandle) masterPtr, 0, 0,
		imageWidth, imageHeight, 0, 0);
	Tcl_Close(NULL, chan);
	if (result != TCL_OK) {
	    goto errorExit;
	}

	Tcl_ResetResult(interp);
	masterPtr->flags |= IMAGE_CHANGED;
    }

    if ((masterPtr->fileString == NULL) && (masterPtr->dataString != NULL)
	    && ((masterPtr->dataString != oldData)
		    || (masterPtr->format != oldFormat))) {

	if (MatchStringFormat(interp, masterPtr->dataString,
		masterPtr->format, &imageFormat, &imageWidth,
		&imageHeight, &oldformat) != TCL_OK) {
	    goto errorExit;
	}
	if (ImgPhotoSetSize(masterPtr, imageWidth, imageHeight) != TCL_OK) {
	    Tcl_ResetResult(interp);
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		    TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
	    goto errorExit;
	}
	tempformat = masterPtr->format;
	tempdata = masterPtr->dataString;
	if (oldformat) {
	    if (tempformat) {
		tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
	    }
	    tempdata = (Tcl_Obj *) Tcl_GetString(tempdata);
	}
	if ((*imageFormat->stringReadProc)(interp, tempdata,
		tempformat, (Tk_PhotoHandle) masterPtr,
		0, 0, imageWidth, imageHeight, 0, 0) != TCL_OK) {
	    goto errorExit;
	}

	Tcl_ResetResult(interp);
	masterPtr->flags |= IMAGE_CHANGED;
    }

    /*
     * Enforce a reasonable value for gamma.
     */

    if (masterPtr->gamma <= 0) {
	masterPtr->gamma = 1.0;
    }

    if ((masterPtr->gamma != oldGamma)
	    || (masterPtr->palette != oldPaletteString)) {
	masterPtr->flags |= IMAGE_CHANGED;
    }

    /*
     * Cycle through all of the instances of this image, regenerating
     * the information for each instance.  Then force the image to be
     * redisplayed everywhere that it is used.
     */

    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
	    instancePtr = instancePtr->nextPtr) {
	ImgPhotoConfigureInstance(instancePtr);
    }

    /*
     * Inform the generic image code that the image
     * has (potentially) changed.
     */

    Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
	    masterPtr->height, masterPtr->width, masterPtr->height);
    masterPtr->flags &= ~IMAGE_CHANGED;

    if (oldData != NULL) {
	Tcl_DecrRefCount(oldData);
    }
    if (oldFormat != NULL) {
	Tcl_DecrRefCount(oldFormat);
    }

    ToggleComplexAlphaIfNeeded(masterPtr);

    return TCL_OK;

  errorExit:
    if (oldData != NULL) {
	Tcl_DecrRefCount(oldData);
    }
    if (oldFormat != NULL) {
	Tcl_DecrRefCount(oldFormat);
    }
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoConfigureInstance --
 *
 *	This procedure is called to create displaying information for
 *	a photo image instance based on the configuration information
 *	in the master.  It is invoked both when new instances are
 *	created and when the master is reconfigured.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Generates errors via Tcl_BackgroundError if there are problems
 *	in setting up the instance.
 *
 *----------------------------------------------------------------------
 */

static void
ImgPhotoConfigureInstance(instancePtr)
    PhotoInstance *instancePtr;	/* Instance to reconfigure. */
{
    PhotoMaster *masterPtr = instancePtr->masterPtr;
    XImage *imagePtr;
    int bitsPerPixel;
    ColorTable *colorTablePtr;
    XRectangle validBox;

    /*
     * If the -palette configuration option has been set for the master,
     * use the value specified for our palette, but only if it is
     * a valid palette for our windows.  Use the gamma value specified
     * the master.
     */

    if ((masterPtr->palette && masterPtr->palette[0])
	    && IsValidPalette(instancePtr, masterPtr->palette)) {
	instancePtr->palette = masterPtr->palette;
    } else {
	instancePtr->palette = instancePtr->defaultPalette;
    }
    instancePtr->gamma = masterPtr->gamma;

    /*
     * If we don't currently have a color table, or if the one we
     * have no longer applies (e.g. because our palette or gamma
     * has changed), get a new one.
     */

    colorTablePtr = instancePtr->colorTablePtr;
    if ((colorTablePtr == NULL)
	    || (instancePtr->colormap != colorTablePtr->id.colormap)
	    || (instancePtr->palette != colorTablePtr->id.palette)
	    || (instancePtr->gamma != colorTablePtr->id.gamma)) {
	/*
	 * Free up our old color table, and get a new one.
	 */

	if (colorTablePtr != NULL) {
	    colorTablePtr->liveRefCount -= 1;
	    FreeColorTable(colorTablePtr, 0);
	}
	GetColorTable(instancePtr);

	/*
	 * Create a new XImage structure for sending data to
	 * the X server, if necessary.
	 */

	if (instancePtr->colorTablePtr->flags & BLACK_AND_WHITE) {
	    bitsPerPixel = 1;
	} else {
	    bitsPerPixel = instancePtr->visualInfo.depth;
	}

	if ((instancePtr->imagePtr == NULL)
		|| (instancePtr->imagePtr->bits_per_pixel != bitsPerPixel)) {
	    if (instancePtr->imagePtr != NULL) {
		XFree((char *) instancePtr->imagePtr);
	    }
	    imagePtr = XCreateImage(instancePtr->display,
		    instancePtr->visualInfo.visual, (unsigned) bitsPerPixel,
		    (bitsPerPixel > 1? ZPixmap: XYBitmap), 0, (char *) NULL,
		    1, 1, 32, 0);
	    instancePtr->imagePtr = imagePtr;

	    /*
	     * Determine the endianness of this machine.
	     * We create images using the local host's endianness, rather
	     * than the endianness of the server; otherwise we would have
	     * to byte-swap any 16 or 32 bit values that we store in the
	     * image in those situations where the server's endianness
	     * is different from ours.
	     *
	     * FIXME: use autoconf to figure this out.
	     */

	    if (imagePtr != NULL) {
		union {
		    int i;
		    char c[sizeof(int)];
		} kludge;

		imagePtr->bitmap_unit = sizeof(pixel) * NBBY;
		kludge.i = 0;
		kludge.c[0] = 1;
		imagePtr->byte_order = (kludge.i == 1) ? LSBFirst : MSBFirst;
		_XInitImageFuncPtrs(imagePtr);
	    }
	}
    }

    /*
     * If the user has specified a width and/or height for the master
     * which is different from our current width/height, set the size
     * to the values specified by the user.  If we have no pixmap, we
     * do this also, since it has the side effect of allocating a
     * pixmap for us.
     */

    if ((instancePtr->pixels == None) || (instancePtr->error == NULL)
	    || (instancePtr->width != masterPtr->width)
	    || (instancePtr->height != masterPtr->height)) {
	ImgPhotoInstanceSetSize(instancePtr);
    }

    /*
     * Redither this instance if necessary.
     */

    if ((masterPtr->flags & IMAGE_CHANGED)
	    || (instancePtr->colorTablePtr != colorTablePtr)) {
	TkClipBox(masterPtr->validRegion, &validBox);
	if ((validBox.width > 0) && (validBox.height > 0)) {
	    DitherInstance(instancePtr, validBox.x, validBox.y,
		    validBox.width, validBox.height);
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoGet --
 *
 *	This procedure is called for each use of a photo image in a
 *	widget.
 *
 * Results:
 *	The return value is a token for the instance, which is passed
 *	back to us in calls to ImgPhotoDisplay and ImgPhotoFree.
 *
 * Side effects:
 *	A data structure is set up for the instance (or, an existing
 *	instance is re-used for the new one).
 *
 *----------------------------------------------------------------------
 */

static ClientData
ImgPhotoGet(tkwin, masterData)
    Tk_Window tkwin;		/* Window in which the instance will be
				 * used. */
    ClientData masterData;	/* Pointer to our master structure for the
				 * image. */
{
    PhotoMaster *masterPtr = (PhotoMaster *) masterData;
    PhotoInstance *instancePtr;
    Colormap colormap;
    int mono, nRed, nGreen, nBlue;
    XVisualInfo visualInfo, *visInfoPtr;
    char buf[TCL_INTEGER_SPACE * 3];
    int numVisuals;
    XColor *white, *black;
    XGCValues gcValues;

    /*
     * Table of "best" choices for palette for PseudoColor displays
     * with between 3 and 15 bits/pixel.
     */

    static int paletteChoice[13][3] = {
	/*  #red, #green, #blue */
	 {2,  2,  2,			/* 3 bits, 8 colors */},
	 {2,  3,  2,			/* 4 bits, 12 colors */},
	 {3,  4,  2,			/* 5 bits, 24 colors */},
	 {4,  5,  3,			/* 6 bits, 60 colors */},
	 {5,  6,  4,			/* 7 bits, 120 colors */},
	 {7,  7,  4,			/* 8 bits, 198 colors */},
	 {8, 10,  6,			/* 9 bits, 480 colors */},
	{10, 12,  8,			/* 10 bits, 960 colors */},
	{14, 15,  9,			/* 11 bits, 1890 colors */},
	{16, 20, 12,			/* 12 bits, 3840 colors */},
	{20, 24, 16,			/* 13 bits, 7680 colors */},
	{26, 30, 20,			/* 14 bits, 15600 colors */},
	{32, 32, 30,			/* 15 bits, 30720 colors */}
    };

    /*
     * See if there is already an instance for windows using
     * the same colormap.  If so then just re-use it.
     */

    colormap = Tk_Colormap(tkwin);
    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
	    instancePtr = instancePtr->nextPtr) {
	if ((colormap == instancePtr->colormap)
		&& (Tk_Display(tkwin) == instancePtr->display)) {

	    /*
	     * Re-use this instance.
	     */

	    if (instancePtr->refCount == 0) {
		/*
		 * We are resurrecting this instance.
		 */

		Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
		if (instancePtr->colorTablePtr != NULL) {
		    FreeColorTable(instancePtr->colorTablePtr, 0);
		}
		GetColorTable(instancePtr);
	    }
	    instancePtr->refCount++;
	    return (ClientData) instancePtr;
	}
    }

    /*
     * The image isn't already in use in a window with the same colormap.
     * Make a new instance of the image.
     */

    instancePtr = (PhotoInstance *) ckalloc(sizeof(PhotoInstance));
    instancePtr->masterPtr = masterPtr;
    instancePtr->display = Tk_Display(tkwin);
    instancePtr->colormap = Tk_Colormap(tkwin);
    Tk_PreserveColormap(instancePtr->display, instancePtr->colormap);
    instancePtr->refCount = 1;
    instancePtr->colorTablePtr = NULL;
    instancePtr->pixels = None;
    instancePtr->error = NULL;
    instancePtr->width = 0;
    instancePtr->height = 0;
    instancePtr->imagePtr = 0;
    instancePtr->nextPtr = masterPtr->instancePtr;
    masterPtr->instancePtr = instancePtr;

    /*
     * Obtain information about the visual and decide on the
     * default palette.
     */

    visualInfo.screen = Tk_ScreenNumber(tkwin);
    visualInfo.visualid = XVisualIDFromVisual(Tk_Visual(tkwin));
    visInfoPtr = XGetVisualInfo(Tk_Display(tkwin),
	    VisualScreenMask | VisualIDMask, &visualInfo, &numVisuals);
    nRed = 2;
    nGreen = nBlue = 0;
    mono = 1;
    if (visInfoPtr != NULL) {
	instancePtr->visualInfo = *visInfoPtr;
	switch (visInfoPtr->class) {
	    case DirectColor:
	    case TrueColor:
		nRed = 1 << CountBits(visInfoPtr->red_mask);
		nGreen = 1 << CountBits(visInfoPtr->green_mask);
		nBlue = 1 << CountBits(visInfoPtr->blue_mask);
		mono = 0;
		break;
	    case PseudoColor:
	    case StaticColor:
		if (visInfoPtr->depth > 15) {
		    nRed = 32;
		    nGreen = 32;
		    nBlue = 32;
		    mono = 0;
		} else if (visInfoPtr->depth >= 3) {
		    int *ip = paletteChoice[visInfoPtr->depth - 3];
    
		    nRed = ip[0];
		    nGreen = ip[1];
		    nBlue = ip[2];
		    mono = 0;
		}
		break;
	    case GrayScale:
	    case StaticGray:
		nRed = 1 << visInfoPtr->depth;
		break;
	}
	XFree((char *) visInfoPtr);

    } else {
	panic("ImgPhotoGet couldn't find visual for window");
    }

    sprintf(buf, ((mono) ? "%d": "%d/%d/%d"), nRed, nGreen, nBlue);
    instancePtr->defaultPalette = Tk_GetUid(buf);

    /*
     * Make a GC with background = black and foreground = white.
     */

    white = Tk_GetColor(masterPtr->interp, tkwin, "white");
    black = Tk_GetColor(masterPtr->interp, tkwin, "black");
    gcValues.foreground = (white != NULL)? white->pixel:
	    WhitePixelOfScreen(Tk_Screen(tkwin));
    gcValues.background = (black != NULL)? black->pixel:
	    BlackPixelOfScreen(Tk_Screen(tkwin));
    gcValues.graphics_exposures = False;
    instancePtr->gc = Tk_GetGC(tkwin,
	    GCForeground|GCBackground|GCGraphicsExposures, &gcValues);

    /*
     * Set configuration options and finish the initialization of the instance.
     * This will also dither the image if necessary.
     */

    ImgPhotoConfigureInstance(instancePtr);

    /*
     * If this is the first instance, must set the size of the image.
     */

    if (instancePtr->nextPtr == NULL) {
	Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
		masterPtr->width, masterPtr->height);
    }

    return (ClientData) instancePtr;
}

/*
 *----------------------------------------------------------------------
 *
 * ToggleComplexAlphaIfNeeded --
 *
 *	This procedure is called when an image is modified to
 *	check if any partially transparent pixels exist, which
 *	requires blending instead of straight copy.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	(Re)sets COMPLEX_ALPHA flag of master.
 *
 *----------------------------------------------------------------------
 */

static int
ToggleComplexAlphaIfNeeded(PhotoMaster *mPtr)
{
    size_t len = MAX(mPtr->userWidth, mPtr->width) *
	MAX(mPtr->userHeight, mPtr->height) * 4;
    unsigned char *c   = mPtr->pix32;
    unsigned char *end = c + len;

    /*
     * Set the COMPLEX_ALPHA flag if we have an image with partially
     * transparent bits.
     */
    mPtr->flags &= ~COMPLEX_ALPHA;
    c += 3; /* start at first alpha byte */
    for (; c < end; c += 4) {
	if (*c && *c != 255) {
     	    mPtr->flags |= COMPLEX_ALPHA;
	    break;
	}
    }
    return (mPtr->flags & COMPLEX_ALPHA);
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoBlendComplexAlpha --
 *
 *	This procedure is called when an image with partially
 *	transparent pixels must be drawn over another image.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Background image passed in gets drawn over with image data.
 *
 *----------------------------------------------------------------------
 */
/*
 * This should work on all platforms that set mask and shift data properly
 * from the visualInfo.
 * RGB is really only a 24+ bpp version whereas RGB15 is the correct version
 * and works for 15bpp+, but it slower, so it's only used for 15bpp+.
 */
#ifndef __WIN32__
#define GetRValue(rgb)	(UCHAR((rgb & red_mask) >> red_shift))
#define GetGValue(rgb)	(UCHAR((rgb & green_mask) >> green_shift))
#define GetBValue(rgb)	(UCHAR((rgb & blue_mask) >> blue_shift))
#define RGB(r,g,b)      ((unsigned)((UCHAR(r)<<red_shift)|(UCHAR(g)<<green_shift)|(UCHAR(b)<<blue_shift)))
#define RGB15(r,g,b)    ((unsigned)(((r*red_mask/255)&red_mask)|((g*green_mask/255)&green_mask)|((b*blue_mask/255)&blue_mask)))
#endif

static void ImgPhotoBlendComplexAlpha (
    XImage *bgImg,            /* background image to draw on */
    PhotoInstance *iPtr,      /* image instance to draw */
    int xOffset, int yOffset, /* X & Y offset into image instance to draw */
    int width, int height     /* width & height of image to draw */
    )
{
    int x, y, line;
    unsigned long pixel;
    unsigned char r, g, b, alpha, unalpha;
    unsigned char *alphaAr = iPtr->masterPtr->pix32;
    unsigned char *masterPtr;

#ifndef __WIN32__
    /*
     * We have to get the mask and shift info from the visual.
     * This might be cached for better performance.
     */
    unsigned long red_mask, green_mask, blue_mask;
    unsigned long red_shift, green_shift, blue_shift;
    Visual *visual = iPtr->visualInfo.visual;

    red_mask    = visual->red_mask;
    green_mask  = visual->green_mask;
    blue_mask   = visual->blue_mask;
    red_shift   = 0;
    green_shift = 0;
    blue_shift  = 0;
    while ((0x0001 & (red_mask >> red_shift)) == 0)	red_shift++;
    while ((0x0001 & (green_mask >> green_shift)) == 0)	green_shift++;
    while ((0x0001 & (blue_mask >> blue_shift)) == 0)	blue_shift++;
#endif

#define ALPHA_BLEND(bgPix, imgPix, alpha, unalpha) \
		((bgPix * unalpha + imgPix * alpha) / 255)

#if !(defined(__WIN32__) || defined(MAC_OSX_TK))
    /*
     * Only unix requires the special case for <24bpp.  It varies with
     * 3 extra shifts and uses RGB15.  The 24+bpp version could also
     * then be further optimized.
     */
    if (bgImg->depth < 24) {
	unsigned char red_mlen, green_mlen, blue_mlen;

	red_mlen   = 8 - CountBits(red_mask >> red_shift);
	green_mlen = 8 - CountBits(green_mask >> green_shift);
	blue_mlen  = 8 - CountBits(blue_mask >> blue_shift);
	for (y = 0; y < height; y++) {
	    line = (y + yOffset) * iPtr->masterPtr->width;
	    for (x = 0; x < width; x++) {
		masterPtr = alphaAr + ((line + x + xOffset) * 4);
		alpha     = masterPtr[3];
		/*
		 * Ignore pixels that are fully transparent
		 */
		if (alpha) {
		    /*
		     * We could perhaps be more efficient than XGetPixel for
		     * 24 and 32 bit displays, but this seems "fast enough".
		     */
		    r = masterPtr[0];
		    g = masterPtr[1];
		    b = masterPtr[2];
		    if (alpha != 255) {
			/*
			 * Only blend pixels that have some transparency
			 */
			unsigned char ra, ga, ba;

			pixel = XGetPixel(bgImg, x, y);
			ra = GetRValue(pixel) << red_mlen;
			ga = GetGValue(pixel) << green_mlen;
			ba = GetBValue(pixel) << blue_mlen;
			unalpha = 255 - alpha;
			r = ALPHA_BLEND(ra, r, alpha, unalpha);
			g = ALPHA_BLEND(ga, g, alpha, unalpha);
			b = ALPHA_BLEND(ba, b, alpha, unalpha);
		    }
		    XPutPixel(bgImg, x, y, RGB15(r, g, b));
		}
	    }
	}
    } else
#endif
	for (y = 0; y < height; y++) {
	    line = (y + yOffset) * iPtr->masterPtr->width;
	    for (x = 0; x < width; x++) {
		masterPtr = alphaAr + ((line + x + xOffset) * 4);
		alpha     = masterPtr[3];
		/*
		 * Ignore pixels that are fully transparent
		 */
		if (alpha) {
		    /*
		     * We could perhaps be more efficient than XGetPixel for
		     * 24 and 32 bit displays, but this seems "fast enough".
		     */
		    r = masterPtr[0];
		    g = masterPtr[1];
		    b = masterPtr[2];
		    if (alpha != 255) {
			/*
			 * Only blend pixels that have some transparency
			 */
			unsigned char ra, ga, ba;

			pixel = XGetPixel(bgImg, x, y);
			ra = GetRValue(pixel);
			ga = GetGValue(pixel);
			ba = GetBValue(pixel);
			unalpha = 255 - alpha;
			r = ALPHA_BLEND(ra, r, alpha, unalpha);
			g = ALPHA_BLEND(ga, g, alpha, unalpha);
			b = ALPHA_BLEND(ba, b, alpha, unalpha);
		    }
		    XPutPixel(bgImg, x, y, RGB(r, g, b));
		}
	    }
	}
#undef ALPHA_BLEND
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoDisplay --
 *
 *	This procedure is invoked to draw a photo image.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	A portion of the image gets rendered in a pixmap or window.
 *
 *----------------------------------------------------------------------
 */

static void
ImgPhotoDisplay(clientData, display, drawable, imageX, imageY, width,
	height, drawableX, drawableY)
    ClientData clientData;	/* Pointer to PhotoInstance structure for
				 * for instance to be displayed. */
    Display *display;		/* Display on which to draw image. */
    Drawable drawable;		/* Pixmap or window in which to draw image. */
    int imageX, imageY;		/* Upper-left corner of region within image
				 * to draw. */
    int width, height;		/* Dimensions of region within image to draw. */
    int drawableX, drawableY;	/* Coordinates within drawable that
				 * correspond to imageX and imageY. */
{
    PhotoInstance *instancePtr = (PhotoInstance *) clientData;
    XVisualInfo visInfo = instancePtr->visualInfo;

    /*
     * If there's no pixmap, it means that an error occurred
     * while creating the image instance so it can't be displayed.
     */

    if (instancePtr->pixels == None) {
	return;
    }

    if (
#if defined(MAC_TCL)
	/*
	 * The retrieval of bgImg is currently not functional on OS9
	 * so skip attempts to alpha blend.
	 */
	0 &&
#endif
	(instancePtr->masterPtr->flags & COMPLEX_ALPHA)
	    && visInfo.depth >= 15
	    && (visInfo.class == DirectColor || visInfo.class == TrueColor)) {
	XImage *bgImg = NULL;

	/*
	 * Pull the current background from the display to blend with
	 */
	bgImg = XGetImage(display, drawable, drawableX, drawableY,
		(unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap);
	if (bgImg == NULL) {
	    return;
	}

	ImgPhotoBlendComplexAlpha(bgImg, instancePtr,
		imageX, imageY, width, height);

	/*
	 * Color info is unimportant as we only do this operation for
	 * depth >= 15.
	 */
	TkPutImage(NULL, 0, display, drawable, instancePtr->gc,
		bgImg, 0, 0, drawableX, drawableY,
		(unsigned int) width, (unsigned int) height);
	XDestroyImage(bgImg);
    } else {
	/*
	 * masterPtr->region describes which parts of the image contain
	 * valid data.  We set this region as the clip mask for the gc,
	 * setting its origin appropriately, and use it when drawing the
	 * image.
	 */
	TkSetRegion(display, instancePtr->gc, instancePtr->masterPtr->validRegion);
	XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
	               drawableY - imageY);
	XCopyArea(display, instancePtr->pixels, drawable, instancePtr->gc,
	          imageX, imageY, (unsigned) width, (unsigned) height,
	          drawableX, drawableY);
	XSetClipMask(display, instancePtr->gc, None);
	XSetClipOrigin(display, instancePtr->gc, 0, 0);
    }
    XFlush (display);
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoFree --
 *
 *	This procedure is called when a widget ceases to use a
 *	particular instance of an image.  We don't actually get
 *	rid of the instance until later because we may be about
 *	to get this instance again.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Internal data structures get cleaned up, later.
 *
 *----------------------------------------------------------------------
 */

static void
ImgPhotoFree(clientData, display)
    ClientData clientData;	/* Pointer to PhotoInstance structure for
				 * for instance to be displayed. */
    Display *display;		/* Display containing window that used image. */
{
    PhotoInstance *instancePtr = (PhotoInstance *) clientData;
    ColorTable *colorPtr;

    instancePtr->refCount -= 1;
    if (instancePtr->refCount > 0) {
	return;
    }

    /*
     * There are no more uses of the image within this widget.
     * Decrement the count of live uses of its color table, so
     * that its colors can be reclaimed if necessary, and
     * set up an idle call to free the instance structure.
     */

    colorPtr = instancePtr->colorTablePtr;
    if (colorPtr != NULL) {
	colorPtr->liveRefCount -= 1;
    }
    
    Tcl_DoWhenIdle(DisposeInstance, (ClientData) instancePtr);
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoDelete --
 *
 *	This procedure is called by the image code to delete the
 *	master structure for an image.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Resources associated with the image get freed.
 *
 *----------------------------------------------------------------------
 */

static void
ImgPhotoDelete(masterData)
    ClientData masterData;	/* Pointer to PhotoMaster structure for
				 * image.  Must not have any more instances. */
{
    PhotoMaster *masterPtr = (PhotoMaster *) masterData;
    PhotoInstance *instancePtr;

    while ((instancePtr = masterPtr->instancePtr) != NULL) {
	if (instancePtr->refCount > 0) {
	    panic("tried to delete photo image when instances still exist");
	}
	Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
	DisposeInstance((ClientData) instancePtr);
    }
    masterPtr->tkMaster = NULL;
    if (masterPtr->imageCmd != NULL) {
	Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd);
    }
    if (masterPtr->pix32 != NULL) {
	ckfree((char *) masterPtr->pix32);
    }
    if (masterPtr->validRegion != NULL) {
	TkDestroyRegion(masterPtr->validRegion);
    }
    if (masterPtr->dataString != NULL) {
	Tcl_DecrRefCount(masterPtr->dataString);
    }
    if (masterPtr->format != NULL) {
	Tcl_DecrRefCount(masterPtr->format);
    }
    Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
    ckfree((char *) masterPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoCmdDeletedProc --
 *
 *	This procedure is invoked when the image command for an image
 *	is deleted.  It deletes the image.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The image is deleted.
 *
 *----------------------------------------------------------------------
 */

static void
ImgPhotoCmdDeletedProc(clientData)
    ClientData clientData;	/* Pointer to PhotoMaster structure for
				 * image. */
{
    PhotoMaster *masterPtr = (PhotoMaster *) clientData;

    masterPtr->imageCmd = NULL;
    if (masterPtr->tkMaster != NULL) {
	Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
    }
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoSetSize --
 *
 *	This procedure reallocates the image storage and instance
 *	pixmaps for a photo image, as necessary, to change the
 *	image's size to `width' x `height' pixels.
 *
 * Results:
 *	TCL_OK if successful, TCL_ERROR if failure occurred (currently
 *	just with memory allocation.)
 *
 * Side effects:
 *	Storage gets reallocated, for the master and all its instances.
 *
 *----------------------------------------------------------------------
 */

static int
ImgPhotoSetSize(masterPtr, width, height)
    PhotoMaster *masterPtr;
    int width, height;
{
    unsigned char *newPix32 = NULL;
    int h, offset, pitch;
    unsigned char *srcPtr, *destPtr;
    XRectangle validBox, clipBox;
    TkRegion clipRegion;
    PhotoInstance *instancePtr;

    if (masterPtr->userWidth > 0) {
	width = masterPtr->userWidth;
    }
    if (masterPtr->userHeight > 0) {
	height = masterPtr->userHeight;
    }

    pitch = width * 4;

    /*
     * Test if we're going to (re)allocate the main buffer now, so
     * that any failures will leave the photo unchanged.
     */
    if ((width != masterPtr->width) || (height != masterPtr->height)
	    || (masterPtr->pix32 == NULL)) {
	/*
	 * Not a u-long, but should be one.
	 */
	unsigned /*long*/ newPixSize = (unsigned /*long*/) (height * pitch);

	/*
	 * Some mallocs() really hate allocating zero bytes. [Bug 619544]
	 */
	if (newPixSize == 0) {
	    newPix32 = NULL;
	} else {
	    newPix32 = (unsigned char *) attemptckalloc(newPixSize);
	    if (newPix32 == NULL) {
		return TCL_ERROR;
	    }
	}
    }

    /*
     * We have to trim the valid region if it is currently
     * larger than the new image size.
     */

    TkClipBox(masterPtr->validRegion, &validBox);
    if ((validBox.x + validBox.width > width)
	    || (validBox.y + validBox.height > height)) {
	clipBox.x = 0;
	clipBox.y = 0;
	clipBox.width = width;
	clipBox.height = height;
	clipRegion = TkCreateRegion();
	TkUnionRectWithRegion(&clipBox, clipRegion, clipRegion);
	TkIntersectRegion(masterPtr->validRegion, clipRegion,
		masterPtr->validRegion);
	TkDestroyRegion(clipRegion);
	TkClipBox(masterPtr->validRegion, &validBox);
    }

    /*
     * Use the reallocated storage (allocation above) for the 32-bit
     * image and copy over valid regions.  Note that this test is true
     * precisely when the allocation has already been done.
     */
    if (newPix32 != NULL) {
	/*
	 * Zero the new array.  The dithering code shouldn't read the
	 * areas outside validBox, but they might be copied to another
	 * photo image or written to a file.
	 */

	if ((masterPtr->pix32 != NULL)
	    && ((width == masterPtr->width) || (width == validBox.width))) {
	    if (validBox.y > 0) {
		memset((VOID *) newPix32, 0, (size_t) (validBox.y * pitch));
	    }
	    h = validBox.y + validBox.height;
	    if (h < height) {
		memset((VOID *) (newPix32 + h * pitch), 0,
			(size_t) ((height - h) * pitch));
	    }
	} else {
	    memset((VOID *) newPix32, 0, (size_t) (height * pitch));
	}

	if (masterPtr->pix32 != NULL) {

	    /*
	     * Copy the common area over to the new array array and
	     * free the old array.
	     */

	    if (width == masterPtr->width) {

		/*
		 * The region to be copied is contiguous.
		 */

		offset = validBox.y * pitch;
		memcpy((VOID *) (newPix32 + offset),
			(VOID *) (masterPtr->pix32 + offset),
			(size_t) (validBox.height * pitch));

	    } else if ((validBox.width > 0) && (validBox.height > 0)) {

		/*
		 * Area to be copied is not contiguous - copy line by line.
		 */

		destPtr = newPix32 + (validBox.y * width + validBox.x) * 4;
		srcPtr = masterPtr->pix32 + (validBox.y * masterPtr->width
			+ validBox.x) * 4;
		for (h = validBox.height; h > 0; h--) {
		    memcpy((VOID *) destPtr, (VOID *) srcPtr,
			    (size_t) (validBox.width * 4));
		    destPtr += width * 4;
		    srcPtr += masterPtr->width * 4;
		}
	    }

	    ckfree((char *) masterPtr->pix32);
	}

	masterPtr->pix32 = newPix32;
	masterPtr->width = width;
	masterPtr->height = height;

	/*
	 * Dithering will be correct up to the end of the last
	 * pre-existing complete scanline.
	 */

	if ((validBox.x > 0) || (validBox.y > 0)) {
	    masterPtr->ditherX = 0;
	    masterPtr->ditherY = 0;
	} else if (validBox.width == width) {
	    if ((int) validBox.height < masterPtr->ditherY) {
		masterPtr->ditherX = 0;
		masterPtr->ditherY = validBox.height;
	    }
	} else if ((masterPtr->ditherY > 0)
		|| ((int) validBox.width < masterPtr->ditherX)) {
	    masterPtr->ditherX = validBox.width;
	    masterPtr->ditherY = 0;
	}
    }

    ToggleComplexAlphaIfNeeded(masterPtr);

    /*
     * Now adjust the sizes of the pixmaps for all of the instances.
     */

    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
	    instancePtr = instancePtr->nextPtr) {
	ImgPhotoInstanceSetSize(instancePtr);
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ImgPhotoInstanceSetSize --
 *
 * 	This procedure reallocates the instance pixmap and dithering
 *	error array for a photo instance, as necessary, to change the
 *	image's size to `width' x `height' pixels.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Storage gets reallocated, here and in the X server.
 *
 *----------------------------------------------------------------------
 */

static void
ImgPhotoInstanceSetSize(instancePtr)
    PhotoInstance *instancePtr;		/* Instance whose size is to be
					 * changed. */
{
    PhotoMaster *masterPtr;
    schar *newError;
    schar *errSrcPtr, *errDestPtr;
    int h, offset;
    XRectangle validBox;
    Pixmap newPixmap;

    masterPtr = instancePtr->masterPtr;
    TkClipBox(masterPtr->validRegion, &validBox);

    if ((instancePtr->width != masterPtr->width)
	    || (instancePtr->height != masterPtr->height)
	    || (instancePtr->pixels == None)) {
	newPixmap = Tk_GetPixmap(instancePtr->display,
		RootWindow(instancePtr->display,
		    instancePtr->visualInfo.screen),
		(masterPtr->width > 0) ? masterPtr->width: 1,
		(masterPtr->height > 0) ? masterPtr->height: 1,
		instancePtr->visualInfo.depth);
        if (!newPixmap) {
            panic("Fail to create pixmap with Tk_GetPixmap in ImgPhotoInstanceSetSize.\n");
            return;
        }

	/*
	 * The following is a gross hack needed to properly support colormaps
	 * under Windows.  Before the pixels can be copied to the pixmap,
	 * the relevent colormap must be associated with the drawable.
	 * Normally we can infer this association from the window that
	 * was used to create the pixmap.  However, in this case we're
	 * using the root window, so we have to be more explicit.
	 */

	TkSetPixmapColormap(newPixmap, instancePtr->colormap);

	if (instancePtr->pixels != None) {
	    /*
	     * Copy any common pixels from the old pixmap and free it.
	     */