diff --git a/contrib/media/updf/COPYING b/contrib/media/updf/COPYING
new file mode 100644
index 000000000..94a9ed024
--- /dev/null
+++ b/contrib/media/updf/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/contrib/media/updf/Makefile b/contrib/media/updf/Makefile
new file mode 100644
index 000000000..89794b8a7
--- /dev/null
+++ b/contrib/media/updf/Makefile
@@ -0,0 +1,162 @@
+# GNU Makefile
+
+build ?= debug
+
+OUT := build/$(build)
+GEN := generated
+
+# --- Variables, Commands, etc... ---
+
+default: all
+LDFLAGS = -Tinclude/scripts/menuetos_app_v01.ld -nostdlib -L include/lib -melf_i386
+CFLAGS += -Ifitz -Ipdf -Ixps -Iscripts -fno-stack-protector -nostdinc -fno-builtin -m32 -I include -fno-pic
+LIBS += -lfreetype2 -lpng -ljbig2dec -ljpeg -lopenjpeg -lz -lm -lc
+
+#include Makerules
+#include Makethird
+
+THIRD_LIBS := $(FREETYPE_LIB)
+THIRD_LIBS += $(JBIG2DEC_LIB)
+THIRD_LIBS += $(JPEG_LIB)
+THIRD_LIBS += $(OPENJPEG_LIB)
+THIRD_LIBS += $(ZLIB_LIB)
+
+ifeq "$(verbose)" ""
+QUIET_AR = @ echo ' ' ' ' AR $@ ;
+QUIET_CC = @ echo ' ' ' ' CC $@ ;
+QUIET_GEN = @ echo ' ' ' ' GEN $@ ;
+QUIET_LINK = @ echo ' ' ' ' LINK $@ ;
+QUIET_MKDIR = @ echo ' ' ' ' MKDIR $@ ;
+endif
+
+CC_CMD = $(QUIET_CC) $(CC) $(CFLAGS) -o $@ -c $<
+AR_CMD = $(QUIET_AR) $(AR) cru $@ $^
+LINK_CMD = $(QUIET_LINK) ld $(LDFLAGS) -o $@ include/crt0.o $^ build/debug/snprintf.o $(LIBS)
+MKDIR_CMD = $(QUIET_MKDIR) mkdir -p $@
+
+# --- Rules ---
+
+$(OUT) $(GEN) :
+ $(MKDIR_CMD)
+
+$(OUT)/%.a :
+ $(AR_CMD)
+
+$(OUT)/% : $(OUT)/%.o
+ $(LINK_CMD)
+
+$(OUT)/%.o : fitz/%.c fitz/fitz.h | $(OUT)
+ $(CC_CMD)
+$(OUT)/%.o : draw/%.c fitz/fitz.h | $(OUT)
+ $(CC_CMD)
+$(OUT)/%.o : pdf/%.c fitz/fitz.h pdf/mupdf.h | $(OUT)
+ $(CC_CMD)
+$(OUT)/%.o : xps/%.c fitz/fitz.h xps/muxps.h | $(OUT)
+ $(CC_CMD)
+$(OUT)/%.o : apps/%.c fitz/fitz.h pdf/mupdf.h xps/muxps.h | $(OUT)
+ $(CC_CMD)
+$(OUT)/%.o : scripts/%.c | $(OUT)
+ $(CC_CMD)
+
+.PRECIOUS : $(OUT)/%.o # Keep intermediates from chained rules
+
+# --- Fitz, MuPDF and MuXPS libraries ---
+
+FITZ_LIB := $(OUT)/libfitz.a
+MUPDF_LIB := $(OUT)/libmupdf.a
+MUXPS_LIB := $(OUT)/libmuxps.a
+
+FITZ_SRC := $(notdir $(wildcard fitz/*.c draw/*.c))
+MUPDF_SRC := $(notdir $(wildcard pdf/*.c))
+MUXPS_SRC := $(notdir $(wildcard xps/*.c))
+
+$(FITZ_LIB) : $(addprefix $(OUT)/, $(FITZ_SRC:%.c=%.o))
+$(MUPDF_LIB) : $(addprefix $(OUT)/, $(MUPDF_SRC:%.c=%.o))
+$(MUXPS_LIB) : $(addprefix $(OUT)/, $(MUXPS_SRC:%.c=%.o))
+
+libs: $(MUXPS_LIB) $(MUPDF_LIB) $(FITZ_LIB) $(THIRD_LIBS)
+ @ echo MuPDF/XPS and underlying libraries built
+
+# --- Generated CMAP and FONT files ---
+
+CMAPDUMP := scripts/cmapdump
+FONTDUMP := scripts/fontdump
+
+CMAP_CNS_SRC := $(wildcard cmaps/cns/*)
+CMAP_GB_SRC := $(wildcard cmaps/gb/*)
+CMAP_JAPAN_SRC := $(wildcard cmaps/japan/*)
+CMAP_KOREA_SRC := $(wildcard cmaps/korea/*)
+FONT_BASE14_SRC := $(wildcard fonts/*.cff)
+FONT_DROID_SRC := fonts/droid/DroidSans.ttf fonts/droid/DroidSansMono.ttf
+FONT_CJK_SRC := fonts/droid/DroidSansFallback.ttf
+
+$(GEN)/cmap_cns.h : $(CMAP_CNS_SRC)
+ $(QUIET_GEN) ./$(CMAPDUMP) $@ $(CMAP_CNS_SRC)
+$(GEN)/cmap_gb.h : $(CMAP_GB_SRC)
+ $(QUIET_GEN) ./$(CMAPDUMP) $@ $(CMAP_GB_SRC)
+$(GEN)/cmap_japan.h : $(CMAP_JAPAN_SRC)
+ $(QUIET_GEN) ./$(CMAPDUMP) $@ $(CMAP_JAPAN_SRC)
+$(GEN)/cmap_korea.h : $(CMAP_KOREA_SRC)
+ $(QUIET_GEN) ./$(CMAPDUMP) $@ $(CMAP_KOREA_SRC)
+
+$(GEN)/font_base14.h : $(FONT_BASE14_SRC)
+ $(QUIET_GEN) ./$(FONTDUMP) $@ $(FONT_BASE14_SRC)
+$(GEN)/font_droid.h : $(FONT_DROID_SRC)
+ $(QUIET_GEN) ./$(FONTDUMP) $@ $(FONT_DROID_SRC)
+$(GEN)/font_cjk.h : $(FONT_CJK_SRC)
+ $(QUIET_GEN) ./$(FONTDUMP) $@ $(FONT_CJK_SRC)
+
+CMAP_HDR := $(addprefix $(GEN)/, cmap_cns.h cmap_gb.h cmap_japan.h cmap_korea.h)
+FONT_HDR := $(GEN)/font_base14.h $(GEN)/font_droid.h $(GEN)/font_cjk.h
+
+ifeq "$(CROSSCOMPILE)" ""
+$(CMAP_HDR) : $(CMAPDUMP) | $(GEN)
+$(FONT_HDR) : $(FONTDUMP) | $(GEN)
+endif
+
+generate: $(CMAP_HDR) $(FONT_HDR)
+
+$(OUT)/pdf_cmap_table.o : $(CMAP_HDR)
+$(OUT)/pdf_fontfile.o : $(FONT_HDR)
+$(OUT)/cmapdump.o : pdf/pdf_cmap.c pdf/pdf_cmap_parse.c
+
+# --- Tools and Apps ---
+
+PDF_APPS := $(addprefix $(OUT)/, pdfdraw pdfclean pdfextract pdfinfo pdfshow)
+XPS_APPS := $(addprefix $(OUT)/, xpsdraw)
+
+$(PDF_APPS) : $(MUPDF_LIB) $(FITZ_LIB) $(THIRD_LIBS)
+$(XPS_APPS) : $(MUXPS_LIB) $(FITZ_LIB) $(THIRD_LIBS)
+
+MUPDF := $(OUT)/mupdf
+$(MUPDF) : $(MUXPS_LIB) $(MUPDF_LIB) $(FITZ_LIB) $(THIRD_LIBS)
+ifeq "$(NOX11)" ""
+$(MUPDF) : $(addprefix $(OUT)/, kos_main.o pdfapp.o)
+ $(LINK_CMD)
+endif
+
+# --- Install ---
+
+prefix ?= /usr/local
+bindir ?= $(prefix)/bin
+libdir ?= $(prefix)/lib
+incdir ?= $(prefix)/include
+mandir ?= $(prefix)/share/man
+
+install: $(MUXPS_LIB) $(MUPDF_LIB) $(FITZ_LIB) $(PDF_APPS) $(XPS_APPS) $(MUPDF)
+ install -d $(bindir) $(libdir) $(incdir) $(mandir)/man1
+ install $(MUXPS_LIB) $(MUPDF_LIB) $(FITZ_LIB) $(libdir)
+ install fitz/fitz.h pdf/mupdf.h xps/muxps.h $(incdir)
+ install $(PDF_APPS) $(XPS_APPS) $(MUPDF) $(bindir)
+ install $(wildcard apps/man/*.1) $(mandir)/man1
+
+# --- Clean and Default ---
+
+all: $(THIRD_LIBS) $(FITZ_LIB) $(PDF_APPS) $(XPS_APPS) $(MUPDF)
+
+clean:
+ rm -rf $(OUT)
+nuke:
+ rm -rf build/* $(GEN)
+
+.PHONY: all clean nuke install
diff --git a/contrib/media/updf/Makerules b/contrib/media/updf/Makerules
new file mode 100644
index 000000000..63a75d6a5
--- /dev/null
+++ b/contrib/media/updf/Makerules
@@ -0,0 +1,84 @@
+# Configuration for the Makefile
+
+OS ?= $(shell uname)
+OS := $(OS:MINGW%=MINGW)
+
+CFLAGS += -Wall
+
+ifeq "$(build)" "debug"
+CFLAGS += -pipe -g
+else ifeq "$(build)" "profile"
+CFLAGS += -pipe -O2 -DNDEBUG -pg
+LDFLAGS += -pg
+else ifeq "$(build)" "release"
+CFLAGS += -pipe -O2 -DNDEBUG -fomit-frame-pointer
+else ifeq "$(build)" "native"
+CFLAGS += -pipe -O2 -DNDEBUG -fomit-frame-pointer -march=native -mfpmath=sse
+else
+$(error unknown build setting: '$(build)')
+endif
+
+ifeq "$(OS)" "Linux"
+SYS_FREETYPE_INC := `pkg-config --cflags freetype2`
+X11_LIBS := -lX11 -lXext
+endif
+
+ifeq "$(OS)" "FreeBSD"
+SYS_FREETYPE_INC := `pkg-config --cflags freetype2`
+LDFLAGS += -L/usr/local/lib
+X11_LIBS := -lX11 -lXext
+endif
+
+# Mac OS X build depends on some thirdparty libs
+ifeq "$(OS)" "Darwin"
+SYS_FREETYPE_INC := -I/usr/X11R6/include/freetype2
+CFLAGS += -I/usr/X11R6/include
+LDFLAGS += -L/usr/X11R6/lib
+X11_LIBS := -lX11 -lXext
+ifeq "$(arch)" "amd64"
+CFLAGS += -m64
+LDFLAGS += -m64
+else
+CFLAGS += -m32
+LDFLAGS += -m32
+endif
+endif
+
+# The following section is an example of how to simply do cross-compilation
+# using these Makefiles. It builds for a beagleboard running ARM linux,
+# compiling on windows with the CodeSourcery G++ compilers.
+# Invoke this as:
+# make OS=beagle-cross build=release
+# This does rely on the generated directory being populated with the cmap
+# files etc first. Either:
+# 1) do 'make generate' first (this relies on you having an appropriate host
+# base C compiler set up - such as you would have on unix or in windows
+# cygwin)
+# 2) do a non cross compile build (e.g. windows in MSVC) first.
+# 3) download the generated files from mupdf.com.
+ifeq "$(OS)" "beagle-cross"
+CC = arm-none-linux-gnueabi-gcc
+LD = arm-none-linux-gnueabi-gcc
+AR = arm-none-linux-gnueabi-ar
+CFLAGS += -O3 -mfpu=neon -mcpu=cortex-a8 -mfloat-abi=softfp -ftree-vectorize -ffast-math -fsingle-precision-constant
+CROSSCOMPILE=yes
+NOX11=yes
+endif
+
+ifeq "$(OS)" "webos-pre-cross"
+CC = arm-none-linux-gnueabi-gcc
+LD = arm-none-linux-gnueabi-gcc
+AR = arm-none-linux-gnueabi-ar
+CFLAGS += -O3 -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -ffast-math -fsingle-precision-constant
+CROSSCOMPILE=yes
+NOX11=yes
+endif
+
+ifeq "$(OS)" "webos-pixi-cross"
+CC = arm-none-linux-gnueabi-gcc
+LD = arm-none-linux-gnueabi-gcc
+AR = arm-none-linux-gnueabi-ar
+CFLAGS += -O3 -mcpu=arm1136jf-s -mfpu=vfp -mfloat-abi=softfp -ffast-math -fsingle-precision-constant
+CROSSCOMPILE=yes
+NOX11=yes
+endif
diff --git a/contrib/media/updf/Makethird b/contrib/media/updf/Makethird
new file mode 100644
index 000000000..62b6e0bb0
--- /dev/null
+++ b/contrib/media/updf/Makethird
@@ -0,0 +1,203 @@
+# GNU Makefile for third party libraries used by MuPDF
+#
+# If thirdparty libraries are supplied, they will be built as
+# static libraries. Download and unzip the the mupdf-thirdparty.zip
+# archive in the source directory.
+
+FREETYPE_DIR := $(wildcard thirdparty/freetype*)
+JBIG2DEC_DIR := $(wildcard thirdparty/jbig2dec*)
+JPEG_DIR := $(wildcard thirdparty/jpeg*)
+OPENJPEG_DIR := $(wildcard thirdparty/openjpeg*/libopenjpeg)
+ZLIB_DIR := $(wildcard thirdparty/zlib*)
+
+# --- FreeType 2 ---
+
+ifneq "$(FREETYPE_DIR)" ""
+CFLAGS += -I$(FREETYPE_DIR)/include
+LIBS := $(filter-out -lfreetype, $(LIBS))
+FREETYPE_LIB := $(OUT)/libfreetype.a
+
+FREETYPE_SRC := \
+ ftbase.c \
+ ftbbox.c \
+ ftbitmap.c \
+ ftgasp.c \
+ ftglyph.c \
+ ftinit.c \
+ ftstroke.c \
+ ftsynth.c \
+ ftsystem.c \
+ fttype1.c \
+ ftxf86.c \
+ cff.c \
+ psaux.c \
+ pshinter.c \
+ psnames.c \
+ raster.c \
+ sfnt.c \
+ smooth.c \
+ truetype.c \
+ type1.c \
+ type1cid.c \
+
+$(FREETYPE_LIB): $(addprefix $(OUT)/ft_, $(FREETYPE_SRC:%.c=%.o))
+
+FT_CFLAGS := -DFT2_BUILD_LIBRARY -DDARWIN_NO_CARBON \
+ '-DFT_CONFIG_MODULES_H="slimftmodules.h"' \
+ '-DFT_CONFIG_OPTIONS_H="slimftoptions.h"'
+
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/base/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/cff/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/cid/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/psaux/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/pshinter/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/psnames/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/raster/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/smooth/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/sfnt/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/truetype/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+$(OUT)/ft_%.o: $(FREETYPE_DIR)/src/type1/%.c | $(OUT)
+ $(CC_CMD) $(FT_CFLAGS)
+
+else
+CFLAGS += $(SYS_FREETYPE_INC)
+endif
+
+# --- JBIG2DEC ---
+
+ifneq "$(JBIG2DEC_DIR)" ""
+CFLAGS += -I$(JBIG2DEC_DIR)
+LIBS := $(filter-out -ljbig2dec, $(LIBS))
+JBIG2DEC_LIB := $(OUT)/libjbig2dec.a
+
+JBIG2DEC_SRC := \
+ jbig2.c \
+ jbig2_arith.c \
+ jbig2_arith_iaid.c \
+ jbig2_arith_int.c \
+ jbig2_generic.c \
+ jbig2_huffman.c \
+ jbig2_image.c \
+ jbig2_metadata.c \
+ jbig2_mmr.c \
+ jbig2_page.c \
+ jbig2_refinement.c \
+ jbig2_segment.c \
+ jbig2_symbol_dict.c \
+ jbig2_text.c \
+
+$(JBIG2DEC_LIB): $(addprefix $(OUT)/, $(JBIG2DEC_SRC:%.c=%.o))
+$(OUT)/%.o: $(JBIG2DEC_DIR)/%.c | $(OUT)
+ $(CC_CMD) -DHAVE_STDINT_H
+endif
+
+# --- JPEG library from IJG ---
+
+ifneq "$(JPEG_DIR)" ""
+CFLAGS += -I$(JPEG_DIR)
+LIBS := $(filter-out -ljpeg, $(LIBS))
+JPEG_LIB := $(OUT)/libjpeg.a
+
+JPEG_SRC := \
+ jaricom.c \
+ jcomapi.c \
+ jdapimin.c \
+ jdapistd.c \
+ jdarith.c \
+ jdatadst.c \
+ jdatasrc.c \
+ jdcoefct.c \
+ jdcolor.c \
+ jddctmgr.c \
+ jdhuff.c \
+ jdinput.c \
+ jdmainct.c \
+ jdmarker.c \
+ jdmaster.c \
+ jdmerge.c \
+ jdpostct.c \
+ jdsample.c \
+ jdtrans.c \
+ jerror.c \
+ jfdctflt.c \
+ jfdctfst.c \
+ jfdctint.c \
+ jidctflt.c \
+ jidctfst.c \
+ jidctint.c \
+ jmemansi.c \
+ jmemmgr.c \
+ jquant1.c \
+ jquant2.c \
+ jutils.c \
+
+$(JPEG_LIB): $(addprefix $(OUT)/jpeg_, $(JPEG_SRC:%.c=%.o))
+$(OUT)/jpeg_%.o: $(JPEG_DIR)/%.c | $(OUT)
+ $(CC_CMD) -Dmain=xxxmain
+endif
+
+# --- OpenJPEG ---
+
+ifneq "$(OPENJPEG_DIR)" ""
+CFLAGS += -I$(OPENJPEG_DIR)
+LIBS := $(filter-out -lopenjpeg, $(LIBS))
+OPENJPEG_LIB := $(OUT)/libopenjpeg.a
+
+OPENJPEG_SRC := \
+ bio.c \
+ cio.c \
+ dwt.c \
+ event.c \
+ image.c \
+ j2k.c \
+ j2k_lib.c \
+ jp2.c \
+ jpt.c \
+ mct.c \
+ mqc.c \
+ openjpeg.c \
+ pi.c \
+ raw.c \
+ t1.c \
+ t2.c \
+ tcd.c \
+ tgt.c \
+
+$(OPENJPEG_LIB): $(addprefix $(OUT)/opj_, $(OPENJPEG_SRC:%.c=%.o))
+$(OUT)/opj_%.o: $(OPENJPEG_DIR)/%.c | $(OUT)
+ $(CC_CMD) -DOPJ_STATIC
+endif
+
+# --- ZLIB ---
+
+ifneq "$(ZLIB_DIR)" ""
+CFLAGS += -I$(ZLIB_DIR)
+LIBS := $(filter-out -lz, $(LIBS))
+ZLIB_LIB := $(OUT)/libz.a
+
+ZLIB_SRC := \
+ adler32.c \
+ compress.c \
+ crc32.c \
+ deflate.c \
+ inffast.c \
+ inflate.c \
+ inftrees.c \
+ trees.c \
+ uncompr.c \
+ zutil.c \
+
+$(ZLIB_LIB): $(addprefix $(OUT)/zlib_, $(ZLIB_SRC:%.c=%.o))
+$(OUT)/zlib_%.o: $(ZLIB_DIR)/%.c | $(OUT)
+ $(CC_CMD)
+endif
diff --git a/contrib/media/updf/README b/contrib/media/updf/README
new file mode 100644
index 000000000..c30e7cbea
--- /dev/null
+++ b/contrib/media/updf/README
@@ -0,0 +1,64 @@
+ABOUT
+
+MuPDF is a lightweight PDF and XPS viewer and parser/rendering library.
+
+The renderer in MuPDF is tailored for high quality anti-aliased graphics. It
+renders text with metrics and spacing accurate to within fractions of a pixel
+for the highest fidelity in reproducing the look of a printed page on screen.
+
+MuPDF is also small, fast, and yet complete. We support PDF 1.7 with
+transparency, encryption, hyperlinks, annotations, search and many other bells
+and whistles. MuPDF can also read XPS documents (OpenXPS / ECMA-388).
+
+We don't support interactive features such as form filling, javascript and
+transitions. MuPDF is written modularly, so such features can be added on by
+integrators if they so desire.
+
+LICENSE
+
+MuPDF is Copyright 2006-2011 Artifex Software, Inc.
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see .
+
+For commercial licensing please contact sales@artifex.com.
+
+COMPILING
+
+If you are compiling from source you will need several third party libraries:
+freetype2, jbig2dec, libjpeg, openjpeg, and zlib. We have prepared a package
+(mupdf-thirdparty.zip) that you can unzip in the mupdf source tree if you don't
+have them installed on your system.
+
+You must unpack mupdf-thirdparty.zip to build using the Visual Studio project.
+
+DOWNLOAD
+
+The latest development source is available directly from the git repository:
+
+ git clone http://mupdf.com/repos/mupdf.git
+
+INSTALLING
+
+Typing "make prefix=/usr/local install" will install the binaries, man-pages,
+static libraries and header files on your system.
+
+REPORTING BUGS AND PROBLEMS
+
+The MuPDF developers hang out on IRC in the #ghostscript channel on irc.freenode.net.
+
+Report bugs on the ghostscript bugzilla, with MuPDF as the selected component.
+
+ http://bugs.ghostscript.com/
+
+If you are reporting a problem with PDF parsing, please include the problematic
+file as an attachment.
diff --git a/contrib/media/updf/android/AndroidManifest.xml b/contrib/media/updf/android/AndroidManifest.xml
new file mode 100644
index 000000000..1bea0f8a7
--- /dev/null
+++ b/contrib/media/updf/android/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/media/updf/android/ReadMe.txt b/contrib/media/updf/android/ReadMe.txt
new file mode 100644
index 000000000..c46c88b6b
--- /dev/null
+++ b/contrib/media/updf/android/ReadMe.txt
@@ -0,0 +1,111 @@
+To build/debug android build.
+
+1) Download the android sdk, and install it. On windows I unpacked it as:
+
+ C:\Program Files\android-sdk-windows
+
+on Macos as:
+
+ /Library/android-sdk-mac_x86
+
+On windows add: C:/Progra~1/android-sdk-windows/tools to your path.
+On linux/macos add the equivalent.
+
+2) Download the android ndk, and install in. On windows I unpacked it as:
+
+ C:\Program Files\android-ndk-r5
+
+on Macos as:
+
+ /Library/android-ndk-r5
+
+On windows add: C:/Progra~1/android-ndk-r5 to your path. On linux/macos
+add the equivalent.
+
+3) On windows, to use the ndk, you *must* be running under cygwin. This means
+you need to install Cygwin 1.7 or greater now.
+
+In the current release of the ndk (r5), when running under cygwin, there are
+bugs to do with the automatic conversion of dependencies from DOS format
+paths to cygwin format paths. The 2 fixes can be found in:
+
+
+
+4) Bring up a shell, and run 'android'. This will bring up a graphical
+gui for the sdk. From here you can install the different SDK components
+for the different flavours of android. Download them all - bandwidth and disk
+space are cheap, right?
+
+5) Now go to the Virtual Devices entry on the right hand side. You need to
+create yourself an emulator image to use. Click 'New...' on the right hand
+side and a window will appear. Fill in the entries as follows:
+
+ Name: FroyoEm
+ Target: Android 2.2 - API Level 8
+ SD card: Size: 1024MiB
+ Skin: Resolution: 480x756 (756 just fits my macbook screen, but 800 may
+ be 'more standard')
+
+Click 'Create AVD' and wait for a minute or so while it is prepared. Now
+you can exit the GUI.
+
+6) Now we are ready to build mupdf for Android. Check out a copy of MuPDF
+(but you've done that already, cos you're reading this, right?).
+
+7) You will also need a copy of mupdf-thirdparty.zip (see the source code
+link on http://mupdf.com/). Unpack the contents of this into a 'thirdparty'
+directory created within the mupdf directory (i.e. at the same level as
+fitz, pdf, android etc).
+
+8) Finally, you will need a copy of a 'generated' directory. This is not
+currently available to download. The easiest way to obtain this is to do
+a standard windows or linux build of mupdf, which generates the required
+files as part of the build process.
+
+9) Change into the android directory, and edit local.properties into your
+favourite editor. Change the sdk path there as appropriate. This should be
+the only bit of localisation you need to do.
+
+10) Change into the android directory (note, the android directory, NOT
+the android/jni directory!), and execute (in a Cygwin window on Windows!):
+
+ ndk-build
+
+This should build the native code portion. Then execute:
+
+ ant debug
+
+or on windows under cygwin:
+
+ ant.bat debug
+
+This should build the java wrapper.
+
+11) Now start the emulator by executing:
+
+ emulator -avd FroyoEm
+
+This will take a while to full start up (be patient).
+
+12) We now need to give the demo file something to chew on, so let's copy
+a file into the SD card image of the emulator (this should only need to be
+done once). With the emulator running type:
+
+ adb push ../../MyTests/pdf_reference17.pdf /mnt/sdcard/Download/test.pdf
+
+(where obviously ../../MyTests/pdf_reference17.pdf is altered for your
+machine). (adb lives in /platform-tools if it's not on your path).
+
+13) With the emulator running (see step 11), execute
+
+ ant install
+
+('ant.bat install' on Windows) and that will copy MuPDF into the emulator
+where you can run it from the launchpad screen.
+
+14) To see debug messages from the emulator (including stdout/stderr from
+our app), execute:
+
+ adb logcat
+
+Good luck!
diff --git a/contrib/media/updf/android/build.properties b/contrib/media/updf/android/build.properties
new file mode 100644
index 000000000..edc7f2305
--- /dev/null
+++ b/contrib/media/updf/android/build.properties
@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
diff --git a/contrib/media/updf/android/build.sh b/contrib/media/updf/android/build.sh
new file mode 100644
index 000000000..36ad883f4
--- /dev/null
+++ b/contrib/media/updf/android/build.sh
@@ -0,0 +1 @@
+ndk-build && ant.bat install
diff --git a/contrib/media/updf/android/build.xml b/contrib/media/updf/android/build.xml
new file mode 100644
index 000000000..3ba2015be
--- /dev/null
+++ b/contrib/media/updf/android/build.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/media/updf/android/default.properties b/contrib/media/updf/android/default.properties
new file mode 100644
index 000000000..0b9250e02
--- /dev/null
+++ b/contrib/media/updf/android/default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
diff --git a/contrib/media/updf/android/jni/Android.mk b/contrib/media/updf/android/jni/Android.mk
new file mode 100644
index 000000000..2e84204e7
--- /dev/null
+++ b/contrib/media/updf/android/jni/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+TOP_LOCAL_PATH := $(LOCAL_PATH)
+
+MUPDF_ROOT := ..
+
+include $(TOP_LOCAL_PATH)/Core.mk
+include $(TOP_LOCAL_PATH)/ThirdParty.mk
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+ $(MUPDF_ROOT)/draw \
+ $(MUPDF_ROOT)/fitz \
+ $(MUPDF_ROOT)/pdf
+LOCAL_CFLAGS :=
+LOCAL_MODULE := mupdf
+LOCAL_SRC_FILES := mupdf.c
+LOCAL_STATIC_LIBRARIES := mupdfcore mupdfthirdparty
+
+LOCAL_LDLIBS := -lm -llog -ljnigraphics
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/contrib/media/updf/android/jni/Application.mk b/contrib/media/updf/android/jni/Application.mk
new file mode 100644
index 000000000..16de57967
--- /dev/null
+++ b/contrib/media/updf/android/jni/Application.mk
@@ -0,0 +1,3 @@
+# The ARMv7 is significanly faster due to the use of the hardware FPU
+APP_ABI := armeabi armeabi-v7a
+APP_OPTIM := debug
diff --git a/contrib/media/updf/android/jni/Core.mk b/contrib/media/updf/android/jni/Core.mk
new file mode 100644
index 000000000..4c3e75b51
--- /dev/null
+++ b/contrib/media/updf/android/jni/Core.mk
@@ -0,0 +1,99 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+MY_ROOT := ../..
+
+LOCAL_C_INCLUDES := \
+ ../thirdparty/jbig2dec \
+ ../thirdparty/openjpeg-1.4/libopenjpeg \
+ ../thirdparty/jpeg-8c \
+ ../thirdparty/zlib-1.2.5 \
+ ../thirdparty/freetype-2.4.4/include \
+ ../draw \
+ ../fitz \
+ ../pdf \
+ ../scripts \
+ ..
+
+LOCAL_MODULE := mupdfcore
+LOCAL_SRC_FILES := \
+ $(MY_ROOT)/fitz/base_error.c \
+ $(MY_ROOT)/fitz/base_geometry.c \
+ $(MY_ROOT)/fitz/base_getopt.c \
+ $(MY_ROOT)/fitz/base_hash.c \
+ $(MY_ROOT)/fitz/base_memory.c \
+ $(MY_ROOT)/fitz/base_object.c \
+ $(MY_ROOT)/fitz/base_string.c \
+ $(MY_ROOT)/fitz/base_time.c \
+ $(MY_ROOT)/fitz/crypt_aes.c \
+ $(MY_ROOT)/fitz/crypt_arc4.c \
+ $(MY_ROOT)/fitz/crypt_md5.c \
+ $(MY_ROOT)/fitz/crypt_sha2.c \
+ $(MY_ROOT)/fitz/dev_bbox.c \
+ $(MY_ROOT)/fitz/dev_list.c \
+ $(MY_ROOT)/fitz/dev_null.c \
+ $(MY_ROOT)/fitz/dev_text.c \
+ $(MY_ROOT)/fitz/dev_trace.c \
+ $(MY_ROOT)/fitz/filt_basic.c \
+ $(MY_ROOT)/fitz/filt_dctd.c \
+ $(MY_ROOT)/fitz/filt_faxd.c \
+ $(MY_ROOT)/fitz/filt_flate.c \
+ $(MY_ROOT)/fitz/filt_jbig2d.c \
+ $(MY_ROOT)/fitz/filt_jpxd.c \
+ $(MY_ROOT)/fitz/filt_lzwd.c \
+ $(MY_ROOT)/fitz/filt_predict.c \
+ $(MY_ROOT)/fitz/obj_print.c \
+ $(MY_ROOT)/fitz/res_colorspace.c \
+ $(MY_ROOT)/fitz/res_font.c \
+ $(MY_ROOT)/fitz/res_path.c \
+ $(MY_ROOT)/fitz/res_pixmap.c \
+ $(MY_ROOT)/fitz/res_shade.c \
+ $(MY_ROOT)/fitz/res_text.c \
+ $(MY_ROOT)/fitz/stm_buffer.c \
+ $(MY_ROOT)/fitz/stm_open.c \
+ $(MY_ROOT)/fitz/stm_read.c \
+ $(MY_ROOT)/draw/arch_arm.c \
+ $(MY_ROOT)/draw/arch_port.c \
+ $(MY_ROOT)/draw/draw_affine.c \
+ $(MY_ROOT)/draw/draw_blend.c \
+ $(MY_ROOT)/draw/draw_device.c \
+ $(MY_ROOT)/draw/draw_edge.c \
+ $(MY_ROOT)/draw/draw_glyph.c \
+ $(MY_ROOT)/draw/draw_mesh.c \
+ $(MY_ROOT)/draw/draw_paint.c \
+ $(MY_ROOT)/draw/draw_path.c \
+ $(MY_ROOT)/draw/draw_scale.c \
+ $(MY_ROOT)/draw/draw_unpack.c \
+ $(MY_ROOT)/pdf/pdf_annot.c \
+ $(MY_ROOT)/pdf/pdf_cmap.c \
+ $(MY_ROOT)/pdf/pdf_cmap_load.c \
+ $(MY_ROOT)/pdf/pdf_cmap_parse.c \
+ $(MY_ROOT)/pdf/pdf_cmap_table.c \
+ $(MY_ROOT)/pdf/pdf_colorspace.c \
+ $(MY_ROOT)/pdf/pdf_crypt.c \
+ $(MY_ROOT)/pdf/pdf_encoding.c \
+ $(MY_ROOT)/pdf/pdf_font.c \
+ $(MY_ROOT)/pdf/pdf_fontfile.c \
+ $(MY_ROOT)/pdf/pdf_function.c \
+ $(MY_ROOT)/pdf/pdf_image.c \
+ $(MY_ROOT)/pdf/pdf_interpret.c \
+ $(MY_ROOT)/pdf/pdf_lex.c \
+ $(MY_ROOT)/pdf/pdf_metrics.c \
+ $(MY_ROOT)/pdf/pdf_nametree.c \
+ $(MY_ROOT)/pdf/pdf_outline.c \
+ $(MY_ROOT)/pdf/pdf_page.c \
+ $(MY_ROOT)/pdf/pdf_parse.c \
+ $(MY_ROOT)/pdf/pdf_pattern.c \
+ $(MY_ROOT)/pdf/pdf_repair.c \
+ $(MY_ROOT)/pdf/pdf_shade.c \
+ $(MY_ROOT)/pdf/pdf_store.c \
+ $(MY_ROOT)/pdf/pdf_stream.c \
+ $(MY_ROOT)/pdf/pdf_type3.c \
+ $(MY_ROOT)/pdf/pdf_unicode.c \
+ $(MY_ROOT)/pdf/pdf_xobject.c \
+ $(MY_ROOT)/pdf/pdf_xref.c
+
+LOCAL_LDLIBS := -lm -llog -ljnigraphics
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/contrib/media/updf/android/jni/ThirdParty.mk b/contrib/media/updf/android/jni/ThirdParty.mk
new file mode 100644
index 000000000..2a50b05fe
--- /dev/null
+++ b/contrib/media/updf/android/jni/ThirdParty.mk
@@ -0,0 +1,153 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+MY_ROOT := ../..
+
+LOCAL_C_INCLUDES := \
+ ../thirdparty/jbig2dec \
+ ../thirdparty/openjpeg-1.4/libopenjpeg \
+ ../thirdparty/jpeg-8c \
+ ../thirdparty/zlib-1.2.5 \
+ ../thirdparty/freetype-2.4.4/include \
+ ../scripts
+
+LOCAL_CFLAGS := \
+ -DFT2_BUILD_LIBRARY -DDARWIN_NO_CARBON -DHAVE_STDINT_H
+
+LOCAL_MODULE := mupdfthirdparty
+LOCAL_SRC_FILES := \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_arith.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_arith_int.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_arith_iaid.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_huffman.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_segment.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_page.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_symbol_dict.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_text.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_generic.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_refinement.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_mmr.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_image.c \
+ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_metadata.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/bio.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/cio.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/dwt.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/event.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/image.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/j2k.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/j2k_lib.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/jp2.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/jpt.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/mct.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/mqc.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/openjpeg.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/pi.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/raw.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/t1.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/t2.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/tcd.c \
+ $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/tgt.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jaricom.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcapimin.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcapistd.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcarith.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jccoefct.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jccolor.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcdctmgr.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jchuff.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcinit.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcmainct.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcmarker.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcmaster.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcomapi.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcparam.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcprepct.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jcsample.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jctrans.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdapimin.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdapistd.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdarith.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdatadst.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdatasrc.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdcoefct.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdcolor.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jddctmgr.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdhuff.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdinput.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdmainct.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdmarker.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdmaster.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdmerge.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdpostct.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdsample.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jdtrans.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jerror.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jfdctflt.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jfdctfst.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jfdctint.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jidctflt.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jidctfst.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jidctint.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jquant1.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jquant2.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jutils.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jmemmgr.c \
+ $(MY_ROOT)/thirdparty/jpeg-8c/jmemansi.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/adler32.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/compress.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/crc32.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/deflate.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/gzclose.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/gzlib.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/gzread.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/gzwrite.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/infback.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/inffast.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/inflate.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/inftrees.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/trees.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/uncompr.c \
+ $(MY_ROOT)/thirdparty/zlib-1.2.5/zutil.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/autofit/autofit.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftbase.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftbbox.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftbdf.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftbitmap.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftdebug.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftgasp.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftglyph.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftgxval.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftinit.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftlcdfil.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftmm.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftotval.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftpfr.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftstroke.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftsynth.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftsystem.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/fttype1.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftwinfnt.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftxf86.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/base/ftpatent.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/bdf/bdf.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/cache/ftcache.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/cff/cff.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/cid/type1cid.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/gzip/ftgzip.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/lzw/ftlzw.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/pcf/pcf.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/pfr/pfr.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/psaux/psaux.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/pshinter/pshinter.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/psnames/psnames.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/raster/raster.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/smooth/smooth.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/sfnt/sfnt.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/truetype/truetype.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/type1/type1.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/type42/type42.c \
+ $(MY_ROOT)/thirdparty/freetype-2.4.4/src/winfonts/winfnt.c
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/contrib/media/updf/android/jni/mupdf.c b/contrib/media/updf/android/jni/mupdf.c
new file mode 100644
index 000000000..463899af1
--- /dev/null
+++ b/contrib/media/updf/android/jni/mupdf.c
@@ -0,0 +1,212 @@
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "fitz.h"
+#include "mupdf.h"
+
+#define LOG_TAG "libmupdf"
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
+
+/* Set to 1 to enable debug log traces. */
+#define DEBUG 0
+
+/* Globals */
+fz_colorspace *colorspace;
+fz_glyph_cache *glyphcache;
+pdf_xref *xref;
+int pagenum = 1;
+int resolution = 160;
+float pageWidth = 100;
+float pageHeight = 100;
+fz_display_list *currentPageList;
+fz_rect currentMediabox;
+int currentRotate;
+
+JNIEXPORT int JNICALL
+Java_com_artifex_mupdf_MuPDFCore_openFile(JNIEnv * env, jobject thiz, jstring jfilename)
+{
+ const char *filename;
+ char *password = "";
+ int accelerate = 1;
+ fz_error error;
+ int pages;
+
+ filename = (*env)->GetStringUTFChars(env, jfilename, NULL);
+ if (filename == NULL)
+ {
+ LOGE("Failed to get filename");
+ return 0;
+ }
+
+ if (accelerate)
+ fz_accelerate();
+ glyphcache = fz_new_glyph_cache();
+ colorspace = fz_device_rgb;
+
+ LOGE("Opening document...");
+ error = pdf_open_xref(&xref, filename, password);
+ if (error)
+ {
+ LOGE("Cannot open document: '%s'\n", filename);
+ return 0;
+ }
+
+ LOGE("Loading page tree...");
+ error = pdf_load_page_tree(xref);
+ if (error)
+ {
+ LOGE("Cannot load page tree: '%s'\n", filename);
+ return 0;
+ }
+ pages = pdf_count_pages(xref);
+ LOGE("Done! %d pages", pages);
+
+ return pages;
+}
+
+JNIEXPORT void JNICALL
+Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(JNIEnv *env, jobject thiz, int page)
+{
+ float zoom;
+ fz_matrix ctm;
+ fz_bbox bbox;
+ fz_error error;
+ fz_device *dev;
+ pdf_page *currentPage;
+
+ /* In the event of an error, ensure we give a non-empty page */
+ pageWidth = 100;
+ pageHeight = 100;
+
+ LOGE("Goto page %d...", page);
+ if (currentPageList != NULL)
+ {
+ fz_free_display_list(currentPageList);
+ currentPageList = NULL;
+ }
+ pagenum = page;
+ error = pdf_load_page(¤tPage, xref, pagenum);
+ if (error)
+ return;
+ zoom = resolution / 72;
+ currentMediabox = currentPage->mediabox;
+ currentRotate = currentPage->rotate;
+ ctm = fz_translate(0, -currentMediabox.y1);
+ ctm = fz_concat(ctm, fz_scale(zoom, -zoom));
+ ctm = fz_concat(ctm, fz_rotate(currentRotate));
+ bbox = fz_round_rect(fz_transform_rect(ctm, currentMediabox));
+ pageWidth = bbox.x1-bbox.x0;
+ pageHeight = bbox.y1-bbox.y0;
+ /* Render to list */
+ currentPageList = fz_new_display_list();
+ dev = fz_new_list_device(currentPageList);
+ error = pdf_run_page(xref, currentPage, dev, fz_identity);
+ pdf_free_page(currentPage);
+ if (error)
+ LOGE("cannot make displaylist from page %d", pagenum);
+ fz_free_device(dev);
+}
+
+JNIEXPORT float JNICALL
+Java_com_artifex_mupdf_MuPDFCore_getPageWidth(JNIEnv *env, jobject thiz)
+{
+ LOGE("PageWidth=%g", pageWidth);
+ return pageWidth;
+}
+
+JNIEXPORT float JNICALL
+Java_com_artifex_mupdf_MuPDFCore_getPageHeight(JNIEnv *env, jobject thiz)
+{
+ LOGE("PageHeight=%g", pageHeight);
+ return pageHeight;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_artifex_mupdf_MuPDFCore_drawPage(JNIEnv *env, jobject thiz, jobject bitmap,
+ int pageW, int pageH, int patchX, int patchY, int patchW, int patchH)
+{
+ AndroidBitmapInfo info;
+ void *pixels;
+ int ret;
+ fz_error error;
+ fz_device *dev;
+ float zoom;
+ fz_matrix ctm;
+ fz_bbox bbox;
+ fz_pixmap *pix;
+ float xscale, yscale;
+ fz_bbox rect;
+
+ LOGI("In native method\n");
+ if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
+ LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
+ return 0;
+ }
+
+ LOGI("Checking format\n");
+ if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
+ LOGE("Bitmap format is not RGBA_8888 !");
+ return 0;
+ }
+
+ LOGI("locking pixels\n");
+ if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
+ LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
+ return 0;
+ }
+
+ /* Call mupdf to render display list to screen */
+ LOGE("Rendering page=%dx%d patch=[%d,%d,%d,%d]",
+ pageW, pageH, patchX, patchY, patchW, patchH);
+
+ rect.x0 = patchX;
+ rect.y0 = patchY;
+ rect.x1 = patchX + patchW;
+ rect.y1 = patchY + patchH;
+ pix = fz_new_pixmap_with_rect_and_data(colorspace, rect, pixels);
+ if (currentPageList == NULL)
+ {
+ fz_clear_pixmap_with_color(pix, 0xd0);
+ return 0;
+ }
+ fz_clear_pixmap_with_color(pix, 0xff);
+
+ zoom = resolution / 72;
+ ctm = fz_translate(-currentMediabox.x0, -currentMediabox.y1);
+ ctm = fz_concat(ctm, fz_scale(zoom, -zoom));
+ ctm = fz_concat(ctm, fz_rotate(currentRotate));
+ bbox = fz_round_rect(fz_transform_rect(ctm,currentMediabox));
+ /* Now, adjust ctm so that it would give the correct page width
+ * heights. */
+ xscale = (float)pageW/(float)(bbox.x1-bbox.x0);
+ yscale = (float)pageH/(float)(bbox.y1-bbox.y0);
+ ctm = fz_concat(ctm, fz_scale(xscale, yscale));
+ bbox = fz_round_rect(fz_transform_rect(ctm,currentMediabox));
+ dev = fz_new_draw_device(glyphcache, pix);
+ fz_execute_display_list(currentPageList, dev, ctm, bbox);
+ fz_free_device(dev);
+ fz_drop_pixmap(pix);
+ LOGE("Rendered");
+
+ AndroidBitmap_unlockPixels(env, bitmap);
+
+ return 1;
+}
+
+JNIEXPORT void JNICALL
+Java_com_artifex_mupdf_MuPDFCore_destroying(JNIEnv * env, jobject thiz)
+{
+ fz_free_display_list(currentPageList);
+ currentPageList = NULL;
+ pdf_free_xref(xref);
+ xref = NULL;
+ fz_free_glyph_cache(glyphcache);
+ glyphcache = NULL;
+}
diff --git a/contrib/media/updf/android/local.properties b/contrib/media/updf/android/local.properties
new file mode 100644
index 000000000..d0fd99a98
--- /dev/null
+++ b/contrib/media/updf/android/local.properties
@@ -0,0 +1,2 @@
+#sdk.dir=/Library/android-sdk-mac_x86
+sdk.dir=C:\\Program Files\\android-sdk-windows
diff --git a/contrib/media/updf/android/res/drawable-hdpi/icon.png b/contrib/media/updf/android/res/drawable-hdpi/icon.png
new file mode 100644
index 000000000..1d47b2353
Binary files /dev/null and b/contrib/media/updf/android/res/drawable-hdpi/icon.png differ
diff --git a/contrib/media/updf/android/res/drawable-ldpi/icon.png b/contrib/media/updf/android/res/drawable-ldpi/icon.png
new file mode 100644
index 000000000..f9fe4d1c8
Binary files /dev/null and b/contrib/media/updf/android/res/drawable-ldpi/icon.png differ
diff --git a/contrib/media/updf/android/res/drawable-mdpi/icon.png b/contrib/media/updf/android/res/drawable-mdpi/icon.png
new file mode 100644
index 000000000..4bb3e7cd9
Binary files /dev/null and b/contrib/media/updf/android/res/drawable-mdpi/icon.png differ
diff --git a/contrib/media/updf/android/res/layout/main.xml b/contrib/media/updf/android/res/layout/main.xml
new file mode 100644
index 000000000..0da95fc50
--- /dev/null
+++ b/contrib/media/updf/android/res/layout/main.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/contrib/media/updf/android/res/values/strings.xml b/contrib/media/updf/android/res/values/strings.xml
new file mode 100644
index 000000000..ec3f9ae6f
--- /dev/null
+++ b/contrib/media/updf/android/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ MuPDF
+
diff --git a/contrib/media/updf/android/res/values/theme.xml b/contrib/media/updf/android/res/values/theme.xml
new file mode 100644
index 000000000..68c55644e
--- /dev/null
+++ b/contrib/media/updf/android/res/values/theme.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/contrib/media/updf/android/src/com/artifex/mupdf/MuPDFActivity.java b/contrib/media/updf/android/src/com/artifex/mupdf/MuPDFActivity.java
new file mode 100644
index 000000000..d5ba3bd8a
--- /dev/null
+++ b/contrib/media/updf/android/src/com/artifex/mupdf/MuPDFActivity.java
@@ -0,0 +1,162 @@
+package com.artifex.mupdf;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Environment;
+import android.view.*;
+import android.view.View.OnClickListener;
+import android.widget.*;
+import android.widget.LinearLayout.*;
+import java.io.File;
+
+import com.artifex.mupdf.PixmapView;
+
+public class MuPDFActivity extends Activity
+{
+ /* The core rendering instance */
+ private MuPDFCore core;
+
+ private MuPDFCore openFile()
+ {
+ String storageState = Environment.getExternalStorageState();
+ File path, file;
+ MuPDFCore core;
+
+ if (Environment.MEDIA_MOUNTED.equals(storageState))
+ {
+ System.out.println("Media mounted read/write");
+ }
+ else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(storageState))
+ {
+ System.out.println("Media mounted read only");
+ }
+ else
+ {
+ System.out.println("No media at all! Bale!\n");
+ return null;
+ }
+ path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ file = new File(path, "test.pdf");
+ System.out.println("Trying to open "+file.toString());
+ try
+ {
+ core = new MuPDFCore(file.toString());
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ return null;
+ }
+ return core;
+ }
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ PixmapView pixmapView;
+
+ if (core == null) {
+ core = (MuPDFCore)getLastNonConfigurationInstance();
+ }
+ if (core == null) {
+ core = openFile();
+ }
+ if (core == null)
+ {
+ /* FIXME: Error handling here! */
+ return;
+ }
+
+ pixmapView = new PixmapView(this, core);
+ super.onCreate(savedInstanceState);
+
+ /* Now create the UI */
+ RelativeLayout layout;
+ LinearLayout bar;
+ MyButtonHandler bh = new MyButtonHandler(pixmapView);
+
+ bar = new LinearLayout(this);
+ bar.setOrientation(LinearLayout.HORIZONTAL);
+ bh.buttonStart = new Button(this);
+ bh.buttonStart.setText("<<");
+ bh.buttonStart.setOnClickListener(bh);
+ bar.addView(bh.buttonStart);
+ bh.buttonPrev = new Button(this);
+ bh.buttonPrev.setText("<");
+ bh.buttonPrev.setOnClickListener(bh);
+ bar.addView(bh.buttonPrev);
+ bh.buttonNext = new Button(this);
+ bh.buttonNext.setText(">");
+ bh.buttonNext.setOnClickListener(bh);
+ bar.addView(bh.buttonNext);
+ bh.buttonEnd = new Button(this);
+ bh.buttonEnd.setText(">>");
+ bh.buttonEnd.setOnClickListener(bh);
+ bar.addView(bh.buttonEnd);
+
+ layout = new RelativeLayout(this);
+ layout.setLayoutParams(new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.FILL_PARENT,
+ RelativeLayout.LayoutParams.FILL_PARENT));
+ layout.setGravity(Gravity.FILL);
+
+ RelativeLayout.LayoutParams barParams =
+ new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.FILL_PARENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ barParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ bar.setId(100);
+ layout.addView(bar, barParams);
+
+ RelativeLayout.LayoutParams pixmapParams =
+ new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.FILL_PARENT,
+ RelativeLayout.LayoutParams.FILL_PARENT);
+ pixmapParams.addRule(RelativeLayout.ABOVE,100);
+ layout.addView(pixmapView, pixmapParams);
+
+ setContentView(layout);
+ }
+
+ public Object onRetainNonConfigurationInstance()
+ {
+ MuPDFCore mycore = core;
+ core = null;
+ return mycore;
+ }
+
+ public void onDestroy()
+ {
+ if (core != null)
+ core.onDestroy();
+ core = null;
+ super.onDestroy();
+ }
+
+ private class MyButtonHandler implements OnClickListener
+ {
+ Button buttonStart;
+ Button buttonPrev;
+ Button buttonNext;
+ Button buttonEnd;
+ PixmapView pixmapView;
+
+ public MyButtonHandler(PixmapView pixmapView)
+ {
+ this.pixmapView = pixmapView;
+ }
+
+ public void onClick(View v)
+ {
+ if (v == buttonStart)
+ pixmapView.changePage(Integer.MIN_VALUE);
+ else if (v == buttonPrev)
+ pixmapView.changePage(-1);
+ else if (v == buttonNext)
+ pixmapView.changePage(+1);
+ else if (v == buttonEnd)
+ pixmapView.changePage(Integer.MAX_VALUE);
+ }
+ }
+}
diff --git a/contrib/media/updf/android/src/com/artifex/mupdf/MuPDFCore.java b/contrib/media/updf/android/src/com/artifex/mupdf/MuPDFCore.java
new file mode 100644
index 000000000..321b4a649
--- /dev/null
+++ b/contrib/media/updf/android/src/com/artifex/mupdf/MuPDFCore.java
@@ -0,0 +1,54 @@
+package com.artifex.mupdf;
+import android.graphics.*;
+
+public class MuPDFCore
+{
+ /* load our native library */
+ static {
+ System.loadLibrary("mupdf");
+ }
+
+ /* Readable members */
+ public int pageNum;
+ public int numPages;
+ public float pageWidth;
+ public float pageHeight;
+
+ /* The native functions */
+ private static native int openFile(String filename);
+ private static native void gotoPageInternal(int localActionPageNum);
+ private static native float getPageWidth();
+ private static native float getPageHeight();
+ public static native void drawPage(Bitmap bitmap,
+ int pageW, int pageH,
+ int patchX, int patchY,
+ int patchW, int patchH);
+ public static native void destroying();
+
+ public MuPDFCore(String filename) throws Exception
+ {
+ numPages = openFile(filename);
+ if (numPages <= 0)
+ {
+ throw new Exception("Failed to open "+filename);
+ }
+ pageNum = 0;
+ }
+
+ /* Shim function */
+ public void gotoPage(int page)
+ {
+ if (page > numPages-1)
+ page = numPages-1;
+ else if (page < 0)
+ page = 0;
+ gotoPageInternal(page);
+ this.pageNum = page;
+ this.pageWidth = getPageWidth();
+ this.pageHeight = getPageHeight();
+ }
+
+ public void onDestroy() {
+ destroying();
+ }
+}
diff --git a/contrib/media/updf/android/src/com/artifex/mupdf/PixmapView.java b/contrib/media/updf/android/src/com/artifex/mupdf/PixmapView.java
new file mode 100644
index 000000000..73e73eda7
--- /dev/null
+++ b/contrib/media/updf/android/src/com/artifex/mupdf/PixmapView.java
@@ -0,0 +1,579 @@
+package com.artifex.mupdf;
+
+import android.app.*;
+import android.os.*;
+import android.content.*;
+import android.content.res.*;
+import android.graphics.*;
+import android.util.*;
+import android.view.*;
+import android.widget.*;
+import java.net.*;
+import java.io.*;
+
+public class PixmapView extends SurfaceView implements SurfaceHolder.Callback
+{
+ private SurfaceHolder holder;
+ private MuPDFThread thread = null;
+ private boolean threadStarted = false;
+ private MuPDFCore core;
+
+ /* Constructor */
+ public PixmapView(Context context, MuPDFCore core)
+ {
+ super(context);
+ System.out.println("PixmapView construct");
+ this.core = core;
+ holder = getHolder();
+ holder.addCallback(this);
+ thread = new MuPDFThread(holder, core);
+ setFocusable(true); // need to get the key events
+ }
+
+ /* load our native library */
+ static {
+ System.loadLibrary("mupdf");
+ }
+
+ /* Handlers for keys - so we can actually do stuff */
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ if (thread.onKeyDown(keyCode, event))
+ return true;
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event)
+ {
+ if (thread.onKeyUp(keyCode, event))
+ return true;
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event)
+ {
+ if (thread.onTouchEvent(event))
+ return true;
+ return super.onTouchEvent(event);
+ }
+
+ public void changePage(int delta)
+ {
+ thread.changePage(delta);
+ }
+
+ /* Handlers for SurfaceHolder callbacks; these are called when the
+ * surface is created/destroyed/changed. We need to ensure that we only
+ * draw into the surface between the created and destroyed calls.
+ * Therefore, we start/stop the thread that actually runs MuPDF on
+ * creation/destruction. */
+ public void surfaceCreated(SurfaceHolder holder)
+ {
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
+ {
+ thread.newScreenSize(width, height);
+ if (!threadStarted)
+ {
+ threadStarted = true;
+ thread.setRunning(true);
+ thread.start();
+ }
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder)
+ {
+ boolean retry = true;
+ System.out.println("Surface destroyed 1 this="+this);
+ thread.setRunning(false);
+ System.out.println("Surface destroyed 2");
+ while (retry)
+ {
+ try
+ {
+ thread.join();
+ retry = false;
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ threadStarted = false;
+ System.out.println("Surface destroyed 3");
+ }
+
+ class MuPDFThread extends Thread
+ {
+ private SurfaceHolder holder;
+ private boolean running = false;
+ private int keycode = -1;
+ private int screenWidth;
+ private int screenHeight;
+ private int screenGeneration;
+ private Bitmap bitmap;
+ private MuPDFCore core;
+
+ /* The following variables deal with the size of the current page;
+ * specifically, its position on the screen, its raw size, its
+ * current scale, and its current scaled size (in terms of whole
+ * pixels).
+ */
+ private int pageOriginX;
+ private int pageOriginY;
+ private float pageScale;
+ private int pageWidth;
+ private int pageHeight;
+
+ /* The following variables deal with the multitouch handling */
+ private final int NONE = 0;
+ private final int DRAG = 1;
+ private final int ZOOM = 2;
+ private int touchMode = NONE;
+ private float touchInitialSpacing;
+ private float touchDragStartX;
+ private float touchDragStartY;
+ private float touchInitialOriginX;
+ private float touchInitialOriginY;
+ private float touchInitialScale;
+ private PointF touchZoomMidpoint;
+
+ /* The following control the inner loop; other events etc cause
+ * action to be set. The inner loop runs around a tight loop
+ * performing the action requested of it.
+ */
+ private boolean wakeMe = false;
+ private int action;
+ private final int SLEEP = 0;
+ private final int REDRAW = 1;
+ private final int DIE = 2;
+ private final int GOTOPAGE = 3;
+ private int actionPageNum;
+
+ /* Members for blitting, declared here to avoid causing gcs */
+ private Rect srcRect;
+ private RectF dstRect;
+
+ public MuPDFThread(SurfaceHolder holder, MuPDFCore core)
+ {
+ this.holder = holder;
+ this.core = core;
+ touchZoomMidpoint = new PointF(0,0);
+ srcRect = new Rect(0,0,0,0);
+ dstRect = new RectF(0,0,0,0);
+ }
+
+ public void setRunning(boolean running)
+ {
+ this.running = running;
+ if (!running)
+ {
+ System.out.println("killing 1");
+ synchronized(this)
+ {
+ System.out.println("killing 2");
+ action = DIE;
+ if (wakeMe)
+ {
+ wakeMe = false;
+ System.out.println("killing 3");
+ this.notify();
+ System.out.println("killing 4");
+ }
+ }
+ }
+ }
+
+ public void newScreenSize(int width, int height)
+ {
+ this.screenWidth = width;
+ this.screenHeight = height;
+ this.screenGeneration++;
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent msg)
+ {
+ keycode = keyCode;
+ return false;
+ }
+
+ public boolean onKeyUp(int keyCode, KeyEvent msg)
+ {
+ return false;
+ }
+
+ public synchronized void changePage(int delta)
+ {
+ action = GOTOPAGE;
+ if (delta == Integer.MIN_VALUE)
+ actionPageNum = 0;
+ else if (delta == Integer.MAX_VALUE)
+ actionPageNum = core.numPages-1;
+ else
+ {
+ actionPageNum += delta;
+ if (actionPageNum < 0)
+ actionPageNum = 0;
+ if (actionPageNum > core.numPages-1)
+ actionPageNum = core.numPages-1;
+ }
+ if (wakeMe)
+ {
+ wakeMe = false;
+ this.notify();
+ }
+ }
+
+ private float spacing(MotionEvent event)
+ {
+ float x = event.getX(0) - event.getX(1);
+ float y = event.getY(0) - event.getY(1);
+ return FloatMath.sqrt(x*x+y*y);
+ }
+
+ private void midpoint(PointF point, MotionEvent event)
+ {
+ float x = event.getX(0) + event.getX(1);
+ float y = event.getY(0) + event.getY(1);
+ point.set(x/2, y/2);
+ }
+
+ private synchronized void forceRedraw()
+ {
+ if (wakeMe)
+ {
+ wakeMe = false;
+ this.notify();
+ }
+ action = REDRAW;
+ }
+
+ public synchronized void setPageOriginTo(int x, int y)
+ {
+ /* Adjust the coordinates so that the page always covers the
+ * centre of the screen. */
+ if (x + pageWidth < screenWidth/2)
+ {
+ x = screenWidth/2 - pageWidth;
+ }
+ else if (x > screenWidth/2)
+ {
+ x = screenWidth/2;
+ }
+ if (y + pageHeight < screenHeight/2)
+ {
+ y = screenHeight/2 - pageHeight;
+ }
+ else if (y > screenHeight/2)
+ {
+ y = screenHeight/2;
+ }
+ if ((x != pageOriginX) || (y != pageOriginY))
+ {
+ pageOriginX = x;
+ pageOriginY = y;
+ }
+ forceRedraw();
+ }
+
+ public void setPageScaleTo(float scale, PointF midpoint)
+ {
+ float x, y;
+ /* Convert midpoint (in screen coords) to page coords */
+ x = (midpoint.x - pageOriginX)/pageScale;
+ y = (midpoint.y - pageOriginY)/pageScale;
+ /* Find new scaled page sizes */
+ synchronized(this)
+ {
+ pageWidth = (int)(core.pageWidth*scale+0.5);
+ if (pageWidth < screenWidth/2)
+ {
+ scale = screenWidth/2/core.pageWidth;
+ pageWidth = (int)(core.pageWidth*scale+0.5);
+ }
+ pageHeight = (int)(core.pageHeight*scale+0.5);
+ if (pageHeight < screenHeight/2)
+ {
+ scale = screenHeight/2/core.pageHeight;
+ pageWidth = (int)(core.pageWidth *scale+0.5);
+ pageHeight = (int)(core.pageHeight*scale+0.5);
+ }
+ pageScale = scale;
+ /* Now given this new scale, calculate page origins so that
+ * x and y are at midpoint */
+ float xscale = (float)pageWidth /core.pageWidth;
+ float yscale = (float)pageHeight/core.pageHeight;
+ setPageOriginTo((int)(midpoint.x - x*xscale + 0.5),
+ (int)(midpoint.y - y*yscale + 0.5));
+ }
+ }
+
+ public void scalePageToScreen()
+ {
+ float scaleX, scaleY;
+ scaleX = (float)screenWidth /core.pageWidth;
+ scaleY = (float)screenHeight/core.pageHeight;
+ synchronized(this)
+ {
+ if (scaleX < scaleY)
+ pageScale = scaleX;
+ else
+ pageScale = scaleY;
+ pageWidth = (int)(core.pageWidth * pageScale + 0.5);
+ pageHeight = (int)(core.pageHeight * pageScale + 0.5);
+ pageOriginX = (screenWidth - pageWidth)/2;
+ pageOriginY = (screenHeight - pageHeight)/2;
+ forceRedraw();
+ }
+ System.out.println("scalePageToScreen: Raw="+
+ core.pageWidth+"x"+core.pageHeight+" scaled="+
+ pageWidth+","+pageHeight+" pageScale="+
+ pageScale);
+ }
+
+ public boolean onTouchEvent(MotionEvent event)
+ {
+ int action = event.getAction();
+ boolean done = false;
+ switch (action & MotionEvent.ACTION_MASK)
+ {
+ case MotionEvent.ACTION_DOWN:
+ touchMode = DRAG;
+ touchDragStartX = event.getX();
+ touchDragStartY = event.getY();
+ touchInitialOriginX = pageOriginX;
+ touchInitialOriginY = pageOriginY;
+ System.out.println("Starting dragging from: "+touchDragStartX+","+touchDragStartY+" ("+pageOriginX+","+pageOriginY+")");
+ done = true;
+ break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ touchInitialSpacing = spacing(event);
+ if (touchInitialSpacing > 10f)
+ {
+ System.out.println("Started zooming: spacing="+touchInitialSpacing);
+ touchInitialScale = pageScale;
+ touchMode = ZOOM;
+ done = true;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ if (touchMode != NONE)
+ {
+ System.out.println("Released!");
+ touchMode = NONE;
+ done = true;
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (touchMode == DRAG)
+ {
+ float x = touchInitialOriginX+event.getX()-touchDragStartX;
+ float y = touchInitialOriginY+event.getY()-touchDragStartY;
+ System.out.println("Dragged to "+x+","+y);
+ setPageOriginTo((int)(x+0.5),(int)(y+0.5));
+ done = true;
+ }
+ else if (touchMode == ZOOM)
+ {
+ float newSpacing = spacing(event);
+ if (newSpacing > 10f)
+ {
+ float newScale = touchInitialScale*newSpacing/touchInitialSpacing;
+ System.out.println("Zoomed to "+newSpacing);
+ midpoint(touchZoomMidpoint,event);
+ setPageScaleTo(newScale,touchZoomMidpoint);
+ done = true;
+ }
+ }
+ }
+ return done;
+ }
+
+ public void run()
+ {
+ boolean redraw = false;
+ int patchW = 0;
+ int patchH = 0;
+ int patchX = 0;
+ int patchY = 0;
+ int localPageW = 0;
+ int localPageH = 0;
+ int localScreenGeneration = screenGeneration;
+ int localAction;
+ int localActionPageNum = core.pageNum;
+
+ /* Set up our default action */
+ action = GOTOPAGE;
+ actionPageNum = core.pageNum;
+ while (action != DIE)
+ {
+ synchronized(this)
+ {
+ while (action == SLEEP)
+ {
+ wakeMe = true;
+ try
+ {
+ System.out.println("Render thread sleeping");
+ this.wait();
+ System.out.println("Render thread woken");
+ }
+ catch (java.lang.InterruptedException e)
+ {
+ System.out.println("Render thread exception:"+e);
+ }
+ }
+
+ /* Now we do as little as we can get away with while
+ * synchronised. In general this means copying any action
+ * or global variables into local ones so that when we
+ * unsynchronoise, other people can alter them again.
+ */
+ switch (action)
+ {
+ case DIE:
+ System.out.println("Woken to die!");
+ break;
+ case GOTOPAGE:
+ localActionPageNum = actionPageNum;
+ break;
+ case REDRAW:
+ /* Figure out what area of the page we want to
+ * redraw (in local variables, in docspace).
+ * We'll always draw a screensized lump, unless
+ * that's too big. */
+ System.out.println("page="+pageWidth+","+pageHeight+" ("+core.pageWidth+","+core.pageHeight+"@"+pageScale+") @ "+pageOriginX+","+pageOriginY);
+ localPageW = pageWidth;
+ localPageH = pageHeight;
+ patchW = pageWidth;
+ patchH = pageHeight;
+ patchX = -pageOriginX;
+ patchY = -pageOriginY;
+ if (patchX < 0)
+ patchX = 0;
+ if (patchW > screenWidth)
+ patchW = screenWidth;
+ srcRect.left = 0;
+ if (patchX+patchW > pageWidth)
+ {
+ srcRect.left += patchX+patchW-pageWidth;
+ patchX = pageWidth-patchW;
+ }
+ if (patchY < 0)
+ patchY = 0;
+ if (patchH > screenHeight)
+ patchH = screenHeight;
+ srcRect.top = 0;
+ if (patchY+patchH > pageHeight)
+ {
+ srcRect.top += patchY+patchH-pageHeight;
+ patchY = pageHeight-patchH;
+ }
+ dstRect.left = pageOriginX;
+ if (dstRect.left < 0)
+ dstRect.left = 0;
+ dstRect.top = pageOriginY;
+ if (dstRect.top < 0)
+ dstRect.top = 0;
+ dstRect.right = dstRect.left + patchW;
+ srcRect.right = srcRect.left + patchW;
+ if (srcRect.right > screenWidth)
+ {
+ dstRect.right -= srcRect.right-screenWidth;
+ srcRect.right = screenWidth;
+ }
+ if (dstRect.right > screenWidth)
+ {
+ srcRect.right -= dstRect.right-screenWidth;
+ dstRect.right = screenWidth;
+ }
+ dstRect.bottom = dstRect.top + patchH;
+ srcRect.bottom = srcRect.top + patchH;
+ if (srcRect.bottom > screenHeight)
+ {
+ dstRect.bottom -=srcRect.bottom-screenHeight;
+ srcRect.bottom = screenHeight;
+ }
+ if (dstRect.bottom > screenHeight)
+ {
+ srcRect.bottom -=dstRect.bottom-screenHeight;
+ dstRect.bottom = screenHeight;
+ }
+ System.out.println("patch=["+patchX+","+patchY+","+patchW+","+patchH+"]");
+ break;
+ }
+ localAction = action;
+ if (action != DIE)
+ action = SLEEP;
+ }
+
+ /* In the redraw case:
+ * pW, pH, pX, pY, localPageW, localPageH are now all set
+ * in local variables, and we are safe from the global vars
+ * being altered in calls from other threads. This is all
+ * the information we need to actually do our render.
+ */
+ switch (localAction)
+ {
+ case GOTOPAGE:
+ core.gotoPage(localActionPageNum);
+ scalePageToScreen();
+ action = REDRAW;
+ break;
+ case REDRAW:
+ if ((bitmap == null) ||
+ (bitmap.getWidth() != patchW) ||
+ (bitmap.getHeight() != patchH))
+ {
+ /* make bitmap of required size */
+ bitmap = Bitmap.createBitmap(patchW, patchH, Bitmap.Config.ARGB_8888);
+ }
+ System.out.println("Calling redraw native method");
+ core.drawPage(bitmap, localPageW, localPageH, patchX, patchY, patchW, patchH);
+ System.out.println("Called native method");
+ {
+ Canvas c = null;
+ try
+ {
+ c = holder.lockCanvas(null);
+ synchronized(holder)
+ {
+ if (localScreenGeneration == screenGeneration)
+ {
+ doDraw(c);
+ }
+ else
+ {
+ /* Someone has changed the screen
+ * under us! Better redraw again...
+ */
+ action = REDRAW;
+ }
+ }
+ }
+ finally
+ {
+ if (c != null)
+ holder.unlockCanvasAndPost(c);
+ }
+ }
+ }
+ }
+ }
+
+ protected void doDraw(Canvas canvas)
+ {
+ if ((canvas == null) || (bitmap == null))
+ return;
+ /* Clear the screen */
+ canvas.drawRGB(128,128,128);
+ /* Draw our bitmap on top */
+ System.out.println("Blitting bitmap from "+srcRect.left+","+srcRect.top+","+srcRect.right+","+srcRect.bottom+" to "+dstRect.left+","+dstRect.top+","+dstRect.right+","+dstRect.bottom);
+ canvas.drawBitmap(bitmap, srcRect, dstRect, (Paint)null);
+ }
+ }
+}
diff --git a/contrib/media/updf/apps/kos_main.c b/contrib/media/updf/apps/kos_main.c
new file mode 100644
index 000000000..2db5e277a
--- /dev/null
+++ b/contrib/media/updf/apps/kos_main.c
@@ -0,0 +1,333 @@
+#include
+#define _WIN32
+#include "fitz.h"
+#include "mupdf.h"
+#include "muxps.h"
+#include "pdfapp.h"
+
+
+
+static char Title[] = "some title";
+static char * filename = "/hd0/1/yand.pdf";
+static pdfapp_t gapp;
+
+void f65(unsigned x, unsigned y, unsigned w, unsigned h, char *d) //Вывод картинки
+{
+asm ("nop"::"c"(w*65536+h), "d"(x*65536+y), "b"(d));
+asm ("xor %eax, %eax");
+asm ("movl %eax, %ebp");
+asm ("pushl $32");
+asm ("popl %esi");
+asm ("int $0x40"::"a"(65));
+
+}
+
+ struct blit_call
+{
+ int dstx;
+ int dsty;
+ int w;
+ int h;
+
+ int srcx;
+ int srcy;
+ int srcw;
+ int srch;
+
+ unsigned char *d;
+ int stride;
+};
+
+void blit(int dstx, int dsty, int w, int h, int srcx, int srcy,int srcw, int srch, int stride, char *d) //Вызов ÑиÑфункции Blitter
+{
+
+struct blit_call image;
+ image.dstx=dstx;
+ image.dsty=dsty;
+ image.w=w;
+ image.h=h;
+ image.srcx=srcx;
+ image.srcy=srcy;
+ image.srcw=srcw;
+ image.srch=srch;
+ image.stride=stride;
+ image.d=d;
+
+
+asm ("int $0x40"::"a"(73),"b"(0),"c"(&image));
+
+}
+
+void winwarn(pdfapp_t *app, char *msg)
+{
+ fprintf(stderr, "mupdf: %s\n", msg);
+}
+
+void winerror(pdfapp_t *app, fz_error error)
+{
+ fz_catch(error, "aborting");
+ exit(1);
+}
+
+char *winpassword(pdfapp_t *app, char *filename)
+{
+ char *r = "";
+ return r;
+}
+
+
+void wincursor(pdfapp_t *app, int curs)
+{
+
+}
+
+void wintitle(pdfapp_t *app, char *s)
+{
+
+sprintf(Title,"uPDF: %s", s);
+}
+
+void winhelp(pdfapp_t *app)
+{
+
+}
+
+void winresize(pdfapp_t *app, int w, int h)
+{
+ //here should be something!!!
+
+
+}
+
+
+void windocopy(pdfapp_t *app)
+{
+}
+
+void winreloadfile(pdfapp_t *app)
+{
+ pdfapp_close(app);
+
+
+ pdfapp_open(app, filename, 0, 1);
+}
+
+void winopenuri(pdfapp_t *app, char *buf)
+{
+ /* here can be browser!
+ char *browser = getenv("BROWSER");
+ if (!browser)
+ browser = "open";
+ if (fork() == 0)
+ execlp(browser, browser, buf, (char*)0);
+ * */
+
+}
+
+
+
+void winclose(pdfapp_t *app)
+{
+ pdfapp_close(&gapp);
+ __menuet__sys_exit();
+}
+
+void kol_paint_bar(unsigned x, unsigned y, unsigned w, unsigned h, unsigned c)
+{
+asm ("int $0x40"::"a"(13), "b"(x*65536+w), "c"(y*65536+h), "d"(c));
+}
+
+
+static void winblit(pdfapp_t *app)
+{
+ char yoba[32];
+ int x0 = gapp.panx;
+ int y0 = gapp.pany;
+ int x1 = gapp.panx + gapp.image->w;
+ int y1 = gapp.pany + gapp.image->h;
+__menuet__debug_out(" Window blit\n");
+/*
+ XSetForeground(xdpy, xgc, xbgcolor.pixel);
+ fillrect(0, 0, x0, gapp.winh);
+ fillrect(x1, 0, gapp.winw - x1, gapp.winh);
+ fillrect(0, 0, gapp.winw, y0);
+ fillrect(0, y1, gapp.winw, gapp.winh - y1);*/
+ if (gapp.image->h-y0 > 0) {
+ kol_paint_bar(0, gapp.image->h-y0, 590, 368, 0xEFEFEF);
+}
+ /*kol_paint_bar(x1, 0, gapp.winw - x1, gapp.winh, 0x00FF00);
+ kol_paint_bar(0, 0, gapp.winw, y0, 0xFF0000);
+ kol_paint_bar(0, y1, gapp.winw, gapp.winh - y1, 0xFFFF);*/
+
+
+ /*XSetForeground(xdpy, xgc, xshcolor.pixel);
+ fillrect(x0+2, y1, gapp.image->w, 2);
+ fillrect(x1, y0+2, 2, gapp.image->h);*/
+sprintf (yoba, "%d x %d, %d x %d \n", gapp.image->w, gapp.image->h, gapp.winw, gapp.winh);
+__menuet__debug_out(yoba);
+
+
+ if (gapp.image->n == 4)
+ /*ximage_blit(xwin, xgc,
+ x0, y0,
+ gapp.image->samples,
+ 0, 0,
+ gapp.image->w,
+ gapp.image->h,
+ gapp.image->w * gapp.image->n);*/
+ // f65(x0,y0+32,gapp.image->w,gapp.image->h,gapp.image->samples);
+
+ blit(6, 24, 588, 368, x0, y0,gapp.image->w, gapp.image->h, gapp.image->w * gapp.image->n, gapp.image->samples);
+
+
+ else if (gapp.image->n == 2)
+ {
+ int i = gapp.image->w*gapp.image->h;
+ unsigned char *color = malloc(i*4);
+ if (color != NULL)
+ {
+ unsigned char *s = gapp.image->samples;
+ unsigned char *d = color;
+ for (; i > 0 ; i--)
+ {
+ d[2] = d[1] = d[0] = *s++;
+ d[3] = *s++;
+ d += 4;
+ }
+ /*ximage_blit(xwin, xgc,
+ x0, y0,
+ color,
+ 0, 0,
+ gapp.image->w,
+ gapp.image->h,
+ gapp.image->w * 4); */
+ //f65(x0,y0,gapp.image->w,gapp.image->h,color);
+ blit(6, 24, 588, 368, x0, y0,gapp.image->w, gapp.image->h, gapp.image->w * 4, color);
+ free(color);
+ }
+ }
+
+
+ __menuet__bar(0,0,600,20,0xFFFFFF);
+ __menuet__make_button(0,0,40,20,7,0x404040FF); //(posirion x, position y, width, height, id, color)
+ __menuet__write_text(5,4,0xFFFFFF,"Open",4);
+
+ __menuet__make_button(550,0,20,20,2,0x404040FF); //prev page
+ __menuet__write_text(555,3,0xFFFFFF,"<",1);
+
+ __menuet__make_button(570,0,20,20,3,0x404040FF); //nex page
+ __menuet__write_text(575,3,0xFFFFFF,">",1);
+
+ __menuet__make_button(40,0,20,20,4,0x404040FF); //show help
+ __menuet__write_text(45,3,0xFFFFFF,"?",1);
+
+ __menuet__make_button(60,0,20,20,5,0x404040FF); //magnify +
+ __menuet__write_text(65,3,0xFFFFFF,"+",1);
+
+ __menuet__make_button(80,0,20,20,6,0x404040FF); //magnify -
+ __menuet__write_text(85,3,0xFFFFFF,"-",1);
+
+ __menuet__make_button(570,20,20,20,8,0x404040FF); // move up
+ __menuet__write_text(575,3,0xFFFFFF,"^",1);
+
+ __menuet__make_button(570,360,20,20,9,0x404040FF); // move down
+ __menuet__write_text(575,363,0xFFFFFF,"v",1);
+
+ __menuet__make_button(100,0,20,20,10,0x404040FF); // rotate + 15 deg
+ __menuet__write_text(105,3,0xFFFFFF,"cw",1);
+
+ __menuet__make_button(120,0,20,20,11,0x404040FF); // rotate - 15 deg
+ __menuet__write_text(125,3,0xFFFFFF,"ccw",1);
+
+
+}
+
+void paint(void)
+{
+ __menuet__window_redraw(1);
+ //__menuet__define_window(10,10,600,400,0x64CFCFCF,0x800000FF,Title);
+ __menuet__define_window(10,10,600,400,0x73CFCFCF,0x800000FF,Title);
+ __menuet__bar(0,0,600,400,0xFFFFFF);
+ winblit(&gapp);
+ __menuet__window_redraw(2);
+ }
+
+void winrepaint(pdfapp_t *app)
+{
+ winblit(&gapp);
+}
+
+void winrepaintsearch(pdfapp_t *app)
+{
+ paint();
+ //search!
+}
+
+
+int main (void)
+{
+ char* original_command_line = *(char**)0x1C;
+ __menuet__debug_out(original_command_line);
+
+ char buf[128];
+ int resolution = 72;
+ int pageno = 1;
+ __menuet__debug_out("\nStarted\n");
+ fz_accelerate();
+ __menuet__debug_out("PDF init\n");
+ pdfapp_init(&gapp);
+ gapp.scrw = 600;
+ gapp.scrh = 400;
+ gapp.resolution = resolution;
+ gapp.pageno = pageno;
+ __menuet__debug_out("PDF Open\n");
+ pdfapp_open(&gapp, original_command_line, 0, 0);
+ __menuet__debug_out("PDF Opened\n");
+
+
+
+ int i;
+ int butt;
+
+ __menuet__debug_out("Inital paint\n");
+ pdfapp_onresize(&gapp, 600, 400);
+ paint();
+ for(;;)
+ {
+
+ i=__menuet__wait_for_event();
+ butt = __menuet__get_button_id();
+ if (gapp.image)
+ {
+
+ gapp.shrinkwrap = 0;
+ }
+ switch(i)
+ {
+ case 1:
+ paint();
+
+ continue;
+ case 2:
+ buf[0]=__menuet__getkey();
+ pdfapp_onkey(&gapp, buf[0]);
+ continue;
+ case 3:
+ if(butt==1) __menuet__sys_exit();//browse file
+ if(butt==2) pdfapp_onkey(&gapp, '['); //previous page
+ if(butt==3) pdfapp_onkey(&gapp, ']'); __menuet__debug_out("\nStarted\n"); //next page
+ if(butt==4) pdfapp_onkey(&gapp, '?'); //show help window
+ if(butt==5) pdfapp_onkey(&gapp, '+'); //magnify +
+ if(butt==6) pdfapp_onkey(&gapp, '-'); //mag -
+ if(butt==7) ;//mag open file
+ if(butt==8) pdfapp_onkey(&gapp, 'j'); //move up
+ if(butt==9) pdfapp_onkey(&gapp, 'k'); //move down
+ if(butt==10) pdfapp_onkey(&gapp, 'a'); //rotate +15 deg
+ if(butt==11) pdfapp_onkey(&gapp, 's'); //rotate -15deg
+ continue;
+
+ }
+ }
+ return 0;
+}
+
diff --git a/contrib/media/updf/apps/man/mupdf.1 b/contrib/media/updf/apps/man/mupdf.1
new file mode 100644
index 000000000..a4162a6ff
--- /dev/null
+++ b/contrib/media/updf/apps/man/mupdf.1
@@ -0,0 +1,86 @@
+.TH MUPDF 1 "March 15, 2010"
+.\" Please adjust this date whenever revising the manpage.
+.SH NAME
+mupdf \- MuPDF is a lightweight PDF viewer written in portable C
+.SH SYNOPSIS
+.B mupdf
+.RI [ options ] " PDFfile"
+.SH DESCRIPTION
+This manual page briefly describes the
+.B mupdf
+command.
+.PP
+.SH OPTIONS
+A description of each of the supported options is included below.
+.TP
+.B \-p password
+Uses the given password to open an encrypted PDF file.
+The password is tried both as user and owner password.
+.TP
+.B \-r resolution
+Changes the initial zoom level, specified as the resolution in dpi.
+The default value is 72.
+.SH MOUSE AND KEY BINDINGS
+In addition to the key bindings described below, the mouse can also be
+used. Clicking the left mouse button follows links within the PDF while
+dragging with the left mouse button pans the page. Dragging with the right
+mouse button selects an area and copies the enclosed text to the clipboard
+buffer. Using the scroll-wheel while pressing Control zooms in/out, if
+Shift is pressed on the other hand then the page is panned.
+.TP
+.B L, R
+Rotate page left (clockwise) or right (counter-clockwise).
+.TP
+.B h, j, k, l
+Scroll page left, down, up, or right.
+.TP
+.B \+, \-
+Zoom in or out.
+.TP
+.B w
+Shrinkwrap window to fit the page.
+.TP
+.B r
+Reload file.
+.TP
+.B . pgdn right space
+Go to the next page
+.TP
+.B , pgup left b
+Go to the previous page
+.TP
+.B <, >
+Skip back/forth 10 pages at a time.
+.TP
+.B m
+Mark page for snap back.
+.TP
+.B t
+Pop back to the latest mark.
+.TP
+.B [0-9]m
+Save the current page number in the numbered register.
+.TP
+.B [0-9]t
+Go to the page saved in the numbered register.
+.TP
+.B 123g
+Go to page 123.
+.TP
+.B /
+Search for text.
+.TP
+.B n, N
+Find the next/previous search result.
+.TP
+.B c
+Toggle between color and grayscale rendering.
+.SH SEE ALSO
+.BR pdfclean (1),
+.BR pdfdraw (1),
+.BR pdfshow (1).
+.SH AUTHOR
+MuPDF was written by Tor Andersson .
+MuPDF is Copyright 2006-2010 Artifex Software, Inc.
+.PP
+This manual page was written by Sebastian Rasmussen .
diff --git a/contrib/media/updf/apps/man/pdfclean.1 b/contrib/media/updf/apps/man/pdfclean.1
new file mode 100644
index 000000000..aa9047afe
--- /dev/null
+++ b/contrib/media/updf/apps/man/pdfclean.1
@@ -0,0 +1,39 @@
+.TH PDFCLEAN 1 "September 4, 2011"
+.\" Please adjust this date whenever revising the manpage.
+.SH NAME
+pdfclean \- pretty print, decompress and garbage collect PDF files
+.SH SYNOPSIS
+.B pdfclean
+.RI [ options ]
+.RI input.pdf
+.RI [ output.pdf ]
+.RI [ pages ]
+.SH DESCRIPTION
+.B pdfclean
+pretty prints and rewrites the contents of a PDF file.
+If no output file is specified, the new file will be written to "out.pdf" in
+the current directory.
+.PP
+.SH OPTIONS
+.TP
+.B \-p password
+Use the specified password if the file is encrypted.
+.TP
+.B \-g
+Garbage collect objects that have no references from other objects.
+Give the option twice to renumber all objects and compact the cross reference table.
+Give it three times to merge and reuse duplicate objects.
+.TP
+.B \-d
+Decompress streams. This will make the output file larger, but provides
+easy access for reading and editing the contents with a text editor.
+.TP
+.B pages
+Comma separated list of ranges to clean.
+.SH SEE ALSO
+.BR mupdf (1),
+.BR pdfdraw (1).
+.BR pdfshow (1).
+.SH AUTHOR
+MuPDF was written by Tor Andersson .
+MuPDF is Copyright 2006-2010 Artifex Software, Inc.
diff --git a/contrib/media/updf/apps/man/pdfdraw.1 b/contrib/media/updf/apps/man/pdfdraw.1
new file mode 100644
index 000000000..7fa0e81c0
--- /dev/null
+++ b/contrib/media/updf/apps/man/pdfdraw.1
@@ -0,0 +1,78 @@
+.TH PDFDRAW 1 "September 4, 2011"
+.\" Please adjust this date whenever revising the manpage.
+.SH NAME
+pdfdraw \- render PDF documents
+.SH SYNOPSIS
+.B pdfdraw
+.RI [ options ]
+.RI input.pdf
+.RI [ pages]
+.SH DESCRIPTION
+.B pdfdraw
+will render a PDF document to image files.
+The supported image formats are: pgm, ppm, pam and png.
+Select the pages to be rendered by specifying a comma
+separated list of ranges and individual page numbers (for example: 1,5,10-15).
+In no pages are specified all the pages will be rendered.
+.SH OPTIONS
+.TP
+.B \-o output
+The image format is deduced from the output file name.
+Embed %d in the name to indicate the page number (for example: "page%d.png").
+.TP
+.B \-p password
+Use the specified password if the file is encrypted.
+.TP
+.B \-r resolution
+Render the page at the specified resolution.
+The default resolution is 72 dpi.
+.TP
+.B \-R angle
+Rotate clockwise by given number of degrees.
+.TP
+.B \-a
+Save the alpha channel.
+The default behavior is to render each page with a white background.
+With this option, the page background is transparent.
+Only supported for pam and png output formats.
+.TP
+.B \-g
+Render in grayscale.
+The default is to render a full color RGB image.
+If the output format is pgm or ppm this option is ignored.
+.TP
+.B \-m
+Show timing information.
+Take the time it takes for each page to render and print
+a summary at the end.
+.TP
+.B \-5
+Print an MD5 checksum of the rendered image data for each page.
+.TP
+.B \-t
+Print the text contents of each page in UTF-8 encoding.
+Give the option twice to print detailed information
+about the location of each character in XML format.
+.TP
+.B \-x
+Print the display list used to render each page.
+.TP
+.B \-A
+Disable the use of accelerated functions.
+.TP
+.B \-G gamma
+Gamma correct the output image.
+Some typical values are 0.7 or 1.4 to thin or darken text rendering.
+.TP
+.B \-I
+Invert the output image colors.
+.TP
+.B pages
+Comma separated list of ranges to render.
+.SH SEE ALSO
+.BR mupdf (1),
+.BR pdfclean (1).
+.BR pdfshow (1).
+.SH AUTHOR
+MuPDF was written by Tor Andersson .
+MuPDF is Copyright 2006-2010 Artifex Software, Inc.
diff --git a/contrib/media/updf/apps/man/pdfshow.1 b/contrib/media/updf/apps/man/pdfshow.1
new file mode 100644
index 000000000..7574f297f
--- /dev/null
+++ b/contrib/media/updf/apps/man/pdfshow.1
@@ -0,0 +1,42 @@
+.TH PDFSHOW 1 "July 19, 2010"
+.\" Please adjust this date whenever revising the manpage.
+.SH NAME
+pdfshow \- show objects and streams that make up a PDF document
+.SH SYNOPSIS
+.B pdfshow
+.RI [ options ]
+.RI file.pdf
+.RI [ xref ]
+.RI [ trailer ]
+.RI [ pages ]
+.RI [ grep ]
+.RI [ object-number... ]
+.SH DESCRIPTION
+.B pdfshow
+pretty prints the objects and streams specified on the command line.
+Streams are decoded and non-printable characters are represented
+with a period.
+Specify objects with their number.
+The special names xref, trailer and pages will
+respectively print the cross reference, trailer,
+and the object numbers for all pages.
+The special name grep will print all objects in the file
+in a compact one-line format suitable for piping to grep.
+.PP
+.SH OPTIONS
+.TP
+.B \-b
+Print streams as binary data and omit the object header.
+.TP
+.B \-e
+Print streams in their original encoded form.
+.TP
+.B \-p password
+Use the specified password if the file is encrypted.
+.SH SEE ALSO
+.BR mupdf (1),
+.BR pdfclean (1).
+.BR pdfdraw (1).
+.SH AUTHOR
+MuPDF was written by Tor Andersson .
+MuPDF is copyright 2006-2010 Artifex Software, Inc.
diff --git a/contrib/media/updf/apps/mupdf_icon_antialias.ico b/contrib/media/updf/apps/mupdf_icon_antialias.ico
new file mode 100644
index 000000000..1397f4416
Binary files /dev/null and b/contrib/media/updf/apps/mupdf_icon_antialias.ico differ
diff --git a/contrib/media/updf/apps/mupdf_icon_bitmap.ico b/contrib/media/updf/apps/mupdf_icon_bitmap.ico
new file mode 100644
index 000000000..d1b0dc9c5
Binary files /dev/null and b/contrib/media/updf/apps/mupdf_icon_bitmap.ico differ
diff --git a/contrib/media/updf/apps/pdfapp.c b/contrib/media/updf/apps/pdfapp.c
new file mode 100644
index 000000000..513235bd9
--- /dev/null
+++ b/contrib/media/updf/apps/pdfapp.c
@@ -0,0 +1,1225 @@
+#include "fitz.h"
+#include "mupdf.h"
+#include "muxps.h"
+#include "pdfapp.h"
+
+#include /* for tolower() */
+
+#define ZOOMSTEP 1.142857
+#define BEYOND_THRESHHOLD 40
+
+enum panning
+{
+ DONT_PAN = 0,
+ PAN_TO_TOP,
+ PAN_TO_BOTTOM
+};
+
+static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint);
+
+static void pdfapp_warn(pdfapp_t *app, const char *fmt, ...)
+{
+ char buf[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+ winwarn(app, buf);
+}
+
+static void pdfapp_error(pdfapp_t *app, fz_error error)
+{
+ winerror(app, error);
+}
+
+char *pdfapp_version(pdfapp_t *app)
+{
+ return
+ "MuPDF 0.9\n"
+ "Copyright 2006-2011 Artifex Sofware, Inc.\n";
+}
+
+char *pdfapp_usage(pdfapp_t *app)
+{
+ return
+ "L\t\t-- rotate left\n"
+ "R\t\t-- rotate right\n"
+ "h\t\t-- scroll left\n"
+ "j down\t\t-- scroll down\n"
+ "k up\t\t-- scroll up\n"
+ "l\t\t-- scroll right\n"
+ "+\t\t-- zoom in\n"
+ "-\t\t-- zoom out\n"
+ "w\t\t-- shrinkwrap\n"
+ "r\t\t-- reload file\n"
+ ". pgdn right space\t-- next page\n"
+ ", pgup left b\t-- previous page\n"
+ ">\t\t-- next 10 pages\n"
+ "<\t\t-- back 10 pages\n"
+ "m\t\t-- mark page for snap back\n"
+ "t\t\t-- pop back to latest mark\n"
+ "1m\t\t-- mark page in register 1\n"
+ "1t\t\t-- go to page in register 1\n"
+ "123g\t\t-- go to page 123\n"
+ "/\t\t-- search for text\n"
+ "n\t\t-- find next search result\n"
+ "N\t\t-- find previous search result\n"
+ "c\t\t-- toggle between color and grayscale\n"
+ ;
+}
+
+void pdfapp_init(pdfapp_t *app)
+{
+ memset(app, 0, sizeof(pdfapp_t));
+ app->scrw = 640;
+ app->scrh = 480;
+ app->resolution = 72;
+}
+
+void pdfapp_invert(pdfapp_t *app, fz_bbox rect)
+{
+ unsigned char *p;
+ int x, y, n;
+
+ int x0 = CLAMP(rect.x0 - app->image->x, 0, app->image->w - 1);
+ int x1 = CLAMP(rect.x1 - app->image->x, 0, app->image->w - 1);
+ int y0 = CLAMP(rect.y0 - app->image->y, 0, app->image->h - 1);
+ int y1 = CLAMP(rect.y1 - app->image->y, 0, app->image->h - 1);
+
+ for (y = y0; y < y1; y++)
+ {
+ p = app->image->samples + (y * app->image->w + x0) * app->image->n;
+ for (x = x0; x < x1; x++)
+ {
+ for (n = app->image->n; n > 0; n--, p++)
+ *p = 255 - *p;
+ }
+ }
+}
+
+static void pdfapp_open_pdf(pdfapp_t *app, char *filename, int fd)
+{
+ fz_error error;
+ fz_stream *file;
+ char *password = "";
+ fz_obj *obj;
+ fz_obj *info;
+
+ /*
+ * Open PDF and load xref table
+ */
+__menuet__debug_out("FZ OPEN\n");
+ //file = fz_open_fd(fd);
+ __menuet__debug_out("FZ ready\n");
+ error = pdf_open_xref(&app->xref, filename, NULL);
+ if (error){
+ __menuet__debug_out("FZ can't open\n");
+ pdfapp_error(app, fz_rethrow(error, "cannot open document '%s'", filename));}
+ fz_close(file);
+
+ /*
+ * Handle encrypted PDF files
+ */
+/*
+ if (pdf_needs_password(app->xref))
+ {
+ int okay = pdf_authenticate_password(app->xref, password);
+ while (!okay)
+ {
+ password = winpassword(app, filename);
+ if (!password)
+ exit(1);
+ okay = pdf_authenticate_password(app->xref, password);
+ if (!okay)
+ pdfapp_warn(app, "Invalid password.");
+ }
+ }
+ * */
+
+ /*
+ * Load meta information
+ */
+
+/*
+ app->outline = pdf_load_outline(app->xref);
+
+ app->doctitle = filename;
+ if (strrchr(app->doctitle, '\\'))
+ app->doctitle = strrchr(app->doctitle, '\\') + 1;
+ if (strrchr(app->doctitle, '/'))
+ app->doctitle = strrchr(app->doctitle, '/') + 1;
+ info = fz_dict_gets(app->xref->trailer, "Info");
+ if (info)
+ {
+ obj = fz_dict_gets(info, "Title");
+ if (obj)
+ app->doctitle = pdf_to_utf8(obj);
+ } */
+
+ /*
+ * Start at first page
+ */
+ __menuet__debug_out("Start at first page\n");
+
+ error = pdf_load_page_tree(app->xref);
+ if (error) {
+ __menuet__debug_out("Can't load tree\n");
+ pdfapp_error(app, fz_rethrow(error, "cannot load page tree"));}
+
+__menuet__debug_out("Page counter\n");
+ app->pagecount = pdf_count_pages(app->xref);
+ __menuet__debug_out("All is set!\n");
+}
+
+static void pdfapp_open_xps(pdfapp_t *app, char *filename, int fd)
+{
+ fz_error error;
+ fz_stream *file;
+
+ file = fz_open_fd(fd);
+ error = xps_open_stream(&app->xps, file);
+ if (error)
+ pdfapp_error(app, fz_rethrow(error, "cannot open document '%s'", filename));
+ fz_close(file);
+
+ app->doctitle = filename;
+
+ app->pagecount = xps_count_pages(app->xps);
+}
+
+void pdfapp_open(pdfapp_t *app, char *filename, int fd, int reload)
+{
+ if (strstr(filename, ".xps") || strstr(filename, ".XPS") || strstr(filename, ".rels"))
+ pdfapp_open_xps(app, filename, fd);
+ else
+ pdfapp_open_pdf(app, filename, fd);
+
+ app->cache = fz_new_glyph_cache();
+
+ if (app->pageno < 1)
+ app->pageno = 1;
+ if (app->pageno > app->pagecount)
+ app->pageno = app->pagecount;
+ if (app->resolution < MINRES)
+ app->resolution = MINRES;
+ if (app->resolution > MAXRES)
+ app->resolution = MAXRES;
+
+ if (!reload)
+ {
+ app->shrinkwrap = 1;
+ app->rotate = 0;
+ app->panx = 0;
+ app->pany = 0;
+ }
+
+ pdfapp_showpage(app, 1, 1, 1);
+}
+
+void pdfapp_close(pdfapp_t *app)
+{
+ if (app->cache)
+ fz_free_glyph_cache(app->cache);
+ app->cache = NULL;
+
+ if (app->image)
+ fz_drop_pixmap(app->image);
+ app->image = NULL;
+
+ if (app->outline)
+ pdf_free_outline(app->outline);
+ app->outline = NULL;
+
+ if (app->xref)
+ {
+ if (app->xref->store)
+ pdf_free_store(app->xref->store);
+ app->xref->store = NULL;
+
+ pdf_free_xref(app->xref);
+ app->xref = NULL;
+ }
+
+ if (app->xps)
+ {
+ xps_free_context(app->xps);
+ app->xps = NULL;
+ }
+
+ fz_flush_warnings();
+}
+
+static fz_matrix pdfapp_viewctm(pdfapp_t *app)
+{
+ fz_matrix ctm;
+ ctm = fz_identity;
+ ctm = fz_concat(ctm, fz_translate(0, -app->page_bbox.y1));
+ if (app->xref)
+ ctm = fz_concat(ctm, fz_scale(app->resolution/72.0f, -app->resolution/72.0f));
+ else
+ ctm = fz_concat(ctm, fz_scale(app->resolution/96.0f, app->resolution/96.0f));
+ ctm = fz_concat(ctm, fz_rotate(app->rotate + app->page_rotate));
+ return ctm;
+}
+
+static void pdfapp_panview(pdfapp_t *app, int newx, int newy)
+{
+ if (newx < 0)
+ newx = 0;
+ if (newy < 0)
+ newy = 0;
+
+ if (newx + app->image->w < app->winw)
+ newx = app->winw - app->image->w;
+ if (newy + app->image->h < app->winh)
+ newy = app->winh - app->image->h;
+
+ if (app->winw >= app->image->w)
+ newx = (app->winw - app->image->w) / 2;
+ if (app->winh >= app->image->h)
+ newy = (app->winh - app->image->h) / 2;
+
+ if (newx != app->panx || newy != app->pany)
+ winrepaint(app);
+
+ if (newy > app->image->h) {
+
+ app->pageno++;
+
+
+ if (app->pageno > app->pagecount)
+ app->pageno = app->pagecount;
+
+
+ newy = 0;
+ app->pany = newy;
+
+ pdfapp_showpage(app, 1, 1, 1);
+ }
+
+ app->panx = newx;
+ app->pany = newy;
+}
+
+static void pdfapp_loadpage_pdf(pdfapp_t *app)
+{
+ pdf_page *page;
+ fz_error error;
+ fz_device *mdev;
+
+ error = pdf_load_page(&page, app->xref, app->pageno - 1);
+ if (error)
+ pdfapp_error(app, error);
+
+ app->page_bbox = page->mediabox;
+ app->page_rotate = page->rotate;
+ app->page_links = page->links;
+ page->links = NULL;
+
+ /* Create display list */
+ app->page_list = fz_new_display_list();
+ mdev = fz_new_list_device(app->page_list);
+ error = pdf_run_page(app->xref, page, mdev, fz_identity);
+ if (error)
+ {
+ error = fz_rethrow(error, "cannot draw page %d in '%s'", app->pageno, app->doctitle);
+ pdfapp_error(app, error);
+ }
+ fz_free_device(mdev);
+
+ pdf_free_page(page);
+
+ pdf_age_store(app->xref->store, 3);
+}
+
+static void pdfapp_loadpage_xps(pdfapp_t *app)
+{
+ xps_page *page;
+ fz_device *mdev;
+ fz_error error;
+
+ error = xps_load_page(&page, app->xps, app->pageno - 1);
+ if (error)
+ pdfapp_error(app, fz_rethrow(error, "cannot load page %d in file '%s'", app->pageno, app->doctitle));
+
+ app->page_bbox.x0 = 0;
+ app->page_bbox.y0 = 0;
+ app->page_bbox.x1 = page->width;
+ app->page_bbox.y1 = page->height;
+ app->page_rotate = 0;
+ app->page_links = NULL;
+
+ /* Create display list */
+ app->page_list = fz_new_display_list();
+ mdev = fz_new_list_device(app->page_list);
+ app->xps->dev = mdev;
+ xps_parse_fixed_page(app->xps, fz_identity, page);
+ app->xps->dev = NULL;
+ fz_free_device(mdev);
+
+ xps_free_page(app->xps, page);
+}
+
+static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint)
+{
+ char buf[256];
+ fz_device *idev;
+ fz_device *tdev;
+ fz_colorspace *colorspace;
+ fz_matrix ctm;
+ fz_bbox bbox;
+
+ wincursor(app, WAIT);
+
+ if (loadpage)
+ {
+ if (app->page_list)
+ fz_free_display_list(app->page_list);
+ if (app->page_text)
+ fz_free_text_span(app->page_text);
+ if (app->page_links)
+ pdf_free_link(app->page_links);
+
+ if (app->xref)
+ pdfapp_loadpage_pdf(app);
+ if (app->xps)
+ pdfapp_loadpage_xps(app);
+
+ /* Zero search hit position */
+ app->hit = -1;
+ app->hitlen = 0;
+
+ /* Extract text */
+ app->page_text = fz_new_text_span();
+ tdev = fz_new_text_device(app->page_text);
+ fz_execute_display_list(app->page_list, tdev, fz_identity, fz_infinite_bbox);
+ fz_free_device(tdev);
+ }
+
+ if (drawpage)
+ {
+ sprintf(buf, "%s - %d/%d (%d dpi)", app->doctitle,
+ app->pageno, app->pagecount, app->resolution);
+ wintitle(app, buf);
+
+ ctm = pdfapp_viewctm(app);
+ bbox = fz_round_rect(fz_transform_rect(ctm, app->page_bbox));
+
+ /* Draw */
+ if (app->image)
+ fz_drop_pixmap(app->image);
+ if (app->grayscale)
+ colorspace = fz_device_gray;
+ else
+//#ifdef _WIN32
+ colorspace = fz_device_bgr;
+//#else
+ // colorspace = fz_device_rgb;
+//#endif
+ app->image = fz_new_pixmap_with_rect(colorspace, bbox);
+ fz_clear_pixmap_with_color(app->image, 255);
+ idev = fz_new_draw_device(app->cache, app->image);
+ fz_execute_display_list(app->page_list, idev, ctm, bbox);
+ fz_free_device(idev);
+ }
+
+ if (repaint)
+ {
+ pdfapp_panview(app, app->panx, app->pany);
+
+ if (app->shrinkwrap)
+ {
+ __menuet__debug_out ("SHRINK\n");
+ int w = app->image->w;
+ int h = app->image->h;
+ if (app->winw == w)
+ app->panx = 0;
+ if (app->winh == h)
+ app->pany = 0;
+ if (w > app->scrw * 90 / 100)
+ w = app->scrw * 90 / 100;
+ if (h > app->scrh * 90 / 100)
+ h = app->scrh * 90 / 100;
+ if (w != app->winw || h != app->winh)
+ winresize(app, w, h);
+ }
+
+ winrepaint(app);
+
+ wincursor(app, ARROW);
+ }
+
+ fz_flush_warnings();
+}
+
+static void pdfapp_gotouri(pdfapp_t *app, fz_obj *uri)
+{
+ char *buf;
+ buf = fz_malloc(fz_to_str_len(uri) + 1);
+ memcpy(buf, fz_to_str_buf(uri), fz_to_str_len(uri));
+ buf[fz_to_str_len(uri)] = 0;
+ winopenuri(app, buf);
+ fz_free(buf);
+}
+
+static void pdfapp_gotopage(pdfapp_t *app, fz_obj *obj)
+{
+ int number;
+
+ number = pdf_find_page_number(app->xref, obj);
+ if (number < 0)
+ return;
+
+ if (app->histlen + 1 == 256)
+ {
+ memmove(app->hist, app->hist + 1, sizeof(int) * 255);
+ app->histlen --;
+ }
+ app->hist[app->histlen++] = app->pageno;
+ app->pageno = number + 1;
+ pdfapp_showpage(app, 1, 1, 1);
+}
+
+static inline fz_bbox bboxcharat(fz_text_span *span, int idx)
+{
+ int ofs = 0;
+ while (span)
+ {
+ if (idx < ofs + span->len)
+ return span->text[idx - ofs].bbox;
+ if (span->eol)
+ {
+ if (idx == ofs + span->len)
+ return fz_empty_bbox;
+ ofs ++;
+ }
+ ofs += span->len;
+ span = span->next;
+ }
+ return fz_empty_bbox;
+}
+
+void pdfapp_inverthit(pdfapp_t *app)
+{
+ fz_bbox hitbox, bbox;
+ fz_matrix ctm;
+ int i;
+
+ if (app->hit < 0)
+ return;
+
+ hitbox = fz_empty_bbox;
+ ctm = pdfapp_viewctm(app);
+
+ for (i = app->hit; i < app->hit + app->hitlen; i++)
+ {
+ bbox = bboxcharat(app->page_text, i);
+ if (fz_is_empty_rect(bbox))
+ {
+ if (!fz_is_empty_rect(hitbox))
+ pdfapp_invert(app, fz_transform_bbox(ctm, hitbox));
+ hitbox = fz_empty_bbox;
+ }
+ else
+ {
+ hitbox = fz_union_bbox(hitbox, bbox);
+ }
+ }
+
+ if (!fz_is_empty_rect(hitbox))
+ pdfapp_invert(app, fz_transform_bbox(ctm, hitbox));
+}
+
+static inline int charat(fz_text_span *span, int idx)
+{
+ int ofs = 0;
+ while (span)
+ {
+ if (idx < ofs + span->len)
+ return span->text[idx - ofs].c;
+ if (span->eol)
+ {
+ if (idx == ofs + span->len)
+ return ' ';
+ ofs ++;
+ }
+ ofs += span->len;
+ span = span->next;
+ }
+ return 0;
+}
+
+static int textlen(fz_text_span *span)
+{
+ int len = 0;
+ while (span)
+ {
+ len += span->len;
+ if (span->eol)
+ len ++;
+ span = span->next;
+ }
+ return len;
+}
+
+static int match(char *s, fz_text_span *span, int n)
+{
+ int orig = n;
+ int c;
+ while ((c = *s++))
+ {
+ if (c == ' ' && charat(span, n) == ' ')
+ {
+ while (charat(span, n) == ' ')
+ n++;
+ }
+ else
+ {
+ if (tolower(c) != tolower(charat(span, n)))
+ return 0;
+ n++;
+ }
+ }
+ return n - orig;
+}
+
+static void pdfapp_searchforward(pdfapp_t *app, enum panning *panto)
+{
+ int matchlen;
+ int test;
+ int len;
+ int startpage;
+
+ wincursor(app, WAIT);
+
+ startpage = app->pageno;
+
+ do
+ {
+ len = textlen(app->page_text);
+
+ if (app->hit >= 0)
+ test = app->hit + strlen(app->search);
+ else
+ test = 0;
+
+ while (test < len)
+ {
+ matchlen = match(app->search, app->page_text, test);
+ if (matchlen)
+ {
+ app->hit = test;
+ app->hitlen = matchlen;
+ wincursor(app, HAND);
+ winrepaint(app);
+ return;
+ }
+ test++;
+ }
+
+ app->pageno++;
+ if (app->pageno > app->pagecount)
+ app->pageno = 1;
+
+ pdfapp_showpage(app, 1, 0, 0);
+ *panto = PAN_TO_TOP;
+
+ } while (app->pageno != startpage);
+
+ if (app->pageno == startpage)
+ {
+ pdfapp_warn(app, "String '%s' not found.", app->search);
+ winrepaintsearch(app);
+ }
+ else
+ winrepaint(app);
+
+ wincursor(app, HAND);
+}
+
+static void pdfapp_searchbackward(pdfapp_t *app, enum panning *panto)
+{
+ int matchlen;
+ int test;
+ int len;
+ int startpage;
+
+ wincursor(app, WAIT);
+
+ startpage = app->pageno;
+
+ do
+ {
+ len = textlen(app->page_text);
+
+ if (app->hit >= 0)
+ test = app->hit - 1;
+ else
+ test = len;
+
+ while (test >= 0)
+ {
+ matchlen = match(app->search, app->page_text, test);
+ if (matchlen)
+ {
+ app->hit = test;
+ app->hitlen = matchlen;
+ wincursor(app, HAND);
+ winrepaint(app);
+ return;
+ }
+ test--;
+ }
+
+ app->pageno--;
+ if (app->pageno < 1)
+ app->pageno = app->pagecount;
+
+ pdfapp_showpage(app, 1, 0, 0);
+ *panto = PAN_TO_BOTTOM;
+
+ } while (app->pageno != startpage);
+
+ if (app->pageno == startpage)
+ {
+ pdfapp_warn(app, "String '%s' not found.", app->search);
+ winrepaintsearch(app);
+ }
+ else
+ winrepaint(app);
+
+ wincursor(app, HAND);
+}
+
+void pdfapp_onresize(pdfapp_t *app, int w, int h)
+{
+ if (app->winw != w || app->winh != h)
+ {
+ app->winw = w;
+ app->winh = h;
+ pdfapp_panview(app, app->panx, app->pany);
+ winrepaint(app);
+ }
+}
+
+void pdfapp_onkey(pdfapp_t *app, int c)
+{
+ int oldpage = app->pageno;
+ enum panning panto = PAN_TO_TOP;
+ int loadpage = 1;
+
+ if (app->isediting)
+ {
+ int n = strlen(app->search);
+ if (c < ' ')
+ {
+ if (c == '\b' && n > 0)
+ {
+ app->search[n - 1] = 0;
+ winrepaintsearch(app);
+ }
+ if (c == '\n' || c == '\r')
+ {
+ app->isediting = 0;
+ if (n > 0)
+ {
+ winrepaintsearch(app);
+ pdfapp_onkey(app, 'n');
+ }
+ else
+ winrepaint(app);
+ }
+ if (c == '\033')
+ {
+ app->isediting = 0;
+ winrepaint(app);
+ }
+ }
+ else
+ {
+ if (n + 2 < sizeof app->search)
+ {
+ app->search[n] = c;
+ app->search[n + 1] = 0;
+ winrepaintsearch(app);
+ }
+ }
+ return;
+ }
+
+ /*
+ * Save numbers typed for later
+ */
+
+ if (c >= '0' && c <= '9')
+ {
+ app->number[app->numberlen++] = c;
+ app->number[app->numberlen] = '\0';
+ }
+
+ switch (c)
+ {
+
+ case '?':
+ winhelp(app);
+ break;
+
+ case 'q':
+ winclose(app);
+ break;
+
+ /*
+ * Zoom and rotate
+ */
+
+ case '+':
+ case '=':
+ app->resolution *= ZOOMSTEP;
+ if (app->resolution > MAXRES)
+ app->resolution = MAXRES;
+ pdfapp_showpage(app, 0, 1, 1);
+ break;
+ case '-':
+ app->resolution /= ZOOMSTEP;
+ if (app->resolution < MINRES)
+ app->resolution = MINRES;
+ pdfapp_showpage(app, 0, 1, 1);
+ break;
+
+ case 'L':
+ app->rotate -= 90;
+ pdfapp_showpage(app, 0, 1, 1);
+ break;
+ case 'R':
+ app->rotate += 90;
+ pdfapp_showpage(app, 0, 1, 1);
+ break;
+
+ case 'c':
+ app->grayscale ^= 1;
+ pdfapp_showpage(app, 0, 1, 1);
+ break;
+
+#ifndef NDEBUG
+ case 'a':
+ app->rotate -= 15;
+ pdfapp_showpage(app, 0, 1, 1);
+ break;
+ case 's':
+ app->rotate += 15;
+ pdfapp_showpage(app, 0, 1, 1);
+ break;
+#endif
+
+ /*
+ * Pan view, but dont need to repaint image
+ */
+
+ case 'w':
+ app->shrinkwrap = 1;
+ app->panx = app->pany = 0;
+ pdfapp_showpage(app, 0, 0, 1);
+ break;
+
+ case 'h':
+ app->panx += app->image->w / 10;
+ pdfapp_showpage(app, 0, 0, 1);
+ break;
+
+ case 'j':
+ app->pany -= app->image->h / 10;
+ pdfapp_showpage(app, 0, 0, 1);
+ break;
+
+ case 'k':
+ app->pany += app->image->h / 10;
+ pdfapp_showpage(app, 0, 0, 1);
+ break;
+
+ case 'l':
+ app->panx -= app->image->w / 10;
+ pdfapp_showpage(app, 0, 0, 1);
+ break;
+
+ /*
+ * Page navigation
+ */
+
+ case 'g':
+ case '\n':
+ case '\r':
+ if (app->numberlen > 0)
+ app->pageno = atoi(app->number);
+ else
+ app->pageno = 1;
+ break;
+
+ case 'G':
+ app->pageno = app->pagecount;
+ break;
+
+ case 'm':
+ if (app->numberlen > 0)
+ {
+ int idx = atoi(app->number);
+
+ if (idx >= 0 && idx < nelem(app->marks))
+ app->marks[idx] = app->pageno;
+ }
+ else
+ {
+ if (app->histlen + 1 == 256)
+ {
+ memmove(app->hist, app->hist + 1, sizeof(int) * 255);
+ app->histlen --;
+ }
+ app->hist[app->histlen++] = app->pageno;
+ }
+ break;
+
+ case 't':
+ if (app->numberlen > 0)
+ {
+ int idx = atoi(app->number);
+
+ if (idx >= 0 && idx < nelem(app->marks))
+ if (app->marks[idx] > 0)
+ app->pageno = app->marks[idx];
+ }
+ else if (app->histlen > 0)
+ app->pageno = app->hist[--app->histlen];
+ break;
+
+ /*
+ * Back and forth ...
+ */
+
+ case ',':
+ panto = PAN_TO_BOTTOM;
+ if (app->numberlen > 0)
+ app->pageno -= atoi(app->number);
+ else
+ app->pageno--;
+ break;
+
+ case '.':
+ panto = PAN_TO_TOP;
+ if (app->numberlen > 0)
+ app->pageno += atoi(app->number);
+ else
+ app->pageno++;
+ break;
+
+ case 'b':
+ panto = DONT_PAN;
+ if (app->numberlen > 0)
+ app->pageno -= atoi(app->number);
+ else
+ app->pageno--;
+ break;
+
+ case ' ':
+ panto = DONT_PAN;
+ if (app->numberlen > 0)
+ app->pageno += atoi(app->number);
+ else
+ app->pageno++;
+ break;
+
+case ']':
+ panto = PAN_TO_TOP;
+ app->pageno++;
+ break;
+
+case '[':
+ panto = PAN_TO_TOP;
+ app->pageno--;
+ break;
+
+
+ case '<':
+ panto = PAN_TO_TOP;
+ app->pageno -= 10;
+ break;
+ case '>':
+ panto = PAN_TO_TOP;
+ app->pageno += 10;
+ break;
+
+ /*
+ * Reloading the file...
+ */
+
+ case 'r':
+ panto = DONT_PAN;
+ oldpage = -1;
+ winreloadfile(app);
+ break;
+
+ /*
+ * Searching
+ */
+
+ case '/':
+ app->isediting = 1;
+ app->search[0] = 0;
+ app->hit = -1;
+ app->hitlen = 0;
+ winrepaintsearch(app);
+ break;
+
+ case 'n':
+ pdfapp_searchforward(app, &panto);
+ loadpage = 0;
+ break;
+
+ case 'N':
+ pdfapp_searchbackward(app, &panto);
+ loadpage = 0;
+ break;
+
+ }
+
+ if (c < '0' || c > '9')
+ app->numberlen = 0;
+
+ if (app->pageno < 1)
+ app->pageno = 1;
+ if (app->pageno > app->pagecount)
+ app->pageno = app->pagecount;
+
+ if (app->pageno != oldpage)
+ {
+ switch (panto)
+ {
+ case PAN_TO_TOP:
+ app->pany = 0;
+ break;
+ case PAN_TO_BOTTOM:
+ app->pany = -2000;
+ break;
+ case DONT_PAN:
+ break;
+ }
+ pdfapp_showpage(app, loadpage, 1, 1);
+ }
+}
+
+void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state)
+{
+ pdf_link *link;
+ fz_matrix ctm;
+ fz_point p;
+
+ p.x = x - app->panx + app->image->x;
+ p.y = y - app->pany + app->image->y;
+
+ ctm = pdfapp_viewctm(app);
+ ctm = fz_invert_matrix(ctm);
+
+ p = fz_transform_point(ctm, p);
+
+ for (link = app->page_links; link; link = link->next)
+ {
+ if (p.x >= link->rect.x0 && p.x <= link->rect.x1)
+ if (p.y >= link->rect.y0 && p.y <= link->rect.y1)
+ break;
+ }
+
+ if (link)
+ {
+ wincursor(app, HAND);
+ if (btn == 1 && state == 1)
+ {
+ if (link->kind == PDF_LINK_URI)
+ pdfapp_gotouri(app, link->dest);
+ else if (link->kind == PDF_LINK_GOTO)
+ pdfapp_gotopage(app, fz_array_get(link->dest, 0)); /* [ pageobj ... ] */
+ return;
+ }
+ }
+ else
+ {
+ wincursor(app, ARROW);
+ }
+
+ if (state == 1)
+ {
+ if (btn == 1 && !app->iscopying)
+ {
+ app->ispanning = 1;
+ app->selx = x;
+ app->sely = y;
+ app->beyondy = 0;
+ }
+ if (btn == 3 && !app->ispanning)
+ {
+ app->iscopying = 1;
+ app->selx = x;
+ app->sely = y;
+ app->selr.x0 = x;
+ app->selr.x1 = x;
+ app->selr.y0 = y;
+ app->selr.y1 = y;
+ }
+ if (btn == 4 || btn == 5) /* scroll wheel */
+ {
+ int dir = btn == 4 ? 1 : -1;
+ app->ispanning = app->iscopying = 0;
+ if (modifiers & (1<<2))
+ {
+ /* zoom in/out if ctrl is pressed */
+ if (dir > 0)
+ app->resolution *= ZOOMSTEP;
+ else
+ app->resolution /= ZOOMSTEP;
+ if (app->resolution > MAXRES)
+ app->resolution = MAXRES;
+ if (app->resolution < MINRES)
+ app->resolution = MINRES;
+ pdfapp_showpage(app, 0, 1, 1);
+ }
+ else
+ {
+ /* scroll up/down, or left/right if
+ shift is pressed */
+ int isx = (modifiers & (1<<0));
+ int xstep = isx ? 20 * dir : 0;
+ int ystep = !isx ? 20 * dir : 0;
+ pdfapp_panview(app, app->panx + xstep, app->pany + ystep);
+ }
+ }
+ }
+
+ else if (state == -1)
+ {
+ if (app->iscopying)
+ {
+ app->iscopying = 0;
+ app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x;
+ app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x;
+ app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y;
+ app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y;
+ winrepaint(app);
+ if (app->selr.x0 < app->selr.x1 && app->selr.y0 < app->selr.y1)
+ windocopy(app);
+ }
+ if (app->ispanning)
+ app->ispanning = 0;
+ }
+
+ else if (app->ispanning)
+ {
+ int newx = app->panx + x - app->selx;
+ int newy = app->pany + y - app->sely;
+ /* Scrolling beyond limits implies flipping pages */
+ /* Are we requested to scroll beyond limits? */
+ if (newy + app->image->h < app->winh || newy > 0)
+ {
+ /* Yes. We can assume that deltay != 0 */
+ int deltay = y - app->sely;
+ /* Check whether the panning has occured in the
+ * direction that we are already crossing the
+ * limit it. If not, we can conclude that we
+ * have switched ends of the page and will thus
+ * start over counting.
+ */
+ if( app->beyondy == 0 || (app->beyondy ^ deltay) >= 0 )
+ {
+ /* Updating how far we are beyond and
+ * flipping pages if beyond threshhold
+ */
+ app->beyondy += deltay;
+ if (app->beyondy > BEYOND_THRESHHOLD)
+ {
+ if( app->pageno > 1 )
+ {
+ app->pageno--;
+ pdfapp_showpage(app, 1, 1, 1);
+ newy = -app->image->h;
+ }
+ app->beyondy = 0;
+ }
+ else if (app->beyondy < -BEYOND_THRESHHOLD)
+ {
+ if( app->pageno < app->pagecount )
+ {
+ app->pageno++;
+ pdfapp_showpage(app, 1, 1, 1);
+ newy = 0;
+ }
+ app->beyondy = 0;
+ }
+ }
+ else
+ app->beyondy = 0;
+ }
+ /* Although at this point we've already determined that
+ * or that no scrolling will be performed in
+ * y-direction, the x-direction has not yet been taken
+ * care off. Therefore
+ */
+ pdfapp_panview(app, newx, newy);
+
+ app->selx = x;
+ app->sely = y;
+ }
+
+ else if (app->iscopying)
+ {
+ app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x;
+ app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x;
+ app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y;
+ app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y;
+ winrepaint(app);
+ }
+
+}
+
+void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen)
+{
+ fz_bbox hitbox;
+ fz_matrix ctm;
+ fz_text_span *span;
+ int c, i, p;
+ int seen;
+
+ int x0 = app->selr.x0;
+ int x1 = app->selr.x1;
+ int y0 = app->selr.y0;
+ int y1 = app->selr.y1;
+
+ ctm = pdfapp_viewctm(app);
+
+ p = 0;
+ for (span = app->page_text; span; span = span->next)
+ {
+ seen = 0;
+
+ for (i = 0; i < span->len; i++)
+ {
+ hitbox = fz_transform_bbox(ctm, span->text[i].bbox);
+ c = span->text[i].c;
+ if (c < 32)
+ c = '?';
+ if (hitbox.x1 >= x0 && hitbox.x0 <= x1 && hitbox.y1 >= y0 && hitbox.y0 <= y1)
+ {
+ if (p < ucslen - 1)
+ ucsbuf[p++] = c;
+ seen = 1;
+ }
+ }
+
+ if (seen && span->eol)
+ {
+#ifdef _WIN32
+ if (p < ucslen - 1)
+ ucsbuf[p++] = '\r';
+#endif
+ if (p < ucslen - 1)
+ ucsbuf[p++] = '\n';
+ }
+ }
+
+ ucsbuf[p] = 0;
+}
diff --git a/contrib/media/updf/apps/pdfapp.h b/contrib/media/updf/apps/pdfapp.h
new file mode 100644
index 000000000..732d637cb
--- /dev/null
+++ b/contrib/media/updf/apps/pdfapp.h
@@ -0,0 +1,105 @@
+/*
+ * Utility object for handling a pdf application / view
+ * Takes care of PDF loading and displaying and navigation,
+ * uses a number of callbacks to the GUI app.
+ */
+
+#define MINRES 54
+#define MAXRES 300
+
+typedef struct pdfapp_s pdfapp_t;
+
+enum { ARROW, HAND, WAIT };
+
+extern void winwarn(pdfapp_t*, char *s);
+extern void winerror(pdfapp_t*, fz_error error);
+extern void wintitle(pdfapp_t*, char *title);
+extern void winresize(pdfapp_t*, int w, int h);
+extern void winrepaint(pdfapp_t*);
+extern void winrepaintsearch(pdfapp_t*);
+extern char *winpassword(pdfapp_t*, char *filename);
+extern void winopenuri(pdfapp_t*, char *s);
+extern void wincursor(pdfapp_t*, int curs);
+extern void windocopy(pdfapp_t*);
+extern void winreloadfile(pdfapp_t*);
+extern void windrawstring(pdfapp_t*, int x, int y, char *s);
+extern void winclose(pdfapp_t*);
+extern void winhelp(pdfapp_t*);
+
+struct pdfapp_s
+{
+ /* current document params */
+ char *doctitle;
+ pdf_xref *xref;
+ pdf_outline *outline;
+ xps_context *xps;
+
+ int pagecount;
+ fz_glyph_cache *cache;
+
+ /* current view params */
+ int resolution;
+ int rotate;
+ fz_pixmap *image;
+ int grayscale;
+
+ /* current page params */
+ int pageno;
+ fz_rect page_bbox;
+ float page_rotate;
+ fz_display_list *page_list;
+ fz_text_span *page_text;
+ pdf_link *page_links;
+
+ /* snapback history */
+ int hist[256];
+ int histlen;
+ int marks[10];
+
+ /* window system sizes */
+ int winw, winh;
+ int scrw, scrh;
+ int shrinkwrap;
+
+ /* event handling state */
+ char number[256];
+ int numberlen;
+
+ int ispanning;
+ int panx, pany;
+
+ int iscopying;
+ int selx, sely;
+ /* TODO - While sely keeps track of the relative change in
+ * cursor position between two ticks/events, beyondy shall keep
+ * track of the relative change in cursor position from the
+ * point where the user hits a scrolling limit. This is ugly.
+ * Used in pdfapp.c:pdfapp_onmouse.
+ */
+ int beyondy;
+ fz_bbox selr;
+
+ /* search state */
+ int isediting;
+ char search[512];
+ int hit;
+ int hitlen;
+
+ /* client context storage */
+ void *userdata;
+};
+
+void pdfapp_init(pdfapp_t *app);
+void pdfapp_open(pdfapp_t *app, char *filename, int fd, int reload);
+void pdfapp_close(pdfapp_t *app);
+
+char *pdfapp_version(pdfapp_t *app);
+char *pdfapp_usage(pdfapp_t *app);
+
+void pdfapp_onkey(pdfapp_t *app, int c);
+void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state);
+void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen);
+void pdfapp_onresize(pdfapp_t *app, int w, int h);
+
+void pdfapp_invert(pdfapp_t *app, fz_bbox rect);
+void pdfapp_inverthit(pdfapp_t *app);
diff --git a/contrib/media/updf/apps/pdfclean.c b/contrib/media/updf/apps/pdfclean.c
new file mode 100644
index 000000000..dd85b1a40
--- /dev/null
+++ b/contrib/media/updf/apps/pdfclean.c
@@ -0,0 +1,775 @@
+/*
+ * PDF cleaning tool: general purpose pdf syntax washer.
+ *
+ * Rewrite PDF with pretty printed objects.
+ * Garbage collect unreachable objects.
+ * Inflate compressed streams.
+ * Create subset documents.
+ *
+ * TODO: linearize document for fast web view
+ */
+
+#include "fitz.h"
+#include "mupdf.h"
+
+static FILE *out = NULL;
+
+static char *uselist = NULL;
+static int *ofslist = NULL;
+static int *genlist = NULL;
+static int *renumbermap = NULL;
+
+static int dogarbage = 0;
+static int doexpand = 0;
+static int doascii = 0;
+
+static pdf_xref *xref = NULL;
+
+void die(fz_error error)
+{
+ fz_catch(error, "aborting");
+ if (xref)
+ pdf_free_xref(xref);
+ exit(1);
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "usage: pdfclean [options] input.pdf [output.pdf] [pages]\n"
+ "\t-p -\tpassword\n"
+ "\t-g\tgarbage collect unused objects\n"
+ "\t-gg\tin addition to -g compact xref table\n"
+ "\t-ggg\tin addition to -gg merge duplicate objects\n"
+ "\t-d\tdecompress streams\n"
+ "\t-a\tascii hex encode binary streams\n"
+ "\tpages\tcomma separated list of ranges\n");
+ exit(1);
+}
+
+/*
+ * Garbage collect objects not reachable from the trailer.
+ */
+
+static void sweepref(fz_obj *ref);
+
+static void sweepobj(fz_obj *obj)
+{
+ int i;
+
+ if (fz_is_indirect(obj))
+ sweepref(obj);
+
+ else if (fz_is_dict(obj))
+ for (i = 0; i < fz_dict_len(obj); i++)
+ sweepobj(fz_dict_get_val(obj, i));
+
+ else if (fz_is_array(obj))
+ for (i = 0; i < fz_array_len(obj); i++)
+ sweepobj(fz_array_get(obj, i));
+}
+
+static void sweepref(fz_obj *obj)
+{
+ int num = fz_to_num(obj);
+ int gen = fz_to_gen(obj);
+
+ if (num < 0 || num >= xref->len)
+ return;
+ if (uselist[num])
+ return;
+
+ uselist[num] = 1;
+
+ /* Bake in /Length in stream objects */
+ if (pdf_is_stream(xref, num, gen))
+ {
+ fz_obj *len = fz_dict_gets(obj, "Length");
+ if (fz_is_indirect(len))
+ {
+ uselist[fz_to_num(len)] = 0;
+ len = fz_resolve_indirect(len);
+ fz_dict_puts(obj, "Length", len);
+ }
+ }
+
+ sweepobj(fz_resolve_indirect(obj));
+}
+
+/*
+ * Scan for and remove duplicate objects (slow)
+ */
+
+static void removeduplicateobjs(void)
+{
+ int num, other;
+
+ for (num = 1; num < xref->len; num++)
+ {
+ /* Only compare an object to objects preceeding it */
+ for (other = 1; other < num; other++)
+ {
+ fz_obj *a, *b;
+
+ if (num == other || !uselist[num] || !uselist[other])
+ continue;
+
+ /*
+ * Comparing stream objects data contents would take too long.
+ *
+ * pdf_is_stream calls pdf_cache_object and ensures
+ * that the xref table has the objects loaded.
+ */
+ if (pdf_is_stream(xref, num, 0) || pdf_is_stream(xref, other, 0))
+ continue;
+
+ a = xref->table[num].obj;
+ b = xref->table[other].obj;
+
+ a = fz_resolve_indirect(a);
+ b = fz_resolve_indirect(b);
+
+ if (fz_objcmp(a, b))
+ continue;
+
+ /* Keep the lowest numbered object */
+ renumbermap[num] = MIN(num, other);
+ renumbermap[other] = MIN(num, other);
+ uselist[MAX(num, other)] = 0;
+
+ /* One duplicate was found, do not look for another */
+ break;
+ }
+ }
+}
+
+/*
+ * Renumber objects sequentially so the xref is more compact
+ */
+
+static void compactxref(void)
+{
+ int num, newnum;
+
+ /*
+ * Update renumbermap in-place, clustering all used
+ * objects together at low object ids. Objects that
+ * already should be renumbered will have their new
+ * object ids be updated to reflect the compaction.
+ */
+
+ newnum = 1;
+ for (num = 1; num < xref->len; num++)
+ {
+ if (uselist[num] && renumbermap[num] == num)
+ renumbermap[num] = newnum++;
+ else if (renumbermap[num] != num)
+ renumbermap[num] = renumbermap[renumbermap[num]];
+ }
+}
+
+/*
+ * Update indirect objects according to renumbering established when
+ * removing duplicate objects and compacting the xref.
+ */
+
+static void renumberobj(fz_obj *obj)
+{
+ int i;
+
+ if (fz_is_dict(obj))
+ {
+ for (i = 0; i < fz_dict_len(obj); i++)
+ {
+ fz_obj *key = fz_dict_get_key(obj, i);
+ fz_obj *val = fz_dict_get_val(obj, i);
+ if (fz_is_indirect(val))
+ {
+ val = fz_new_indirect(renumbermap[fz_to_num(val)], 0, xref);
+ fz_dict_put(obj, key, val);
+ fz_drop_obj(val);
+ }
+ else
+ {
+ renumberobj(val);
+ }
+ }
+ }
+
+ else if (fz_is_array(obj))
+ {
+ for (i = 0; i < fz_array_len(obj); i++)
+ {
+ fz_obj *val = fz_array_get(obj, i);
+ if (fz_is_indirect(val))
+ {
+ val = fz_new_indirect(renumbermap[fz_to_num(val)], 0, xref);
+ fz_array_put(obj, i, val);
+ fz_drop_obj(val);
+ }
+ else
+ {
+ renumberobj(val);
+ }
+ }
+ }
+}
+
+static void renumberobjs(void)
+{
+ pdf_xref_entry *oldxref;
+ int newlen;
+ int num;
+
+ /* Apply renumber map to indirect references in all objects in xref */
+ renumberobj(xref->trailer);
+ for (num = 0; num < xref->len; num++)
+ {
+ fz_obj *obj = xref->table[num].obj;
+
+ if (fz_is_indirect(obj))
+ {
+ obj = fz_new_indirect(renumbermap[fz_to_num(obj)], 0, xref);
+ pdf_update_object(xref, num, 0, obj);
+ fz_drop_obj(obj);
+ }
+ else
+ {
+ renumberobj(obj);
+ }
+ }
+
+ /* Create new table for the reordered, compacted xref */
+ oldxref = xref->table;
+ xref->table = fz_calloc(xref->len, sizeof(pdf_xref_entry));
+ xref->table[0] = oldxref[0];
+
+ /* Move used objects into the new compacted xref */
+ newlen = 0;
+ for (num = 1; num < xref->len; num++)
+ {
+ if (uselist[num])
+ {
+ if (newlen < renumbermap[num])
+ newlen = renumbermap[num];
+ xref->table[renumbermap[num]] = oldxref[num];
+ }
+ else
+ {
+ if (oldxref[num].obj)
+ fz_drop_obj(oldxref[num].obj);
+ }
+ }
+
+ fz_free(oldxref);
+
+ /* Update the used objects count in compacted xref */
+ xref->len = newlen + 1;
+
+ /* Update list of used objects to fit with compacted xref */
+ for (num = 1; num < xref->len; num++)
+ uselist[num] = 1;
+}
+
+/*
+ * Recreate page tree to only retain specified pages.
+ */
+
+static void retainpages(int argc, char **argv)
+{
+ fz_error error;
+ fz_obj *oldroot, *root, *pages, *kids, *countobj, *parent;
+
+ /* Load the old page tree */
+ error = pdf_load_page_tree(xref);
+ if (error)
+ die(fz_rethrow(error, "cannot load page tree"));
+
+ /* Keep only pages/type entry to avoid references to unretained pages */
+ oldroot = fz_dict_gets(xref->trailer, "Root");
+ pages = fz_dict_gets(oldroot, "Pages");
+
+ root = fz_new_dict(2);
+ fz_dict_puts(root, "Type", fz_dict_gets(oldroot, "Type"));
+ fz_dict_puts(root, "Pages", fz_dict_gets(oldroot, "Pages"));
+
+ pdf_update_object(xref, fz_to_num(oldroot), fz_to_gen(oldroot), root);
+
+ fz_drop_obj(root);
+
+ /* Create a new kids array with only the pages we want to keep */
+ parent = fz_new_indirect(fz_to_num(pages), fz_to_gen(pages), xref);
+ kids = fz_new_array(1);
+
+ /* Retain pages specified */
+ while (argc - fz_optind)
+ {
+ int page, spage, epage;
+ char *spec, *dash;
+ char *pagelist = argv[fz_optind];
+
+ spec = fz_strsep(&pagelist, ",");
+ while (spec)
+ {
+ dash = strchr(spec, '-');
+
+ if (dash == spec)
+ spage = epage = pdf_count_pages(xref);
+ else
+ spage = epage = atoi(spec);
+
+ if (dash)
+ {
+ if (strlen(dash) > 1)
+ epage = atoi(dash + 1);
+ else
+ epage = pdf_count_pages(xref);
+ }
+
+ if (spage > epage)
+ page = spage, spage = epage, epage = page;
+
+ if (spage < 1)
+ spage = 1;
+ if (epage > pdf_count_pages(xref))
+ epage = pdf_count_pages(xref);
+
+ for (page = spage; page <= epage; page++)
+ {
+ fz_obj *pageobj = xref->page_objs[page-1];
+ fz_obj *pageref = xref->page_refs[page-1];
+
+ fz_dict_puts(pageobj, "Parent", parent);
+
+ /* Store page object in new kids array */
+ fz_array_push(kids, pageref);
+ }
+
+ spec = fz_strsep(&pagelist, ",");
+ }
+
+ fz_optind++;
+ }
+
+ fz_drop_obj(parent);
+
+ /* Update page count and kids array */
+ countobj = fz_new_int(fz_array_len(kids));
+ fz_dict_puts(pages, "Count", countobj);
+ fz_drop_obj(countobj);
+ fz_dict_puts(pages, "Kids", kids);
+ fz_drop_obj(kids);
+}
+
+/*
+ * Make sure we have loaded objects from object streams.
+ */
+
+static void preloadobjstms(void)
+{
+ fz_error error;
+ fz_obj *obj;
+ int num;
+
+ for (num = 0; num < xref->len; num++)
+ {
+ if (xref->table[num].type == 'o')
+ {
+ error = pdf_load_object(&obj, xref, num, 0);
+ if (error)
+ die(error);
+ fz_drop_obj(obj);
+ }
+ }
+}
+
+/*
+ * Save streams and objects to the output
+ */
+
+static inline int isbinary(int c)
+{
+ if (c == '\n' || c == '\r' || c == '\t')
+ return 0;
+ return c < 32 || c > 127;
+}
+
+static int isbinarystream(fz_buffer *buf)
+{
+ int i;
+ for (i = 0; i < buf->len; i++)
+ if (isbinary(buf->data[i]))
+ return 1;
+ return 0;
+}
+
+static fz_buffer *hexbuf(unsigned char *p, int n)
+{
+ static const char hex[16] = "0123456789abcdef";
+ fz_buffer *buf;
+ int x = 0;
+
+ buf = fz_new_buffer(n * 2 + (n / 32) + 2);
+
+ while (n--)
+ {
+ buf->data[buf->len++] = hex[*p >> 4];
+ buf->data[buf->len++] = hex[*p & 15];
+ if (++x == 32)
+ {
+ buf->data[buf->len++] = '\n';
+ x = 0;
+ }
+ p++;
+ }
+
+ buf->data[buf->len++] = '>';
+ buf->data[buf->len++] = '\n';
+
+ return buf;
+}
+
+static void addhexfilter(fz_obj *dict)
+{
+ fz_obj *f, *dp, *newf, *newdp;
+ fz_obj *ahx, *nullobj;
+
+ ahx = fz_new_name("ASCIIHexDecode");
+ nullobj = fz_new_null();
+ newf = newdp = NULL;
+
+ f = fz_dict_gets(dict, "Filter");
+ dp = fz_dict_gets(dict, "DecodeParms");
+
+ if (fz_is_name(f))
+ {
+ newf = fz_new_array(2);
+ fz_array_push(newf, ahx);
+ fz_array_push(newf, f);
+ f = newf;
+ if (fz_is_dict(dp))
+ {
+ newdp = fz_new_array(2);
+ fz_array_push(newdp, nullobj);
+ fz_array_push(newdp, dp);
+ dp = newdp;
+ }
+ }
+ else if (fz_is_array(f))
+ {
+ fz_array_insert(f, ahx);
+ if (fz_is_array(dp))
+ fz_array_insert(dp, nullobj);
+ }
+ else
+ f = ahx;
+
+ fz_dict_puts(dict, "Filter", f);
+ if (dp)
+ fz_dict_puts(dict, "DecodeParms", dp);
+
+ fz_drop_obj(ahx);
+ fz_drop_obj(nullobj);
+ if (newf)
+ fz_drop_obj(newf);
+ if (newdp)
+ fz_drop_obj(newdp);
+}
+
+static void copystream(fz_obj *obj, int num, int gen)
+{
+ fz_error error;
+ fz_buffer *buf, *tmp;
+ fz_obj *newlen;
+
+ error = pdf_load_raw_stream(&buf, xref, num, gen);
+ if (error)
+ die(error);
+
+ if (doascii && isbinarystream(buf))
+ {
+ tmp = hexbuf(buf->data, buf->len);
+ fz_drop_buffer(buf);
+ buf = tmp;
+
+ addhexfilter(obj);
+
+ newlen = fz_new_int(buf->len);
+ fz_dict_puts(obj, "Length", newlen);
+ fz_drop_obj(newlen);
+ }
+
+ fprintf(out, "%d %d obj\n", num, gen);
+ fz_fprint_obj(out, obj, !doexpand);
+ fprintf(out, "stream\n");
+ fwrite(buf->data, 1, buf->len, out);
+ fprintf(out, "endstream\nendobj\n\n");
+
+ fz_drop_buffer(buf);
+}
+
+static void expandstream(fz_obj *obj, int num, int gen)
+{
+ fz_error error;
+ fz_buffer *buf, *tmp;
+ fz_obj *newlen;
+
+ error = pdf_load_stream(&buf, xref, num, gen);
+ if (error)
+ die(error);
+
+ fz_dict_dels(obj, "Filter");
+ fz_dict_dels(obj, "DecodeParms");
+
+ if (doascii && isbinarystream(buf))
+ {
+ tmp = hexbuf(buf->data, buf->len);
+ fz_drop_buffer(buf);
+ buf = tmp;
+
+ addhexfilter(obj);
+ }
+
+ newlen = fz_new_int(buf->len);
+ fz_dict_puts(obj, "Length", newlen);
+ fz_drop_obj(newlen);
+
+ fprintf(out, "%d %d obj\n", num, gen);
+ fz_fprint_obj(out, obj, !doexpand);
+ fprintf(out, "stream\n");
+ fwrite(buf->data, 1, buf->len, out);
+ fprintf(out, "endstream\nendobj\n\n");
+
+ fz_drop_buffer(buf);
+}
+
+static void writeobject(int num, int gen)
+{
+ fz_error error;
+ fz_obj *obj;
+ fz_obj *type;
+
+ error = pdf_load_object(&obj, xref, num, gen);
+ if (error)
+ die(error);
+
+ /* skip ObjStm and XRef objects */
+ if (fz_is_dict(obj))
+ {
+ type = fz_dict_gets(obj, "Type");
+ if (fz_is_name(type) && !strcmp(fz_to_name(type), "ObjStm"))
+ {
+ uselist[num] = 0;
+ fz_drop_obj(obj);
+ return;
+ }
+ if (fz_is_name(type) && !strcmp(fz_to_name(type), "XRef"))
+ {
+ uselist[num] = 0;
+ fz_drop_obj(obj);
+ return;
+ }
+ }
+
+ if (!pdf_is_stream(xref, num, gen))
+ {
+ fprintf(out, "%d %d obj\n", num, gen);
+ fz_fprint_obj(out, obj, !doexpand);
+ fprintf(out, "endobj\n\n");
+ }
+ else
+ {
+ if (doexpand && !pdf_is_jpx_image(obj))
+ expandstream(obj, num, gen);
+ else
+ copystream(obj, num, gen);
+ }
+
+ fz_drop_obj(obj);
+}
+
+static void writexref(void)
+{
+ fz_obj *trailer;
+ fz_obj *obj;
+ int startxref;
+ int num;
+
+ startxref = ftell(out);
+
+ fprintf(out, "xref\n0 %d\n", xref->len);
+ for (num = 0; num < xref->len; num++)
+ {
+ if (uselist[num])
+ fprintf(out, "%010d %05d n \n", ofslist[num], genlist[num]);
+ else
+ fprintf(out, "%010d %05d f \n", ofslist[num], genlist[num]);
+ }
+ fprintf(out, "\n");
+
+ trailer = fz_new_dict(5);
+
+ obj = fz_new_int(xref->len);
+ fz_dict_puts(trailer, "Size", obj);
+ fz_drop_obj(obj);
+
+ obj = fz_dict_gets(xref->trailer, "Info");
+ if (obj)
+ fz_dict_puts(trailer, "Info", obj);
+
+ obj = fz_dict_gets(xref->trailer, "Root");
+ if (obj)
+ fz_dict_puts(trailer, "Root", obj);
+
+ obj = fz_dict_gets(xref->trailer, "ID");
+ if (obj)
+ fz_dict_puts(trailer, "ID", obj);
+
+ fprintf(out, "trailer\n");
+ fz_fprint_obj(out, trailer, !doexpand);
+ fprintf(out, "\n");
+
+ fz_drop_obj(trailer);
+
+ fprintf(out, "startxref\n%d\n%%%%EOF\n", startxref);
+}
+
+static void writepdf(void)
+{
+ int lastfree;
+ int num;
+
+ for (num = 0; num < xref->len; num++)
+ {
+ if (xref->table[num].type == 'f')
+ genlist[num] = xref->table[num].gen;
+ if (xref->table[num].type == 'n')
+ genlist[num] = xref->table[num].gen;
+ if (xref->table[num].type == 'o')
+ genlist[num] = 0;
+
+ if (dogarbage && !uselist[num])
+ continue;
+
+ if (xref->table[num].type == 'n' || xref->table[num].type == 'o')
+ {
+ uselist[num] = 1;
+ ofslist[num] = ftell(out);
+ writeobject(num, genlist[num]);
+ }
+ }
+
+ /* Construct linked list of free object slots */
+ lastfree = 0;
+ for (num = 0; num < xref->len; num++)
+ {
+ if (!uselist[num])
+ {
+ genlist[num]++;
+ ofslist[lastfree] = num;
+ lastfree = num;
+ }
+ }
+
+ writexref();
+}
+
+int main(int argc, char **argv)
+{
+ fz_error error;
+ char *infile;
+ char *outfile = "out.pdf";
+ char *password = "";
+ int c, num;
+ int subset;
+
+ while ((c = fz_getopt(argc, argv, "adgp:")) != -1)
+ {
+ switch (c)
+ {
+ case 'p': password = fz_optarg; break;
+ case 'g': dogarbage ++; break;
+ case 'd': doexpand ++; break;
+ case 'a': doascii ++; break;
+ default: usage(); break;
+ }
+ }
+
+ if (argc - fz_optind < 1)
+ usage();
+
+ infile = argv[fz_optind++];
+
+ if (argc - fz_optind > 0 &&
+ (strstr(argv[fz_optind], ".pdf") || strstr(argv[fz_optind], ".PDF")))
+ {
+ outfile = argv[fz_optind++];
+ }
+
+ subset = 0;
+ if (argc - fz_optind > 0)
+ subset = 1;
+
+ error = pdf_open_xref(&xref, infile, password);
+ if (error)
+ die(fz_rethrow(error, "cannot open input file '%s'", infile));
+
+ out = fopen(outfile, "wb");
+ if (!out)
+ die(fz_throw("cannot open output file '%s'", outfile));
+
+ fprintf(out, "%%PDF-%d.%d\n", xref->version / 10, xref->version % 10);
+ fprintf(out, "%%\316\274\341\277\246\n\n");
+
+ uselist = fz_calloc(xref->len + 1, sizeof(char));
+ ofslist = fz_calloc(xref->len + 1, sizeof(int));
+ genlist = fz_calloc(xref->len + 1, sizeof(int));
+ renumbermap = fz_calloc(xref->len + 1, sizeof(int));
+
+ for (num = 0; num < xref->len; num++)
+ {
+ uselist[num] = 0;
+ ofslist[num] = 0;
+ genlist[num] = 0;
+ renumbermap[num] = num;
+ }
+
+ /* Make sure any objects hidden in compressed streams have been loaded */
+ preloadobjstms();
+
+ /* Only retain the specified subset of the pages */
+ if (subset)
+ retainpages(argc, argv);
+
+ /* Sweep & mark objects from the trailer */
+ if (dogarbage >= 1)
+ sweepobj(xref->trailer);
+
+ /* Coalesce and renumber duplicate objects */
+ if (dogarbage >= 3)
+ removeduplicateobjs();
+
+ /* Compact xref by renumbering and removing unused objects */
+ if (dogarbage >= 2)
+ compactxref();
+
+ /* Make renumbering affect all indirect references and update xref */
+ if (dogarbage >= 2)
+ renumberobjs();
+
+ writepdf();
+
+ if (fclose(out))
+ die(fz_throw("cannot close output file '%s'", outfile));
+
+ fz_free(uselist);
+ fz_free(ofslist);
+ fz_free(genlist);
+ fz_free(renumbermap);
+
+ pdf_free_xref(xref);
+
+ fz_flush_warnings();
+
+ return 0;
+}
diff --git a/contrib/media/updf/apps/pdfdraw.c b/contrib/media/updf/apps/pdfdraw.c
new file mode 100644
index 000000000..a5f6aa1e8
--- /dev/null
+++ b/contrib/media/updf/apps/pdfdraw.c
@@ -0,0 +1,405 @@
+/*
+ * pdfdraw -- command line tool for drawing pdf documents
+ */
+
+#include "fitz.h"
+#include "mupdf.h"
+
+#ifdef _MSC_VER
+#include
+#else
+#include
+#endif
+
+char *output = NULL;
+float resolution = 72;
+float rotation = 0;
+
+int showxml = 0;
+int showtext = 0;
+int showtime = 0;
+int showmd5 = 0;
+int savealpha = 0;
+int uselist = 1;
+int alphabits = 8;
+float gamma_value = 1;
+int invert = 0;
+
+fz_colorspace *colorspace;
+fz_glyph_cache *glyphcache;
+char *filename;
+
+struct {
+ int count, total;
+ int min, max;
+ int minpage, maxpage;
+} timing;
+
+static void die(fz_error error)
+{
+ fz_catch(error, "aborting");
+ exit(1);
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "usage: pdfdraw [options] input.pdf [pages]\n"
+ "\t-o -\toutput filename (%%d for page number)\n"
+ "\t\tsupported formats: pgm, ppm, pam, png, pbm\n"
+ "\t-p -\tpassword\n"
+ "\t-r -\tresolution in dpi (default: 72)\n"
+ "\t-A\tdisable accelerated functions\n"
+ "\t-a\tsave alpha channel (only pam and png)\n"
+ "\t-b -\tnumber of bits of antialiasing (0 to 8)\n"
+ "\t-g\trender in grayscale\n"
+ "\t-m\tshow timing information\n"
+ "\t-t\tshow text (-tt for xml)\n"
+ "\t-x\tshow display list\n"
+ "\t-d\tdisable use of display list\n"
+ "\t-5\tshow md5 checksums\n"
+ "\t-R -\trotate clockwise by given number of degrees\n"
+ "\t-G gamma\tgamma correct output\n"
+ "\t-I\tinvert output\n"
+ "\tpages\tcomma separated list of ranges\n");
+ exit(1);
+}
+
+static int gettime(void)
+{
+ static struct timeval first;
+ static int once = 1;
+ struct timeval now;
+ if (once)
+ {
+ gettimeofday(&first, NULL);
+ once = 0;
+ }
+ gettimeofday(&now, NULL);
+ return (now.tv_sec - first.tv_sec) * 1000 + (now.tv_usec - first.tv_usec) / 1000;
+}
+
+static int isrange(char *s)
+{
+ while (*s)
+ {
+ if ((*s < '0' || *s > '9') && *s != '-' && *s != ',')
+ return 0;
+ s++;
+ }
+ return 1;
+}
+
+static void drawpage(pdf_xref *xref, int pagenum)
+{
+ fz_error error;
+ pdf_page *page;
+ fz_display_list *list;
+ fz_device *dev;
+ int start;
+
+ if (showtime)
+ {
+ start = gettime();
+ }
+
+ error = pdf_load_page(&page, xref, pagenum - 1);
+ if (error)
+ die(fz_rethrow(error, "cannot load page %d in file '%s'", pagenum, filename));
+
+ list = NULL;
+
+ if (uselist)
+ {
+ list = fz_new_display_list();
+ dev = fz_new_list_device(list);
+ error = pdf_run_page(xref, page, dev, fz_identity);
+ if (error)
+ die(fz_rethrow(error, "cannot draw page %d in file '%s'", pagenum, filename));
+ fz_free_device(dev);
+ }
+
+ if (showxml)
+ {
+ dev = fz_new_trace_device();
+ printf("\n", pagenum);
+ if (list)
+ fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox);
+ else
+ pdf_run_page(xref, page, dev, fz_identity);
+ printf("\n");
+ fz_free_device(dev);
+ }
+
+ if (showtext)
+ {
+ fz_text_span *text = fz_new_text_span();
+ dev = fz_new_text_device(text);
+ if (list)
+ fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox);
+ else
+ pdf_run_page(xref, page, dev, fz_identity);
+ fz_free_device(dev);
+ printf("[Page %d]\n", pagenum);
+ if (showtext > 1)
+ fz_debug_text_span_xml(text);
+ else
+ fz_debug_text_span(text);
+ printf("\n");
+ fz_free_text_span(text);
+ }
+
+ if (showmd5 || showtime)
+ printf("page %s %d", filename, pagenum);
+
+ if (output || showmd5 || showtime)
+ {
+ float zoom;
+ fz_matrix ctm;
+ fz_bbox bbox;
+ fz_pixmap *pix;
+
+ zoom = resolution / 72;
+ ctm = fz_translate(0, -page->mediabox.y1);
+ ctm = fz_concat(ctm, fz_scale(zoom, -zoom));
+ ctm = fz_concat(ctm, fz_rotate(page->rotate));
+ ctm = fz_concat(ctm, fz_rotate(rotation));
+ bbox = fz_round_rect(fz_transform_rect(ctm, page->mediabox));
+
+ /* TODO: banded rendering and multi-page ppm */
+
+ pix = fz_new_pixmap_with_rect(colorspace, bbox);
+
+ if (savealpha)
+ fz_clear_pixmap(pix);
+ else
+ fz_clear_pixmap_with_color(pix, 255);
+
+ dev = fz_new_draw_device(glyphcache, pix);
+ if (list)
+ fz_execute_display_list(list, dev, ctm, bbox);
+ else
+ pdf_run_page(xref, page, dev, ctm);
+ fz_free_device(dev);
+
+ if (invert)
+ fz_invert_pixmap(pix);
+ if (gamma_value != 1)
+ fz_gamma_pixmap(pix, gamma_value);
+
+ if (output)
+ {
+ char buf[512];
+ sprintf(buf, output, pagenum);
+ if (strstr(output, ".pgm") || strstr(output, ".ppm") || strstr(output, ".pnm"))
+ fz_write_pnm(pix, buf);
+ else if (strstr(output, ".pam"))
+ fz_write_pam(pix, buf, savealpha);
+ else if (strstr(output, ".png"))
+ fz_write_png(pix, buf, savealpha);
+ else if (strstr(output, ".pbm")) {
+ fz_halftone *ht = fz_get_default_halftone(1);
+ fz_bitmap *bit = fz_halftone_pixmap(pix, ht);
+ fz_write_pbm(bit, buf);
+ fz_drop_bitmap(bit);
+ fz_drop_halftone(ht);
+ }
+ }
+
+ if (showmd5)
+ {
+ fz_md5 md5;
+ unsigned char digest[16];
+ int i;
+
+ fz_md5_init(&md5);
+ fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n);
+ fz_md5_final(&md5, digest);
+
+ printf(" ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", digest[i]);
+ }
+
+ fz_drop_pixmap(pix);
+ }
+
+ if (list)
+ fz_free_display_list(list);
+
+ pdf_free_page(page);
+
+ if (showtime)
+ {
+ int end = gettime();
+ int diff = end - start;
+
+ if (diff < timing.min)
+ {
+ timing.min = diff;
+ timing.minpage = pagenum;
+ }
+ if (diff > timing.max)
+ {
+ timing.max = diff;
+ timing.maxpage = pagenum;
+ }
+ timing.total += diff;
+ timing.count ++;
+
+ printf(" %dms", diff);
+ }
+
+ if (showmd5 || showtime)
+ printf("\n");
+
+ pdf_age_store(xref->store, 3);
+
+ fz_flush_warnings();
+}
+
+static void drawrange(pdf_xref *xref, char *range)
+{
+ int page, spage, epage;
+ char *spec, *dash;
+
+ spec = fz_strsep(&range, ",");
+ while (spec)
+ {
+ dash = strchr(spec, '-');
+
+ if (dash == spec)
+ spage = epage = pdf_count_pages(xref);
+ else
+ spage = epage = atoi(spec);
+
+ if (dash)
+ {
+ if (strlen(dash) > 1)
+ epage = atoi(dash + 1);
+ else
+ epage = pdf_count_pages(xref);
+ }
+
+ spage = CLAMP(spage, 1, pdf_count_pages(xref));
+ epage = CLAMP(epage, 1, pdf_count_pages(xref));
+
+ if (spage < epage)
+ for (page = spage; page <= epage; page++)
+ drawpage(xref, page);
+ else
+ for (page = spage; page >= epage; page--)
+ drawpage(xref, page);
+
+ spec = fz_strsep(&range, ",");
+ }
+}
+
+int main(int argc, char **argv)
+{
+ char *password = "";
+ int grayscale = 0;
+ int accelerate = 1;
+ pdf_xref *xref;
+ fz_error error;
+ int c;
+
+ while ((c = fz_getopt(argc, argv, "o:p:r:R:Aab:dgmtx5G:I")) != -1)
+ {
+ switch (c)
+ {
+ case 'o': output = fz_optarg; break;
+ case 'p': password = fz_optarg; break;
+ case 'r': resolution = atof(fz_optarg); break;
+ case 'R': rotation = atof(fz_optarg); break;
+ case 'A': accelerate = 0; break;
+ case 'a': savealpha = 1; break;
+ case 'b': alphabits = atoi(fz_optarg); break;
+ case 'm': showtime++; break;
+ case 't': showtext++; break;
+ case 'x': showxml++; break;
+ case '5': showmd5++; break;
+ case 'g': grayscale++; break;
+ case 'd': uselist = 0; break;
+ case 'G': gamma_value = atof(fz_optarg); break;
+ case 'I': invert++; break;
+ default: usage(); break;
+ }
+ }
+
+ fz_set_aa_level(alphabits);
+
+ if (fz_optind == argc)
+ usage();
+
+ if (!showtext && !showxml && !showtime && !showmd5 && !output)
+ {
+ printf("nothing to do\n");
+ exit(0);
+ }
+
+ if (accelerate)
+ fz_accelerate();
+
+ glyphcache = fz_new_glyph_cache();
+
+ colorspace = fz_device_rgb;
+ if (grayscale)
+ colorspace = fz_device_gray;
+ if (output && strstr(output, ".pgm"))
+ colorspace = fz_device_gray;
+ if (output && strstr(output, ".ppm"))
+ colorspace = fz_device_rgb;
+ if (output && strstr(output, ".pbm"))
+ colorspace = fz_device_gray;
+
+ timing.count = 0;
+ timing.total = 0;
+ timing.min = 1 << 30;
+ timing.max = 0;
+ timing.minpage = 0;
+ timing.maxpage = 0;
+
+ if (showxml)
+ printf("\n");
+
+ while (fz_optind < argc)
+ {
+ filename = argv[fz_optind++];
+
+ error = pdf_open_xref(&xref, filename, password);
+ if (error)
+ die(fz_rethrow(error, "cannot open document: %s", filename));
+
+ error = pdf_load_page_tree(xref);
+ if (error)
+ die(fz_rethrow(error, "cannot load page tree: %s", filename));
+
+ if (showxml)
+ printf("\n", filename);
+
+ if (fz_optind == argc || !isrange(argv[fz_optind]))
+ drawrange(xref, "1-");
+ if (fz_optind < argc && isrange(argv[fz_optind]))
+ drawrange(xref, argv[fz_optind++]);
+
+ if (showxml)
+ printf("\n");
+
+ pdf_free_xref(xref);
+ }
+
+ if (showtime)
+ {
+ printf("total %dms / %d pages for an average of %dms\n",
+ timing.total, timing.count, timing.total / timing.count);
+ printf("fastest page %d: %dms\n", timing.minpage, timing.min);
+ printf("slowest page %d: %dms\n", timing.maxpage, timing.max);
+ }
+
+ fz_free_glyph_cache(glyphcache);
+
+ fz_flush_warnings();
+
+ return 0;
+}
diff --git a/contrib/media/updf/apps/pdfextract.c b/contrib/media/updf/apps/pdfextract.c
new file mode 100644
index 000000000..7e6e4ace4
--- /dev/null
+++ b/contrib/media/updf/apps/pdfextract.c
@@ -0,0 +1,222 @@
+/*
+ * pdfextract -- the ultimate way to extract images and fonts from pdfs
+ */
+
+#include "fitz.h"
+#include "mupdf.h"
+
+static pdf_xref *xref = NULL;
+static int dorgb = 0;
+
+void die(fz_error error)
+{
+ fz_catch(error, "aborting");
+ if (xref)
+ pdf_free_xref(xref);
+ exit(1);
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "usage: pdfextract [options] file.pdf [object numbers]\n");
+ fprintf(stderr, "\t-p\tpassword\n");
+ fprintf(stderr, "\t-r\tconvert images to rgb\n");
+ exit(1);
+}
+
+static int isimage(fz_obj *obj)
+{
+ fz_obj *type = fz_dict_gets(obj, "Subtype");
+ return fz_is_name(type) && !strcmp(fz_to_name(type), "Image");
+}
+
+static int isfontdesc(fz_obj *obj)
+{
+ fz_obj *type = fz_dict_gets(obj, "Type");
+ return fz_is_name(type) && !strcmp(fz_to_name(type), "FontDescriptor");
+}
+
+static void saveimage(int num)
+{
+ fz_error error;
+ fz_pixmap *img;
+ fz_obj *ref;
+ char name[1024];
+
+ ref = fz_new_indirect(num, 0, xref);
+
+ /* TODO: detect DCTD and save as jpeg */
+
+ error = pdf_load_image(&img, xref, ref);
+ if (error)
+ die(error);
+
+ if (dorgb && img->colorspace && img->colorspace != fz_device_rgb)
+ {
+ fz_pixmap *temp;
+ temp = fz_new_pixmap_with_rect(fz_device_rgb, fz_bound_pixmap(img));
+ fz_convert_pixmap(img, temp);
+ fz_drop_pixmap(img);
+ img = temp;
+ }
+
+ if (img->n <= 4)
+ {
+ sprintf(name, "img-%04d.png", num);
+ printf("extracting image %s\n", name);
+ fz_write_png(img, name, 0);
+ }
+ else
+ {
+ sprintf(name, "img-%04d.pam", num);
+ printf("extracting image %s\n", name);
+ fz_write_pam(img, name, 0);
+ }
+
+ fz_drop_pixmap(img);
+ fz_drop_obj(ref);
+}
+
+static void savefont(fz_obj *dict, int num)
+{
+ fz_error error;
+ char name[1024];
+ char *subtype;
+ fz_buffer *buf;
+ fz_obj *stream = NULL;
+ fz_obj *obj;
+ char *ext = "";
+ FILE *f;
+ char *fontname = "font";
+ int n;
+
+ obj = fz_dict_gets(dict, "FontName");
+ if (obj)
+ fontname = fz_to_name(obj);
+
+ obj = fz_dict_gets(dict, "FontFile");
+ if (obj)
+ {
+ stream = obj;
+ ext = "pfa";
+ }
+
+ obj = fz_dict_gets(dict, "FontFile2");
+ if (obj)
+ {
+ stream = obj;
+ ext = "ttf";
+ }
+
+ obj = fz_dict_gets(dict, "FontFile3");
+ if (obj)
+ {
+ stream = obj;
+
+ obj = fz_dict_gets(obj, "Subtype");
+ if (obj && !fz_is_name(obj))
+ die(fz_throw("Invalid font descriptor subtype"));
+
+ subtype = fz_to_name(obj);
+ if (!strcmp(subtype, "Type1C"))
+ ext = "cff";
+ else if (!strcmp(subtype, "CIDFontType0C"))
+ ext = "cid";
+ else
+ die(fz_throw("Unhandled font type '%s'", subtype));
+ }
+
+ if (!stream)
+ {
+ fz_warn("Unhandled font type");
+ return;
+ }
+
+ buf = fz_new_buffer(0);
+
+ error = pdf_load_stream(&buf, xref, fz_to_num(stream), fz_to_gen(stream));
+ if (error)
+ die(error);
+
+ sprintf(name, "%s-%04d.%s", fontname, num, ext);
+ printf("extracting font %s\n", name);
+
+ f = fopen(name, "wb");
+ if (f == NULL)
+ die(fz_throw("Error creating font file"));
+
+ n = fwrite(buf->data, 1, buf->len, f);
+ if (n < buf->len)
+ die(fz_throw("Error writing font file"));
+
+ if (fclose(f) < 0)
+ die(fz_throw("Error closing font file"));
+
+ fz_drop_buffer(buf);
+}
+
+static void showobject(int num)
+{
+ fz_error error;
+ fz_obj *obj;
+
+ if (!xref)
+ die(fz_throw("no file specified"));
+
+ error = pdf_load_object(&obj, xref, num, 0);
+ if (error)
+ die(error);
+
+ if (isimage(obj))
+ saveimage(num);
+ else if (isfontdesc(obj))
+ savefont(obj, num);
+
+ fz_drop_obj(obj);
+}
+
+int main(int argc, char **argv)
+{
+ fz_error error;
+ char *infile;
+ char *password = "";
+ int c, o;
+
+ while ((c = fz_getopt(argc, argv, "p:r")) != -1)
+ {
+ switch (c)
+ {
+ case 'p': password = fz_optarg; break;
+ case 'r': dorgb++; break;
+ default: usage(); break;
+ }
+ }
+
+ if (fz_optind == argc)
+ usage();
+
+ infile = argv[fz_optind++];
+ error = pdf_open_xref(&xref, infile, password);
+ if (error)
+ die(fz_rethrow(error, "cannot open input file '%s'", infile));
+
+ if (fz_optind == argc)
+ {
+ for (o = 0; o < xref->len; o++)
+ showobject(o);
+ }
+ else
+ {
+ while (fz_optind < argc)
+ {
+ showobject(atoi(argv[fz_optind]));
+ fz_optind++;
+ }
+ }
+
+ pdf_free_xref(xref);
+
+ fz_flush_warnings();
+
+ return 0;
+}
diff --git a/contrib/media/updf/apps/pdfinfo.c b/contrib/media/updf/apps/pdfinfo.c
new file mode 100644
index 000000000..d89482645
--- /dev/null
+++ b/contrib/media/updf/apps/pdfinfo.c
@@ -0,0 +1,1011 @@
+/*
+ * Information tool.
+ * Print information about the input pdf.
+ */
+
+#include "fitz.h"
+#include "mupdf.h"
+
+pdf_xref *xref;
+int pagecount;
+
+void closexref(void);
+
+void die(fz_error error)
+{
+ fz_catch(error, "aborting");
+ closexref();
+ exit(1);
+}
+
+void openxref(char *filename, char *password, int dieonbadpass, int loadpages);
+
+enum
+{
+ DIMENSIONS = 0x01,
+ FONTS = 0x02,
+ IMAGES = 0x04,
+ SHADINGS = 0x08,
+ PATTERNS = 0x10,
+ XOBJS = 0x20,
+ ALL = DIMENSIONS | FONTS | IMAGES | SHADINGS | PATTERNS | XOBJS
+};
+
+struct info
+{
+ int page;
+ fz_obj *pageref;
+ fz_obj *pageobj;
+ union {
+ struct {
+ fz_obj *obj;
+ } info;
+ struct {
+ fz_obj *obj;
+ } crypt;
+ struct {
+ fz_obj *obj;
+ fz_rect *bbox;
+ } dim;
+ struct {
+ fz_obj *obj;
+ fz_obj *subtype;
+ fz_obj *name;
+ } font;
+ struct {
+ fz_obj *obj;
+ fz_obj *width;
+ fz_obj *height;
+ fz_obj *bpc;
+ fz_obj *filter;
+ fz_obj *cs;
+ fz_obj *altcs;
+ } image;
+ struct {
+ fz_obj *obj;
+ fz_obj *type;
+ } shading;
+ struct {
+ fz_obj *obj;
+ fz_obj *type;
+ fz_obj *paint;
+ fz_obj *tiling;
+ fz_obj *shading;
+ } pattern;
+ struct {
+ fz_obj *obj;
+ fz_obj *groupsubtype;
+ fz_obj *reference;
+ } form;
+ } u;
+};
+
+static struct info *dim = NULL;
+static int dims = 0;
+static struct info *font = NULL;
+static int fonts = 0;
+static struct info *image = NULL;
+static int images = 0;
+static struct info *shading = NULL;
+static int shadings = 0;
+static struct info *pattern = NULL;
+static int patterns = 0;
+static struct info *form = NULL;
+static int forms = 0;
+static struct info *psobj = NULL;
+static int psobjs = 0;
+
+void closexref(void)
+{
+ int i;
+ if (xref)
+ {
+ pdf_free_xref(xref);
+ xref = NULL;
+ }
+
+ if (dim)
+ {
+ for (i = 0; i < dims; i++)
+ fz_free(dim[i].u.dim.bbox);
+ fz_free(dim);
+ dim = NULL;
+ dims = 0;
+ }
+
+ if (font)
+ {
+ fz_free(font);
+ font = NULL;
+ fonts = 0;
+ }
+
+ if (image)
+ {
+ fz_free(image);
+ image = NULL;
+ images = 0;
+ }
+
+ if (shading)
+ {
+ fz_free(shading);
+ shading = NULL;
+ shadings = 0;
+ }
+
+ if (pattern)
+ {
+ fz_free(pattern);
+ pattern = NULL;
+ patterns = 0;
+ }
+
+ if (form)
+ {
+ fz_free(form);
+ form = NULL;
+ forms = 0;
+ }
+
+ if (psobj)
+ {
+ fz_free(psobj);
+ psobj = NULL;
+ psobjs = 0;
+ }
+
+ if (xref && xref->store)
+ {
+ pdf_free_store(xref->store);
+ xref->store = NULL;
+ }
+}
+
+static void
+infousage(void)
+{
+ fprintf(stderr,
+ "usage: pdfinfo [options] [file.pdf ... ]\n"
+ "\t-d -\tpassword for decryption\n"
+ "\t-f\tlist fonts\n"
+ "\t-i\tlist images\n"
+ "\t-m\tlist dimensions\n"
+ "\t-p\tlist patterns\n"
+ "\t-s\tlist shadings\n"
+ "\t-x\tlist form and postscript xobjects\n");
+ exit(1);
+}
+
+static void
+showglobalinfo(void)
+{
+ fz_obj *obj;
+
+ printf("\nPDF-%d.%d\n", xref->version / 10, xref->version % 10);
+
+ obj = fz_dict_gets(xref->trailer, "Info");
+ if (obj)
+ {
+ printf("Info object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj));
+ fz_debug_obj(fz_resolve_indirect(obj));
+ }
+
+ obj = fz_dict_gets(xref->trailer, "Encrypt");
+ if (obj)
+ {
+ printf("\nEncryption object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj));
+ fz_debug_obj(fz_resolve_indirect(obj));
+ }
+
+ printf("\nPages: %d\n\n", pagecount);
+}
+
+static void
+gatherdimensions(int page, fz_obj *pageref, fz_obj *pageobj)
+{
+ fz_rect bbox;
+ fz_obj *obj;
+ int j;
+
+ obj = fz_dict_gets(pageobj, "MediaBox");
+ if (!fz_is_array(obj))
+ return;
+
+ bbox = pdf_to_rect(obj);
+
+ for (j = 0; j < dims; j++)
+ if (!memcmp(dim[j].u.dim.bbox, &bbox, sizeof (fz_rect)))
+ break;
+
+ if (j < dims)
+ return;
+
+ dims++;
+
+ dim = fz_realloc(dim, dims, sizeof(struct info));
+ dim[dims - 1].page = page;
+ dim[dims - 1].pageref = pageref;
+ dim[dims - 1].pageobj = pageobj;
+ dim[dims - 1].u.dim.bbox = fz_malloc(sizeof(fz_rect));
+ memcpy(dim[dims - 1].u.dim.bbox, &bbox, sizeof (fz_rect));
+
+ return;
+}
+
+static void
+gatherfonts(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i;
+
+ for (i = 0; i < fz_dict_len(dict); i++)
+ {
+ fz_obj *fontdict = NULL;
+ fz_obj *subtype = NULL;
+ fz_obj *basefont = NULL;
+ fz_obj *name = NULL;
+ int k;
+
+ fontdict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(fontdict))
+ {
+ fz_warn("not a font dict (%d %d R)", fz_to_num(fontdict), fz_to_gen(fontdict));
+ continue;
+ }
+
+ subtype = fz_dict_gets(fontdict, "Subtype");
+ basefont = fz_dict_gets(fontdict, "BaseFont");
+ if (!basefont || fz_is_null(basefont))
+ name = fz_dict_gets(fontdict, "Name");
+
+ for (k = 0; k < fonts; k++)
+ if (!fz_objcmp(font[k].u.font.obj, fontdict))
+ break;
+
+ if (k < fonts)
+ continue;
+
+ fonts++;
+
+ font = fz_realloc(font, fonts, sizeof(struct info));
+ font[fonts - 1].page = page;
+ font[fonts - 1].pageref = pageref;
+ font[fonts - 1].pageobj = pageobj;
+ font[fonts - 1].u.font.obj = fontdict;
+ font[fonts - 1].u.font.subtype = subtype;
+ font[fonts - 1].u.font.name = basefont ? basefont : name;
+ }
+}
+
+static void
+gatherimages(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i;
+
+ for (i = 0; i < fz_dict_len(dict); i++)
+ {
+ fz_obj *imagedict;
+ fz_obj *type;
+ fz_obj *width;
+ fz_obj *height;
+ fz_obj *bpc = NULL;
+ fz_obj *filter = NULL;
+ fz_obj *cs = NULL;
+ fz_obj *altcs;
+ int k;
+
+ imagedict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(imagedict))
+ {
+ fz_warn("not an image dict (%d %d R)", fz_to_num(imagedict), fz_to_gen(imagedict));
+ continue;
+ }
+
+ type = fz_dict_gets(imagedict, "Subtype");
+ if (strcmp(fz_to_name(type), "Image"))
+ continue;
+
+ filter = fz_dict_gets(imagedict, "Filter");
+
+ altcs = NULL;
+ cs = fz_dict_gets(imagedict, "ColorSpace");
+ if (fz_is_array(cs))
+ {
+ fz_obj *cses = cs;
+
+ cs = fz_array_get(cses, 0);
+ if (fz_is_name(cs) && (!strcmp(fz_to_name(cs), "DeviceN") || !strcmp(fz_to_name(cs), "Separation")))
+ {
+ altcs = fz_array_get(cses, 2);
+ if (fz_is_array(altcs))
+ altcs = fz_array_get(altcs, 0);
+ }
+ }
+
+ width = fz_dict_gets(imagedict, "Width");
+ height = fz_dict_gets(imagedict, "Height");
+ bpc = fz_dict_gets(imagedict, "BitsPerComponent");
+
+ for (k = 0; k < images; k++)
+ if (!fz_objcmp(image[k].u.image.obj, imagedict))
+ break;
+
+ if (k < images)
+ continue;
+
+ images++;
+
+ image = fz_realloc(image, images, sizeof(struct info));
+ image[images - 1].page = page;
+ image[images - 1].pageref = pageref;
+ image[images - 1].pageobj = pageobj;
+ image[images - 1].u.image.obj = imagedict;
+ image[images - 1].u.image.width = width;
+ image[images - 1].u.image.height = height;
+ image[images - 1].u.image.bpc = bpc;
+ image[images - 1].u.image.filter = filter;
+ image[images - 1].u.image.cs = cs;
+ image[images - 1].u.image.altcs = altcs;
+ }
+}
+
+static void
+gatherforms(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i;
+
+ for (i = 0; i < fz_dict_len(dict); i++)
+ {
+ fz_obj *xobjdict;
+ fz_obj *type;
+ fz_obj *subtype;
+ fz_obj *group;
+ fz_obj *groupsubtype;
+ fz_obj *reference;
+ int k;
+
+ xobjdict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(xobjdict))
+ {
+ fz_warn("not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict));
+ continue;
+ }
+
+ type = fz_dict_gets(xobjdict, "Subtype");
+ if (strcmp(fz_to_name(type), "Form"))
+ continue;
+
+ subtype = fz_dict_gets(xobjdict, "Subtype2");
+ if (!strcmp(fz_to_name(subtype), "PS"))
+ continue;
+
+ group = fz_dict_gets(xobjdict, "Group");
+ groupsubtype = fz_dict_gets(group, "S");
+ reference = fz_dict_gets(xobjdict, "Ref");
+
+ for (k = 0; k < forms; k++)
+ if (!fz_objcmp(form[k].u.form.obj, xobjdict))
+ break;
+
+ if (k < forms)
+ continue;
+
+ forms++;
+
+ form = fz_realloc(form, forms, sizeof(struct info));
+ form[forms - 1].page = page;
+ form[forms - 1].pageref = pageref;
+ form[forms - 1].pageobj = pageobj;
+ form[forms - 1].u.form.obj = xobjdict;
+ form[forms - 1].u.form.groupsubtype = groupsubtype;
+ form[forms - 1].u.form.reference = reference;
+ }
+}
+
+static void
+gatherpsobjs(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i;
+
+ for (i = 0; i < fz_dict_len(dict); i++)
+ {
+ fz_obj *xobjdict;
+ fz_obj *type;
+ fz_obj *subtype;
+ int k;
+
+ xobjdict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(xobjdict))
+ {
+ fz_warn("not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict));
+ continue;
+ }
+
+ type = fz_dict_gets(xobjdict, "Subtype");
+ subtype = fz_dict_gets(xobjdict, "Subtype2");
+ if (strcmp(fz_to_name(type), "PS") &&
+ (strcmp(fz_to_name(type), "Form") || strcmp(fz_to_name(subtype), "PS")))
+ continue;
+
+ for (k = 0; k < psobjs; k++)
+ if (!fz_objcmp(psobj[k].u.form.obj, xobjdict))
+ break;
+
+ if (k < psobjs)
+ continue;
+
+ psobjs++;
+
+ psobj = fz_realloc(psobj, psobjs, sizeof(struct info));
+ psobj[psobjs - 1].page = page;
+ psobj[psobjs - 1].pageref = pageref;
+ psobj[psobjs - 1].pageobj = pageobj;
+ psobj[psobjs - 1].u.form.obj = xobjdict;
+ }
+}
+
+static void
+gathershadings(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i;
+
+ for (i = 0; i < fz_dict_len(dict); i++)
+ {
+ fz_obj *shade;
+ fz_obj *type;
+ int k;
+
+ shade = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(shade))
+ {
+ fz_warn("not a shading dict (%d %d R)", fz_to_num(shade), fz_to_gen(shade));
+ continue;
+ }
+
+ type = fz_dict_gets(shade, "ShadingType");
+ if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 7)
+ {
+ fz_warn("not a shading type (%d %d R)", fz_to_num(shade), fz_to_gen(shade));
+ type = NULL;
+ }
+
+ for (k = 0; k < shadings; k++)
+ if (!fz_objcmp(shading[k].u.shading.obj, shade))
+ break;
+
+ if (k < shadings)
+ continue;
+
+ shadings++;
+
+ shading = fz_realloc(shading, shadings, sizeof(struct info));
+ shading[shadings - 1].page = page;
+ shading[shadings - 1].pageref = pageref;
+ shading[shadings - 1].pageobj = pageobj;
+ shading[shadings - 1].u.shading.obj = shade;
+ shading[shadings - 1].u.shading.type = type;
+ }
+}
+
+static void
+gatherpatterns(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i;
+
+ for (i = 0; i < fz_dict_len(dict); i++)
+ {
+ fz_obj *patterndict;
+ fz_obj *type;
+ fz_obj *paint = NULL;
+ fz_obj *tiling = NULL;
+ fz_obj *shading = NULL;
+ int k;
+
+ patterndict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(patterndict))
+ {
+ fz_warn("not a pattern dict (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
+ continue;
+ }
+
+ type = fz_dict_gets(patterndict, "PatternType");
+ if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 2)
+ {
+ fz_warn("not a pattern type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
+ type = NULL;
+ }
+
+ if (fz_to_int(type) == 1)
+ {
+ paint = fz_dict_gets(patterndict, "PaintType");
+ if (!fz_is_int(paint) || fz_to_int(paint) < 1 || fz_to_int(paint) > 2)
+ {
+ fz_warn("not a pattern paint type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
+ paint = NULL;
+ }
+
+ tiling = fz_dict_gets(patterndict, "TilingType");
+ if (!fz_is_int(tiling) || fz_to_int(tiling) < 1 || fz_to_int(tiling) > 3)
+ {
+ fz_warn("not a pattern tiling type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
+ tiling = NULL;
+ }
+ }
+ else
+ {
+ shading = fz_dict_gets(patterndict, "Shading");
+ }
+
+ for (k = 0; k < patterns; k++)
+ if (!fz_objcmp(pattern[k].u.pattern.obj, patterndict))
+ break;
+
+ if (k < patterns)
+ continue;
+
+ patterns++;
+
+ pattern = fz_realloc(pattern, patterns, sizeof(struct info));
+ pattern[patterns - 1].page = page;
+ pattern[patterns - 1].pageref = pageref;
+ pattern[patterns - 1].pageobj = pageobj;
+ pattern[patterns - 1].u.pattern.obj = patterndict;
+ pattern[patterns - 1].u.pattern.type = type;
+ pattern[patterns - 1].u.pattern.paint = paint;
+ pattern[patterns - 1].u.pattern.tiling = tiling;
+ pattern[patterns - 1].u.pattern.shading = shading;
+ }
+}
+
+static void
+gatherresourceinfo(int page, fz_obj *rsrc)
+{
+ fz_obj *pageobj;
+ fz_obj *pageref;
+ fz_obj *font;
+ fz_obj *xobj;
+ fz_obj *shade;
+ fz_obj *pattern;
+ fz_obj *subrsrc;
+ int i;
+
+ pageobj = xref->page_objs[page-1];
+ pageref = xref->page_refs[page-1];
+
+ if (!pageobj)
+ die(fz_throw("cannot retrieve info from page %d", page));
+
+ font = fz_dict_gets(rsrc, "Font");
+ if (font)
+ {
+ gatherfonts(page, pageref, pageobj, font);
+
+ for (i = 0; i < fz_dict_len(font); i++)
+ {
+ fz_obj *obj = fz_dict_get_val(font, i);
+
+ subrsrc = fz_dict_gets(obj, "Resources");
+ if (subrsrc && fz_objcmp(rsrc, subrsrc))
+ gatherresourceinfo(page, subrsrc);
+ }
+ }
+
+ xobj = fz_dict_gets(rsrc, "XObject");
+ if (xobj)
+ {
+ gatherimages(page, pageref, pageobj, xobj);
+ gatherforms(page, pageref, pageobj, xobj);
+ gatherpsobjs(page, pageref, pageobj, xobj);
+
+ for (i = 0; i < fz_dict_len(xobj); i++)
+ {
+ fz_obj *obj = fz_dict_get_val(xobj, i);
+ subrsrc = fz_dict_gets(obj, "Resources");
+ if (subrsrc && fz_objcmp(rsrc, subrsrc))
+ gatherresourceinfo(page, subrsrc);
+ }
+ }
+
+ shade = fz_dict_gets(rsrc, "Shading");
+ if (shade)
+ gathershadings(page, pageref, pageobj, shade);
+
+ pattern = fz_dict_gets(rsrc, "Pattern");
+ if (pattern)
+ {
+ gatherpatterns(page, pageref, pageobj, pattern);
+
+ for (i = 0; i < fz_dict_len(pattern); i++)
+ {
+ fz_obj *obj = fz_dict_get_val(pattern, i);
+ subrsrc = fz_dict_gets(obj, "Resources");
+ if (subrsrc && fz_objcmp(rsrc, subrsrc))
+ gatherresourceinfo(page, subrsrc);
+ }
+ }
+}
+
+static void
+gatherpageinfo(int page)
+{
+ fz_obj *pageobj;
+ fz_obj *pageref;
+ fz_obj *rsrc;
+
+ pageobj = xref->page_objs[page-1];
+ pageref = xref->page_refs[page-1];
+
+ if (!pageobj)
+ die(fz_throw("cannot retrieve info from page %d", page));
+
+ gatherdimensions(page, pageref, pageobj);
+
+ rsrc = fz_dict_gets(pageobj, "Resources");
+ gatherresourceinfo(page, rsrc);
+}
+
+static void
+printinfo(char *filename, int show, int page)
+{
+ int i;
+ int j;
+
+#define PAGE_FMT "\t% 5d (% 7d %1d R): "
+
+ if (show & DIMENSIONS && dims > 0)
+ {
+ printf("Mediaboxes (%d):\n", dims);
+ for (i = 0; i < dims; i++)
+ {
+ printf(PAGE_FMT "[ %g %g %g %g ]\n",
+ dim[i].page,
+ fz_to_num(dim[i].pageref), fz_to_gen(dim[i].pageref),
+ dim[i].u.dim.bbox->x0,
+ dim[i].u.dim.bbox->y0,
+ dim[i].u.dim.bbox->x1,
+ dim[i].u.dim.bbox->y1);
+ }
+ printf("\n");
+ }
+
+ if (show & FONTS && fonts > 0)
+ {
+ printf("Fonts (%d):\n", fonts);
+ for (i = 0; i < fonts; i++)
+ {
+ printf(PAGE_FMT "%s '%s' (%d %d R)\n",
+ font[i].page,
+ fz_to_num(font[i].pageref), fz_to_gen(font[i].pageref),
+ fz_to_name(font[i].u.font.subtype),
+ fz_to_name(font[i].u.font.name),
+ fz_to_num(font[i].u.font.obj), fz_to_gen(font[i].u.font.obj));
+ }
+ printf("\n");
+ }
+
+ if (show & IMAGES && images > 0)
+ {
+ printf("Images (%d):\n", images);
+ for (i = 0; i < images; i++)
+ {
+ char *cs = NULL;
+ char *altcs = NULL;
+
+ printf(PAGE_FMT "[ ",
+ image[i].page,
+ fz_to_num(image[i].pageref), fz_to_gen(image[i].pageref));
+
+ if (fz_is_array(image[i].u.image.filter))
+ for (j = 0; j < fz_array_len(image[i].u.image.filter); j++)
+ {
+ fz_obj *obj = fz_array_get(image[i].u.image.filter, j);
+ char *filter = fz_strdup(fz_to_name(obj));
+
+ if (strstr(filter, "Decode"))
+ *(strstr(filter, "Decode")) = '\0';
+
+ printf("%s%s",
+ filter,
+ j == fz_array_len(image[i].u.image.filter) - 1 ? "" : " ");
+ fz_free(filter);
+ }
+ else if (image[i].u.image.filter)
+ {
+ fz_obj *obj = image[i].u.image.filter;
+ char *filter = fz_strdup(fz_to_name(obj));
+
+ if (strstr(filter, "Decode"))
+ *(strstr(filter, "Decode")) = '\0';
+
+ printf("%s", filter);
+ fz_free(filter);
+ }
+ else
+ printf("Raw");
+
+ if (image[i].u.image.cs)
+ {
+ cs = fz_strdup(fz_to_name(image[i].u.image.cs));
+
+ if (!strncmp(cs, "Device", 6))
+ {
+ int len = strlen(cs + 6);
+ memmove(cs + 3, cs + 6, len + 1);
+ cs[3 + len + 1] = '\0';
+ }
+ if (strstr(cs, "ICC"))
+ fz_strlcpy(cs, "ICC", 4);
+ if (strstr(cs, "Indexed"))
+ fz_strlcpy(cs, "Idx", 4);
+ if (strstr(cs, "Pattern"))
+ fz_strlcpy(cs, "Pat", 4);
+ if (strstr(cs, "Separation"))
+ fz_strlcpy(cs, "Sep", 4);
+ }
+ if (image[i].u.image.altcs)
+ {
+ altcs = fz_strdup(fz_to_name(image[i].u.image.altcs));
+
+ if (!strncmp(altcs, "Device", 6))
+ {
+ int len = strlen(altcs + 6);
+ memmove(altcs + 3, altcs + 6, len + 1);
+ altcs[3 + len + 1] = '\0';
+ }
+ if (strstr(altcs, "ICC"))
+ fz_strlcpy(altcs, "ICC", 4);
+ if (strstr(altcs, "Indexed"))
+ fz_strlcpy(altcs, "Idx", 4);
+ if (strstr(altcs, "Pattern"))
+ fz_strlcpy(altcs, "Pat", 4);
+ if (strstr(altcs, "Separation"))
+ fz_strlcpy(altcs, "Sep", 4);
+ }
+
+ printf(" ] %dx%d %dbpc %s%s%s (%d %d R)\n",
+ fz_to_int(image[i].u.image.width),
+ fz_to_int(image[i].u.image.height),
+ image[i].u.image.bpc ? fz_to_int(image[i].u.image.bpc) : 1,
+ image[i].u.image.cs ? cs : "ImageMask",
+ image[i].u.image.altcs ? " " : "",
+ image[i].u.image.altcs ? altcs : "",
+ fz_to_num(image[i].u.image.obj), fz_to_gen(image[i].u.image.obj));
+
+ fz_free(cs);
+ fz_free(altcs);
+ }
+ printf("\n");
+ }
+
+ if (show & SHADINGS && shadings > 0)
+ {
+ printf("Shading patterns (%d):\n", shadings);
+ for (i = 0; i < shadings; i++)
+ {
+ char *shadingtype[] =
+ {
+ "",
+ "Function",
+ "Axial",
+ "Radial",
+ "Triangle mesh",
+ "Lattice",
+ "Coons patch",
+ "Tensor patch",
+ };
+
+ printf(PAGE_FMT "%s (%d %d R)\n",
+ shading[i].page,
+ fz_to_num(shading[i].pageref), fz_to_gen(shading[i].pageref),
+ shadingtype[fz_to_int(shading[i].u.shading.type)],
+ fz_to_num(shading[i].u.shading.obj), fz_to_gen(shading[i].u.shading.obj));
+ }
+ printf("\n");
+ }
+
+ if (show & PATTERNS && patterns > 0)
+ {
+ printf("Patterns (%d):\n", patterns);
+ for (i = 0; i < patterns; i++)
+ {
+ if (fz_to_int(pattern[i].u.pattern.type) == 1)
+ {
+ char *painttype[] =
+ {
+ "",
+ "Colored",
+ "Uncolored",
+ };
+ char *tilingtype[] =
+ {
+ "",
+ "Constant",
+ "No distortion",
+ "Constant/fast tiling",
+ };
+
+ printf(PAGE_FMT "Tiling %s %s (%d %d R)\n",
+ pattern[i].page,
+ fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref),
+ painttype[fz_to_int(pattern[i].u.pattern.paint)],
+ tilingtype[fz_to_int(pattern[i].u.pattern.tiling)],
+ fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj));
+ }
+ else
+ {
+ printf(PAGE_FMT "Shading %d %d R (%d %d R)\n",
+ pattern[i].page,
+ fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref),
+ fz_to_num(pattern[i].u.pattern.shading), fz_to_gen(pattern[i].u.pattern.shading),
+ fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj));
+ }
+ }
+ printf("\n");
+ }
+
+ if (show & XOBJS && forms > 0)
+ {
+ printf("Form xobjects (%d):\n", forms);
+ for (i = 0; i < forms; i++)
+ {
+ printf(PAGE_FMT "Form%s%s%s%s (%d %d R)\n",
+ form[i].page,
+ fz_to_num(form[i].pageref), fz_to_gen(form[i].pageref),
+ form[i].u.form.groupsubtype ? " " : "",
+ form[i].u.form.groupsubtype ? fz_to_name(form[i].u.form.groupsubtype) : "",
+ form[i].u.form.groupsubtype ? " Group" : "",
+ form[i].u.form.reference ? " Reference" : "",
+ fz_to_num(form[i].u.form.obj), fz_to_gen(form[i].u.form.obj));
+ }
+ printf("\n");
+ }
+
+ if (show & XOBJS && psobjs > 0)
+ {
+ printf("Postscript xobjects (%d):\n", psobjs);
+ for (i = 0; i < psobjs; i++)
+ {
+ printf(PAGE_FMT "(%d %d R)\n",
+ psobj[i].page,
+ fz_to_num(psobj[i].pageref), fz_to_gen(psobj[i].pageref),
+ fz_to_num(psobj[i].u.form.obj), fz_to_gen(psobj[i].u.form.obj));
+ }
+ printf("\n");
+ }
+}
+
+static void
+showinfo(char *filename, int show, char *pagelist)
+{
+ int page, spage, epage;
+ char *spec, *dash;
+ int allpages;
+
+ if (!xref)
+ infousage();
+
+ allpages = !strcmp(pagelist, "1-");
+
+ spec = fz_strsep(&pagelist, ",");
+ while (spec)
+ {
+ dash = strchr(spec, '-');
+
+ if (dash == spec)
+ spage = epage = pagecount;
+ else
+ spage = epage = atoi(spec);
+
+ if (dash)
+ {
+ if (strlen(dash) > 1)
+ epage = atoi(dash + 1);
+ else
+ epage = pagecount;
+ }
+
+ if (spage > epage)
+ page = spage, spage = epage, epage = page;
+
+ if (spage < 1)
+ spage = 1;
+ if (epage > pagecount)
+ epage = pagecount;
+ if (spage > pagecount)
+ spage = pagecount;
+
+ if (allpages)
+ printf("Retrieving info from pages %d-%d...\n", spage, epage);
+ if (spage >= 1)
+ {
+ for (page = spage; page <= epage; page++)
+ {
+ gatherpageinfo(page);
+ if (!allpages)
+ {
+ printf("Page %d:\n", page);
+ printinfo(filename, show, page);
+ printf("\n");
+ }
+ }
+ }
+
+ spec = fz_strsep(&pagelist, ",");
+ }
+
+ if (allpages)
+ printinfo(filename, show, -1);
+}
+
+int main(int argc, char **argv)
+{
+ enum { NO_FILE_OPENED, NO_INFO_GATHERED, INFO_SHOWN } state;
+ fz_error error;
+ char *filename = "";
+ char *password = "";
+ int show = ALL;
+ int c;
+
+ while ((c = fz_getopt(argc, argv, "mfispxd:")) != -1)
+ {
+ switch (c)
+ {
+ case 'm': if (show == ALL) show = DIMENSIONS; else show |= DIMENSIONS; break;
+ case 'f': if (show == ALL) show = FONTS; else show |= FONTS; break;
+ case 'i': if (show == ALL) show = IMAGES; else show |= IMAGES; break;
+ case 's': if (show == ALL) show = SHADINGS; else show |= SHADINGS; break;
+ case 'p': if (show == ALL) show = PATTERNS; else show |= PATTERNS; break;
+ case 'x': if (show == ALL) show = XOBJS; else show |= XOBJS; break;
+ case 'd': password = fz_optarg; break;
+ default:
+ infousage();
+ break;
+ }
+ }
+
+ if (fz_optind == argc)
+ infousage();
+
+ state = NO_FILE_OPENED;
+ while (fz_optind < argc)
+ {
+ if (strstr(argv[fz_optind], ".pdf") || strstr(argv[fz_optind], ".PDF"))
+ {
+ if (state == NO_INFO_GATHERED)
+ {
+ showinfo(filename, show, "1-");
+ closexref();
+ }
+
+ closexref();
+
+ filename = argv[fz_optind];
+ printf("%s:\n", filename);
+ error = pdf_open_xref(&xref, filename, password);
+ if (error)
+ die(fz_rethrow(error, "cannot open input file '%s'", filename));
+
+ error = pdf_load_page_tree(xref);
+ if (error)
+ die(fz_rethrow(error, "cannot load page tree: %s", filename));
+ pagecount = pdf_count_pages(xref);
+
+ showglobalinfo();
+ state = NO_INFO_GATHERED;
+ }
+ else
+ {
+ showinfo(filename, show, argv[fz_optind]);
+ state = INFO_SHOWN;
+ }
+
+ fz_optind++;
+ }
+
+ if (state == NO_INFO_GATHERED)
+ showinfo(filename, show, "1-");
+
+ closexref();
+
+ return 0;
+}
diff --git a/contrib/media/updf/apps/pdfshow.c b/contrib/media/updf/apps/pdfshow.c
new file mode 100644
index 000000000..5e74042bf
--- /dev/null
+++ b/contrib/media/updf/apps/pdfshow.c
@@ -0,0 +1,240 @@
+/*
+ * pdfshow -- the ultimate pdf debugging tool
+ */
+
+#include "fitz.h"
+#include "mupdf.h"
+
+static pdf_xref *xref = NULL;
+static int showbinary = 0;
+static int showdecode = 1;
+static int showcolumn;
+
+void die(fz_error error)
+{
+ fz_catch(error, "aborting");
+ if (xref)
+ pdf_free_xref(xref);
+ exit(1);
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "usage: pdfshow [options] file.pdf [grepable] [xref] [trailer] [pagetree] [object numbers]\n");
+ fprintf(stderr, "\t-b\tprint streams as binary data\n");
+ fprintf(stderr, "\t-e\tprint encoded streams (don't decode)\n");
+ fprintf(stderr, "\t-p\tpassword\n");
+ exit(1);
+}
+
+static void showtrailer(void)
+{
+ if (!xref)
+ die(fz_throw("no file specified"));
+ printf("trailer\n");
+ fz_debug_obj(xref->trailer);
+ printf("\n");
+}
+
+static void showxref(void)
+{
+ if (!xref)
+ die(fz_throw("no file specified"));
+ pdf_debug_xref(xref);
+ printf("\n");
+}
+
+static void showpagetree(void)
+{
+ fz_error error;
+ fz_obj *ref;
+ int count;
+ int i;
+
+ if (!xref)
+ die(fz_throw("no file specified"));
+
+ if (!xref->page_len)
+ {
+ error = pdf_load_page_tree(xref);
+ if (error)
+ die(fz_rethrow(error, "cannot load page tree"));
+ }
+
+ count = pdf_count_pages(xref);
+ for (i = 0; i < count; i++)
+ {
+ ref = xref->page_refs[i];
+ printf("page %d = %d %d R\n", i + 1, fz_to_num(ref), fz_to_gen(ref));
+ }
+ printf("\n");
+}
+
+static void showsafe(unsigned char *buf, int n)
+{
+ int i;
+ for (i = 0; i < n; i++) {
+ if (buf[i] == '\r' || buf[i] == '\n') {
+ putchar('\n');
+ showcolumn = 0;
+ }
+ else if (buf[i] < 32 || buf[i] > 126) {
+ putchar('.');
+ showcolumn ++;
+ }
+ else {
+ putchar(buf[i]);
+ showcolumn ++;
+ }
+ if (showcolumn == 79) {
+ putchar('\n');
+ showcolumn = 0;
+ }
+ }
+}
+
+static void showstream(int num, int gen)
+{
+ fz_error error;
+ fz_stream *stm;
+ unsigned char buf[2048];
+ int n;
+
+ showcolumn = 0;
+
+ if (showdecode)
+ error = pdf_open_stream(&stm, xref, num, gen);
+ else
+ error = pdf_open_raw_stream(&stm, xref, num, gen);
+ if (error)
+ die(error);
+
+ while (1)
+ {
+ n = fz_read(stm, buf, sizeof buf);
+ if (n < 0)
+ die(n);
+ if (n == 0)
+ break;
+ if (showbinary)
+ fwrite(buf, 1, n, stdout);
+ else
+ showsafe(buf, n);
+ }
+
+ fz_close(stm);
+}
+
+static void showobject(int num, int gen)
+{
+ fz_error error;
+ fz_obj *obj;
+
+ if (!xref)
+ die(fz_throw("no file specified"));
+
+ error = pdf_load_object(&obj, xref, num, gen);
+ if (error)
+ die(error);
+
+ if (pdf_is_stream(xref, num, gen))
+ {
+ if (showbinary)
+ {
+ showstream(num, gen);
+ }
+ else
+ {
+ printf("%d %d obj\n", num, gen);
+ fz_debug_obj(obj);
+ printf("stream\n");
+ showstream(num, gen);
+ printf("endstream\n");
+ printf("endobj\n\n");
+ }
+ }
+ else
+ {
+ printf("%d %d obj\n", num, gen);
+ fz_debug_obj(obj);
+ printf("endobj\n\n");
+ }
+
+ fz_drop_obj(obj);
+}
+
+static void showgrep(char *filename)
+{
+ fz_error error;
+ fz_obj *obj;
+ int i;
+
+ for (i = 0; i < xref->len; i++)
+ {
+ if (xref->table[i].type == 'n' || xref->table[i].type == 'o')
+ {
+ error = pdf_load_object(&obj, xref, i, 0);
+ if (error)
+ die(error);
+
+ fz_sort_dict(obj);
+
+ printf("%s:%d: ", filename, i);
+ fz_fprint_obj(stdout, obj, 1);
+
+ fz_drop_obj(obj);
+ }
+ }
+
+ printf("%s:trailer: ", filename);
+ fz_fprint_obj(stdout, xref->trailer, 1);
+}
+
+int main(int argc, char **argv)
+{
+ char *password = NULL; /* don't throw errors if encrypted */
+ char *filename;
+ fz_error error;
+ int c;
+
+ while ((c = fz_getopt(argc, argv, "p:be")) != -1)
+ {
+ switch (c)
+ {
+ case 'p': password = fz_optarg; break;
+ case 'b': showbinary = 1; break;
+ case 'e': showdecode = 0; break;
+ default: usage(); break;
+ }
+ }
+
+ if (fz_optind == argc)
+ usage();
+
+ filename = argv[fz_optind++];
+ error = pdf_open_xref(&xref, filename, password);
+ if (error)
+ die(fz_rethrow(error, "cannot open document: %s", filename));
+
+ if (fz_optind == argc)
+ showtrailer();
+
+ while (fz_optind < argc)
+ {
+ switch (argv[fz_optind][0])
+ {
+ case 't': showtrailer(); break;
+ case 'x': showxref(); break;
+ case 'p': showpagetree(); break;
+ case 'g': showgrep(filename); break;
+ default: showobject(atoi(argv[fz_optind]), 0); break;
+ }
+ fz_optind++;
+ }
+
+ pdf_free_xref(xref);
+
+ fz_flush_warnings();
+
+ return 0;
+}
diff --git a/contrib/media/updf/apps/win_main.c b/contrib/media/updf/apps/win_main.c
new file mode 100644
index 000000000..da97b011a
--- /dev/null
+++ b/contrib/media/updf/apps/win_main.c
@@ -0,0 +1,895 @@
+#include "fitz.h"
+#include "mupdf.h"
+#include "muxps.h"
+#include "pdfapp.h"
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+#ifndef _UNICODE
+#define _UNICODE
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+#include
+
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x020A
+#endif
+
+#define ID_ABOUT 0x1000
+#define ID_DOCINFO 0x1001
+
+static HWND hwndframe = NULL;
+static HWND hwndview = NULL;
+static HDC hdc;
+static HBRUSH bgbrush;
+static HBRUSH shbrush;
+static BITMAPINFO *dibinf;
+static HCURSOR arrowcurs, handcurs, waitcurs;
+static LRESULT CALLBACK frameproc(HWND, UINT, WPARAM, LPARAM);
+static LRESULT CALLBACK viewproc(HWND, UINT, WPARAM, LPARAM);
+
+static int justcopied = 0;
+
+static pdfapp_t gapp;
+
+static wchar_t wbuf[1024];
+static char filename[1024];
+
+/*
+ * Create registry keys to associate MuPDF with PDF and XPS files.
+ */
+
+#define OPEN_KEY(parent, name, ptr) \
+ RegCreateKeyExA(parent, name, 0, 0, 0, KEY_WRITE, 0, &ptr, 0)
+
+#define SET_KEY(parent, name, value) \
+ RegSetValueExA(parent, name, 0, REG_SZ, value, strlen(value) + 1)
+
+void install_app(char *argv0)
+{
+ char buf[512];
+ HKEY software, classes, mupdf, dotpdf, dotxps;
+ HKEY shell, open, command, supported_types;
+ HKEY pdf_progids, xps_progids;
+
+ OPEN_KEY(HKEY_CURRENT_USER, "Software", software);
+ OPEN_KEY(software, "Classes", classes);
+ OPEN_KEY(classes, ".pdf", dotpdf);
+ OPEN_KEY(dotpdf, "OpenWithProgids", pdf_progids);
+ OPEN_KEY(classes, ".xps", dotxps);
+ OPEN_KEY(dotxps, "OpenWithProgids", xps_progids);
+ OPEN_KEY(classes, "MuPDF", mupdf);
+ OPEN_KEY(mupdf, "SupportedTypes", supported_types);
+ OPEN_KEY(mupdf, "shell", shell);
+ OPEN_KEY(shell, "open", open);
+ OPEN_KEY(open, "command", command);
+
+ sprintf(buf, "\"%s\" \"%%1\"", argv0);
+
+ SET_KEY(open, "FriendlyAppName", "MuPDF");
+ SET_KEY(command, "", buf);
+ SET_KEY(supported_types, ".pdf", "");
+ SET_KEY(supported_types, ".xps", "");
+ SET_KEY(pdf_progids, "MuPDF", "");
+ SET_KEY(xps_progids, "MuPDF", "");
+
+ RegCloseKey(dotxps);
+ RegCloseKey(dotpdf);
+ RegCloseKey(mupdf);
+ RegCloseKey(classes);
+ RegCloseKey(software);
+}
+
+/*
+ * Dialog boxes
+ */
+
+void winwarn(pdfapp_t *app, char *msg)
+{
+ MessageBoxA(hwndframe, msg, "MuPDF: Warning", MB_ICONWARNING);
+}
+
+void winerror(pdfapp_t *app, fz_error error)
+{
+ char msgbuf[160 * 30];
+ int i;
+
+ /* TODO: redirect stderr to a log file and display here */
+ fz_catch(error, "displaying error message to user");
+
+ fz_strlcpy(msgbuf, "An error has occurred.\n\n", sizeof msgbuf);
+ for (i = 0; i < fz_get_error_count(); i++)
+ {
+ fz_strlcat(msgbuf, fz_get_error_line(i), sizeof msgbuf);
+ fz_strlcat(msgbuf, "\n", sizeof msgbuf);
+ }
+
+ MessageBoxA(hwndframe, msgbuf, "MuPDF: Error", MB_ICONERROR);
+ exit(1);
+}
+
+void win32error(char *msg)
+{
+ LPSTR buf;
+ int code = GetLastError();
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ code,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&buf, 0, NULL);
+ winerror(&gapp, fz_throw("%s:\n%s", msg, buf));
+}
+
+int winfilename(wchar_t *buf, int len)
+{
+ OPENFILENAME ofn;
+ buf[0] = 0;
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hwndframe;
+ ofn.lpstrFile = buf;
+ ofn.nMaxFile = len;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = L"MuPDF: Open PDF file";
+ ofn.lpstrFilter = L"Documents (*.pdf;*.xps)\0*.xps;*.pdf\0PDF Files (*.pdf)\0*.pdf\0XPS Files (*.xps)\0*.xps\0All Files\0*\0\0";
+ ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
+ return GetOpenFileNameW(&ofn);
+}
+
+static char pd_filename[256] = "The file is encrypted.";
+static char pd_password[256] = "";
+static int pd_okay = 0;
+
+INT CALLBACK
+dlogpassproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemTextA(hwnd, 4, pd_filename);
+ return TRUE;
+ case WM_COMMAND:
+ switch(wParam)
+ {
+ case 1:
+ pd_okay = 1;
+ GetDlgItemTextA(hwnd, 3, pd_password, sizeof pd_password);
+ EndDialog(hwnd, 1);
+ return TRUE;
+ case 2:
+ pd_okay = 0;
+ EndDialog(hwnd, 1);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+char *winpassword(pdfapp_t *app, char *filename)
+{
+ char buf[1024], *s;
+ int code;
+ strcpy(buf, filename);
+ s = buf;
+ if (strrchr(s, '\\')) s = strrchr(s, '\\') + 1;
+ if (strrchr(s, '/')) s = strrchr(s, '/') + 1;
+ if (strlen(s) > 32)
+ strcpy(s + 30, "...");
+ sprintf(pd_filename, "The file \"%s\" is encrypted.", s);
+ code = DialogBoxW(NULL, L"IDD_DLOGPASS", hwndframe, dlogpassproc);
+ if (code <= 0)
+ win32error("cannot create password dialog");
+ if (pd_okay)
+ return pd_password;
+ return NULL;
+}
+
+INT CALLBACK
+dloginfoproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ char buf[256];
+ pdf_xref *xref = gapp.xref;
+ fz_obj *info, *obj;
+
+ switch(message)
+ {
+ case WM_INITDIALOG:
+
+ SetDlgItemTextW(hwnd, 0x10, wbuf);
+
+ if (!xref)
+ {
+ SetDlgItemTextA(hwnd, 0x11, "XPS");
+ SetDlgItemTextA(hwnd, 0x12, "None");
+ SetDlgItemTextA(hwnd, 0x13, "n/a");
+ return TRUE;
+ }
+
+ sprintf(buf, "PDF %d.%d", xref->version / 10, xref->version % 10);
+ SetDlgItemTextA(hwnd, 0x11, buf);
+
+ if (xref->crypt)
+ {
+ sprintf(buf, "Standard V%d %d-bit %s", pdf_get_crypt_revision(xref),
+ pdf_get_crypt_length(xref), pdf_get_crypt_method(xref));
+ SetDlgItemTextA(hwnd, 0x12, buf);
+ strcpy(buf, "");
+ if (pdf_has_permission(xref, PDF_PERM_PRINT))
+ strcat(buf, "print, ");
+ if (pdf_has_permission(xref, PDF_PERM_CHANGE))
+ strcat(buf, "modify, ");
+ if (pdf_has_permission(xref, PDF_PERM_COPY))
+ strcat(buf, "copy, ");
+ if (pdf_has_permission(xref, PDF_PERM_NOTES))
+ strcat(buf, "annotate, ");
+ if (strlen(buf) > 2)
+ buf[strlen(buf)-2] = 0;
+ else
+ strcpy(buf, "none");
+ SetDlgItemTextA(hwnd, 0x13, buf);
+ }
+ else
+ {
+ SetDlgItemTextA(hwnd, 0x12, "None");
+ SetDlgItemTextA(hwnd, 0x13, "n/a");
+ }
+
+ info = fz_dict_gets(xref->trailer, "Info");
+ if (!info)
+ return TRUE;
+
+#define SETUCS(ID) \
+ { \
+ unsigned short *ucs; \
+ ucs = pdf_to_ucs2(obj); \
+ SetDlgItemTextW(hwnd, ID, ucs); \
+ fz_free(ucs); \
+ }
+
+ if ((obj = fz_dict_gets(info, "Title")))
+ SETUCS(0x20);
+ if ((obj = fz_dict_gets(info, "Author")))
+ SETUCS(0x21);
+ if ((obj = fz_dict_gets(info, "Subject")))
+ SETUCS(0x22);
+ if ((obj = fz_dict_gets(info, "Keywords")))
+ SETUCS(0x23);
+ if ((obj = fz_dict_gets(info, "Creator")))
+ SETUCS(0x24);
+ if ((obj = fz_dict_gets(info, "Producer")))
+ SETUCS(0x25);
+ if ((obj = fz_dict_gets(info, "CreationDate")))
+ SETUCS(0x26);
+ if ((obj = fz_dict_gets(info, "ModDate")))
+ SETUCS(0x27);
+ return TRUE;
+
+ case WM_COMMAND:
+ EndDialog(hwnd, 1);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void info()
+{
+ int code = DialogBoxW(NULL, L"IDD_DLOGINFO", hwndframe, dloginfoproc);
+ if (code <= 0)
+ win32error("cannot create info dialog");
+}
+
+INT CALLBACK
+dlogaboutproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemTextA(hwnd, 2, pdfapp_version(&gapp));
+ SetDlgItemTextA(hwnd, 3, pdfapp_usage(&gapp));
+ return TRUE;
+ case WM_COMMAND:
+ EndDialog(hwnd, 1);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void winhelp(pdfapp_t*app)
+{
+ int code = DialogBoxW(NULL, L"IDD_DLOGABOUT", hwndframe, dlogaboutproc);
+ if (code <= 0)
+ win32error("cannot create help dialog");
+}
+
+/*
+ * Main window
+ */
+
+void winopen()
+{
+ WNDCLASS wc;
+ HMENU menu;
+ RECT r;
+ ATOM a;
+
+ /* Create and register window frame class */
+ memset(&wc, 0, sizeof(wc));
+ wc.style = 0;
+ wc.lpfnWndProc = frameproc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIconA(wc.hInstance, "IDI_ICONAPP");
+ wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = L"FrameWindow";
+ a = RegisterClassW(&wc);
+ if (!a)
+ win32error("cannot register frame window class");
+
+ /* Create and register window view class */
+ memset(&wc, 0, sizeof(wc));
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = viewproc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = L"ViewWindow";
+ a = RegisterClassW(&wc);
+ if (!a)
+ win32error("cannot register view window class");
+
+ /* Get screen size */
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+ gapp.scrw = r.right - r.left;
+ gapp.scrh = r.bottom - r.top;
+
+ /* Create cursors */
+ arrowcurs = LoadCursor(NULL, IDC_ARROW);
+ handcurs = LoadCursor(NULL, IDC_HAND);
+ waitcurs = LoadCursor(NULL, IDC_WAIT);
+
+ /* And a background color */
+ bgbrush = CreateSolidBrush(RGB(0x70,0x70,0x70));
+ shbrush = CreateSolidBrush(RGB(0x40,0x40,0x40));
+
+ /* Init DIB info for buffer */
+ dibinf = malloc(sizeof(BITMAPINFO) + 12);
+ assert(dibinf != NULL);
+ dibinf->bmiHeader.biSize = sizeof(dibinf->bmiHeader);
+ dibinf->bmiHeader.biPlanes = 1;
+ dibinf->bmiHeader.biBitCount = 32;
+ dibinf->bmiHeader.biCompression = BI_RGB;
+ dibinf->bmiHeader.biXPelsPerMeter = 2834;
+ dibinf->bmiHeader.biYPelsPerMeter = 2834;
+ dibinf->bmiHeader.biClrUsed = 0;
+ dibinf->bmiHeader.biClrImportant = 0;
+ dibinf->bmiHeader.biClrUsed = 0;
+
+ /* Create window */
+ hwndframe = CreateWindowW(L"FrameWindow", // window class name
+ NULL, // window caption
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ CW_USEDEFAULT, CW_USEDEFAULT, // initial position
+ 300, // initial x size
+ 300, // initial y size
+ 0, // parent window handle
+ 0, // window menu handle
+ 0, // program instance handle
+ 0); // creation parameters
+ if (!hwndframe)
+ win32error("cannot create frame: %s");
+
+ hwndview = CreateWindowW(L"ViewWindow", // window class name
+ NULL,
+ WS_VISIBLE | WS_CHILD,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ hwndframe, 0, 0, 0);
+ if (!hwndview)
+ win32error("cannot create view: %s");
+
+ hdc = NULL;
+
+ SetWindowTextW(hwndframe, L"MuPDF");
+
+ menu = GetSystemMenu(hwndframe, 0);
+ AppendMenuW(menu, MF_SEPARATOR, 0, NULL);
+ AppendMenuW(menu, MF_STRING, ID_ABOUT, L"About MuPDF...");
+ AppendMenuW(menu, MF_STRING, ID_DOCINFO, L"Document Properties...");
+
+ SetCursor(arrowcurs);
+}
+
+void winclose(pdfapp_t *app)
+{
+ pdfapp_close(app);
+ exit(0);
+}
+
+void wincursor(pdfapp_t *app, int curs)
+{
+ if (curs == ARROW)
+ SetCursor(arrowcurs);
+ if (curs == HAND)
+ SetCursor(handcurs);
+ if (curs == WAIT)
+ SetCursor(waitcurs);
+}
+
+void wintitle(pdfapp_t *app, char *title)
+{
+ wchar_t wide[256], *dp;
+ char *sp;
+ int rune;
+
+ dp = wide;
+ sp = title;
+ while (*sp && dp < wide + 255)
+ {
+ sp += chartorune(&rune, sp);
+ *dp++ = rune;
+ }
+ *dp = 0;
+
+ SetWindowTextW(hwndframe, wide);
+}
+
+void windrawrect(pdfapp_t *app, int x0, int y0, int x1, int y1)
+{
+ RECT r;
+ r.left = x0;
+ r.top = y0;
+ r.right = x1;
+ r.bottom = y1;
+ FillRect(hdc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
+}
+
+void windrawstring(pdfapp_t *app, int x, int y, char *s)
+{
+ HFONT font = (HFONT)GetStockObject(ANSI_FIXED_FONT);
+ SelectObject(hdc, font);
+ TextOutA(hdc, x, y - 12, s, strlen(s));
+}
+
+void winblitsearch()
+{
+ if (gapp.isediting)
+ {
+ char buf[sizeof(gapp.search) + 50];
+ sprintf(buf, "Search: %s", gapp.search);
+ windrawrect(&gapp, 0, 0, gapp.winw, 30);
+ windrawstring(&gapp, 10, 20, buf);
+ }
+}
+
+void winblit()
+{
+ int x0 = gapp.panx;
+ int y0 = gapp.pany;
+ int x1 = gapp.panx + gapp.image->w;
+ int y1 = gapp.pany + gapp.image->h;
+ RECT r;
+
+ if (gapp.image)
+ {
+ if (gapp.iscopying || justcopied)
+ {
+ pdfapp_invert(&gapp, gapp.selr);
+ justcopied = 1;
+ }
+
+ pdfapp_inverthit(&gapp);
+
+ dibinf->bmiHeader.biWidth = gapp.image->w;
+ dibinf->bmiHeader.biHeight = -gapp.image->h;
+ dibinf->bmiHeader.biSizeImage = gapp.image->h * 4;
+
+ if (gapp.image->n == 2)
+ {
+ int i = gapp.image->w * gapp.image->h;
+ unsigned char *color = malloc(i*4);
+ unsigned char *s = gapp.image->samples;
+ unsigned char *d = color;
+ for (; i > 0 ; i--)
+ {
+ d[2] = d[1] = d[0] = *s++;
+ d[3] = *s++;
+ d += 4;
+ }
+ SetDIBitsToDevice(hdc,
+ gapp.panx, gapp.pany, gapp.image->w, gapp.image->h,
+ 0, 0, 0, gapp.image->h, color,
+ dibinf, DIB_RGB_COLORS);
+ free(color);
+ }
+ if (gapp.image->n == 4)
+ {
+ SetDIBitsToDevice(hdc,
+ gapp.panx, gapp.pany, gapp.image->w, gapp.image->h,
+ 0, 0, 0, gapp.image->h, gapp.image->samples,
+ dibinf, DIB_RGB_COLORS);
+ }
+
+ pdfapp_inverthit(&gapp);
+
+ if (gapp.iscopying || justcopied)
+ {
+ pdfapp_invert(&gapp, gapp.selr);
+ justcopied = 1;
+ }
+ }
+
+ /* Grey background */
+ r.top = 0; r.bottom = gapp.winh;
+ r.left = 0; r.right = x0;
+ FillRect(hdc, &r, bgbrush);
+ r.left = x1; r.right = gapp.winw;
+ FillRect(hdc, &r, bgbrush);
+ r.left = 0; r.right = gapp.winw;
+ r.top = 0; r.bottom = y0;
+ FillRect(hdc, &r, bgbrush);
+ r.top = y1; r.bottom = gapp.winh;
+ FillRect(hdc, &r, bgbrush);
+
+ /* Drop shadow */
+ r.left = x0 + 2;
+ r.right = x1 + 2;
+ r.top = y1;
+ r.bottom = y1 + 2;
+ FillRect(hdc, &r, shbrush);
+ r.left = x1;
+ r.right = x1 + 2;
+ r.top = y0 + 2;
+ r.bottom = y1;
+ FillRect(hdc, &r, shbrush);
+
+ winblitsearch();
+}
+
+void winresize(pdfapp_t *app, int w, int h)
+{
+ ShowWindow(hwndframe, SW_SHOWDEFAULT);
+ w += GetSystemMetrics(SM_CXFRAME) * 2;
+ h += GetSystemMetrics(SM_CYFRAME) * 2;
+ h += GetSystemMetrics(SM_CYCAPTION);
+ SetWindowPos(hwndframe, 0, 0, 0, w, h, SWP_NOZORDER | SWP_NOMOVE);
+}
+
+void winrepaint(pdfapp_t *app)
+{
+ InvalidateRect(hwndview, NULL, 0);
+}
+
+void winrepaintsearch(pdfapp_t *app)
+{
+ // TODO: invalidate only search area and
+ // call only search redraw routine.
+ InvalidateRect(hwndview, NULL, 0);
+}
+
+/*
+ * Event handling
+ */
+
+void windocopy(pdfapp_t *app)
+{
+ HGLOBAL handle;
+ unsigned short *ucsbuf;
+
+ if (!OpenClipboard(hwndframe))
+ return;
+ EmptyClipboard();
+
+ handle = GlobalAlloc(GMEM_MOVEABLE, 4096 * sizeof(unsigned short));
+ if (!handle)
+ {
+ CloseClipboard();
+ return;
+ }
+
+ ucsbuf = GlobalLock(handle);
+ pdfapp_oncopy(&gapp, ucsbuf, 4096);
+ GlobalUnlock(handle);
+
+ SetClipboardData(CF_UNICODETEXT, handle);
+ CloseClipboard();
+
+ justcopied = 1; /* keep inversion around for a while... */
+}
+
+void winreloadfile(pdfapp_t *app)
+{
+ int fd;
+
+ pdfapp_close(app);
+
+ fd = _wopen(wbuf, O_BINARY | O_RDONLY, 0666);
+ if (fd < 0)
+ winerror(&gapp, fz_throw("cannot reload file '%s'", filename));
+
+ pdfapp_open(app, filename, fd, 1);
+}
+
+void winopenuri(pdfapp_t *app, char *buf)
+{
+ ShellExecuteA(hwndframe, "open", buf, 0, 0, SW_SHOWNORMAL);
+}
+
+void handlekey(int c)
+{
+ if (GetCapture() == hwndview)
+ return;
+
+ if (justcopied)
+ {
+ justcopied = 0;
+ winrepaint(&gapp);
+ }
+
+ /* translate VK into ascii equivalents */
+ if (c > 256)
+ {
+ switch (c - 256)
+ {
+ case VK_F1: c = '?'; break;
+ case VK_ESCAPE: c = '\033'; break;
+ case VK_DOWN: c = 'j'; break;
+ case VK_UP: c = 'k'; break;
+ case VK_LEFT: c = 'b'; break;
+ case VK_RIGHT: c = ' '; break;
+ case VK_PRIOR: c = ','; break;
+ case VK_NEXT: c = '.'; break;
+ }
+ }
+
+ pdfapp_onkey(&gapp, c);
+ winrepaint(&gapp);
+}
+
+void handlemouse(int x, int y, int btn, int state)
+{
+ if (state != 0 && justcopied)
+ {
+ justcopied = 0;
+ winrepaint(&gapp);
+ }
+
+ if (state == 1)
+ SetCapture(hwndview);
+ if (state == -1)
+ ReleaseCapture();
+
+ pdfapp_onmouse(&gapp, x, y, btn, 0, state);
+}
+
+LRESULT CALLBACK
+frameproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_SETFOCUS:
+ PostMessage(hwnd, WM_APP+5, 0, 0);
+ return 0;
+ case WM_APP+5:
+ SetFocus(hwndview);
+ return 0;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_SYSCOMMAND:
+ if (wParam == ID_ABOUT)
+ {
+ winhelp(&gapp);
+ return 0;
+ }
+ if (wParam == ID_DOCINFO)
+ {
+ info();
+ return 0;
+ }
+ if (wParam == SC_MAXIMIZE)
+ gapp.shrinkwrap = 0;
+ break;
+
+ case WM_SIZE:
+ {
+ // More generally, you should use GetEffectiveClientRect
+ // if you have a toolbar etc.
+ RECT rect;
+ GetClientRect(hwnd, &rect);
+ MoveWindow(hwndview, rect.left, rect.top,
+ rect.right-rect.left, rect.bottom-rect.top, TRUE);
+ return 0;
+ }
+
+ case WM_SIZING:
+ gapp.shrinkwrap = 0;
+ break;
+
+ case WM_NOTIFY:
+ case WM_COMMAND:
+ return SendMessage(hwndview, message, wParam, lParam);
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+LRESULT CALLBACK
+viewproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static int oldx = 0;
+ static int oldy = 0;
+ int x = (signed short) LOWORD(lParam);
+ int y = (signed short) HIWORD(lParam);
+
+ switch (message)
+ {
+ case WM_SIZE:
+ if (wParam == SIZE_MINIMIZED)
+ return 0;
+ if (wParam == SIZE_MAXIMIZED)
+ gapp.shrinkwrap = 0;
+ pdfapp_onresize(&gapp, LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ /* Paint events are low priority and automagically catenated
+ * so we don't need to do any fancy waiting to defer repainting.
+ */
+ case WM_PAINT:
+ {
+ //puts("WM_PAINT");
+ PAINTSTRUCT ps;
+ hdc = BeginPaint(hwnd, &ps);
+ winblit();
+ hdc = NULL;
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ return 1; // well, we don't need to erase to redraw cleanly
+
+ /* Mouse events */
+
+ case WM_LBUTTONDOWN:
+ SetFocus(hwndview);
+ oldx = x; oldy = y;
+ handlemouse(x, y, 1, 1);
+ return 0;
+ case WM_MBUTTONDOWN:
+ SetFocus(hwndview);
+ oldx = x; oldy = y;
+ handlemouse(x, y, 2, 1);
+ return 0;
+ case WM_RBUTTONDOWN:
+ SetFocus(hwndview);
+ oldx = x; oldy = y;
+ handlemouse(x, y, 3, 1);
+ return 0;
+
+ case WM_LBUTTONUP:
+ oldx = x; oldy = y;
+ handlemouse(x, y, 1, -1);
+ return 0;
+ case WM_MBUTTONUP:
+ oldx = x; oldy = y;
+ handlemouse(x, y, 2, -1);
+ return 0;
+ case WM_RBUTTONUP:
+ oldx = x; oldy = y;
+ handlemouse(x, y, 3, -1);
+ return 0;
+
+ case WM_MOUSEMOVE:
+ oldx = x; oldy = y;
+ handlemouse(x, y, 0, 0);
+ return 0;
+
+ /* Mouse wheel */
+
+ case WM_MOUSEWHEEL:
+ if ((signed short)HIWORD(wParam) > 0)
+ handlekey(LOWORD(wParam) & MK_SHIFT ? '+' : 'k');
+ else
+ handlekey(LOWORD(wParam) & MK_SHIFT ? '-' : 'j');
+ return 0;
+
+ /* Keyboard events */
+
+ case WM_KEYDOWN:
+ /* only handle special keys */
+ switch (wParam)
+ {
+ case VK_F1:
+ case VK_LEFT:
+ case VK_UP:
+ case VK_PRIOR:
+ case VK_RIGHT:
+ case VK_DOWN:
+ case VK_NEXT:
+ case VK_ESCAPE:
+ handlekey(wParam + 256);
+ handlemouse(oldx, oldy, 0, 0); /* update cursor */
+ return 0;
+ }
+ return 1;
+
+ /* unicode encoded chars, including escape, backspace etc... */
+ case WM_CHAR:
+ if (wParam < 256)
+ {
+ handlekey(wParam);
+ handlemouse(oldx, oldy, 0, 0); /* update cursor */
+ }
+ return 0;
+ }
+
+ fflush(stdout);
+
+ /* Pass on unhandled events to Windows */
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+int WINAPI
+WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
+{
+ int argc;
+ LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
+ char argv0[256];
+ MSG msg;
+ int fd;
+ int code;
+
+ fz_accelerate();
+
+ pdfapp_init(&gapp);
+
+ GetModuleFileNameA(NULL, argv0, sizeof argv0);
+ install_app(argv0);
+
+ winopen();
+
+ if (argc == 2)
+ {
+ wcscpy(wbuf, argv[1]);
+ }
+ else
+ {
+ if (!winfilename(wbuf, nelem(wbuf)))
+ exit(0);
+ }
+
+ fd = _wopen(wbuf, O_BINARY | O_RDONLY, 0666);
+ if (fd < 0)
+ winerror(&gapp, fz_throw("cannot open file '%s'", filename));
+
+ code = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, filename, sizeof filename, NULL, NULL);
+ if (code == 0)
+ win32error("cannot convert filename to utf-8");
+
+ pdfapp_open(&gapp, filename, fd, 0);
+
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ pdfapp_close(&gapp);
+
+ return 0;
+}
diff --git a/contrib/media/updf/apps/win_res.rc b/contrib/media/updf/apps/win_res.rc
new file mode 100644
index 000000000..23faa9e28
--- /dev/null
+++ b/contrib/media/updf/apps/win_res.rc
@@ -0,0 +1,61 @@
+IDI_ICONAPP ICON "mupdf_icon_antialias.ico"
+
+IDD_DLOGPASS DIALOG 50, 50, 204, 60
+//STYLE DS_MODALFRAME | WS_POPUP
+STYLE 128 | 0x80000000
+CAPTION " MuPDF: Password "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ EDITTEXT 3, 57, 20, 140, 12, 32
+ DEFPUSHBUTTON "Okay", 1, 90, 40, 50, 14, 0x50010001
+ PUSHBUTTON "Cancel", 2, 147, 40, 50, 14, 0x50010000
+ LTEXT "The file is encrypted.", 4, 10, 7, 180, 10, 0x00000
+ LTEXT "Password:", 5, 17, 22, 40, 10, 0x00000
+END
+
+IDD_DLOGINFO DIALOG 50, 50, 300, 145
+STYLE 128 | 0x80000000
+CAPTION " Document Properties "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Okay", 1, 300-10-50, 145-7-14, 50, 14, 0x50010001
+
+ LTEXT "File:", -1, 10, 10, 50, 10, 0
+ LTEXT "Format:", -1, 10, 20, 50, 10, 0
+ LTEXT "Encryption:", -1, 10, 30, 50, 10, 0
+ LTEXT "Permissions:", -1, 10, 40, 50, 10, 0
+
+ LTEXT "", 2, 10, 10, 180, 20, 0
+ LTEXT "", 3, 10, 35, 180, 160, 0
+END
+
diff --git a/contrib/media/updf/apps/x11_image.c b/contrib/media/updf/apps/x11_image.c
new file mode 100644
index 000000000..9383c5450
--- /dev/null
+++ b/contrib/media/updf/apps/x11_image.c
@@ -0,0 +1,697 @@
+/*
+ * Blit RGBA images to X with X(Shm)Images
+ */
+
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 1
+#endif
+
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 1
+#endif
+
+#define noSHOWINFO
+
+#include "fitz.h"
+
+#include
+#include
+#include
+#include
+#include
+
+extern int ffs(int);
+
+typedef void (*ximage_convert_func_t)
+(
+ const unsigned char *src,
+ int srcstride,
+ unsigned char *dst,
+ int dststride,
+ int w,
+ int h
+ );
+
+#define POOLSIZE 4
+#define WIDTH 256
+#define HEIGHT 256
+
+enum {
+ ARGB8888,
+ BGRA8888,
+ RGBA8888,
+ ABGR8888,
+ RGB888,
+ BGR888,
+ RGB565,
+ RGB565_BR,
+ RGB555,
+ RGB555_BR,
+ BGR233,
+ UNKNOWN
+};
+
+#ifdef SHOWINFO
+static char *modename[] = {
+ "ARGB8888",
+ "BGRA8888",
+ "RGBA8888",
+ "ABGR8888",
+ "RGB888",
+ "BGR888",
+ "RGB565",
+ "RGB565_BR",
+ "RGB555",
+ "RGB555_BR",
+ "BGR233",
+ "UNKNOWN"
+};
+#endif
+
+extern ximage_convert_func_t ximage_convert_funcs[];
+
+static struct
+{
+ Display *display;
+ int screen;
+ XVisualInfo visual;
+ Colormap colormap;
+
+ int bitsperpixel;
+ int mode;
+
+ XColor rgbcube[256];
+
+ ximage_convert_func_t convert_func;
+
+ int useshm;
+ int shmcode;
+ XImage *pool[POOLSIZE];
+ /* MUST exist during the lifetime of the shared ximage according to the
+ xc/doc/hardcopy/Xext/mit-shm.PS.gz */
+ XShmSegmentInfo shminfo[POOLSIZE];
+ int lastused;
+} info;
+
+static XImage *
+createximage(Display *dpy, Visual *vis, XShmSegmentInfo *xsi, int depth, int w, int h)
+{
+ XImage *img;
+ Status status;
+
+ if (!XShmQueryExtension(dpy))
+ goto fallback;
+ if (!info.useshm)
+ goto fallback;
+
+ img = XShmCreateImage(dpy, vis, depth, ZPixmap, NULL, xsi, w, h);
+ if (!img)
+ {
+ fprintf(stderr, "warn: could not XShmCreateImage\n");
+ goto fallback;
+ }
+
+ xsi->shmid = shmget(IPC_PRIVATE,
+ img->bytes_per_line * img->height,
+ IPC_CREAT | 0777);
+ if (xsi->shmid < 0)
+ {
+ XDestroyImage(img);
+ fprintf(stderr, "warn: could not shmget\n");
+ goto fallback;
+ }
+
+ img->data = xsi->shmaddr = shmat(xsi->shmid, NULL, 0);
+ if (img->data == (char*)-1)
+ {
+ XDestroyImage(img);
+ fprintf(stderr, "warn: could not shmat\n");
+ goto fallback;
+ }
+
+ xsi->readOnly = False;
+ status = XShmAttach(dpy, xsi);
+ if (!status)
+ {
+ shmdt(xsi->shmaddr);
+ XDestroyImage(img);
+ fprintf(stderr, "warn: could not XShmAttach\n");
+ goto fallback;
+ }
+
+ XSync(dpy, False);
+
+ shmctl(xsi->shmid, IPC_RMID, NULL);
+
+ return img;
+
+fallback:
+ info.useshm = 0;
+
+ img = XCreateImage(dpy, vis, depth, ZPixmap, 0, NULL, w, h, 32, 0);
+ if (!img)
+ {
+ fprintf(stderr, "fail: could not XCreateImage");
+ abort();
+ }
+
+ img->data = malloc(h * img->bytes_per_line);
+ if (!img->data)
+ {
+ fprintf(stderr, "fail: could not malloc");
+ abort();
+ }
+
+ return img;
+}
+
+static void
+make_colormap(void)
+{
+ if (info.visual.class == PseudoColor && info.visual.depth == 8)
+ {
+ int i, r, g, b;
+ i = 0;
+ for (b = 0; b < 4; b++) {
+ for (g = 0; g < 8; g++) {
+ for (r = 0; r < 8; r++) {
+ info.rgbcube[i].pixel = i;
+ info.rgbcube[i].red = (r * 36) << 8;
+ info.rgbcube[i].green = (g * 36) << 8;
+ info.rgbcube[i].blue = (b * 85) << 8;
+ info.rgbcube[i].flags =
+ DoRed | DoGreen | DoBlue;
+ i++;
+ }
+ }
+ }
+ info.colormap = XCreateColormap(info.display,
+ RootWindow(info.display, info.screen),
+ info.visual.visual,
+ AllocAll);
+ XStoreColors(info.display, info.colormap, info.rgbcube, 256);
+ return;
+ }
+ else if (info.visual.class == TrueColor)
+ {
+ info.colormap = 0;
+ return;
+ }
+ fprintf(stderr, "Cannot handle visual class %d with depth: %d\n",
+ info.visual.class, info.visual.depth);
+ return;
+}
+
+static void
+select_mode(void)
+{
+
+ int byteorder;
+ int byterev;
+ unsigned long rm, gm, bm;
+ unsigned long rs, gs, bs;
+
+ byteorder = ImageByteOrder(info.display);
+ if (fz_is_big_endian())
+ byterev = byteorder != MSBFirst;
+ else
+ byterev = byteorder != LSBFirst;
+
+ rm = info.visual.red_mask;
+ gm = info.visual.green_mask;
+ bm = info.visual.blue_mask;
+
+ rs = ffs(rm) - 1;
+ gs = ffs(gm) - 1;
+ bs = ffs(bm) - 1;
+
+#ifdef SHOWINFO
+ printf("ximage: mode %d/%d %08lx %08lx %08lx (%ld,%ld,%ld) %s%s\n",
+ info.visual.depth,
+ info.bitsperpixel,
+ rm, gm, bm, rs, gs, bs,
+ byteorder == MSBFirst ? "msb" : "lsb",
+ byterev ? " ":"");
+#endif
+
+ info.mode = UNKNOWN;
+ if (info.bitsperpixel == 8) {
+ /* Either PseudoColor with BGR233 colormap, or TrueColor */
+ info.mode = BGR233;
+ }
+ else if (info.bitsperpixel == 16) {
+ if (rm == 0xF800 && gm == 0x07E0 && bm == 0x001F)
+ info.mode = !byterev ? RGB565 : RGB565_BR;
+ if (rm == 0x7C00 && gm == 0x03E0 && bm == 0x001F)
+ info.mode = !byterev ? RGB555 : RGB555_BR;
+ }
+ else if (info.bitsperpixel == 24) {
+ if (rs == 0 && gs == 8 && bs == 16)
+ info.mode = byteorder == MSBFirst ? RGB888 : BGR888;
+ if (rs == 16 && gs == 8 && bs == 0)
+ info.mode = byteorder == MSBFirst ? BGR888 : RGB888;
+ }
+ else if (info.bitsperpixel == 32) {
+ if (rs == 0 && gs == 8 && bs == 16)
+ info.mode = byteorder == MSBFirst ? ABGR8888 : RGBA8888;
+ if (rs == 8 && gs == 16 && bs == 24)
+ info.mode = byteorder == MSBFirst ? BGRA8888 : ARGB8888;
+ if (rs == 16 && gs == 8 && bs == 0)
+ info.mode = byteorder == MSBFirst ? ARGB8888 : BGRA8888;
+ if (rs == 24 && gs == 16 && bs == 8)
+ info.mode = byteorder == MSBFirst ? RGBA8888 : ABGR8888;
+ }
+
+#ifdef SHOWINFO
+ printf("ximage: RGBA8888 to %s\n", modename[info.mode]);
+#endif
+
+ /* select conversion function */
+ info.convert_func = ximage_convert_funcs[info.mode];
+}
+
+static int
+create_pool(void)
+{
+ int i;
+
+ info.lastused = 0;
+
+ for (i = 0; i < POOLSIZE; i++) {
+ info.pool[i] = NULL;
+ }
+
+ for (i = 0; i < POOLSIZE; i++) {
+ info.pool[i] = createximage(info.display,
+ info.visual.visual, &info.shminfo[i], info.visual.depth,
+ WIDTH, HEIGHT);
+ if (info.pool[i] == NULL) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static XImage *
+next_pool_image(void)
+{
+ if (info.lastused + 1 >= POOLSIZE) {
+ if (info.useshm)
+ XSync(info.display, False);
+ else
+ XFlush(info.display);
+ info.lastused = 0;
+ }
+ return info.pool[info.lastused ++];
+}
+
+static int
+ximage_error_handler(Display *display, XErrorEvent *event)
+{
+ /* Turn off shared memory images if we get an error from the MIT-SHM extension */
+ if (event->request_code == info.shmcode)
+ {
+ char buf[80];
+ XGetErrorText(display, event->error_code, buf, sizeof buf);
+ fprintf(stderr, "ximage: disabling shared memory extension: %s\n", buf);
+ info.useshm = 0;
+ return 0;
+ }
+
+ XSetErrorHandler(NULL);
+ return (XSetErrorHandler(ximage_error_handler))(display, event);
+}
+
+int
+ximage_init(Display *display, int screen, Visual *visual)
+{
+ XVisualInfo template;
+ XVisualInfo *visuals;
+ int nvisuals;
+ XPixmapFormatValues *formats;
+ int nformats;
+ int ok;
+ int i;
+ int major;
+ int event;
+ int error;
+
+ info.display = display;
+ info.screen = screen;
+ info.colormap = 0;
+
+ /* Get XVisualInfo for this visual */
+ template.visualid = XVisualIDFromVisual(visual);
+ visuals = XGetVisualInfo(display, VisualIDMask, &template, &nvisuals);
+ if (nvisuals != 1) {
+ fprintf(stderr, "Visual not found!\n");
+ XFree(visuals);
+ return 0;
+ }
+ memcpy(&info.visual, visuals, sizeof (XVisualInfo));
+ XFree(visuals);
+
+ /* Get appropriate PixmapFormat for this visual */
+ formats = XListPixmapFormats(info.display, &nformats);
+ for (i = 0; i < nformats; i++) {
+ if (formats[i].depth == info.visual.depth) {
+ info.bitsperpixel = formats[i].bits_per_pixel;
+ break;
+ }
+ }
+ XFree(formats);
+ if (i == nformats) {
+ fprintf(stderr, "PixmapFormat not found!\n");
+ return 0;
+ }
+
+ /* extract mode */
+ select_mode();
+
+ /* prepare colormap */
+ make_colormap();
+
+ /* identify code for MIT-SHM extension */
+ if (XQueryExtension(display, "MIT-SHM", &major, &event, &error) &&
+ XShmQueryExtension(display))
+ info.shmcode = major;
+
+ /* intercept errors looking for SHM code */
+ XSetErrorHandler(ximage_error_handler);
+
+ /* prepare pool of XImages */
+ info.useshm = 1;
+ ok = create_pool();
+ if (!ok)
+ return 0;
+
+#ifdef SHOWINFO
+ printf("ximage: %sPutImage\n", info.useshm ? "XShm" : "X");
+#endif
+
+ return 1;
+}
+
+int
+ximage_get_depth(void)
+{
+ return info.visual.depth;
+}
+
+Visual *
+ximage_get_visual(void)
+{
+ return info.visual.visual;
+}
+
+Colormap
+ximage_get_colormap(void)
+{
+ return info.colormap;
+}
+
+void
+ximage_blit(Drawable d, GC gc,
+ int dstx, int dsty,
+ unsigned char *srcdata,
+ int srcx, int srcy,
+ int srcw, int srch,
+ int srcstride)
+{
+ XImage *image;
+ int ax, ay;
+ int w, h;
+ unsigned char *srcptr;
+
+ for (ay = 0; ay < srch; ay += HEIGHT)
+ {
+ h = MIN(srch - ay, HEIGHT);
+ for (ax = 0; ax < srcw; ax += WIDTH)
+ {
+ w = MIN(srcw - ax, WIDTH);
+
+ image = next_pool_image();
+
+ srcptr = srcdata +
+ (ay + srcy) * srcstride +
+ (ax + srcx) * 4;
+
+ info.convert_func(srcptr, srcstride,
+ (unsigned char *) image->data,
+ image->bytes_per_line, w, h);
+
+ if (info.useshm)
+ {
+ XShmPutImage(info.display, d, gc, image,
+ 0, 0, dstx + ax, dsty + ay,
+ w, h, False);
+ }
+ else
+ {
+ XPutImage(info.display, d, gc, image,
+ 0, 0,
+ dstx + ax,
+ dsty + ay,
+ w, h);
+ }
+ }
+ }
+}
+
+/*
+ * Primitive conversion functions
+ */
+
+#ifndef restrict
+#ifndef _C99
+#ifdef __GNUC__
+#define restrict __restrict__
+#else
+#define restrict
+#endif
+#endif
+#endif
+
+#define PARAMS \
+ const unsigned char * restrict src, \
+ int srcstride, \
+ unsigned char * restrict dst, \
+ int dststride, \
+ int w, \
+ int h
+
+/*
+ * Convert byte:RGBA8888 to various formats
+ */
+
+static void
+ximage_convert_argb8888(PARAMS)
+{
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x ++) {
+ dst[x * 4 + 0] = src[x * 4 + 3]; /* a */
+ dst[x * 4 + 1] = src[x * 4 + 0]; /* r */
+ dst[x * 4 + 2] = src[x * 4 + 1]; /* g */
+ dst[x * 4 + 3] = src[x * 4 + 2]; /* b */
+ }
+ dst += dststride;
+ src += srcstride;
+ }
+}
+
+static void
+ximage_convert_bgra8888(PARAMS)
+{
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ dst[x * 4 + 0] = src[x * 4 + 2];
+ dst[x * 4 + 1] = src[x * 4 + 1];
+ dst[x * 4 + 2] = src[x * 4 + 0];
+ dst[x * 4 + 3] = src[x * 4 + 3];
+ }
+ dst += dststride;
+ src += srcstride;
+ }
+}
+
+static void
+ximage_convert_abgr8888(PARAMS)
+{
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ dst[x * 4 + 0] = src[x * 4 + 3];
+ dst[x * 4 + 1] = src[x * 4 + 2];
+ dst[x * 4 + 2] = src[x * 4 + 1];
+ dst[x * 4 + 3] = src[x * 4 + 0];
+ }
+ dst += dststride;
+ src += srcstride;
+ }
+}
+
+static void
+ximage_convert_rgba8888(PARAMS)
+{
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ dst[x] = src[x];
+ }
+ dst += dststride;
+ src += srcstride;
+ }
+}
+
+static void
+ximage_convert_bgr888(PARAMS)
+{
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ dst[3*x + 0] = src[4*x + 2];
+ dst[3*x + 1] = src[4*x + 1];
+ dst[3*x + 2] = src[4*x + 0];
+ }
+ src += srcstride;
+ dst += dststride;
+ }
+}
+
+static void
+ximage_convert_rgb888(PARAMS)
+{
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ dst[3*x + 0] = src[4*x + 0];
+ dst[3*x + 1] = src[4*x + 1];
+ dst[3*x + 2] = src[4*x + 2];
+ }
+ src += srcstride;
+ dst += dststride;
+ }
+}
+
+static void
+ximage_convert_rgb565(PARAMS)
+{
+ unsigned char r, g, b;
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ r = src[4*x + 0];
+ g = src[4*x + 1];
+ b = src[4*x + 2];
+ ((unsigned short *)dst)[x] =
+ ((r & 0xF8) << 8) |
+ ((g & 0xFC) << 3) |
+ (b >> 3);
+ }
+ src += srcstride;
+ dst += dststride;
+ }
+}
+
+static void
+ximage_convert_rgb565_br(PARAMS)
+{
+ unsigned char r, g, b;
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ r = src[4*x + 0];
+ g = src[4*x + 1];
+ b = src[4*x + 2];
+ /* final word is:
+ g4 g3 g2 b7 b6 b5 b4 b3 : r7 r6 r5 r4 r3 g7 g6 g5
+ */
+ ((unsigned short *)dst)[x] =
+ (r & 0xF8) |
+ ((g & 0xE0) >> 5) |
+ ((g & 0x1C) << 11) |
+ ((b & 0xF8) << 5);
+ }
+ src += srcstride;
+ dst += dststride;
+ }
+}
+
+static void
+ximage_convert_rgb555(PARAMS)
+{
+ unsigned char r, g, b;
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ r = src[4*x + 0];
+ g = src[4*x + 1];
+ b = src[4*x + 2];
+ ((unsigned short *)dst)[x] =
+ ((r & 0xF8) << 7) |
+ ((g & 0xF8) << 2) |
+ (b >> 3);
+ }
+ src += srcstride;
+ dst += dststride;
+ }
+}
+
+static void
+ximage_convert_rgb555_br(PARAMS)
+{
+ unsigned char r, g, b;
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ r = src[4*x + 0];
+ g = src[4*x + 1];
+ b = src[4*x + 2];
+ /* final word is:
+ g5 g4 g3 b7 b6 b5 b4 b3 : 0 r7 r6 r5 r4 r3 g7 g6
+ */
+ ((unsigned short *)dst)[x] =
+ ((r & 0xF8) >> 1) |
+ ((g & 0xC0) >> 6) |
+ ((g & 0x38) << 10) |
+ ((b & 0xF8) << 5);
+ }
+ src += srcstride;
+ dst += dststride;
+ }
+}
+
+static void
+ximage_convert_bgr233(PARAMS)
+{
+ unsigned char r, g, b;
+ int x,y;
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ r = src[4*x + 0];
+ g = src[4*x + 1];
+ b = src[4*x + 2];
+ /* format: b7 b6 g7 g6 g5 r7 r6 r5 */
+ dst[x] = (b&0xC0) | ((g>>2)&0x38) | ((r>>5)&0x7);
+ }
+ src += srcstride;
+ dst += dststride;
+ }
+}
+
+ximage_convert_func_t ximage_convert_funcs[] = {
+ ximage_convert_argb8888,
+ ximage_convert_bgra8888,
+ ximage_convert_rgba8888,
+ ximage_convert_abgr8888,
+ ximage_convert_rgb888,
+ ximage_convert_bgr888,
+ ximage_convert_rgb565,
+ ximage_convert_rgb565_br,
+ ximage_convert_rgb555,
+ ximage_convert_rgb555_br,
+ ximage_convert_bgr233,
+};
diff --git a/contrib/media/updf/apps/x11_main.c b/contrib/media/updf/apps/x11_main.c
new file mode 100644
index 000000000..98a776466
--- /dev/null
+++ b/contrib/media/updf/apps/x11_main.c
@@ -0,0 +1,629 @@
+#include "fitz.h"
+#include "mupdf.h"
+#include "muxps.h"
+#include "pdfapp.h"
+
+#include
+
+// #include
+#include
+#include
+#include
+#include
+
+
+
+#ifndef timeradd
+#define timeradd(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
+ if ((result)->tv_usec >= 1000000) \
+ { \
+ ++(result)->tv_sec; \
+ (result)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#endif
+
+#ifndef timersub
+#define timersub(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif
+
+extern int ximage_init(Display *display, int screen, Visual *visual);
+extern int ximage_get_depth(void);
+extern Visual *ximage_get_visual(void);
+extern Colormap ximage_get_colormap(void);
+extern void ximage_blit(Drawable d, GC gc, int dstx, int dsty,
+ unsigned char *srcdata,
+ int srcx, int srcy, int srcw, int srch, int srcstride);
+
+static Display *xdpy;
+static Atom XA_TARGETS;
+static Atom XA_TIMESTAMP;
+static Atom XA_UTF8_STRING;
+static Atom WM_DELETE_WINDOW;
+static int x11fd;
+static int xscr;
+static Window xwin;
+static Pixmap xicon, xmask;
+static GC xgc;
+static XEvent xevt;
+static int mapped = 0;
+static Cursor xcarrow, xchand, xcwait;
+static int justcopied = 0;
+static int dirty = 0;
+static int dirtysearch = 0;
+static char *password = "";
+static XColor xbgcolor;
+static XColor xshcolor;
+static int reqw = 0;
+static int reqh = 0;
+static char copylatin1[1024 * 16] = "";
+static char copyutf8[1024 * 48] = "";
+static Time copytime;
+static char *filename;
+
+static pdfapp_t gapp;
+static int closing = 0;
+static int reloading = 0;
+
+/*
+ * Dialog boxes
+ */
+
+void winwarn(pdfapp_t *app, char *msg)
+{
+ fprintf(stderr, "mupdf: %s\n", msg);
+}
+
+void winerror(pdfapp_t *app, fz_error error)
+{
+ fz_catch(error, "aborting");
+ exit(1);
+}
+
+char *winpassword(pdfapp_t *app, char *filename)
+{
+ char *r = password;
+ password = NULL;
+ return r;
+}
+
+/*
+ * X11 magic
+ */
+
+static void winopen(void)
+{
+
+
+ /*
+ xwin = XCreateWindow(xdpy, DefaultRootWindow(xdpy),
+ 10, 10, 200, 100, 1,
+ ximage_get_depth(),
+ InputOutput,
+ ximage_get_visual(),
+ 0,
+ NULL); */
+
+ __menuet__define_window(10,10,200,200,
+ 0,0,0);
+
+}
+
+void winclose(pdfapp_t *app)
+{
+ closing = 1;
+}
+
+void wincursor(pdfapp_t *app, int curs)
+{
+
+}
+
+void wintitle(pdfapp_t *app, char *s)
+{
+
+}
+
+void winhelp(pdfapp_t *app)
+{
+
+}
+
+void winresize(pdfapp_t *app, int w, int h)
+{
+
+
+
+
+}
+
+static void fillrect(int x, int y, int w, int h)
+{
+ if (w > 0 && h > 0)
+ XFillRectangle(xdpy, xwin, xgc, x, y, w, h);
+}
+
+static void winblitsearch(pdfapp_t *app)
+{
+ if (gapp.isediting)
+ {
+ char buf[sizeof(gapp.search) + 50];
+ sprintf(buf, "Search: %s", gapp.search);
+ XSetForeground(xdpy, xgc, WhitePixel(xdpy, xscr));
+ fillrect(0, 0, gapp.winw, 30);
+ windrawstring(&gapp, 10, 20, buf);
+ }
+}
+
+static void winblit(pdfapp_t *app)
+{
+ int x0 = gapp.panx;
+ int y0 = gapp.pany;
+ int x1 = gapp.panx + gapp.image->w;
+ int y1 = gapp.pany + gapp.image->h;
+
+ XSetForeground(xdpy, xgc, xbgcolor.pixel);
+ fillrect(0, 0, x0, gapp.winh);
+ fillrect(x1, 0, gapp.winw - x1, gapp.winh);
+ fillrect(0, 0, gapp.winw, y0);
+ fillrect(0, y1, gapp.winw, gapp.winh - y1);
+
+ XSetForeground(xdpy, xgc, xshcolor.pixel);
+ fillrect(x0+2, y1, gapp.image->w, 2);
+ fillrect(x1, y0+2, 2, gapp.image->h);
+
+ if (gapp.iscopying || justcopied)
+ {
+ pdfapp_invert(&gapp, gapp.selr);
+ justcopied = 1;
+ }
+
+ pdfapp_inverthit(&gapp);
+
+ if (gapp.image->n == 4)
+ ximage_blit(xwin, xgc,
+ x0, y0,
+ gapp.image->samples,
+ 0, 0,
+ gapp.image->w,
+ gapp.image->h,
+ gapp.image->w * gapp.image->n);
+ else if (gapp.image->n == 2)
+ {
+ int i = gapp.image->w*gapp.image->h;
+ unsigned char *color = malloc(i*4);
+ if (color != NULL)
+ {
+ unsigned char *s = gapp.image->samples;
+ unsigned char *d = color;
+ for (; i > 0 ; i--)
+ {
+ d[2] = d[1] = d[0] = *s++;
+ d[3] = *s++;
+ d += 4;
+ }
+ ximage_blit(xwin, xgc,
+ x0, y0,
+ color,
+ 0, 0,
+ gapp.image->w,
+ gapp.image->h,
+ gapp.image->w * 4);
+ free(color);
+ }
+ }
+
+ pdfapp_inverthit(&gapp);
+
+ if (gapp.iscopying || justcopied)
+ {
+ pdfapp_invert(&gapp, gapp.selr);
+ justcopied = 1;
+ }
+
+ winblitsearch(app);
+}
+
+void winrepaint(pdfapp_t *app)
+{
+ dirty = 1;
+}
+
+void winrepaintsearch(pdfapp_t *app)
+{
+ dirtysearch = 1;
+}
+
+void windrawstringxor(pdfapp_t *app, int x, int y, char *s)
+{
+ int prevfunction;
+ XGCValues xgcv;
+
+ XGetGCValues(xdpy, xgc, GCFunction, &xgcv);
+ prevfunction = xgcv.function;
+ xgcv.function = GXxor;
+ XChangeGC(xdpy, xgc, GCFunction, &xgcv);
+
+ XSetForeground(xdpy, xgc, WhitePixel(xdpy, DefaultScreen(xdpy)));
+
+ XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s));
+ XFlush(xdpy);
+
+ XGetGCValues(xdpy, xgc, GCFunction, &xgcv);
+ xgcv.function = prevfunction;
+ XChangeGC(xdpy, xgc, GCFunction, &xgcv);
+
+ printf("drawstring '%s'\n", s);
+}
+
+void windrawstring(pdfapp_t *app, int x, int y, char *s)
+{
+ XSetForeground(xdpy, xgc, BlackPixel(xdpy, DefaultScreen(xdpy)));
+ XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s));
+}
+
+void windocopy(pdfapp_t *app)
+{
+/* unsigned short copyucs2[16 * 1024];
+ char *latin1 = copylatin1;
+ char *utf8 = copyutf8;
+ unsigned short *ucs2;
+ int ucs;
+
+ pdfapp_oncopy(&gapp, copyucs2, 16 * 1024);
+
+ for (ucs2 = copyucs2; ucs2[0] != 0; ucs2++)
+ {
+ ucs = ucs2[0];
+
+ utf8 += runetochar(utf8, &ucs);
+
+ if (ucs < 256)
+ *latin1++ = ucs;
+ else
+ *latin1++ = '?';
+ }
+
+ *utf8 = 0;
+ *latin1 = 0;
+
+ XSetSelectionOwner(xdpy, XA_PRIMARY, xwin, copytime);
+
+ justcopied = 1;*/
+}
+
+void onselreq(Window requestor, Atom selection, Atom target, Atom property, Time time)
+{
+/* XEvent nevt;
+
+ if (property == None)
+ property = target;
+
+ nevt.xselection.type = SelectionNotify;
+ nevt.xselection.send_event = True;
+ nevt.xselection.display = xdpy;
+ nevt.xselection.requestor = requestor;
+ nevt.xselection.selection = selection;
+ nevt.xselection.target = target;
+ nevt.xselection.property = property;
+ nevt.xselection.time = time;
+
+ if (target == XA_TARGETS)
+ {
+ Atom atomlist[4];
+ atomlist[0] = XA_TARGETS;
+ atomlist[1] = XA_TIMESTAMP;
+ atomlist[2] = XA_STRING;
+ atomlist[3] = XA_UTF8_STRING;
+ printf(" -> targets\n");
+ XChangeProperty(xdpy, requestor, property, target,
+ 32, PropModeReplace,
+ (unsigned char *)atomlist, sizeof(atomlist)/sizeof(Atom));
+ }
+
+ else if (target == XA_STRING)
+ {
+ XChangeProperty(xdpy, requestor, property, target,
+ 8, PropModeReplace,
+ (unsigned char *)copylatin1, strlen(copylatin1));
+ }
+
+ else if (target == XA_UTF8_STRING)
+ {
+ XChangeProperty(xdpy, requestor, property, target,
+ 8, PropModeReplace,
+ (unsigned char *)copyutf8, strlen(copyutf8));
+ }
+
+ else
+ {
+ nevt.xselection.property = None;
+ }
+
+ XSendEvent(xdpy, requestor, False, SelectionNotify, &nevt);
+ * */
+}
+
+void winreloadfile(pdfapp_t *app)
+{
+ int fd;
+
+ pdfapp_close(app);
+
+ fd = open(filename, O_BINARY | O_RDONLY, 0666);
+ if (fd < 0)
+ winerror(app, fz_throw("cannot reload file '%s'", filename));
+
+ pdfapp_open(app, filename, fd, 1);
+}
+
+void winopenuri(pdfapp_t *app, char *buf)
+{
+ /*
+ char *browser = getenv("BROWSER");
+ if (!browser)
+ browser = "open";
+ if (fork() == 0)
+ execlp(browser, browser, buf, (char*)0);
+ * */
+
+}
+
+static void onkey(int c)
+{
+/* if (justcopied)
+ {
+ justcopied = 0;
+ winrepaint(&gapp);
+ }
+ * */
+
+ pdfapp_onkey(&gapp, c);
+}
+
+static void onmouse(int x, int y, int btn, int modifiers, int state)
+{
+/* if (state != 0 && justcopied)
+ {
+ justcopied = 0;
+ winrepaint(&gapp);
+ }*/
+
+ pdfapp_onmouse(&gapp, x, y, btn, modifiers, state);
+}
+
+static void signal_handler(int signal)
+{
+ /*
+ if (signal == SIGHUP)
+ reloading = 1;
+ * */
+
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "usage: mupdf [options] file.pdf [page]\n");
+ fprintf(stderr, "\t-b -\tset anti-aliasing quality in bits (0=off, 8=best)\n");
+ fprintf(stderr, "\t-p -\tpassword\n");
+ fprintf(stderr, "\t-r -\tresolution\n");
+ fprintf(stderr, "\t-A\tdisable accelerated functions\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ int len;
+ char buf[128];
+ KeySym keysym;
+ int oldx = 0;
+ int oldy = 0;
+ int resolution = 72;
+ int pageno = 1;
+ int accelerate = 1;
+ int fd;
+ fd_set fds;
+ int width = -1;
+ int height = -1;
+
+ while ((c = fz_getopt(argc, argv, "p:r:b:A")) != -1)
+ {
+ switch (c)
+ {
+ case 'p': password = fz_optarg; break;
+ case 'r': resolution = atoi(fz_optarg); break;
+ case 'A': accelerate = 0; break;
+ case 'b': fz_set_aa_level(atoi(fz_optarg)); break;
+ default: usage();
+ }
+ }
+
+ if (resolution < MINRES)
+ resolution = MINRES;
+ if (resolution > MAXRES)
+ resolution = MAXRES;
+
+ if (argc - fz_optind == 0)
+ usage();
+
+ filename = argv[fz_optind++];
+
+ if (argc - fz_optind == 1)
+ pageno = atoi(argv[fz_optind++]);
+
+ if (accelerate)
+ fz_accelerate();
+
+ winopen();
+
+ pdfapp_init(&gapp);
+ gapp.scrw = DisplayWidth(xdpy, xscr);
+ gapp.scrh = DisplayHeight(xdpy, xscr);
+ gapp.resolution = resolution;
+ gapp.pageno = pageno;
+
+ fd = open(filename, O_BINARY | O_RDONLY, 0666);
+ if (fd < 0)
+ winerror(&gapp, fz_throw("cannot open file '%s'", filename));
+
+ pdfapp_open(&gapp, filename, fd, 0);
+
+ FD_ZERO(&fds);
+ FD_SET(x11fd, &fds);
+
+ signal(SIGHUP, signal_handler);
+
+ while (!closing)
+ {
+ do
+ {
+ XNextEvent(xdpy, &xevt);
+
+ switch (xevt.type)
+ {
+ case Expose:
+ dirty = 1;
+ break;
+
+ case ConfigureNotify:
+ if (gapp.image)
+ {
+ if (xevt.xconfigure.width != reqw ||
+ xevt.xconfigure.height != reqh)
+ gapp.shrinkwrap = 0;
+ }
+ width = xevt.xconfigure.width;
+ height = xevt.xconfigure.height;
+
+ break;
+
+ case KeyPress:
+ len = XLookupString(&xevt.xkey, buf, sizeof buf, &keysym, NULL);
+
+ if (!gapp.isediting)
+ switch (keysym)
+ {
+ case XK_Escape:
+ len = 1; buf[0] = '\033';
+ break;
+
+ case XK_Up:
+ len = 1; buf[0] = 'k';
+ break;
+ case XK_Down:
+ len = 1; buf[0] = 'j';
+ break;
+
+ case XK_Left:
+ len = 1; buf[0] = 'b';
+ break;
+ case XK_Right:
+ len = 1; buf[0] = ' ';
+ break;
+
+ case XK_Page_Up:
+ len = 1; buf[0] = ',';
+ break;
+ case XK_Page_Down:
+ len = 1; buf[0] = '.';
+ break;
+ }
+ if (len)
+ onkey(buf[0]);
+
+ onmouse(oldx, oldy, 0, 0, 0);
+
+ break;
+
+ case MotionNotify:
+ oldx = xevt.xbutton.x;
+ oldy = xevt.xbutton.y;
+ onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, 0);
+ break;
+
+ case ButtonPress:
+ onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, 1);
+ break;
+
+ case ButtonRelease:
+ copytime = xevt.xbutton.time;
+ onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, -1);
+ break;
+
+ case SelectionRequest:
+ onselreq(xevt.xselectionrequest.requestor,
+ xevt.xselectionrequest.selection,
+ xevt.xselectionrequest.target,
+ xevt.xselectionrequest.property,
+ xevt.xselectionrequest.time);
+ break;
+
+ case ClientMessage:
+ if (xevt.xclient.format == 32 && xevt.xclient.data.l[0] == WM_DELETE_WINDOW)
+ closing = 1;
+ break;
+ }
+ }
+ while (!closing && XPending(xdpy));
+
+ if (closing)
+ continue;
+
+ if (width != -1 || height != -1)
+ {
+ pdfapp_onresize(&gapp, width, height);
+ width = -1;
+ height = -1;
+ }
+
+ if (dirty || dirtysearch)
+ {
+ if (dirty)
+ winblit(&gapp);
+ else if (dirtysearch)
+ winblitsearch(&gapp);
+ dirty = 0;
+ dirtysearch = 0;
+ }
+
+ if (XPending(xdpy))
+ continue;
+
+ if (select(x11fd + 1, &fds, NULL, NULL, NULL) < 0)
+ {
+ if (reloading)
+ {
+ winreloadfile(&gapp);
+ reloading = 0;
+ }
+ }
+ }
+
+ pdfapp_close(&gapp);
+
+ XDestroyWindow(xdpy, xwin);
+
+ XFreePixmap(xdpy, xicon);
+
+ XFreeCursor(xdpy, xcwait);
+ XFreeCursor(xdpy, xchand);
+ XFreeCursor(xdpy, xcarrow);
+
+ XFreeGC(xdpy, xgc);
+
+ XCloseDisplay(xdpy);
+
+ return 0;
+}
diff --git a/contrib/media/updf/apps/xpsdraw.c b/contrib/media/updf/apps/xpsdraw.c
new file mode 100644
index 000000000..29738e6bf
--- /dev/null
+++ b/contrib/media/updf/apps/xpsdraw.c
@@ -0,0 +1,366 @@
+#include "fitz.h"
+#include "muxps.h"
+
+#ifdef _MSC_VER
+#include
+#else
+#include
+#endif
+
+char *output = NULL;
+float resolution = 72;
+
+int showxml = 0;
+int showtext = 0;
+int showtime = 0;
+int showmd5 = 0;
+int savealpha = 0;
+int uselist = 1;
+
+fz_colorspace *colorspace;
+fz_glyph_cache *glyphcache;
+char *filename;
+
+struct {
+ int count, total;
+ int min, max;
+ int minpage, maxpage;
+} timing;
+
+static void die(fz_error error)
+{
+ fz_catch(error, "aborting");
+ exit(1);
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "usage: xpsdraw [options] input.xps [pages]\n"
+ "\t-o -\toutput filename (%%d for page number)\n"
+ "\t\tsupported formats: pgm, ppm, pam, png\n"
+ "\t-r -\tresolution in dpi (default: 72)\n"
+ "\t-a\tsave alpha channel (only pam and png)\n"
+ "\t-g\trender in grayscale\n"
+ "\t-m\tshow timing information\n"
+ "\t-t\tshow text (-tt for xml)\n"
+ "\t-x\tshow display list\n"
+ "\t-d\tdisable use of display list\n"
+ "\t-5\tshow md5 checksums\n"
+ "\tpages\tcomma separated list of ranges\n");
+ exit(1);
+}
+
+static int gettime(void)
+{
+ static struct timeval first;
+ static int once = 1;
+ struct timeval now;
+ if (once)
+ {
+ gettimeofday(&first, NULL);
+ once = 0;
+ }
+ gettimeofday(&now, NULL);
+ return (now.tv_sec - first.tv_sec) * 1000 + (now.tv_usec - first.tv_usec) / 1000;
+}
+
+static int isrange(char *s)
+{
+ while (*s)
+ {
+ if ((*s < '0' || *s > '9') && *s != '-' && *s != ',')
+ return 0;
+ s++;
+ }
+ return 1;
+}
+
+static void
+xps_run_page(xps_context *ctx, xps_page *page, fz_device *dev, fz_matrix ctm)
+{
+ ctx->dev = dev;
+ xps_parse_fixed_page(ctx, ctm, page);
+ ctx->dev = NULL;
+}
+
+static void drawpage(xps_context *ctx, int pagenum)
+{
+ xps_page *page;
+ fz_display_list *list;
+ fz_device *dev;
+ int start;
+ int code;
+
+ if (showtime)
+ {
+ start = gettime();
+ }
+
+ code = xps_load_page(&page, ctx, pagenum - 1);
+ if (code)
+ die(fz_rethrow(code, "cannot load page %d in file '%s'", pagenum, filename));
+
+ list = NULL;
+
+ if (uselist)
+ {
+ list = fz_new_display_list();
+ dev = fz_new_list_device(list);
+ xps_run_page(ctx, page, dev, fz_identity);
+ fz_free_device(dev);
+ }
+
+ if (showxml)
+ {
+ dev = fz_new_trace_device();
+ printf("\n", pagenum);
+ if (list)
+ fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox);
+ else
+ xps_run_page(ctx, page, dev, fz_identity);
+ printf("\n");
+ fz_free_device(dev);
+ }
+
+ if (showtext)
+ {
+ fz_text_span *text = fz_new_text_span();
+ dev = fz_new_text_device(text);
+ if (list)
+ fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox);
+ else
+ xps_run_page(ctx, page, dev, fz_identity);
+ fz_free_device(dev);
+ printf("[Page %d]\n", pagenum);
+ if (showtext > 1)
+ fz_debug_text_span_xml(text);
+ else
+ fz_debug_text_span(text);
+ printf("\n");
+ fz_free_text_span(text);
+ }
+
+ if (showmd5 || showtime)
+ printf("page %s %d", filename, pagenum);
+
+ if (output || showmd5 || showtime)
+ {
+ float zoom;
+ fz_matrix ctm;
+ fz_rect rect;
+ fz_bbox bbox;
+ fz_pixmap *pix;
+
+ rect.x0 = rect.y0 = 0;
+ rect.x1 = page->width;
+ rect.y1 = page->height;
+
+ zoom = resolution / 96;
+ ctm = fz_translate(0, -page->height);
+ ctm = fz_concat(ctm, fz_scale(zoom, zoom));
+ bbox = fz_round_rect(fz_transform_rect(ctm, rect));
+
+ /* TODO: banded rendering and multi-page ppm */
+
+ pix = fz_new_pixmap_with_rect(colorspace, bbox);
+
+ if (savealpha)
+ fz_clear_pixmap(pix);
+ else
+ fz_clear_pixmap_with_color(pix, 255);
+
+ dev = fz_new_draw_device(glyphcache, pix);
+ if (list)
+ fz_execute_display_list(list, dev, ctm, bbox);
+ else
+ xps_run_page(ctx, page, dev, ctm);
+ fz_free_device(dev);
+
+ if (output)
+ {
+ char buf[512];
+ sprintf(buf, output, pagenum);
+ if (strstr(output, ".pgm") || strstr(output, ".ppm") || strstr(output, ".pnm"))
+ fz_write_pnm(pix, buf);
+ else if (strstr(output, ".pam"))
+ fz_write_pam(pix, buf, savealpha);
+ else if (strstr(output, ".png"))
+ fz_write_png(pix, buf, savealpha);
+ }
+
+ if (showmd5)
+ {
+ fz_md5 md5;
+ unsigned char digest[16];
+ int i;
+
+ fz_md5_init(&md5);
+ fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n);
+ fz_md5_final(&md5, digest);
+
+ printf(" ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", digest[i]);
+ }
+
+ fz_drop_pixmap(pix);
+ }
+
+ if (list)
+ fz_free_display_list(list);
+
+ if (showtime)
+ {
+ int end = gettime();
+ int diff = end - start;
+
+ if (diff < timing.min)
+ {
+ timing.min = diff;
+ timing.minpage = pagenum;
+ }
+ if (diff > timing.max)
+ {
+ timing.max = diff;
+ timing.maxpage = pagenum;
+ }
+ timing.total += diff;
+ timing.count ++;
+
+ printf(" %dms", diff);
+ }
+
+ if (showmd5 || showtime)
+ printf("\n");
+}
+
+static void drawrange(xps_context *ctx, char *range)
+{
+ int page, spage, epage;
+ char *spec, *dash;
+
+ spec = fz_strsep(&range, ",");
+ while (spec)
+ {
+ dash = strchr(spec, '-');
+
+ if (dash == spec)
+ spage = epage = xps_count_pages(ctx);
+ else
+ spage = epage = atoi(spec);
+
+ if (dash)
+ {
+ if (strlen(dash) > 1)
+ epage = atoi(dash + 1);
+ else
+ epage = xps_count_pages(ctx);
+ }
+
+ spage = CLAMP(spage, 1, xps_count_pages(ctx));
+ epage = CLAMP(epage, 1, xps_count_pages(ctx));
+
+ if (spage < epage)
+ for (page = spage; page <= epage; page++)
+ drawpage(ctx, page);
+ else
+ for (page = spage; page >= epage; page--)
+ drawpage(ctx, page);
+
+ spec = fz_strsep(&range, ",");
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int grayscale = 0;
+ int accelerate = 1;
+ xps_context *ctx;
+ int code;
+ int c;
+
+ while ((c = fz_getopt(argc, argv, "o:p:r:Aadgmtx5")) != -1)
+ {
+ switch (c)
+ {
+ case 'o': output = fz_optarg; break;
+ case 'r': resolution = atof(fz_optarg); break;
+ case 'A': accelerate = 0; break;
+ case 'a': savealpha = 1; break;
+ case 'm': showtime++; break;
+ case 't': showtext++; break;
+ case 'x': showxml++; break;
+ case '5': showmd5++; break;
+ case 'g': grayscale++; break;
+ case 'd': uselist = 0; break;
+ default: usage(); break;
+ }
+ }
+
+ if (fz_optind == argc)
+ usage();
+
+ if (!showtext && !showxml && !showtime && !showmd5 && !output)
+ {
+ printf("nothing to do\n");
+ exit(0);
+ }
+
+ if (accelerate)
+ fz_accelerate();
+
+ glyphcache = fz_new_glyph_cache();
+
+ colorspace = fz_device_rgb;
+ if (grayscale)
+ colorspace = fz_device_gray;
+ if (output && strstr(output, ".pgm"))
+ colorspace = fz_device_gray;
+ if (output && strstr(output, ".ppm"))
+ colorspace = fz_device_rgb;
+
+ timing.count = 0;
+ timing.total = 0;
+ timing.min = 1 << 30;
+ timing.max = 0;
+ timing.minpage = 0;
+ timing.maxpage = 0;
+
+ if (showxml)
+ printf("\n");
+
+ while (fz_optind < argc)
+ {
+ filename = argv[fz_optind++];
+
+ code = xps_open_file(&ctx, filename);
+ if (code)
+ die(fz_rethrow(code, "cannot open document: %s", filename));
+
+ if (showxml)
+ printf("\n", filename);
+
+ if (fz_optind == argc || !isrange(argv[fz_optind]))
+ drawrange(ctx, "1-");
+ if (fz_optind < argc && isrange(argv[fz_optind]))
+ drawrange(ctx, argv[fz_optind++]);
+
+ if (showxml)
+ printf("\n");
+
+ xps_free_context(ctx);
+ }
+
+ if (showtime)
+ {
+ printf("total %dms / %d pages for an average of %dms\n",
+ timing.total, timing.count, timing.total / timing.count);
+ printf("fastest page %d: %dms\n", timing.minpage, timing.min);
+ printf("slowest page %d: %dms\n", timing.maxpage, timing.max);
+ }
+
+ fz_free_glyph_cache(glyphcache);
+
+ return 0;
+}
diff --git a/contrib/media/updf/build/debug/mupdf b/contrib/media/updf/build/debug/mupdf
new file mode 100755
index 000000000..3501e4171
Binary files /dev/null and b/contrib/media/updf/build/debug/mupdf differ
diff --git a/contrib/media/updf/build/debug/pdfclean b/contrib/media/updf/build/debug/pdfclean
new file mode 100755
index 000000000..2d2cc339d
Binary files /dev/null and b/contrib/media/updf/build/debug/pdfclean differ
diff --git a/contrib/media/updf/build/debug/pdfdraw b/contrib/media/updf/build/debug/pdfdraw
new file mode 100755
index 000000000..58072868c
Binary files /dev/null and b/contrib/media/updf/build/debug/pdfdraw differ
diff --git a/contrib/media/updf/build/debug/pdfextract b/contrib/media/updf/build/debug/pdfextract
new file mode 100755
index 000000000..072f8ec7b
Binary files /dev/null and b/contrib/media/updf/build/debug/pdfextract differ
diff --git a/contrib/media/updf/build/debug/pdfinfo b/contrib/media/updf/build/debug/pdfinfo
new file mode 100755
index 000000000..7d3690e87
Binary files /dev/null and b/contrib/media/updf/build/debug/pdfinfo differ
diff --git a/contrib/media/updf/build/debug/pdfshow b/contrib/media/updf/build/debug/pdfshow
new file mode 100755
index 000000000..941ab3152
Binary files /dev/null and b/contrib/media/updf/build/debug/pdfshow differ
diff --git a/contrib/media/updf/build/debug/xpsdraw b/contrib/media/updf/build/debug/xpsdraw
new file mode 100755
index 000000000..50a7bfb16
Binary files /dev/null and b/contrib/media/updf/build/debug/xpsdraw differ
diff --git a/contrib/media/updf/cmaps/README b/contrib/media/updf/cmaps/README
new file mode 100644
index 000000000..fb352e929
--- /dev/null
+++ b/contrib/media/updf/cmaps/README
@@ -0,0 +1,6 @@
+These resources are from Adobe and are covered by their
+own copyright and license.
+
+http://opensource.adobe.com/wiki/display/cmap/CMap+Resources
+http://opensource.adobe.com/wiki/display/pdfmapping/Mapping+Resources+for+PDF
+
diff --git a/contrib/media/updf/cmaps/cns/Adobe-CNS1-0 b/contrib/media/updf/cmaps/cns/Adobe-CNS1-0
new file mode 100644
index 000000000..80d7f7859
--- /dev/null
+++ b/contrib/media/updf/cmaps/cns/Adobe-CNS1-0
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%DocumentNeededResources: CMap (B5-H)
+%%IncludeResource: ProcSet (CIDInit)
+%%IncludeResource: CMap (B5-H)
+%%BeginResource: CMap (B5-V)
+%%Title: (B5-V Adobe CNS1 0)
+%%Version: 10.003
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
+%%EndComments
+
+/CIDInit /ProcSet findresource begin
+
+12 dict begin
+
+begincmap
+
+/B5-H usecmap
+
+/CIDSystemInfo 3 dict dup begin
+ /Registry (Adobe) def
+ /Ordering (CNS1) def
+ /Supplement 0 def
+end def
+
+/CMapName /B5-V def
+/CMapVersion 10.003 def
+/CMapType 1 def
+
+/UIDOffset 910 def
+/XUID [1 10 25381] def
+
+/WMode 1 def
+
+12 begincidrange
+ 13646
+ 13743
+ 13745
+ 130
+ 134
+ 138
+ 142
+ 146
+ 150
+ 154
+ 158
+ 13647
+endcidrange
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+
+%%EndResource
+%%EOF
diff --git a/contrib/media/updf/cmaps/cns/Adobe-CNS1-1 b/contrib/media/updf/cmaps/cns/Adobe-CNS1-1
new file mode 100644
index 000000000..80d7f7859
--- /dev/null
+++ b/contrib/media/updf/cmaps/cns/Adobe-CNS1-1
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%DocumentNeededResources: CMap (B5-H)
+%%IncludeResource: ProcSet (CIDInit)
+%%IncludeResource: CMap (B5-H)
+%%BeginResource: CMap (B5-V)
+%%Title: (B5-V Adobe CNS1 0)
+%%Version: 10.003
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
+%%EndComments
+
+/CIDInit /ProcSet findresource begin
+
+12 dict begin
+
+begincmap
+
+/B5-H usecmap
+
+/CIDSystemInfo 3 dict dup begin
+ /Registry (Adobe) def
+ /Ordering (CNS1) def
+ /Supplement 0 def
+end def
+
+/CMapName /B5-V def
+/CMapVersion 10.003 def
+/CMapType 1 def
+
+/UIDOffset 910 def
+/XUID [1 10 25381] def
+
+/WMode 1 def
+
+12 begincidrange
+ 13646
+ 13743
+ 13745
+ 130
+ 134
+ 138
+ 142
+ 146
+ 150
+ 154
+ 158
+ 13647
+endcidrange
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+
+%%EndResource
+%%EOF
diff --git a/contrib/media/updf/cmaps/cns/Adobe-CNS1-2 b/contrib/media/updf/cmaps/cns/Adobe-CNS1-2
new file mode 100644
index 000000000..80d7f7859
--- /dev/null
+++ b/contrib/media/updf/cmaps/cns/Adobe-CNS1-2
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%DocumentNeededResources: CMap (B5-H)
+%%IncludeResource: ProcSet (CIDInit)
+%%IncludeResource: CMap (B5-H)
+%%BeginResource: CMap (B5-V)
+%%Title: (B5-V Adobe CNS1 0)
+%%Version: 10.003
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
+%%EndComments
+
+/CIDInit /ProcSet findresource begin
+
+12 dict begin
+
+begincmap
+
+/B5-H usecmap
+
+/CIDSystemInfo 3 dict dup begin
+ /Registry (Adobe) def
+ /Ordering (CNS1) def
+ /Supplement 0 def
+end def
+
+/CMapName /B5-V def
+/CMapVersion 10.003 def
+/CMapType 1 def
+
+/UIDOffset 910 def
+/XUID [1 10 25381] def
+
+/WMode 1 def
+
+12 begincidrange
+ 13646
+ 13743
+ 13745
+ 130
+ 134
+ 138
+ 142
+ 146
+ 150
+ 154
+ 158
+ 13647
+endcidrange
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+
+%%EndResource
+%%EOF
diff --git a/contrib/media/updf/cmaps/cns/Adobe-CNS1-3 b/contrib/media/updf/cmaps/cns/Adobe-CNS1-3
new file mode 100644
index 000000000..80d7f7859
--- /dev/null
+++ b/contrib/media/updf/cmaps/cns/Adobe-CNS1-3
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%DocumentNeededResources: CMap (B5-H)
+%%IncludeResource: ProcSet (CIDInit)
+%%IncludeResource: CMap (B5-H)
+%%BeginResource: CMap (B5-V)
+%%Title: (B5-V Adobe CNS1 0)
+%%Version: 10.003
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
+%%EndComments
+
+/CIDInit /ProcSet findresource begin
+
+12 dict begin
+
+begincmap
+
+/B5-H usecmap
+
+/CIDSystemInfo 3 dict dup begin
+ /Registry (Adobe) def
+ /Ordering (CNS1) def
+ /Supplement 0 def
+end def
+
+/CMapName /B5-V def
+/CMapVersion 10.003 def
+/CMapType 1 def
+
+/UIDOffset 910 def
+/XUID [1 10 25381] def
+
+/WMode 1 def
+
+12 begincidrange
+ 13646
+ 13743
+ 13745
+ 130
+ 134
+ 138
+ 142
+ 146
+ 150
+ 154
+ 158
+ 13647
+endcidrange
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+
+%%EndResource
+%%EOF
diff --git a/contrib/media/updf/cmaps/cns/Adobe-CNS1-4 b/contrib/media/updf/cmaps/cns/Adobe-CNS1-4
new file mode 100644
index 000000000..80d7f7859
--- /dev/null
+++ b/contrib/media/updf/cmaps/cns/Adobe-CNS1-4
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%DocumentNeededResources: CMap (B5-H)
+%%IncludeResource: ProcSet (CIDInit)
+%%IncludeResource: CMap (B5-H)
+%%BeginResource: CMap (B5-V)
+%%Title: (B5-V Adobe CNS1 0)
+%%Version: 10.003
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
+%%EndComments
+
+/CIDInit /ProcSet findresource begin
+
+12 dict begin
+
+begincmap
+
+/B5-H usecmap
+
+/CIDSystemInfo 3 dict dup begin
+ /Registry (Adobe) def
+ /Ordering (CNS1) def
+ /Supplement 0 def
+end def
+
+/CMapName /B5-V def
+/CMapVersion 10.003 def
+/CMapType 1 def
+
+/UIDOffset 910 def
+/XUID [1 10 25381] def
+
+/WMode 1 def
+
+12 begincidrange
+ 13646
+ 13743
+ 13745
+ 130
+ 134
+ 138
+ 142
+ 146
+ 150
+ 154
+ 158
+ 13647
+endcidrange
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+
+%%EndResource
+%%EOF
diff --git a/contrib/media/updf/cmaps/cns/Adobe-CNS1-5 b/contrib/media/updf/cmaps/cns/Adobe-CNS1-5
new file mode 100644
index 000000000..80d7f7859
--- /dev/null
+++ b/contrib/media/updf/cmaps/cns/Adobe-CNS1-5
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%DocumentNeededResources: CMap (B5-H)
+%%IncludeResource: ProcSet (CIDInit)
+%%IncludeResource: CMap (B5-H)
+%%BeginResource: CMap (B5-V)
+%%Title: (B5-V Adobe CNS1 0)
+%%Version: 10.003
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
+%%EndComments
+
+/CIDInit /ProcSet findresource begin
+
+12 dict begin
+
+begincmap
+
+/B5-H usecmap
+
+/CIDSystemInfo 3 dict dup begin
+ /Registry (Adobe) def
+ /Ordering (CNS1) def
+ /Supplement 0 def
+end def
+
+/CMapName /B5-V def
+/CMapVersion 10.003 def
+/CMapType 1 def
+
+/UIDOffset 910 def
+/XUID [1 10 25381] def
+
+/WMode 1 def
+
+12 begincidrange
+ 13646
+ 13743
+ 13745
+ 130
+ 134
+ 138
+ 142
+ 146
+ 150
+ 154
+ 158
+ 13647
+endcidrange
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+
+%%EndResource
+%%EOF
diff --git a/contrib/media/updf/cmaps/cns/Adobe-CNS1-6 b/contrib/media/updf/cmaps/cns/Adobe-CNS1-6
new file mode 100644
index 000000000..80d7f7859
--- /dev/null
+++ b/contrib/media/updf/cmaps/cns/Adobe-CNS1-6
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%DocumentNeededResources: CMap (B5-H)
+%%IncludeResource: ProcSet (CIDInit)
+%%IncludeResource: CMap (B5-H)
+%%BeginResource: CMap (B5-V)
+%%Title: (B5-V Adobe CNS1 0)
+%%Version: 10.003
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
+%%EndComments
+
+/CIDInit /ProcSet findresource begin
+
+12 dict begin
+
+begincmap
+
+/B5-H usecmap
+
+/CIDSystemInfo 3 dict dup begin
+ /Registry (Adobe) def
+ /Ordering (CNS1) def
+ /Supplement 0 def
+end def
+
+/CMapName /B5-V def
+/CMapVersion 10.003 def
+/CMapType 1 def
+
+/UIDOffset 910 def
+/XUID [1 10 25381] def
+
+/WMode 1 def
+
+12 begincidrange
+ 13646
+ 13743
+ 13745
+ 130
+ 134
+ 138
+ 142
+ 146
+ 150
+ 154
+ 158
+ 13647
+endcidrange
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+
+%%EndResource
+%%EOF
diff --git a/contrib/media/updf/cmaps/cns/Adobe-CNS1-UCS2 b/contrib/media/updf/cmaps/cns/Adobe-CNS1-UCS2
new file mode 100644
index 000000000..80d7f7859
--- /dev/null
+++ b/contrib/media/updf/cmaps/cns/Adobe-CNS1-UCS2
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%DocumentNeededResources: CMap (B5-H)
+%%IncludeResource: ProcSet (CIDInit)
+%%IncludeResource: CMap (B5-H)
+%%BeginResource: CMap (B5-V)
+%%Title: (B5-V Adobe CNS1 0)
+%%Version: 10.003
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
+%%EndComments
+
+/CIDInit /ProcSet findresource begin
+
+12 dict begin
+
+begincmap
+
+/B5-H usecmap
+
+/CIDSystemInfo 3 dict dup begin
+ /Registry (Adobe) def
+ /Ordering (CNS1) def
+ /Supplement 0 def
+end def
+
+/CMapName /B5-V def
+/CMapVersion 10.003 def
+/CMapType 1 def
+
+/UIDOffset 910 def
+/XUID [1 10 25381] def
+
+/WMode 1 def
+
+12 begincidrange
+ 13646
+ 13743
+ 13745
+ 130
+ 134
+ 138
+ 142
+ 146
+ 150
+ 154
+ 158
+ 13647
+endcidrange
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+
+%%EndResource
+%%EOF
diff --git a/contrib/media/updf/cmaps/cns/B5-H b/contrib/media/updf/cmaps/cns/B5-H
new file mode 100644
index 000000000..80d7f7859
--- /dev/null
+++ b/contrib/media/updf/cmaps/cns/B5-H
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%DocumentNeededResources: CMap (B5-H)
+%%IncludeResource: ProcSet (CIDInit)
+%%IncludeResource: CMap (B5-H)
+%%BeginResource: CMap (B5-V)
+%%Title: (B5-V Adobe CNS1 0)
+%%Version: 10.003
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
+%%EndComments
+
+/CIDInit /ProcSet findresource begin
+
+12 dict begin
+
+begincmap
+
+/B5-H usecmap
+
+/CIDSystemInfo 3 dict dup begin
+ /Registry (Adobe) def
+ /Ordering (CNS1) def
+ /Supplement 0 def
+end def
+
+/CMapName /B5-V def
+/CMapVersion 10.003 def
+/CMapType 1 def
+
+/UIDOffset 910 def
+/XUID [1 10 25381] def
+
+/WMode 1 def
+
+12 begincidrange
+ 13646
+ 13743
+ 13745
+ 130
+ 134
+ 138
+ 142
+ 146
+ 150
+