1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-25 21:33:04 +04:00

Compare commits

..

22 Commits

Author SHA1 Message Date
Alexander Smorkalov 215f78eee2 Merge branch 'android_manager_version_inc4' into 2.4.8.1-prep 2014-01-31 22:25:36 +04:00
Vladislav Vinogradov 4425dac7f4 disable gpu CvtColor.*2HSV tests:
possible bug in CPU version(cherry picked from commit 3cb8b352e52f85847d98d2b0ece32ba5bdb5c31b)
2014-01-31 22:24:20 +04:00
Vladislav Vinogradov 4f79b9de48 disable gpu Subtract_Array test:
possible bug in CPU version(cherry picked from commit 59155c1eefb6f22e362e34a8d73b31841eb3413a)
2014-01-31 22:23:55 +04:00
Vladislav Vinogradov 397ac5e68f disable gpu Canny and HoughCircles perf tests:
it fails because driver terminates CUDA kernels after time out
(cherry picked from commit fa5bbb5f8dc1a86cfe004fb258d66e56c90560d6)
2014-01-31 22:23:39 +04:00
Vladislav Vinogradov 43c75c64b5 disable NPP for GpuMat methods and for copyMakeBorder(cherry picked from commit 316d49fc0fb7a609ebb0a65efc207faea6b978a4) 2014-01-31 22:23:22 +04:00
Vladislav Vinogradov c319625a07 disable some gpu tests if library was built without CUFFT(cherry picked from commit b4b929d27cc25822dd15b5b96b8d335c59d4408c) 2014-01-31 22:23:05 +04:00
Vladislav Vinogradov a7d0448faa gpu test output files moved from cwd to temp folder(cherry picked from commit 49731ad530) 2014-01-31 22:22:49 +04:00
Alexander Smorkalov ca10e5e8ae Highgui test output fixes.
Useless output to console fixed;
Test output files moved from cwd to temp folder.
(cherry picked from commit 87935f3560)
2014-01-31 22:22:33 +04:00
Vladislav Vinogradov 32414afe72 disable performance test for gpu generalized hough(cherry picked from commit 063d8b4211) 2014-01-31 22:22:14 +04:00
Alexander Smorkalov ed10f50d25 Reports path fix for opencv_run_all_tests.sh.in script.
(cherry picked from commit 3d261e8a01)
2014-01-31 22:21:57 +04:00
Alexander Smorkalov 48d9be70d5 Android toolchain file sync with original project.
Original project: https://github.com/taka-no-me/android-cmake/
Revision: 5db45cfb87fec180b74963d3680dd60d4d8d8c3a
(cherry picked from commit c815043607)
2014-01-31 22:21:34 +04:00
Alexander Smorkalov c6b31481b6 OpenCV Manager version++. 2014-01-31 12:15:22 +04:00
Alexander Smorkalov 514b714cc2 opencv_run_all_tests.sh script added to -tests package.
(cherry picked from commit d45350a06a)
2014-01-29 17:41:59 +04:00
Alexander Smorkalov 7fec87d3f6 Multiple fixes for tests deb package build.
Added opencv_testing.sh.in file;
opencv_testing.sh installation guarded by OS check.
(cherry picked from commit d9dc5ffa91)
2014-01-28 17:56:22 +04:00
Alexander Smorkalov 00d555f051 Code review notes fixed.
Env setup for testing package implemented using /etc/profile.d;
Variable with path for all native samples added;
Path for test binaries and test data updated.
(cherry picked from commit 39201e68e2)
2014-01-27 21:37:01 +04:00
Alexander Smorkalov 6cf7d6ef4e OpenCV C/C++/OCL/CUDA samples install path fixed. Install rools for tests added.
(cherry picked from commit f332cba14b)
2014-01-27 21:36:43 +04:00
Alexander Smorkalov 3ebdcafdd3 All installed files marked with component names for install customization.
(cherry picked from commit b75cbfde45)

Conflicts:

	cmake/OpenCVModule.cmake
2014-01-24 17:13:22 +04:00
Alexander Smorkalov a348f3eeaa OpenCV version++ 2014-01-24 14:49:56 +04:00
Alexander Smorkalov 33f423de04 Improvements in package build.
(cherry picked from commit 086792ec06)
2014-01-24 14:48:51 +04:00
Alexander Smorkalov d6ba52c3f9 Initial Linux packages build rools for CPack.
(cherry picked from commit 7821fe2bde)

Conflicts:

	cmake/OpenCVModule.cmake
2014-01-24 14:48:19 +04:00
Vladislav Vinogradov e9638d0997 disable CUDA generalized Hough Transform
(cherry picked from commit 33d42b740c)
2014-01-24 14:46:36 +04:00
Vladislav Vinogradov 5cb0084547 split CUDA Hough sources
(cherry picked from commit d847387694)
2014-01-24 14:46:16 +04:00
4557 changed files with 1147446 additions and 1337639 deletions
-1
View File
@@ -23,7 +23,6 @@
*.idl text
*.java text
*.js text
*.m text
*.mk text
*.mm text
*.plist text
-16
View File
@@ -1,24 +1,8 @@
*.autosave
*.pyc
*.user
*~
.*.swp
.DS_Store
.sw[a-z]
Thumbs.db
tags
tegra/
bin/
*.sdf
*.opensdf
*.obj
*.stamp
*.depend
*.rule
*.tmp
*/debug
*/CMakeFiles
CMakeCache.txt
*.suo
*.log
*.tlog
-2
View File
@@ -1,2 +0,0 @@
[tgit]
icon = doc/opencv.ico
-42
View File
@@ -1,42 +0,0 @@
The build script is to be fixed.
Right now it assumes that 32-bit MinGW is in the system path and
64-bit mingw is installed to c:\Apps\MinGW64.
It is important that gcc is used, not g++!
Otherwise the produced DLL will likely be dependent on libgcc_s_dw2-1.dll or similar DLL.
While we want to make the DLLs with minimum dependencies: Win32 libraries + msvcrt.dll.
ffopencv.c is really a C++ source, hence -x c++ is used.
How to update opencv_ffmpeg.dll and opencv_ffmpeg_64.dll when a new version of FFMPEG is release?
1. Install 32-bit MinGW + MSYS from
http://sourceforge.net/projects/mingw/files/Automated%20MinGW%20Installer/mingw-get-inst/
Let's assume, it's installed in C:\MSYS32.
2. Install 64-bit MinGW. http://mingw-w64.sourceforge.net/
Let's assume, it's installed in C:\MSYS64
3. Copy C:\MSYS32\msys to C:\MSYS64\msys. Edit C:\MSYS64\msys\etc\fstab, change C:\MSYS32 to C:\MSYS64.
4. Now you have working MSYS32 and MSYS64 environments.
Launch, one by one, C:\MSYS32\msys\msys.bat and C:\MSYS64\msys\msys.bat to create your home directories.
4. Download ffmpeg-x.y.z.tar.gz (where x.y.z denotes the actual ffmpeg version).
Copy it to C:\MSYS{32|64}\msys\home\<loginname> directory.
5. To build 32-bit ffmpeg libraries, run C:\MSYS32\msys\msys.bat and type the following commands:
5.1. tar -xzf ffmpeg-x.y.z.tar.gz
5.2. mkdir build
5.3. cd build
5.4. ../ffmpeg-x.y.z/configure --enable-w32threads
5.5. make
5.6. make install
5.7. cd /local/lib
5.8. strip -g *.a
6. Then repeat the same for 64-bit case. The output libs: libavcodec.a etc. need to be renamed to libavcodec64.a etc.
7. Then, copy all those libs to <opencv>\3rdparty\lib\, copy the headers to <opencv>\3rdparty\include\ffmpeg_.
8. Then, go to <opencv>\3rdparty\ffmpeg, edit make.bat
(change paths to the actual paths to your msys32 and msys64 distributions) and then run make.bat
-2
View File
@@ -3,11 +3,9 @@ set(HAVE_FFMPEG_CODEC 1)
set(HAVE_FFMPEG_FORMAT 1)
set(HAVE_FFMPEG_UTIL 1)
set(HAVE_FFMPEG_SWSCALE 1)
set(HAVE_FFMPEG_RESAMPLE 0)
set(HAVE_GENTOO_FFMPEG 1)
set(ALIASOF_libavcodec_VERSION 55.18.102)
set(ALIASOF_libavformat_VERSION 55.12.100)
set(ALIASOF_libavutil_VERSION 52.38.100)
set(ALIASOF_libswscale_VERSION 2.3.100)
set(ALIASOF_libavresample_VERSION 1.0.1)
-520
View File
@@ -1,520 +0,0 @@
Copyright (C) 2001 Fabrice Bellard
FFmpeg is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
FFmpeg 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with FFmpeg; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
==================================================================================
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
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 this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
+40 -30
View File
@@ -1,32 +1,42 @@
* On Linux and other Unix flavors OpenCV uses default or user-built ffmpeg/libav libraries.
If user builds ffmpeg/libav from source and wants OpenCV to stay BSD library, not GPL/LGPL,
he/she should use --enabled-shared configure flag and make sure that no GPL components are
enabled (some notable examples are x264 (H264 encoder) and libac3 (Dolby AC3 audio codec)).
See https://www.ffmpeg.org/legal.html for details.
If you want to play very safe and do not want to use FFMPEG at all, regardless of whether it's installed on
your system or not, configure and build OpenCV using CMake with WITH_FFMPEG=OFF flag. OpenCV will then use
AVFoundation (OSX), GStreamer (Linux) or other available backends supported by opencv_videoio module.
There is also our self-contained motion jpeg codec, which you can use without any worries.
It handles CV_FOURCC('M', 'J', 'P', 'G') streams within an AVI container (".avi").
* On Windows OpenCV uses pre-built ffmpeg binaries, built with proper flags (without GPL components) and
wrapped with simple, stable OpenCV-compatible API.
The binaries are opencv_ffmpeg.dll (version for 32-bit Windows) and
opencv_ffmpeg_64.dll (version for 64-bit Windows).
See build_win32.txt for the build instructions, if you want to rebuild opencv_ffmpeg*.dll from scratch.
The build script is to be fixed.
Right now it assumes that 32-bit MinGW is in the system path and
64-bit mingw is installed to c:\Apps\MinGW64.
The pre-built opencv_ffmpeg*.dll is:
* LGPL library, not BSD libraries.
* Loaded at runtime by opencv_videoio module.
If it succeeds, ffmpeg can be used to decode/encode videos;
otherwise, other API is used.
It is important that gcc is used, not g++!
Otherwise the produced DLL will likely be dependent on libgcc_s_dw2-1.dll or similar DLL.
While we want to make the DLLs with minimum dependencies: Win32 libraries + msvcrt.dll.
If LGPL/GPL software can not be supplied with your OpenCV-based product, simply exclude
opencv_ffmpeg*.dll from your distribution; OpenCV will stay fully functional except for the ability to
decode/encode videos using FFMPEG (though, it may still be able to do that using other API,
such as Video for Windows, Windows Media Foundation or our self-contained motion jpeg codec).
See license.txt for the FFMPEG copyright notice and the licensing terms.
ffopencv.c is really a C++ source, hence -x c++ is used.
How to update opencv_ffmpeg.dll and opencv_ffmpeg_64.dll when a new version of FFMPEG is release?
1. Install 32-bit MinGW + MSYS from
http://sourceforge.net/projects/mingw/files/Automated%20MinGW%20Installer/mingw-get-inst/
Let's assume, it's installed in C:\MSYS32.
2. Install 64-bit MinGW. http://mingw-w64.sourceforge.net/
Let's assume, it's installed in C:\MSYS64
3. Copy C:\MSYS32\msys to C:\MSYS64\msys. Edit C:\MSYS64\msys\etc\fstab, change C:\MSYS32 to C:\MSYS64.
4. Now you have working MSYS32 and MSYS64 environments.
Launch, one by one, C:\MSYS32\msys\msys.bat and C:\MSYS64\msys\msys.bat to create your home directories.
4. Download ffmpeg-x.y.z.tar.gz (where x.y.z denotes the actual ffmpeg version).
Copy it to C:\MSYS{32|64}\msys\home\<loginname> directory.
5. To build 32-bit ffmpeg libraries, run C:\MSYS32\msys\msys.bat and type the following commands:
5.1. tar -xzf ffmpeg-x.y.z.tar.gz
5.2. mkdir build
5.3. cd build
5.4. ../ffmpeg-x.y.z/configure --enable-w32threads
5.5. make
5.6. make install
5.7. cd /local/lib
5.8. strip -g *.a
6. Then repeat the same for 64-bit case. The output libs: libavcodec.a etc. need to be renamed to libavcodec64.a etc.
7. Then, copy all those libs to <opencv>\3rdparty\lib\, copy the headers to <opencv>\3rdparty\include\ffmpeg_.
8. Then, go to <opencv>\3rdparty\ffmpeg, edit make.bat
(change paths to the actual paths to your msys32 and msys64 distributions) and then run make.bat
+1 -1
View File
@@ -210,7 +210,7 @@
#include <string>
#endif
#if defined(__linux__) || defined(__APPLE__) || defined(__MACOSX)
#if defined(linux) || defined(__APPLE__) || defined(__MACOSX)
#include <alloca.h>
#include <emmintrin.h>
+7 -7
View File
@@ -332,13 +332,13 @@ typedef unsigned int cl_GLenum;
/* Define basic vector types */
#if defined( __VEC__ )
#include <altivec.h> /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */
typedef __vector unsigned char __cl_uchar16;
typedef __vector signed char __cl_char16;
typedef __vector unsigned short __cl_ushort8;
typedef __vector signed short __cl_short8;
typedef __vector unsigned int __cl_uint4;
typedef __vector signed int __cl_int4;
typedef __vector float __cl_float4;
typedef vector unsigned char __cl_uchar16;
typedef vector signed char __cl_char16;
typedef vector unsigned short __cl_ushort8;
typedef vector signed short __cl_short8;
typedef vector unsigned int __cl_uint4;
typedef vector signed int __cl_int4;
typedef vector float __cl_float4;
#define __CL_UCHAR16__ 1
#define __CL_CHAR16__ 1
#define __CL_USHORT8__ 1
-2
View File
@@ -1,2 +0,0 @@
downloads/
unpack/
-108
View File
@@ -1,108 +0,0 @@
#
# The script downloads ICV package
#
# On return this will define:
# OPENCV_ICV_PATH - path to unpacked downloaded package
#
function(_icv_downloader)
# Define actual ICV versions
if(APPLE)
set(OPENCV_ICV_PACKAGE_NAME "ippicv_macosx_20141027.tgz")
set(OPENCV_ICV_PACKAGE_HASH "9662fe0694a67e59491a0dcc82fa26e0")
set(OPENCV_ICV_PLATFORM "macosx")
set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_osx")
elseif(UNIX)
if(ANDROID AND (NOT ANDROID_ABI STREQUAL x86))
return()
endif()
set(OPENCV_ICV_PACKAGE_NAME "ippicv_linux_20141027.tgz")
set(OPENCV_ICV_PACKAGE_HASH "8b449a536a2157bcad08a2b9f266828b")
set(OPENCV_ICV_PLATFORM "linux")
set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_lnx")
elseif(WIN32 AND NOT ARM)
set(OPENCV_ICV_PACKAGE_NAME "ippicv_windows_20141027.zip")
set(OPENCV_ICV_PACKAGE_HASH "b59f865d1ba16e8c84124e19d78eec57")
set(OPENCV_ICV_PLATFORM "windows")
set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_win")
else()
return() # Not supported
endif()
set(OPENCV_ICV_UNPACK_PATH "${CMAKE_CURRENT_LIST_DIR}/unpack")
set(OPENCV_ICV_PATH "${OPENCV_ICV_UNPACK_PATH}${OPENCV_ICV_PACKAGE_SUBDIR}")
if(DEFINED OPENCV_ICV_PACKAGE_DOWNLOADED
AND OPENCV_ICV_PACKAGE_DOWNLOADED STREQUAL OPENCV_ICV_PACKAGE_HASH
AND EXISTS ${OPENCV_ICV_PATH})
# Package has been downloaded and checked by the previous build
set(OPENCV_ICV_PATH "${OPENCV_ICV_PATH}" PARENT_SCOPE)
return()
else()
if(EXISTS ${OPENCV_ICV_UNPACK_PATH})
message(STATUS "ICV: Removing previous unpacked package: ${OPENCV_ICV_UNPACK_PATH}")
file(REMOVE_RECURSE ${OPENCV_ICV_UNPACK_PATH})
endif()
endif()
unset(OPENCV_ICV_PACKAGE_DOWNLOADED CACHE)
set(OPENCV_ICV_PACKAGE_ARCHIVE "${CMAKE_CURRENT_LIST_DIR}/downloads/${OPENCV_ICV_PLATFORM}-${OPENCV_ICV_PACKAGE_HASH}/${OPENCV_ICV_PACKAGE_NAME}")
get_filename_component(OPENCV_ICV_PACKAGE_ARCHIVE_DIR "${OPENCV_ICV_PACKAGE_ARCHIVE}" PATH)
if(EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}")
file(MD5 "${OPENCV_ICV_PACKAGE_ARCHIVE}" archive_md5)
if(NOT archive_md5 STREQUAL OPENCV_ICV_PACKAGE_HASH)
message(WARNING "ICV: Local copy of ICV package has invalid MD5 hash: ${archive_md5} (expected: ${OPENCV_ICV_PACKAGE_HASH})")
file(REMOVE "${OPENCV_ICV_PACKAGE_ARCHIVE}")
file(REMOVE_RECURSE "${OPENCV_ICV_PACKAGE_ARCHIVE_DIR}")
endif()
endif()
if(NOT EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}")
if(NOT DEFINED OPENCV_ICV_URL)
if(DEFINED ENV{OPENCV_ICV_URL})
set(OPENCV_ICV_URL $ENV{OPENCV_ICV_URL})
else()
set(OPENCV_ICV_URL "http://sourceforge.net/projects/opencvlibrary/files/3rdparty/ippicv")
endif()
endif()
file(MAKE_DIRECTORY ${OPENCV_ICV_PACKAGE_ARCHIVE_DIR})
message(STATUS "ICV: Downloading ${OPENCV_ICV_PACKAGE_NAME}...")
file(DOWNLOAD "${OPENCV_ICV_URL}/${OPENCV_ICV_PACKAGE_NAME}" "${OPENCV_ICV_PACKAGE_ARCHIVE}"
TIMEOUT 600 STATUS __status
EXPECTED_MD5 ${OPENCV_ICV_PACKAGE_HASH})
if(NOT __status EQUAL 0)
message(FATAL_ERROR "ICV: Failed to download ICV package: ${OPENCV_ICV_PACKAGE_NAME}. Status=${__status}")
else()
# Don't remove this code, because EXPECTED_MD5 parameter doesn't fail "file(DOWNLOAD)" step
# on wrong hash
file(MD5 "${OPENCV_ICV_PACKAGE_ARCHIVE}" archive_md5)
if(NOT archive_md5 STREQUAL OPENCV_ICV_PACKAGE_HASH)
message(FATAL_ERROR "ICV: Downloaded copy of ICV package has invalid MD5 hash: ${archive_md5} (expected: ${OPENCV_ICV_PACKAGE_HASH})")
endif()
endif()
endif()
ocv_assert(EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}")
ocv_assert(NOT EXISTS "${OPENCV_ICV_UNPACK_PATH}")
file(MAKE_DIRECTORY ${OPENCV_ICV_UNPACK_PATH})
ocv_assert(EXISTS "${OPENCV_ICV_UNPACK_PATH}")
message(STATUS "ICV: Unpacking ${OPENCV_ICV_PACKAGE_NAME} to ${OPENCV_ICV_UNPACK_PATH}...")
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xz "${OPENCV_ICV_PACKAGE_ARCHIVE}"
WORKING_DIRECTORY "${OPENCV_ICV_UNPACK_PATH}"
RESULT_VARIABLE __result)
if(NOT __result EQUAL 0)
message(FATAL_ERROR "ICV: Failed to unpack ICV package from ${OPENCV_ICV_PACKAGE_ARCHIVE} to ${OPENCV_ICV_UNPACK_PATH} with error ${__result}")
endif()
ocv_assert(EXISTS "${OPENCV_ICV_PATH}")
set(OPENCV_ICV_PACKAGE_DOWNLOADED "${OPENCV_ICV_PACKAGE_HASH}" CACHE INTERNAL "ICV package hash")
message(STATUS "ICV: Package successfully downloaded")
set(OPENCV_ICV_PATH "${OPENCV_ICV_PATH}" PARENT_SCOPE)
endfunction()
_icv_downloader()
-33
View File
@@ -1,33 +0,0 @@
Jinja is written and maintained by the Jinja Team and various
contributors:
Lead Developer:
- Armin Ronacher <armin.ronacher@active-4.com>
Developers:
- Christoph Hack
- Georg Brandl
Contributors:
- Bryan McLemore
- Mickaël Guérin <kael@crocobox.org>
- Cameron Knight
- Lawrence Journal-World.
- David Cramer
Patches and suggestions:
- Ronny Pfannschmidt
- Axel Böhm
- Alexey Melchakov
- Bryan McLemore
- Clovis Fabricio (nosklo)
- Cameron Knight
- Peter van Dijk (Habbie)
- Stefan Ebner
- Rene Leonhardt
- Thomas Waldmann
- Cory Benfield (Lukasa)
-31
View File
@@ -1,31 +0,0 @@
Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-69
View File
@@ -1,69 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2
~~~~~~
Jinja2 is a template engine written in pure Python. It provides a
Django inspired non-XML syntax but supports inline expressions and
an optional sandboxed environment.
Nutshell
--------
Here a small example of a Jinja2 template::
{% extends 'base.html' %}
{% block title %}Memberlist{% endblock %}
{% block content %}
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
{% endblock %}
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
__docformat__ = 'restructuredtext en'
__version__ = '2.7.1'
# high level interface
from jinja2.environment import Environment, Template
# loaders
from jinja2.loaders import BaseLoader, FileSystemLoader, PackageLoader, \
DictLoader, FunctionLoader, PrefixLoader, ChoiceLoader, \
ModuleLoader
# bytecode caches
from jinja2.bccache import BytecodeCache, FileSystemBytecodeCache, \
MemcachedBytecodeCache
# undefined types
from jinja2.runtime import Undefined, DebugUndefined, StrictUndefined
# exceptions
from jinja2.exceptions import TemplateError, UndefinedError, \
TemplateNotFound, TemplatesNotFound, TemplateSyntaxError, \
TemplateAssertionError
# decorators and public utilities
from jinja2.filters import environmentfilter, contextfilter, \
evalcontextfilter
from jinja2.utils import Markup, escape, clear_caches, \
environmentfunction, evalcontextfunction, contextfunction, \
is_undefined
__all__ = [
'Environment', 'Template', 'BaseLoader', 'FileSystemLoader',
'PackageLoader', 'DictLoader', 'FunctionLoader', 'PrefixLoader',
'ChoiceLoader', 'BytecodeCache', 'FileSystemBytecodeCache',
'MemcachedBytecodeCache', 'Undefined', 'DebugUndefined',
'StrictUndefined', 'TemplateError', 'UndefinedError', 'TemplateNotFound',
'TemplatesNotFound', 'TemplateSyntaxError', 'TemplateAssertionError',
'ModuleLoader', 'environmentfilter', 'contextfilter', 'Markup', 'escape',
'environmentfunction', 'contextfunction', 'clear_caches', 'is_undefined',
'evalcontextfilter', 'evalcontextfunction'
]
-150
View File
@@ -1,150 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2._compat
~~~~~~~~~~~~~~
Some py2/py3 compatibility support based on a stripped down
version of six so we don't have to depend on a specific version
of it.
:copyright: Copyright 2013 by the Jinja team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import sys
PY2 = sys.version_info[0] == 2
PYPY = hasattr(sys, 'pypy_translation_info')
_identity = lambda x: x
if not PY2:
unichr = chr
range_type = range
text_type = str
string_types = (str,)
iterkeys = lambda d: iter(d.keys())
itervalues = lambda d: iter(d.values())
iteritems = lambda d: iter(d.items())
import pickle
from io import BytesIO, StringIO
NativeStringIO = StringIO
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
ifilter = filter
imap = map
izip = zip
intern = sys.intern
implements_iterator = _identity
implements_to_string = _identity
encode_filename = _identity
get_next = lambda x: x.__next__
else:
unichr = unichr
text_type = unicode
range_type = xrange
string_types = (str, unicode)
iterkeys = lambda d: d.iterkeys()
itervalues = lambda d: d.itervalues()
iteritems = lambda d: d.iteritems()
import cPickle as pickle
from cStringIO import StringIO as BytesIO, StringIO
NativeStringIO = BytesIO
exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
from itertools import imap, izip, ifilter
intern = intern
def implements_iterator(cls):
cls.next = cls.__next__
del cls.__next__
return cls
def implements_to_string(cls):
cls.__unicode__ = cls.__str__
cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
return cls
get_next = lambda x: x.next
def encode_filename(filename):
if isinstance(filename, unicode):
return filename.encode('utf-8')
return filename
try:
next = next
except NameError:
def next(it):
return it.next()
def with_metaclass(meta, *bases):
# This requires a bit of explanation: the basic idea is to make a
# dummy metaclass for one level of class instanciation that replaces
# itself with the actual metaclass. Because of internal type checks
# we also need to make sure that we downgrade the custom metaclass
# for one level to something closer to type (that's why __call__ and
# __init__ comes back from type etc.).
#
# This has the advantage over six.with_metaclass in that it does not
# introduce dummy classes into the final MRO.
class metaclass(meta):
__call__ = type.__call__
__init__ = type.__init__
def __new__(cls, name, this_bases, d):
if this_bases is None:
return type.__new__(cls, name, (), d)
return meta(name, bases, d)
return metaclass('temporary_class', None, {})
try:
from collections import Mapping as mapping_types
except ImportError:
import UserDict
mapping_types = (UserDict.UserDict, UserDict.DictMixin, dict)
# common types. These do exist in the special types module too which however
# does not exist in IronPython out of the box. Also that way we don't have
# to deal with implementation specific stuff here
class _C(object):
def method(self): pass
def _func():
yield None
function_type = type(_func)
generator_type = type(_func())
method_type = type(_C().method)
code_type = type(_C.method.__code__)
try:
raise TypeError()
except TypeError:
_tb = sys.exc_info()[2]
traceback_type = type(_tb)
frame_type = type(_tb.tb_frame)
try:
from urllib.parse import quote_from_bytes as url_quote
except ImportError:
from urllib import quote as url_quote
try:
from thread import allocate_lock
except ImportError:
try:
from threading import Lock as allocate_lock
except ImportError:
from dummy_thread import allocate_lock
-132
View File
File diff suppressed because one or more lines are too long
-311
View File
@@ -1,311 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.bccache
~~~~~~~~~~~~~~
This module implements the bytecode cache system Jinja is optionally
using. This is useful if you have very complex template situations and
the compiliation of all those templates slow down your application too
much.
Situations where this is useful are often forking web applications that
are initialized on the first request.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD.
"""
from os import path, listdir
import sys
import marshal
import tempfile
import fnmatch
from hashlib import sha1
from jinja2.utils import open_if_exists
from jinja2._compat import BytesIO, pickle, PY2, text_type
# marshal works better on 3.x, one hack less required
if not PY2:
marshal_dump = marshal.dump
marshal_load = marshal.load
else:
def marshal_dump(code, f):
if isinstance(f, file):
marshal.dump(code, f)
else:
f.write(marshal.dumps(code))
def marshal_load(f):
if isinstance(f, file):
return marshal.load(f)
return marshal.loads(f.read())
bc_version = 2
# magic version used to only change with new jinja versions. With 2.6
# we change this to also take Python version changes into account. The
# reason for this is that Python tends to segfault if fed earlier bytecode
# versions because someone thought it would be a good idea to reuse opcodes
# or make Python incompatible with earlier versions.
bc_magic = 'j2'.encode('ascii') + \
pickle.dumps(bc_version, 2) + \
pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1])
class Bucket(object):
"""Buckets are used to store the bytecode for one template. It's created
and initialized by the bytecode cache and passed to the loading functions.
The buckets get an internal checksum from the cache assigned and use this
to automatically reject outdated cache material. Individual bytecode
cache subclasses don't have to care about cache invalidation.
"""
def __init__(self, environment, key, checksum):
self.environment = environment
self.key = key
self.checksum = checksum
self.reset()
def reset(self):
"""Resets the bucket (unloads the bytecode)."""
self.code = None
def load_bytecode(self, f):
"""Loads bytecode from a file or file like object."""
# make sure the magic header is correct
magic = f.read(len(bc_magic))
if magic != bc_magic:
self.reset()
return
# the source code of the file changed, we need to reload
checksum = pickle.load(f)
if self.checksum != checksum:
self.reset()
return
self.code = marshal_load(f)
def write_bytecode(self, f):
"""Dump the bytecode into the file or file like object passed."""
if self.code is None:
raise TypeError('can\'t write empty bucket')
f.write(bc_magic)
pickle.dump(self.checksum, f, 2)
marshal_dump(self.code, f)
def bytecode_from_string(self, string):
"""Load bytecode from a string."""
self.load_bytecode(BytesIO(string))
def bytecode_to_string(self):
"""Return the bytecode as string."""
out = BytesIO()
self.write_bytecode(out)
return out.getvalue()
class BytecodeCache(object):
"""To implement your own bytecode cache you have to subclass this class
and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of
these methods are passed a :class:`~jinja2.bccache.Bucket`.
A very basic bytecode cache that saves the bytecode on the file system::
from os import path
class MyCache(BytecodeCache):
def __init__(self, directory):
self.directory = directory
def load_bytecode(self, bucket):
filename = path.join(self.directory, bucket.key)
if path.exists(filename):
with open(filename, 'rb') as f:
bucket.load_bytecode(f)
def dump_bytecode(self, bucket):
filename = path.join(self.directory, bucket.key)
with open(filename, 'wb') as f:
bucket.write_bytecode(f)
A more advanced version of a filesystem based bytecode cache is part of
Jinja2.
"""
def load_bytecode(self, bucket):
"""Subclasses have to override this method to load bytecode into a
bucket. If they are not able to find code in the cache for the
bucket, it must not do anything.
"""
raise NotImplementedError()
def dump_bytecode(self, bucket):
"""Subclasses have to override this method to write the bytecode
from a bucket back to the cache. If it unable to do so it must not
fail silently but raise an exception.
"""
raise NotImplementedError()
def clear(self):
"""Clears the cache. This method is not used by Jinja2 but should be
implemented to allow applications to clear the bytecode cache used
by a particular environment.
"""
def get_cache_key(self, name, filename=None):
"""Returns the unique hash key for this template name."""
hash = sha1(name.encode('utf-8'))
if filename is not None:
filename = '|' + filename
if isinstance(filename, text_type):
filename = filename.encode('utf-8')
hash.update(filename)
return hash.hexdigest()
def get_source_checksum(self, source):
"""Returns a checksum for the source."""
return sha1(source.encode('utf-8')).hexdigest()
def get_bucket(self, environment, name, filename, source):
"""Return a cache bucket for the given template. All arguments are
mandatory but filename may be `None`.
"""
key = self.get_cache_key(name, filename)
checksum = self.get_source_checksum(source)
bucket = Bucket(environment, key, checksum)
self.load_bytecode(bucket)
return bucket
def set_bucket(self, bucket):
"""Put the bucket into the cache."""
self.dump_bytecode(bucket)
class FileSystemBytecodeCache(BytecodeCache):
"""A bytecode cache that stores bytecode on the filesystem. It accepts
two arguments: The directory where the cache items are stored and a
pattern string that is used to build the filename.
If no directory is specified the system temporary items folder is used.
The pattern can be used to have multiple separate caches operate on the
same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s``
is replaced with the cache key.
>>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache')
This bytecode cache supports clearing of the cache using the clear method.
"""
def __init__(self, directory=None, pattern='__jinja2_%s.cache'):
if directory is None:
directory = tempfile.gettempdir()
self.directory = directory
self.pattern = pattern
def _get_cache_filename(self, bucket):
return path.join(self.directory, self.pattern % bucket.key)
def load_bytecode(self, bucket):
f = open_if_exists(self._get_cache_filename(bucket), 'rb')
if f is not None:
try:
bucket.load_bytecode(f)
finally:
f.close()
def dump_bytecode(self, bucket):
f = open(self._get_cache_filename(bucket), 'wb')
try:
bucket.write_bytecode(f)
finally:
f.close()
def clear(self):
# imported lazily here because google app-engine doesn't support
# write access on the file system and the function does not exist
# normally.
from os import remove
files = fnmatch.filter(listdir(self.directory), self.pattern % '*')
for filename in files:
try:
remove(path.join(self.directory, filename))
except OSError:
pass
class MemcachedBytecodeCache(BytecodeCache):
"""This class implements a bytecode cache that uses a memcache cache for
storing the information. It does not enforce a specific memcache library
(tummy's memcache or cmemcache) but will accept any class that provides
the minimal interface required.
Libraries compatible with this class:
- `werkzeug <http://werkzeug.pocoo.org/>`_.contrib.cache
- `python-memcached <http://www.tummy.com/Community/software/python-memcached/>`_
- `cmemcache <http://gijsbert.org/cmemcache/>`_
(Unfortunately the django cache interface is not compatible because it
does not support storing binary data, only unicode. You can however pass
the underlying cache client to the bytecode cache which is available
as `django.core.cache.cache._client`.)
The minimal interface for the client passed to the constructor is this:
.. class:: MinimalClientInterface
.. method:: set(key, value[, timeout])
Stores the bytecode in the cache. `value` is a string and
`timeout` the timeout of the key. If timeout is not provided
a default timeout or no timeout should be assumed, if it's
provided it's an integer with the number of seconds the cache
item should exist.
.. method:: get(key)
Returns the value for the cache key. If the item does not
exist in the cache the return value must be `None`.
The other arguments to the constructor are the prefix for all keys that
is added before the actual cache key and the timeout for the bytecode in
the cache system. We recommend a high (or no) timeout.
This bytecode cache does not support clearing of used items in the cache.
The clear method is a no-operation function.
.. versionadded:: 2.7
Added support for ignoring memcache errors through the
`ignore_memcache_errors` parameter.
"""
def __init__(self, client, prefix='jinja2/bytecode/', timeout=None,
ignore_memcache_errors=True):
self.client = client
self.prefix = prefix
self.timeout = timeout
self.ignore_memcache_errors = ignore_memcache_errors
def load_bytecode(self, bucket):
try:
code = self.client.get(self.prefix + bucket.key)
except Exception:
if not self.ignore_memcache_errors:
raise
code = None
if code is not None:
bucket.bytecode_from_string(code)
def dump_bytecode(self, bucket):
args = (self.prefix + bucket.key, bucket.bytecode_to_string())
if self.timeout is not None:
args += (self.timeout,)
try:
self.client.set(*args)
except Exception:
if not self.ignore_memcache_errors:
raise
-1640
View File
File diff suppressed because it is too large Load Diff
-32
View File
@@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja.constants
~~~~~~~~~~~~~~~
Various constants.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
#: list of lorem ipsum words used by the lipsum() helper function
LOREM_IPSUM_WORDS = u'''\
a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at
auctor augue bibendum blandit class commodo condimentum congue consectetuer
consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus
diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend
elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames
faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac
hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum
justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem
luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie
mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non
nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque
penatibus per pharetra phasellus placerat platea porta porttitor posuere
potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus
ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit
sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor
tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices
ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus
viverra volutpat vulputate'''
-337
View File
@@ -1,337 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.debug
~~~~~~~~~~~~
Implements the debug interface for Jinja. This module does some pretty
ugly stuff with the Python traceback system in order to achieve tracebacks
with correct line numbers, locals and contents.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
import sys
import traceback
from types import TracebackType
from jinja2.utils import missing, internal_code
from jinja2.exceptions import TemplateSyntaxError
from jinja2._compat import iteritems, reraise, code_type
# on pypy we can take advantage of transparent proxies
try:
from __pypy__ import tproxy
except ImportError:
tproxy = None
# how does the raise helper look like?
try:
exec("raise TypeError, 'foo'")
except SyntaxError:
raise_helper = 'raise __jinja_exception__[1]'
except TypeError:
raise_helper = 'raise __jinja_exception__[0], __jinja_exception__[1]'
class TracebackFrameProxy(object):
"""Proxies a traceback frame."""
def __init__(self, tb):
self.tb = tb
self._tb_next = None
@property
def tb_next(self):
return self._tb_next
def set_next(self, next):
if tb_set_next is not None:
try:
tb_set_next(self.tb, next and next.tb or None)
except Exception:
# this function can fail due to all the hackery it does
# on various python implementations. We just catch errors
# down and ignore them if necessary.
pass
self._tb_next = next
@property
def is_jinja_frame(self):
return '__jinja_template__' in self.tb.tb_frame.f_globals
def __getattr__(self, name):
return getattr(self.tb, name)
def make_frame_proxy(frame):
proxy = TracebackFrameProxy(frame)
if tproxy is None:
return proxy
def operation_handler(operation, *args, **kwargs):
if operation in ('__getattribute__', '__getattr__'):
return getattr(proxy, args[0])
elif operation == '__setattr__':
proxy.__setattr__(*args, **kwargs)
else:
return getattr(proxy, operation)(*args, **kwargs)
return tproxy(TracebackType, operation_handler)
class ProcessedTraceback(object):
"""Holds a Jinja preprocessed traceback for printing or reraising."""
def __init__(self, exc_type, exc_value, frames):
assert frames, 'no frames for this traceback?'
self.exc_type = exc_type
self.exc_value = exc_value
self.frames = frames
# newly concatenate the frames (which are proxies)
prev_tb = None
for tb in self.frames:
if prev_tb is not None:
prev_tb.set_next(tb)
prev_tb = tb
prev_tb.set_next(None)
def render_as_text(self, limit=None):
"""Return a string with the traceback."""
lines = traceback.format_exception(self.exc_type, self.exc_value,
self.frames[0], limit=limit)
return ''.join(lines).rstrip()
def render_as_html(self, full=False):
"""Return a unicode string with the traceback as rendered HTML."""
from jinja2.debugrenderer import render_traceback
return u'%s\n\n<!--\n%s\n-->' % (
render_traceback(self, full=full),
self.render_as_text().decode('utf-8', 'replace')
)
@property
def is_template_syntax_error(self):
"""`True` if this is a template syntax error."""
return isinstance(self.exc_value, TemplateSyntaxError)
@property
def exc_info(self):
"""Exception info tuple with a proxy around the frame objects."""
return self.exc_type, self.exc_value, self.frames[0]
@property
def standard_exc_info(self):
"""Standard python exc_info for re-raising"""
tb = self.frames[0]
# the frame will be an actual traceback (or transparent proxy) if
# we are on pypy or a python implementation with support for tproxy
if type(tb) is not TracebackType:
tb = tb.tb
return self.exc_type, self.exc_value, tb
def make_traceback(exc_info, source_hint=None):
"""Creates a processed traceback object from the exc_info."""
exc_type, exc_value, tb = exc_info
if isinstance(exc_value, TemplateSyntaxError):
exc_info = translate_syntax_error(exc_value, source_hint)
initial_skip = 0
else:
initial_skip = 1
return translate_exception(exc_info, initial_skip)
def translate_syntax_error(error, source=None):
"""Rewrites a syntax error to please traceback systems."""
error.source = source
error.translated = True
exc_info = (error.__class__, error, None)
filename = error.filename
if filename is None:
filename = '<unknown>'
return fake_exc_info(exc_info, filename, error.lineno)
def translate_exception(exc_info, initial_skip=0):
"""If passed an exc_info it will automatically rewrite the exceptions
all the way down to the correct line numbers and frames.
"""
tb = exc_info[2]
frames = []
# skip some internal frames if wanted
for x in range(initial_skip):
if tb is not None:
tb = tb.tb_next
initial_tb = tb
while tb is not None:
# skip frames decorated with @internalcode. These are internal
# calls we can't avoid and that are useless in template debugging
# output.
if tb.tb_frame.f_code in internal_code:
tb = tb.tb_next
continue
# save a reference to the next frame if we override the current
# one with a faked one.
next = tb.tb_next
# fake template exceptions
template = tb.tb_frame.f_globals.get('__jinja_template__')
if template is not None:
lineno = template.get_corresponding_lineno(tb.tb_lineno)
tb = fake_exc_info(exc_info[:2] + (tb,), template.filename,
lineno)[2]
frames.append(make_frame_proxy(tb))
tb = next
# if we don't have any exceptions in the frames left, we have to
# reraise it unchanged.
# XXX: can we backup here? when could this happen?
if not frames:
reraise(exc_info[0], exc_info[1], exc_info[2])
return ProcessedTraceback(exc_info[0], exc_info[1], frames)
def fake_exc_info(exc_info, filename, lineno):
"""Helper for `translate_exception`."""
exc_type, exc_value, tb = exc_info
# figure the real context out
if tb is not None:
real_locals = tb.tb_frame.f_locals.copy()
ctx = real_locals.get('context')
if ctx:
locals = ctx.get_all()
else:
locals = {}
for name, value in iteritems(real_locals):
if name.startswith('l_') and value is not missing:
locals[name[2:]] = value
# if there is a local called __jinja_exception__, we get
# rid of it to not break the debug functionality.
locals.pop('__jinja_exception__', None)
else:
locals = {}
# assamble fake globals we need
globals = {
'__name__': filename,
'__file__': filename,
'__jinja_exception__': exc_info[:2],
# we don't want to keep the reference to the template around
# to not cause circular dependencies, but we mark it as Jinja
# frame for the ProcessedTraceback
'__jinja_template__': None
}
# and fake the exception
code = compile('\n' * (lineno - 1) + raise_helper, filename, 'exec')
# if it's possible, change the name of the code. This won't work
# on some python environments such as google appengine
try:
if tb is None:
location = 'template'
else:
function = tb.tb_frame.f_code.co_name
if function == 'root':
location = 'top-level template code'
elif function.startswith('block_'):
location = 'block "%s"' % function[6:]
else:
location = 'template'
code = code_type(0, code.co_nlocals, code.co_stacksize,
code.co_flags, code.co_code, code.co_consts,
code.co_names, code.co_varnames, filename,
location, code.co_firstlineno,
code.co_lnotab, (), ())
except:
pass
# execute the code and catch the new traceback
try:
exec(code, globals, locals)
except:
exc_info = sys.exc_info()
new_tb = exc_info[2].tb_next
# return without this frame
return exc_info[:2] + (new_tb,)
def _init_ugly_crap():
"""This function implements a few ugly things so that we can patch the
traceback objects. The function returned allows resetting `tb_next` on
any python traceback object. Do not attempt to use this on non cpython
interpreters
"""
import ctypes
from types import TracebackType
# figure out side of _Py_ssize_t
if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'):
_Py_ssize_t = ctypes.c_int64
else:
_Py_ssize_t = ctypes.c_int
# regular python
class _PyObject(ctypes.Structure):
pass
_PyObject._fields_ = [
('ob_refcnt', _Py_ssize_t),
('ob_type', ctypes.POINTER(_PyObject))
]
# python with trace
if hasattr(sys, 'getobjects'):
class _PyObject(ctypes.Structure):
pass
_PyObject._fields_ = [
('_ob_next', ctypes.POINTER(_PyObject)),
('_ob_prev', ctypes.POINTER(_PyObject)),
('ob_refcnt', _Py_ssize_t),
('ob_type', ctypes.POINTER(_PyObject))
]
class _Traceback(_PyObject):
pass
_Traceback._fields_ = [
('tb_next', ctypes.POINTER(_Traceback)),
('tb_frame', ctypes.POINTER(_PyObject)),
('tb_lasti', ctypes.c_int),
('tb_lineno', ctypes.c_int)
]
def tb_set_next(tb, next):
"""Set the tb_next attribute of a traceback object."""
if not (isinstance(tb, TracebackType) and
(next is None or isinstance(next, TracebackType))):
raise TypeError('tb_set_next arguments must be traceback objects')
obj = _Traceback.from_address(id(tb))
if tb.tb_next is not None:
old = _Traceback.from_address(id(tb.tb_next))
old.ob_refcnt -= 1
if next is None:
obj.tb_next = ctypes.POINTER(_Traceback)()
else:
next = _Traceback.from_address(id(next))
next.ob_refcnt += 1
obj.tb_next = ctypes.pointer(next)
return tb_set_next
# try to get a tb_set_next implementation if we don't have transparent
# proxies.
tb_set_next = None
if tproxy is None:
try:
tb_set_next = _init_ugly_crap()
except:
pass
del _init_ugly_crap
-43
View File
@@ -1,43 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.defaults
~~~~~~~~~~~~~~~
Jinja default filters and tags.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
from jinja2._compat import range_type
from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner
# defaults for the parser / lexer
BLOCK_START_STRING = '{%'
BLOCK_END_STRING = '%}'
VARIABLE_START_STRING = '{{'
VARIABLE_END_STRING = '}}'
COMMENT_START_STRING = '{#'
COMMENT_END_STRING = '#}'
LINE_STATEMENT_PREFIX = None
LINE_COMMENT_PREFIX = None
TRIM_BLOCKS = False
LSTRIP_BLOCKS = False
NEWLINE_SEQUENCE = '\n'
KEEP_TRAILING_NEWLINE = False
# default filters, tests and namespace
from jinja2.filters import FILTERS as DEFAULT_FILTERS
from jinja2.tests import TESTS as DEFAULT_TESTS
DEFAULT_NAMESPACE = {
'range': range_type,
'dict': lambda **kw: kw,
'lipsum': generate_lorem_ipsum,
'cycler': Cycler,
'joiner': Joiner
}
# export all constants
__all__ = tuple(x for x in locals().keys() if x.isupper())
-1191
View File
File diff suppressed because it is too large Load Diff
-146
View File
@@ -1,146 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.exceptions
~~~~~~~~~~~~~~~~~
Jinja exceptions.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
from jinja2._compat import imap, text_type, PY2, implements_to_string
class TemplateError(Exception):
"""Baseclass for all template errors."""
if PY2:
def __init__(self, message=None):
if message is not None:
message = text_type(message).encode('utf-8')
Exception.__init__(self, message)
@property
def message(self):
if self.args:
message = self.args[0]
if message is not None:
return message.decode('utf-8', 'replace')
def __unicode__(self):
return self.message or u''
else:
def __init__(self, message=None):
Exception.__init__(self, message)
@property
def message(self):
if self.args:
message = self.args[0]
if message is not None:
return message
@implements_to_string
class TemplateNotFound(IOError, LookupError, TemplateError):
"""Raised if a template does not exist."""
# looks weird, but removes the warning descriptor that just
# bogusly warns us about message being deprecated
message = None
def __init__(self, name, message=None):
IOError.__init__(self)
if message is None:
message = name
self.message = message
self.name = name
self.templates = [name]
def __str__(self):
return self.message
class TemplatesNotFound(TemplateNotFound):
"""Like :class:`TemplateNotFound` but raised if multiple templates
are selected. This is a subclass of :class:`TemplateNotFound`
exception, so just catching the base exception will catch both.
.. versionadded:: 2.2
"""
def __init__(self, names=(), message=None):
if message is None:
message = u'none of the templates given were found: ' + \
u', '.join(imap(text_type, names))
TemplateNotFound.__init__(self, names and names[-1] or None, message)
self.templates = list(names)
@implements_to_string
class TemplateSyntaxError(TemplateError):
"""Raised to tell the user that there is a problem with the template."""
def __init__(self, message, lineno, name=None, filename=None):
TemplateError.__init__(self, message)
self.lineno = lineno
self.name = name
self.filename = filename
self.source = None
# this is set to True if the debug.translate_syntax_error
# function translated the syntax error into a new traceback
self.translated = False
def __str__(self):
# for translated errors we only return the message
if self.translated:
return self.message
# otherwise attach some stuff
location = 'line %d' % self.lineno
name = self.filename or self.name
if name:
location = 'File "%s", %s' % (name, location)
lines = [self.message, ' ' + location]
# if the source is set, add the line to the output
if self.source is not None:
try:
line = self.source.splitlines()[self.lineno - 1]
except IndexError:
line = None
if line:
lines.append(' ' + line.strip())
return u'\n'.join(lines)
class TemplateAssertionError(TemplateSyntaxError):
"""Like a template syntax error, but covers cases where something in the
template caused an error at compile time that wasn't necessarily caused
by a syntax error. However it's a direct subclass of
:exc:`TemplateSyntaxError` and has the same attributes.
"""
class TemplateRuntimeError(TemplateError):
"""A generic runtime error in the template engine. Under some situations
Jinja may raise this exception.
"""
class UndefinedError(TemplateRuntimeError):
"""Raised if a template tries to operate on :class:`Undefined`."""
class SecurityError(TemplateRuntimeError):
"""Raised if a template tries to do something insecure if the
sandbox is enabled.
"""
class FilterArgumentError(TemplateRuntimeError):
"""This error is raised if a filter was called with inappropriate
arguments
"""
-636
View File
@@ -1,636 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.ext
~~~~~~~~~~
Jinja extensions allow to add custom tags similar to the way django custom
tags work. By default two example extensions exist: an i18n and a cache
extension.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD.
"""
from jinja2 import nodes
from jinja2.defaults import BLOCK_START_STRING, \
BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \
COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \
LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \
KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS
from jinja2.environment import Environment
from jinja2.runtime import concat
from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError
from jinja2.utils import contextfunction, import_string, Markup
from jinja2._compat import next, with_metaclass, string_types, iteritems
# the only real useful gettext functions for a Jinja template. Note
# that ugettext must be assigned to gettext as Jinja doesn't support
# non unicode strings.
GETTEXT_FUNCTIONS = ('_', 'gettext', 'ngettext')
class ExtensionRegistry(type):
"""Gives the extension an unique identifier."""
def __new__(cls, name, bases, d):
rv = type.__new__(cls, name, bases, d)
rv.identifier = rv.__module__ + '.' + rv.__name__
return rv
class Extension(with_metaclass(ExtensionRegistry, object)):
"""Extensions can be used to add extra functionality to the Jinja template
system at the parser level. Custom extensions are bound to an environment
but may not store environment specific data on `self`. The reason for
this is that an extension can be bound to another environment (for
overlays) by creating a copy and reassigning the `environment` attribute.
As extensions are created by the environment they cannot accept any
arguments for configuration. One may want to work around that by using
a factory function, but that is not possible as extensions are identified
by their import name. The correct way to configure the extension is
storing the configuration values on the environment. Because this way the
environment ends up acting as central configuration storage the
attributes may clash which is why extensions have to ensure that the names
they choose for configuration are not too generic. ``prefix`` for example
is a terrible name, ``fragment_cache_prefix`` on the other hand is a good
name as includes the name of the extension (fragment cache).
"""
#: if this extension parses this is the list of tags it's listening to.
tags = set()
#: the priority of that extension. This is especially useful for
#: extensions that preprocess values. A lower value means higher
#: priority.
#:
#: .. versionadded:: 2.4
priority = 100
def __init__(self, environment):
self.environment = environment
def bind(self, environment):
"""Create a copy of this extension bound to another environment."""
rv = object.__new__(self.__class__)
rv.__dict__.update(self.__dict__)
rv.environment = environment
return rv
def preprocess(self, source, name, filename=None):
"""This method is called before the actual lexing and can be used to
preprocess the source. The `filename` is optional. The return value
must be the preprocessed source.
"""
return source
def filter_stream(self, stream):
"""It's passed a :class:`~jinja2.lexer.TokenStream` that can be used
to filter tokens returned. This method has to return an iterable of
:class:`~jinja2.lexer.Token`\s, but it doesn't have to return a
:class:`~jinja2.lexer.TokenStream`.
In the `ext` folder of the Jinja2 source distribution there is a file
called `inlinegettext.py` which implements a filter that utilizes this
method.
"""
return stream
def parse(self, parser):
"""If any of the :attr:`tags` matched this method is called with the
parser as first argument. The token the parser stream is pointing at
is the name token that matched. This method has to return one or a
list of multiple nodes.
"""
raise NotImplementedError()
def attr(self, name, lineno=None):
"""Return an attribute node for the current extension. This is useful
to pass constants on extensions to generated template code.
::
self.attr('_my_attribute', lineno=lineno)
"""
return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno)
def call_method(self, name, args=None, kwargs=None, dyn_args=None,
dyn_kwargs=None, lineno=None):
"""Call a method of the extension. This is a shortcut for
:meth:`attr` + :class:`jinja2.nodes.Call`.
"""
if args is None:
args = []
if kwargs is None:
kwargs = []
return nodes.Call(self.attr(name, lineno=lineno), args, kwargs,
dyn_args, dyn_kwargs, lineno=lineno)
@contextfunction
def _gettext_alias(__context, *args, **kwargs):
return __context.call(__context.resolve('gettext'), *args, **kwargs)
def _make_new_gettext(func):
@contextfunction
def gettext(__context, __string, **variables):
rv = __context.call(func, __string)
if __context.eval_ctx.autoescape:
rv = Markup(rv)
return rv % variables
return gettext
def _make_new_ngettext(func):
@contextfunction
def ngettext(__context, __singular, __plural, __num, **variables):
variables.setdefault('num', __num)
rv = __context.call(func, __singular, __plural, __num)
if __context.eval_ctx.autoescape:
rv = Markup(rv)
return rv % variables
return ngettext
class InternationalizationExtension(Extension):
"""This extension adds gettext support to Jinja2."""
tags = set(['trans'])
# TODO: the i18n extension is currently reevaluating values in a few
# situations. Take this example:
# {% trans count=something() %}{{ count }} foo{% pluralize
# %}{{ count }} fooss{% endtrans %}
# something is called twice here. One time for the gettext value and
# the other time for the n-parameter of the ngettext function.
def __init__(self, environment):
Extension.__init__(self, environment)
environment.globals['_'] = _gettext_alias
environment.extend(
install_gettext_translations=self._install,
install_null_translations=self._install_null,
install_gettext_callables=self._install_callables,
uninstall_gettext_translations=self._uninstall,
extract_translations=self._extract,
newstyle_gettext=False
)
def _install(self, translations, newstyle=None):
gettext = getattr(translations, 'ugettext', None)
if gettext is None:
gettext = translations.gettext
ngettext = getattr(translations, 'ungettext', None)
if ngettext is None:
ngettext = translations.ngettext
self._install_callables(gettext, ngettext, newstyle)
def _install_null(self, newstyle=None):
self._install_callables(
lambda x: x,
lambda s, p, n: (n != 1 and (p,) or (s,))[0],
newstyle
)
def _install_callables(self, gettext, ngettext, newstyle=None):
if newstyle is not None:
self.environment.newstyle_gettext = newstyle
if self.environment.newstyle_gettext:
gettext = _make_new_gettext(gettext)
ngettext = _make_new_ngettext(ngettext)
self.environment.globals.update(
gettext=gettext,
ngettext=ngettext
)
def _uninstall(self, translations):
for key in 'gettext', 'ngettext':
self.environment.globals.pop(key, None)
def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS):
if isinstance(source, string_types):
source = self.environment.parse(source)
return extract_from_ast(source, gettext_functions)
def parse(self, parser):
"""Parse a translatable tag."""
lineno = next(parser.stream).lineno
num_called_num = False
# find all the variables referenced. Additionally a variable can be
# defined in the body of the trans block too, but this is checked at
# a later state.
plural_expr = None
plural_expr_assignment = None
variables = {}
while parser.stream.current.type != 'block_end':
if variables:
parser.stream.expect('comma')
# skip colon for python compatibility
if parser.stream.skip_if('colon'):
break
name = parser.stream.expect('name')
if name.value in variables:
parser.fail('translatable variable %r defined twice.' %
name.value, name.lineno,
exc=TemplateAssertionError)
# expressions
if parser.stream.current.type == 'assign':
next(parser.stream)
variables[name.value] = var = parser.parse_expression()
else:
variables[name.value] = var = nodes.Name(name.value, 'load')
if plural_expr is None:
if isinstance(var, nodes.Call):
plural_expr = nodes.Name('_trans', 'load')
variables[name.value] = plural_expr
plural_expr_assignment = nodes.Assign(
nodes.Name('_trans', 'store'), var)
else:
plural_expr = var
num_called_num = name.value == 'num'
parser.stream.expect('block_end')
plural = plural_names = None
have_plural = False
referenced = set()
# now parse until endtrans or pluralize
singular_names, singular = self._parse_block(parser, True)
if singular_names:
referenced.update(singular_names)
if plural_expr is None:
plural_expr = nodes.Name(singular_names[0], 'load')
num_called_num = singular_names[0] == 'num'
# if we have a pluralize block, we parse that too
if parser.stream.current.test('name:pluralize'):
have_plural = True
next(parser.stream)
if parser.stream.current.type != 'block_end':
name = parser.stream.expect('name')
if name.value not in variables:
parser.fail('unknown variable %r for pluralization' %
name.value, name.lineno,
exc=TemplateAssertionError)
plural_expr = variables[name.value]
num_called_num = name.value == 'num'
parser.stream.expect('block_end')
plural_names, plural = self._parse_block(parser, False)
next(parser.stream)
referenced.update(plural_names)
else:
next(parser.stream)
# register free names as simple name expressions
for var in referenced:
if var not in variables:
variables[var] = nodes.Name(var, 'load')
if not have_plural:
plural_expr = None
elif plural_expr is None:
parser.fail('pluralize without variables', lineno)
node = self._make_node(singular, plural, variables, plural_expr,
bool(referenced),
num_called_num and have_plural)
node.set_lineno(lineno)
if plural_expr_assignment is not None:
return [plural_expr_assignment, node]
else:
return node
def _parse_block(self, parser, allow_pluralize):
"""Parse until the next block tag with a given name."""
referenced = []
buf = []
while 1:
if parser.stream.current.type == 'data':
buf.append(parser.stream.current.value.replace('%', '%%'))
next(parser.stream)
elif parser.stream.current.type == 'variable_begin':
next(parser.stream)
name = parser.stream.expect('name').value
referenced.append(name)
buf.append('%%(%s)s' % name)
parser.stream.expect('variable_end')
elif parser.stream.current.type == 'block_begin':
next(parser.stream)
if parser.stream.current.test('name:endtrans'):
break
elif parser.stream.current.test('name:pluralize'):
if allow_pluralize:
break
parser.fail('a translatable section can have only one '
'pluralize section')
parser.fail('control structures in translatable sections are '
'not allowed')
elif parser.stream.eos:
parser.fail('unclosed translation block')
else:
assert False, 'internal parser error'
return referenced, concat(buf)
def _make_node(self, singular, plural, variables, plural_expr,
vars_referenced, num_called_num):
"""Generates a useful node from the data provided."""
# no variables referenced? no need to escape for old style
# gettext invocations only if there are vars.
if not vars_referenced and not self.environment.newstyle_gettext:
singular = singular.replace('%%', '%')
if plural:
plural = plural.replace('%%', '%')
# singular only:
if plural_expr is None:
gettext = nodes.Name('gettext', 'load')
node = nodes.Call(gettext, [nodes.Const(singular)],
[], None, None)
# singular and plural
else:
ngettext = nodes.Name('ngettext', 'load')
node = nodes.Call(ngettext, [
nodes.Const(singular),
nodes.Const(plural),
plural_expr
], [], None, None)
# in case newstyle gettext is used, the method is powerful
# enough to handle the variable expansion and autoescape
# handling itself
if self.environment.newstyle_gettext:
for key, value in iteritems(variables):
# the function adds that later anyways in case num was
# called num, so just skip it.
if num_called_num and key == 'num':
continue
node.kwargs.append(nodes.Keyword(key, value))
# otherwise do that here
else:
# mark the return value as safe if we are in an
# environment with autoescaping turned on
node = nodes.MarkSafeIfAutoescape(node)
if variables:
node = nodes.Mod(node, nodes.Dict([
nodes.Pair(nodes.Const(key), value)
for key, value in variables.items()
]))
return nodes.Output([node])
class ExprStmtExtension(Extension):
"""Adds a `do` tag to Jinja2 that works like the print statement just
that it doesn't print the return value.
"""
tags = set(['do'])
def parse(self, parser):
node = nodes.ExprStmt(lineno=next(parser.stream).lineno)
node.node = parser.parse_tuple()
return node
class LoopControlExtension(Extension):
"""Adds break and continue to the template engine."""
tags = set(['break', 'continue'])
def parse(self, parser):
token = next(parser.stream)
if token.value == 'break':
return nodes.Break(lineno=token.lineno)
return nodes.Continue(lineno=token.lineno)
class WithExtension(Extension):
"""Adds support for a django-like with block."""
tags = set(['with'])
def parse(self, parser):
node = nodes.Scope(lineno=next(parser.stream).lineno)
assignments = []
while parser.stream.current.type != 'block_end':
lineno = parser.stream.current.lineno
if assignments:
parser.stream.expect('comma')
target = parser.parse_assign_target()
parser.stream.expect('assign')
expr = parser.parse_expression()
assignments.append(nodes.Assign(target, expr, lineno=lineno))
node.body = assignments + \
list(parser.parse_statements(('name:endwith',),
drop_needle=True))
return node
class AutoEscapeExtension(Extension):
"""Changes auto escape rules for a scope."""
tags = set(['autoescape'])
def parse(self, parser):
node = nodes.ScopedEvalContextModifier(lineno=next(parser.stream).lineno)
node.options = [
nodes.Keyword('autoescape', parser.parse_expression())
]
node.body = parser.parse_statements(('name:endautoescape',),
drop_needle=True)
return nodes.Scope([node])
def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS,
babel_style=True):
"""Extract localizable strings from the given template node. Per
default this function returns matches in babel style that means non string
parameters as well as keyword arguments are returned as `None`. This
allows Babel to figure out what you really meant if you are using
gettext functions that allow keyword arguments for placeholder expansion.
If you don't want that behavior set the `babel_style` parameter to `False`
which causes only strings to be returned and parameters are always stored
in tuples. As a consequence invalid gettext calls (calls without a single
string parameter or string parameters after non-string parameters) are
skipped.
This example explains the behavior:
>>> from jinja2 import Environment
>>> env = Environment()
>>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}')
>>> list(extract_from_ast(node))
[(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))]
>>> list(extract_from_ast(node, babel_style=False))
[(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))]
For every string found this function yields a ``(lineno, function,
message)`` tuple, where:
* ``lineno`` is the number of the line on which the string was found,
* ``function`` is the name of the ``gettext`` function used (if the
string was extracted from embedded Python code), and
* ``message`` is the string itself (a ``unicode`` object, or a tuple
of ``unicode`` objects for functions with multiple string arguments).
This extraction function operates on the AST and is because of that unable
to extract any comments. For comment support you have to use the babel
extraction interface or extract comments yourself.
"""
for node in node.find_all(nodes.Call):
if not isinstance(node.node, nodes.Name) or \
node.node.name not in gettext_functions:
continue
strings = []
for arg in node.args:
if isinstance(arg, nodes.Const) and \
isinstance(arg.value, string_types):
strings.append(arg.value)
else:
strings.append(None)
for arg in node.kwargs:
strings.append(None)
if node.dyn_args is not None:
strings.append(None)
if node.dyn_kwargs is not None:
strings.append(None)
if not babel_style:
strings = tuple(x for x in strings if x is not None)
if not strings:
continue
else:
if len(strings) == 1:
strings = strings[0]
else:
strings = tuple(strings)
yield node.lineno, node.node.name, strings
class _CommentFinder(object):
"""Helper class to find comments in a token stream. Can only
find comments for gettext calls forwards. Once the comment
from line 4 is found, a comment for line 1 will not return a
usable value.
"""
def __init__(self, tokens, comment_tags):
self.tokens = tokens
self.comment_tags = comment_tags
self.offset = 0
self.last_lineno = 0
def find_backwards(self, offset):
try:
for _, token_type, token_value in \
reversed(self.tokens[self.offset:offset]):
if token_type in ('comment', 'linecomment'):
try:
prefix, comment = token_value.split(None, 1)
except ValueError:
continue
if prefix in self.comment_tags:
return [comment.rstrip()]
return []
finally:
self.offset = offset
def find_comments(self, lineno):
if not self.comment_tags or self.last_lineno > lineno:
return []
for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset:]):
if token_lineno > lineno:
return self.find_backwards(self.offset + idx)
return self.find_backwards(len(self.tokens))
def babel_extract(fileobj, keywords, comment_tags, options):
"""Babel extraction method for Jinja templates.
.. versionchanged:: 2.3
Basic support for translation comments was added. If `comment_tags`
is now set to a list of keywords for extraction, the extractor will
try to find the best preceeding comment that begins with one of the
keywords. For best results, make sure to not have more than one
gettext call in one line of code and the matching comment in the
same line or the line before.
.. versionchanged:: 2.5.1
The `newstyle_gettext` flag can be set to `True` to enable newstyle
gettext calls.
.. versionchanged:: 2.7
A `silent` option can now be provided. If set to `False` template
syntax errors are propagated instead of being ignored.
:param fileobj: the file-like object the messages should be extracted from
:param keywords: a list of keywords (i.e. function names) that should be
recognized as translation functions
:param comment_tags: a list of translator tags to search for and include
in the results.
:param options: a dictionary of additional options (optional)
:return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
(comments will be empty currently)
"""
extensions = set()
for extension in options.get('extensions', '').split(','):
extension = extension.strip()
if not extension:
continue
extensions.add(import_string(extension))
if InternationalizationExtension not in extensions:
extensions.add(InternationalizationExtension)
def getbool(options, key, default=False):
return options.get(key, str(default)).lower() in \
('1', 'on', 'yes', 'true')
silent = getbool(options, 'silent', True)
environment = Environment(
options.get('block_start_string', BLOCK_START_STRING),
options.get('block_end_string', BLOCK_END_STRING),
options.get('variable_start_string', VARIABLE_START_STRING),
options.get('variable_end_string', VARIABLE_END_STRING),
options.get('comment_start_string', COMMENT_START_STRING),
options.get('comment_end_string', COMMENT_END_STRING),
options.get('line_statement_prefix') or LINE_STATEMENT_PREFIX,
options.get('line_comment_prefix') or LINE_COMMENT_PREFIX,
getbool(options, 'trim_blocks', TRIM_BLOCKS),
getbool(options, 'lstrip_blocks', LSTRIP_BLOCKS),
NEWLINE_SEQUENCE,
getbool(options, 'keep_trailing_newline', KEEP_TRAILING_NEWLINE),
frozenset(extensions),
cache_size=0,
auto_reload=False
)
if getbool(options, 'newstyle_gettext'):
environment.newstyle_gettext = True
source = fileobj.read().decode(options.get('encoding', 'utf-8'))
try:
node = environment.parse(source)
tokens = list(environment.lex(environment.preprocess(source)))
except TemplateSyntaxError as e:
if not silent:
raise
# skip templates with syntax errors
return
finder = _CommentFinder(tokens, comment_tags)
for lineno, func, message in extract_from_ast(node, keywords):
yield lineno, func, message, finder.find_comments(lineno)
#: nicer import names
i18n = InternationalizationExtension
do = ExprStmtExtension
loopcontrols = LoopControlExtension
with_ = WithExtension
autoescape = AutoEscapeExtension
-987
View File
@@ -1,987 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.filters
~~~~~~~~~~~~~~
Bundled jinja filters.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
import re
import math
from random import choice
from operator import itemgetter
from itertools import groupby
from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \
unicode_urlencode
from jinja2.runtime import Undefined
from jinja2.exceptions import FilterArgumentError
from jinja2._compat import next, imap, string_types, text_type, iteritems
_word_re = re.compile(r'\w+(?u)')
def contextfilter(f):
"""Decorator for marking context dependent filters. The current
:class:`Context` will be passed as first argument.
"""
f.contextfilter = True
return f
def evalcontextfilter(f):
"""Decorator for marking eval-context dependent filters. An eval
context object is passed as first argument. For more information
about the eval context, see :ref:`eval-context`.
.. versionadded:: 2.4
"""
f.evalcontextfilter = True
return f
def environmentfilter(f):
"""Decorator for marking evironment dependent filters. The current
:class:`Environment` is passed to the filter as first argument.
"""
f.environmentfilter = True
return f
def make_attrgetter(environment, attribute):
"""Returns a callable that looks up the given attribute from a
passed object with the rules of the environment. Dots are allowed
to access attributes of attributes. Integer parts in paths are
looked up as integers.
"""
if not isinstance(attribute, string_types) \
or ('.' not in attribute and not attribute.isdigit()):
return lambda x: environment.getitem(x, attribute)
attribute = attribute.split('.')
def attrgetter(item):
for part in attribute:
if part.isdigit():
part = int(part)
item = environment.getitem(item, part)
return item
return attrgetter
def do_forceescape(value):
"""Enforce HTML escaping. This will probably double escape variables."""
if hasattr(value, '__html__'):
value = value.__html__()
return escape(text_type(value))
def do_urlencode(value):
"""Escape strings for use in URLs (uses UTF-8 encoding). It accepts both
dictionaries and regular strings as well as pairwise iterables.
.. versionadded:: 2.7
"""
itemiter = None
if isinstance(value, dict):
itemiter = iteritems(value)
elif not isinstance(value, string_types):
try:
itemiter = iter(value)
except TypeError:
pass
if itemiter is None:
return unicode_urlencode(value)
return u'&'.join(unicode_urlencode(k) + '=' +
unicode_urlencode(v) for k, v in itemiter)
@evalcontextfilter
def do_replace(eval_ctx, s, old, new, count=None):
"""Return a copy of the value with all occurrences of a substring
replaced with a new one. The first argument is the substring
that should be replaced, the second is the replacement string.
If the optional third argument ``count`` is given, only the first
``count`` occurrences are replaced:
.. sourcecode:: jinja
{{ "Hello World"|replace("Hello", "Goodbye") }}
-> Goodbye World
{{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
-> d'oh, d'oh, aaargh
"""
if count is None:
count = -1
if not eval_ctx.autoescape:
return text_type(s).replace(text_type(old), text_type(new), count)
if hasattr(old, '__html__') or hasattr(new, '__html__') and \
not hasattr(s, '__html__'):
s = escape(s)
else:
s = soft_unicode(s)
return s.replace(soft_unicode(old), soft_unicode(new), count)
def do_upper(s):
"""Convert a value to uppercase."""
return soft_unicode(s).upper()
def do_lower(s):
"""Convert a value to lowercase."""
return soft_unicode(s).lower()
@evalcontextfilter
def do_xmlattr(_eval_ctx, d, autospace=True):
"""Create an SGML/XML attribute string based on the items in a dict.
All values that are neither `none` nor `undefined` are automatically
escaped:
.. sourcecode:: html+jinja
<ul{{ {'class': 'my_list', 'missing': none,
'id': 'list-%d'|format(variable)}|xmlattr }}>
...
</ul>
Results in something like this:
.. sourcecode:: html
<ul class="my_list" id="list-42">
...
</ul>
As you can see it automatically prepends a space in front of the item
if the filter returned something unless the second parameter is false.
"""
rv = u' '.join(
u'%s="%s"' % (escape(key), escape(value))
for key, value in iteritems(d)
if value is not None and not isinstance(value, Undefined)
)
if autospace and rv:
rv = u' ' + rv
if _eval_ctx.autoescape:
rv = Markup(rv)
return rv
def do_capitalize(s):
"""Capitalize a value. The first character will be uppercase, all others
lowercase.
"""
return soft_unicode(s).capitalize()
def do_title(s):
"""Return a titlecased version of the value. I.e. words will start with
uppercase letters, all remaining characters are lowercase.
"""
rv = []
for item in re.compile(r'([-\s]+)(?u)').split(s):
if not item:
continue
rv.append(item[0].upper() + item[1:].lower())
return ''.join(rv)
def do_dictsort(value, case_sensitive=False, by='key'):
"""Sort a dict and yield (key, value) pairs. Because python dicts are
unsorted you may want to use this function to order them by either
key or value:
.. sourcecode:: jinja
{% for item in mydict|dictsort %}
sort the dict by key, case insensitive
{% for item in mydict|dictsort(true) %}
sort the dict by key, case sensitive
{% for item in mydict|dictsort(false, 'value') %}
sort the dict by key, case insensitive, sorted
normally and ordered by value.
"""
if by == 'key':
pos = 0
elif by == 'value':
pos = 1
else:
raise FilterArgumentError('You can only sort by either '
'"key" or "value"')
def sort_func(item):
value = item[pos]
if isinstance(value, string_types) and not case_sensitive:
value = value.lower()
return value
return sorted(value.items(), key=sort_func)
@environmentfilter
def do_sort(environment, value, reverse=False, case_sensitive=False,
attribute=None):
"""Sort an iterable. Per default it sorts ascending, if you pass it
true as first argument it will reverse the sorting.
If the iterable is made of strings the third parameter can be used to
control the case sensitiveness of the comparison which is disabled by
default.
.. sourcecode:: jinja
{% for item in iterable|sort %}
...
{% endfor %}
It is also possible to sort by an attribute (for example to sort
by the date of an object) by specifying the `attribute` parameter:
.. sourcecode:: jinja
{% for item in iterable|sort(attribute='date') %}
...
{% endfor %}
.. versionchanged:: 2.6
The `attribute` parameter was added.
"""
if not case_sensitive:
def sort_func(item):
if isinstance(item, string_types):
item = item.lower()
return item
else:
sort_func = None
if attribute is not None:
getter = make_attrgetter(environment, attribute)
def sort_func(item, processor=sort_func or (lambda x: x)):
return processor(getter(item))
return sorted(value, key=sort_func, reverse=reverse)
def do_default(value, default_value=u'', boolean=False):
"""If the value is undefined it will return the passed default value,
otherwise the value of the variable:
.. sourcecode:: jinja
{{ my_variable|default('my_variable is not defined') }}
This will output the value of ``my_variable`` if the variable was
defined, otherwise ``'my_variable is not defined'``. If you want
to use default with variables that evaluate to false you have to
set the second parameter to `true`:
.. sourcecode:: jinja
{{ ''|default('the string was empty', true) }}
"""
if isinstance(value, Undefined) or (boolean and not value):
return default_value
return value
@evalcontextfilter
def do_join(eval_ctx, value, d=u'', attribute=None):
"""Return a string which is the concatenation of the strings in the
sequence. The separator between elements is an empty string per
default, you can define it with the optional parameter:
.. sourcecode:: jinja
{{ [1, 2, 3]|join('|') }}
-> 1|2|3
{{ [1, 2, 3]|join }}
-> 123
It is also possible to join certain attributes of an object:
.. sourcecode:: jinja
{{ users|join(', ', attribute='username') }}
.. versionadded:: 2.6
The `attribute` parameter was added.
"""
if attribute is not None:
value = imap(make_attrgetter(eval_ctx.environment, attribute), value)
# no automatic escaping? joining is a lot eaiser then
if not eval_ctx.autoescape:
return text_type(d).join(imap(text_type, value))
# if the delimiter doesn't have an html representation we check
# if any of the items has. If yes we do a coercion to Markup
if not hasattr(d, '__html__'):
value = list(value)
do_escape = False
for idx, item in enumerate(value):
if hasattr(item, '__html__'):
do_escape = True
else:
value[idx] = text_type(item)
if do_escape:
d = escape(d)
else:
d = text_type(d)
return d.join(value)
# no html involved, to normal joining
return soft_unicode(d).join(imap(soft_unicode, value))
def do_center(value, width=80):
"""Centers the value in a field of a given width."""
return text_type(value).center(width)
@environmentfilter
def do_first(environment, seq):
"""Return the first item of a sequence."""
try:
return next(iter(seq))
except StopIteration:
return environment.undefined('No first item, sequence was empty.')
@environmentfilter
def do_last(environment, seq):
"""Return the last item of a sequence."""
try:
return next(iter(reversed(seq)))
except StopIteration:
return environment.undefined('No last item, sequence was empty.')
@environmentfilter
def do_random(environment, seq):
"""Return a random item from the sequence."""
try:
return choice(seq)
except IndexError:
return environment.undefined('No random item, sequence was empty.')
def do_filesizeformat(value, binary=False):
"""Format the value like a 'human-readable' file size (i.e. 13 kB,
4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
Giga, etc.), if the second parameter is set to `True` the binary
prefixes are used (Mebi, Gibi).
"""
bytes = float(value)
base = binary and 1024 or 1000
prefixes = [
(binary and 'KiB' or 'kB'),
(binary and 'MiB' or 'MB'),
(binary and 'GiB' or 'GB'),
(binary and 'TiB' or 'TB'),
(binary and 'PiB' or 'PB'),
(binary and 'EiB' or 'EB'),
(binary and 'ZiB' or 'ZB'),
(binary and 'YiB' or 'YB')
]
if bytes == 1:
return '1 Byte'
elif bytes < base:
return '%d Bytes' % bytes
else:
for i, prefix in enumerate(prefixes):
unit = base ** (i + 2)
if bytes < unit:
return '%.1f %s' % ((base * bytes / unit), prefix)
return '%.1f %s' % ((base * bytes / unit), prefix)
def do_pprint(value, verbose=False):
"""Pretty print a variable. Useful for debugging.
With Jinja 1.2 onwards you can pass it a parameter. If this parameter
is truthy the output will be more verbose (this requires `pretty`)
"""
return pformat(value, verbose=verbose)
@evalcontextfilter
def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False):
"""Converts URLs in plain text into clickable links.
If you pass the filter an additional integer it will shorten the urls
to that number. Also a third argument exists that makes the urls
"nofollow":
.. sourcecode:: jinja
{{ mytext|urlize(40, true) }}
links are shortened to 40 chars and defined with rel="nofollow"
"""
rv = urlize(value, trim_url_limit, nofollow)
if eval_ctx.autoescape:
rv = Markup(rv)
return rv
def do_indent(s, width=4, indentfirst=False):
"""Return a copy of the passed string, each line indented by
4 spaces. The first line is not indented. If you want to
change the number of spaces or indent the first line too
you can pass additional parameters to the filter:
.. sourcecode:: jinja
{{ mytext|indent(2, true) }}
indent by two spaces and indent the first line too.
"""
indention = u' ' * width
rv = (u'\n' + indention).join(s.splitlines())
if indentfirst:
rv = indention + rv
return rv
def do_truncate(s, length=255, killwords=False, end='...'):
"""Return a truncated copy of the string. The length is specified
with the first parameter which defaults to ``255``. If the second
parameter is ``true`` the filter will cut the text at length. Otherwise
it will discard the last word. If the text was in fact
truncated it will append an ellipsis sign (``"..."``). If you want a
different ellipsis sign than ``"..."`` you can specify it using the
third parameter.
.. sourcecode:: jinja
{{ "foo bar"|truncate(5) }}
-> "foo ..."
{{ "foo bar"|truncate(5, True) }}
-> "foo b..."
"""
if len(s) <= length:
return s
elif killwords:
return s[:length] + end
words = s.split(' ')
result = []
m = 0
for word in words:
m += len(word) + 1
if m > length:
break
result.append(word)
result.append(end)
return u' '.join(result)
@environmentfilter
def do_wordwrap(environment, s, width=79, break_long_words=True,
wrapstring=None):
"""
Return a copy of the string passed to the filter wrapped after
``79`` characters. You can override this default using the first
parameter. If you set the second parameter to `false` Jinja will not
split words apart if they are longer than `width`. By default, the newlines
will be the default newlines for the environment, but this can be changed
using the wrapstring keyword argument.
.. versionadded:: 2.7
Added support for the `wrapstring` parameter.
"""
if not wrapstring:
wrapstring = environment.newline_sequence
import textwrap
return wrapstring.join(textwrap.wrap(s, width=width, expand_tabs=False,
replace_whitespace=False,
break_long_words=break_long_words))
def do_wordcount(s):
"""Count the words in that string."""
return len(_word_re.findall(s))
def do_int(value, default=0):
"""Convert the value into an integer. If the
conversion doesn't work it will return ``0``. You can
override this default using the first parameter.
"""
try:
return int(value)
except (TypeError, ValueError):
# this quirk is necessary so that "42.23"|int gives 42.
try:
return int(float(value))
except (TypeError, ValueError):
return default
def do_float(value, default=0.0):
"""Convert the value into a floating point number. If the
conversion doesn't work it will return ``0.0``. You can
override this default using the first parameter.
"""
try:
return float(value)
except (TypeError, ValueError):
return default
def do_format(value, *args, **kwargs):
"""
Apply python string formatting on an object:
.. sourcecode:: jinja
{{ "%s - %s"|format("Hello?", "Foo!") }}
-> Hello? - Foo!
"""
if args and kwargs:
raise FilterArgumentError('can\'t handle positional and keyword '
'arguments at the same time')
return soft_unicode(value) % (kwargs or args)
def do_trim(value):
"""Strip leading and trailing whitespace."""
return soft_unicode(value).strip()
def do_striptags(value):
"""Strip SGML/XML tags and replace adjacent whitespace by one space.
"""
if hasattr(value, '__html__'):
value = value.__html__()
return Markup(text_type(value)).striptags()
def do_slice(value, slices, fill_with=None):
"""Slice an iterator and return a list of lists containing
those items. Useful if you want to create a div containing
three ul tags that represent columns:
.. sourcecode:: html+jinja
<div class="columwrapper">
{%- for column in items|slice(3) %}
<ul class="column-{{ loop.index }}">
{%- for item in column %}
<li>{{ item }}</li>
{%- endfor %}
</ul>
{%- endfor %}
</div>
If you pass it a second argument it's used to fill missing
values on the last iteration.
"""
seq = list(value)
length = len(seq)
items_per_slice = length // slices
slices_with_extra = length % slices
offset = 0
for slice_number in range(slices):
start = offset + slice_number * items_per_slice
if slice_number < slices_with_extra:
offset += 1
end = offset + (slice_number + 1) * items_per_slice
tmp = seq[start:end]
if fill_with is not None and slice_number >= slices_with_extra:
tmp.append(fill_with)
yield tmp
def do_batch(value, linecount, fill_with=None):
"""
A filter that batches items. It works pretty much like `slice`
just the other way round. It returns a list of lists with the
given number of items. If you provide a second parameter this
is used to fill up missing items. See this example:
.. sourcecode:: html+jinja
<table>
{%- for row in items|batch(3, '&nbsp;') %}
<tr>
{%- for column in row %}
<td>{{ column }}</td>
{%- endfor %}
</tr>
{%- endfor %}
</table>
"""
result = []
tmp = []
for item in value:
if len(tmp) == linecount:
yield tmp
tmp = []
tmp.append(item)
if tmp:
if fill_with is not None and len(tmp) < linecount:
tmp += [fill_with] * (linecount - len(tmp))
yield tmp
def do_round(value, precision=0, method='common'):
"""Round the number to a given precision. The first
parameter specifies the precision (default is ``0``), the
second the rounding method:
- ``'common'`` rounds either up or down
- ``'ceil'`` always rounds up
- ``'floor'`` always rounds down
If you don't specify a method ``'common'`` is used.
.. sourcecode:: jinja
{{ 42.55|round }}
-> 43.0
{{ 42.55|round(1, 'floor') }}
-> 42.5
Note that even if rounded to 0 precision, a float is returned. If
you need a real integer, pipe it through `int`:
.. sourcecode:: jinja
{{ 42.55|round|int }}
-> 43
"""
if not method in ('common', 'ceil', 'floor'):
raise FilterArgumentError('method must be common, ceil or floor')
if method == 'common':
return round(value, precision)
func = getattr(math, method)
return func(value * (10 ** precision)) / (10 ** precision)
@environmentfilter
def do_groupby(environment, value, attribute):
"""Group a sequence of objects by a common attribute.
If you for example have a list of dicts or objects that represent persons
with `gender`, `first_name` and `last_name` attributes and you want to
group all users by genders you can do something like the following
snippet:
.. sourcecode:: html+jinja
<ul>
{% for group in persons|groupby('gender') %}
<li>{{ group.grouper }}<ul>
{% for person in group.list %}
<li>{{ person.first_name }} {{ person.last_name }}</li>
{% endfor %}</ul></li>
{% endfor %}
</ul>
Additionally it's possible to use tuple unpacking for the grouper and
list:
.. sourcecode:: html+jinja
<ul>
{% for grouper, list in persons|groupby('gender') %}
...
{% endfor %}
</ul>
As you can see the item we're grouping by is stored in the `grouper`
attribute and the `list` contains all the objects that have this grouper
in common.
.. versionchanged:: 2.6
It's now possible to use dotted notation to group by the child
attribute of another attribute.
"""
expr = make_attrgetter(environment, attribute)
return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr)))
class _GroupTuple(tuple):
__slots__ = ()
grouper = property(itemgetter(0))
list = property(itemgetter(1))
def __new__(cls, xxx_todo_changeme):
(key, value) = xxx_todo_changeme
return tuple.__new__(cls, (key, list(value)))
@environmentfilter
def do_sum(environment, iterable, attribute=None, start=0):
"""Returns the sum of a sequence of numbers plus the value of parameter
'start' (which defaults to 0). When the sequence is empty it returns
start.
It is also possible to sum up only certain attributes:
.. sourcecode:: jinja
Total: {{ items|sum(attribute='price') }}
.. versionchanged:: 2.6
The `attribute` parameter was added to allow suming up over
attributes. Also the `start` parameter was moved on to the right.
"""
if attribute is not None:
iterable = imap(make_attrgetter(environment, attribute), iterable)
return sum(iterable, start)
def do_list(value):
"""Convert the value into a list. If it was a string the returned list
will be a list of characters.
"""
return list(value)
def do_mark_safe(value):
"""Mark the value as safe which means that in an environment with automatic
escaping enabled this variable will not be escaped.
"""
return Markup(value)
def do_mark_unsafe(value):
"""Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
return text_type(value)
def do_reverse(value):
"""Reverse the object or return an iterator the iterates over it the other
way round.
"""
if isinstance(value, string_types):
return value[::-1]
try:
return reversed(value)
except TypeError:
try:
rv = list(value)
rv.reverse()
return rv
except TypeError:
raise FilterArgumentError('argument must be iterable')
@environmentfilter
def do_attr(environment, obj, name):
"""Get an attribute of an object. ``foo|attr("bar")`` works like
``foo["bar"]`` just that always an attribute is returned and items are not
looked up.
See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
"""
try:
name = str(name)
except UnicodeError:
pass
else:
try:
value = getattr(obj, name)
except AttributeError:
pass
else:
if environment.sandboxed and not \
environment.is_safe_attribute(obj, name, value):
return environment.unsafe_undefined(obj, name)
return value
return environment.undefined(obj=obj, name=name)
@contextfilter
def do_map(*args, **kwargs):
"""Applies a filter on a sequence of objects or looks up an attribute.
This is useful when dealing with lists of objects but you are really
only interested in a certain value of it.
The basic usage is mapping on an attribute. Imagine you have a list
of users but you are only interested in a list of usernames:
.. sourcecode:: jinja
Users on this page: {{ users|map(attribute='username')|join(', ') }}
Alternatively you can let it invoke a filter by passing the name of the
filter and the arguments afterwards. A good example would be applying a
text conversion filter on a sequence:
.. sourcecode:: jinja
Users on this page: {{ titles|map('lower')|join(', ') }}
.. versionadded:: 2.7
"""
context = args[0]
seq = args[1]
if len(args) == 2 and 'attribute' in kwargs:
attribute = kwargs.pop('attribute')
if kwargs:
raise FilterArgumentError('Unexpected keyword argument %r' %
next(iter(kwargs)))
func = make_attrgetter(context.environment, attribute)
else:
try:
name = args[2]
args = args[3:]
except LookupError:
raise FilterArgumentError('map requires a filter argument')
func = lambda item: context.environment.call_filter(
name, item, args, kwargs, context=context)
if seq:
for item in seq:
yield func(item)
@contextfilter
def do_select(*args, **kwargs):
"""Filters a sequence of objects by appying a test to either the object
or the attribute and only selecting the ones with the test succeeding.
Example usage:
.. sourcecode:: jinja
{{ numbers|select("odd") }}
.. versionadded:: 2.7
"""
return _select_or_reject(args, kwargs, lambda x: x, False)
@contextfilter
def do_reject(*args, **kwargs):
"""Filters a sequence of objects by appying a test to either the object
or the attribute and rejecting the ones with the test succeeding.
Example usage:
.. sourcecode:: jinja
{{ numbers|reject("odd") }}
.. versionadded:: 2.7
"""
return _select_or_reject(args, kwargs, lambda x: not x, False)
@contextfilter
def do_selectattr(*args, **kwargs):
"""Filters a sequence of objects by appying a test to either the object
or the attribute and only selecting the ones with the test succeeding.
Example usage:
.. sourcecode:: jinja
{{ users|selectattr("is_active") }}
{{ users|selectattr("email", "none") }}
.. versionadded:: 2.7
"""
return _select_or_reject(args, kwargs, lambda x: x, True)
@contextfilter
def do_rejectattr(*args, **kwargs):
"""Filters a sequence of objects by appying a test to either the object
or the attribute and rejecting the ones with the test succeeding.
.. sourcecode:: jinja
{{ users|rejectattr("is_active") }}
{{ users|rejectattr("email", "none") }}
.. versionadded:: 2.7
"""
return _select_or_reject(args, kwargs, lambda x: not x, True)
def _select_or_reject(args, kwargs, modfunc, lookup_attr):
context = args[0]
seq = args[1]
if lookup_attr:
try:
attr = args[2]
except LookupError:
raise FilterArgumentError('Missing parameter for attribute name')
transfunc = make_attrgetter(context.environment, attr)
off = 1
else:
off = 0
transfunc = lambda x: x
try:
name = args[2 + off]
args = args[3 + off:]
func = lambda item: context.environment.call_test(
name, item, args, kwargs)
except LookupError:
func = bool
if seq:
for item in seq:
if modfunc(func(transfunc(item))):
yield item
FILTERS = {
'attr': do_attr,
'replace': do_replace,
'upper': do_upper,
'lower': do_lower,
'escape': escape,
'e': escape,
'forceescape': do_forceescape,
'capitalize': do_capitalize,
'title': do_title,
'default': do_default,
'd': do_default,
'join': do_join,
'count': len,
'dictsort': do_dictsort,
'sort': do_sort,
'length': len,
'reverse': do_reverse,
'center': do_center,
'indent': do_indent,
'title': do_title,
'capitalize': do_capitalize,
'first': do_first,
'last': do_last,
'map': do_map,
'random': do_random,
'reject': do_reject,
'rejectattr': do_rejectattr,
'filesizeformat': do_filesizeformat,
'pprint': do_pprint,
'truncate': do_truncate,
'wordwrap': do_wordwrap,
'wordcount': do_wordcount,
'int': do_int,
'float': do_float,
'string': soft_unicode,
'list': do_list,
'urlize': do_urlize,
'format': do_format,
'trim': do_trim,
'striptags': do_striptags,
'select': do_select,
'selectattr': do_selectattr,
'slice': do_slice,
'batch': do_batch,
'sum': do_sum,
'abs': abs,
'round': do_round,
'groupby': do_groupby,
'safe': do_mark_safe,
'xmlattr': do_xmlattr,
'urlencode': do_urlencode
}
-733
View File
@@ -1,733 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.lexer
~~~~~~~~~~~~
This module implements a Jinja / Python combination lexer. The
`Lexer` class provided by this module is used to do some preprocessing
for Jinja.
On the one hand it filters out invalid operators like the bitshift
operators we don't allow in templates. On the other hand it separates
template code and python code in expressions.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
import re
from operator import itemgetter
from collections import deque
from jinja2.exceptions import TemplateSyntaxError
from jinja2.utils import LRUCache
from jinja2._compat import next, iteritems, implements_iterator, text_type, \
intern
# cache for the lexers. Exists in order to be able to have multiple
# environments with the same lexer
_lexer_cache = LRUCache(50)
# static regular expressions
whitespace_re = re.compile(r'\s+', re.U)
string_re = re.compile(r"('([^'\\]*(?:\\.[^'\\]*)*)'"
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
integer_re = re.compile(r'\d+')
# we use the unicode identifier rule if this python version is able
# to handle unicode identifiers, otherwise the standard ASCII one.
try:
compile('föö', '<unknown>', 'eval')
except SyntaxError:
name_re = re.compile(r'\b[a-zA-Z_][a-zA-Z0-9_]*\b')
else:
from jinja2 import _stringdefs
name_re = re.compile(r'[%s][%s]*' % (_stringdefs.xid_start,
_stringdefs.xid_continue))
float_re = re.compile(r'(?<!\.)\d+\.\d+')
newline_re = re.compile(r'(\r\n|\r|\n)')
# internal the tokens and keep references to them
TOKEN_ADD = intern('add')
TOKEN_ASSIGN = intern('assign')
TOKEN_COLON = intern('colon')
TOKEN_COMMA = intern('comma')
TOKEN_DIV = intern('div')
TOKEN_DOT = intern('dot')
TOKEN_EQ = intern('eq')
TOKEN_FLOORDIV = intern('floordiv')
TOKEN_GT = intern('gt')
TOKEN_GTEQ = intern('gteq')
TOKEN_LBRACE = intern('lbrace')
TOKEN_LBRACKET = intern('lbracket')
TOKEN_LPAREN = intern('lparen')
TOKEN_LT = intern('lt')
TOKEN_LTEQ = intern('lteq')
TOKEN_MOD = intern('mod')
TOKEN_MUL = intern('mul')
TOKEN_NE = intern('ne')
TOKEN_PIPE = intern('pipe')
TOKEN_POW = intern('pow')
TOKEN_RBRACE = intern('rbrace')
TOKEN_RBRACKET = intern('rbracket')
TOKEN_RPAREN = intern('rparen')
TOKEN_SEMICOLON = intern('semicolon')
TOKEN_SUB = intern('sub')
TOKEN_TILDE = intern('tilde')
TOKEN_WHITESPACE = intern('whitespace')
TOKEN_FLOAT = intern('float')
TOKEN_INTEGER = intern('integer')
TOKEN_NAME = intern('name')
TOKEN_STRING = intern('string')
TOKEN_OPERATOR = intern('operator')
TOKEN_BLOCK_BEGIN = intern('block_begin')
TOKEN_BLOCK_END = intern('block_end')
TOKEN_VARIABLE_BEGIN = intern('variable_begin')
TOKEN_VARIABLE_END = intern('variable_end')
TOKEN_RAW_BEGIN = intern('raw_begin')
TOKEN_RAW_END = intern('raw_end')
TOKEN_COMMENT_BEGIN = intern('comment_begin')
TOKEN_COMMENT_END = intern('comment_end')
TOKEN_COMMENT = intern('comment')
TOKEN_LINESTATEMENT_BEGIN = intern('linestatement_begin')
TOKEN_LINESTATEMENT_END = intern('linestatement_end')
TOKEN_LINECOMMENT_BEGIN = intern('linecomment_begin')
TOKEN_LINECOMMENT_END = intern('linecomment_end')
TOKEN_LINECOMMENT = intern('linecomment')
TOKEN_DATA = intern('data')
TOKEN_INITIAL = intern('initial')
TOKEN_EOF = intern('eof')
# bind operators to token types
operators = {
'+': TOKEN_ADD,
'-': TOKEN_SUB,
'/': TOKEN_DIV,
'//': TOKEN_FLOORDIV,
'*': TOKEN_MUL,
'%': TOKEN_MOD,
'**': TOKEN_POW,
'~': TOKEN_TILDE,
'[': TOKEN_LBRACKET,
']': TOKEN_RBRACKET,
'(': TOKEN_LPAREN,
')': TOKEN_RPAREN,
'{': TOKEN_LBRACE,
'}': TOKEN_RBRACE,
'==': TOKEN_EQ,
'!=': TOKEN_NE,
'>': TOKEN_GT,
'>=': TOKEN_GTEQ,
'<': TOKEN_LT,
'<=': TOKEN_LTEQ,
'=': TOKEN_ASSIGN,
'.': TOKEN_DOT,
':': TOKEN_COLON,
'|': TOKEN_PIPE,
',': TOKEN_COMMA,
';': TOKEN_SEMICOLON
}
reverse_operators = dict([(v, k) for k, v in iteritems(operators)])
assert len(operators) == len(reverse_operators), 'operators dropped'
operator_re = re.compile('(%s)' % '|'.join(re.escape(x) for x in
sorted(operators, key=lambda x: -len(x))))
ignored_tokens = frozenset([TOKEN_COMMENT_BEGIN, TOKEN_COMMENT,
TOKEN_COMMENT_END, TOKEN_WHITESPACE,
TOKEN_WHITESPACE, TOKEN_LINECOMMENT_BEGIN,
TOKEN_LINECOMMENT_END, TOKEN_LINECOMMENT])
ignore_if_empty = frozenset([TOKEN_WHITESPACE, TOKEN_DATA,
TOKEN_COMMENT, TOKEN_LINECOMMENT])
def _describe_token_type(token_type):
if token_type in reverse_operators:
return reverse_operators[token_type]
return {
TOKEN_COMMENT_BEGIN: 'begin of comment',
TOKEN_COMMENT_END: 'end of comment',
TOKEN_COMMENT: 'comment',
TOKEN_LINECOMMENT: 'comment',
TOKEN_BLOCK_BEGIN: 'begin of statement block',
TOKEN_BLOCK_END: 'end of statement block',
TOKEN_VARIABLE_BEGIN: 'begin of print statement',
TOKEN_VARIABLE_END: 'end of print statement',
TOKEN_LINESTATEMENT_BEGIN: 'begin of line statement',
TOKEN_LINESTATEMENT_END: 'end of line statement',
TOKEN_DATA: 'template data / text',
TOKEN_EOF: 'end of template'
}.get(token_type, token_type)
def describe_token(token):
"""Returns a description of the token."""
if token.type == 'name':
return token.value
return _describe_token_type(token.type)
def describe_token_expr(expr):
"""Like `describe_token` but for token expressions."""
if ':' in expr:
type, value = expr.split(':', 1)
if type == 'name':
return value
else:
type = expr
return _describe_token_type(type)
def count_newlines(value):
"""Count the number of newline characters in the string. This is
useful for extensions that filter a stream.
"""
return len(newline_re.findall(value))
def compile_rules(environment):
"""Compiles all the rules from the environment into a list of rules."""
e = re.escape
rules = [
(len(environment.comment_start_string), 'comment',
e(environment.comment_start_string)),
(len(environment.block_start_string), 'block',
e(environment.block_start_string)),
(len(environment.variable_start_string), 'variable',
e(environment.variable_start_string))
]
if environment.line_statement_prefix is not None:
rules.append((len(environment.line_statement_prefix), 'linestatement',
r'^[ \t\v]*' + e(environment.line_statement_prefix)))
if environment.line_comment_prefix is not None:
rules.append((len(environment.line_comment_prefix), 'linecomment',
r'(?:^|(?<=\S))[^\S\r\n]*' +
e(environment.line_comment_prefix)))
return [x[1:] for x in sorted(rules, reverse=True)]
class Failure(object):
"""Class that raises a `TemplateSyntaxError` if called.
Used by the `Lexer` to specify known errors.
"""
def __init__(self, message, cls=TemplateSyntaxError):
self.message = message
self.error_class = cls
def __call__(self, lineno, filename):
raise self.error_class(self.message, lineno, filename)
class Token(tuple):
"""Token class."""
__slots__ = ()
lineno, type, value = (property(itemgetter(x)) for x in range(3))
def __new__(cls, lineno, type, value):
return tuple.__new__(cls, (lineno, intern(str(type)), value))
def __str__(self):
if self.type in reverse_operators:
return reverse_operators[self.type]
elif self.type == 'name':
return self.value
return self.type
def test(self, expr):
"""Test a token against a token expression. This can either be a
token type or ``'token_type:token_value'``. This can only test
against string values and types.
"""
# here we do a regular string equality check as test_any is usually
# passed an iterable of not interned strings.
if self.type == expr:
return True
elif ':' in expr:
return expr.split(':', 1) == [self.type, self.value]
return False
def test_any(self, *iterable):
"""Test against multiple token expressions."""
for expr in iterable:
if self.test(expr):
return True
return False
def __repr__(self):
return 'Token(%r, %r, %r)' % (
self.lineno,
self.type,
self.value
)
@implements_iterator
class TokenStreamIterator(object):
"""The iterator for tokenstreams. Iterate over the stream
until the eof token is reached.
"""
def __init__(self, stream):
self.stream = stream
def __iter__(self):
return self
def __next__(self):
token = self.stream.current
if token.type is TOKEN_EOF:
self.stream.close()
raise StopIteration()
next(self.stream)
return token
@implements_iterator
class TokenStream(object):
"""A token stream is an iterable that yields :class:`Token`\s. The
parser however does not iterate over it but calls :meth:`next` to go
one token ahead. The current active token is stored as :attr:`current`.
"""
def __init__(self, generator, name, filename):
self._iter = iter(generator)
self._pushed = deque()
self.name = name
self.filename = filename
self.closed = False
self.current = Token(1, TOKEN_INITIAL, '')
next(self)
def __iter__(self):
return TokenStreamIterator(self)
def __bool__(self):
return bool(self._pushed) or self.current.type is not TOKEN_EOF
__nonzero__ = __bool__ # py2
eos = property(lambda x: not x, doc="Are we at the end of the stream?")
def push(self, token):
"""Push a token back to the stream."""
self._pushed.append(token)
def look(self):
"""Look at the next token."""
old_token = next(self)
result = self.current
self.push(result)
self.current = old_token
return result
def skip(self, n=1):
"""Got n tokens ahead."""
for x in range(n):
next(self)
def next_if(self, expr):
"""Perform the token test and return the token if it matched.
Otherwise the return value is `None`.
"""
if self.current.test(expr):
return next(self)
def skip_if(self, expr):
"""Like :meth:`next_if` but only returns `True` or `False`."""
return self.next_if(expr) is not None
def __next__(self):
"""Go one token ahead and return the old one"""
rv = self.current
if self._pushed:
self.current = self._pushed.popleft()
elif self.current.type is not TOKEN_EOF:
try:
self.current = next(self._iter)
except StopIteration:
self.close()
return rv
def close(self):
"""Close the stream."""
self.current = Token(self.current.lineno, TOKEN_EOF, '')
self._iter = None
self.closed = True
def expect(self, expr):
"""Expect a given token type and return it. This accepts the same
argument as :meth:`jinja2.lexer.Token.test`.
"""
if not self.current.test(expr):
expr = describe_token_expr(expr)
if self.current.type is TOKEN_EOF:
raise TemplateSyntaxError('unexpected end of template, '
'expected %r.' % expr,
self.current.lineno,
self.name, self.filename)
raise TemplateSyntaxError("expected token %r, got %r" %
(expr, describe_token(self.current)),
self.current.lineno,
self.name, self.filename)
try:
return self.current
finally:
next(self)
def get_lexer(environment):
"""Return a lexer which is probably cached."""
key = (environment.block_start_string,
environment.block_end_string,
environment.variable_start_string,
environment.variable_end_string,
environment.comment_start_string,
environment.comment_end_string,
environment.line_statement_prefix,
environment.line_comment_prefix,
environment.trim_blocks,
environment.lstrip_blocks,
environment.newline_sequence,
environment.keep_trailing_newline)
lexer = _lexer_cache.get(key)
if lexer is None:
lexer = Lexer(environment)
_lexer_cache[key] = lexer
return lexer
class Lexer(object):
"""Class that implements a lexer for a given environment. Automatically
created by the environment class, usually you don't have to do that.
Note that the lexer is not automatically bound to an environment.
Multiple environments can share the same lexer.
"""
def __init__(self, environment):
# shortcuts
c = lambda x: re.compile(x, re.M | re.S)
e = re.escape
# lexing rules for tags
tag_rules = [
(whitespace_re, TOKEN_WHITESPACE, None),
(float_re, TOKEN_FLOAT, None),
(integer_re, TOKEN_INTEGER, None),
(name_re, TOKEN_NAME, None),
(string_re, TOKEN_STRING, None),
(operator_re, TOKEN_OPERATOR, None)
]
# assemble the root lexing rule. because "|" is ungreedy
# we have to sort by length so that the lexer continues working
# as expected when we have parsing rules like <% for block and
# <%= for variables. (if someone wants asp like syntax)
# variables are just part of the rules if variable processing
# is required.
root_tag_rules = compile_rules(environment)
# block suffix if trimming is enabled
block_suffix_re = environment.trim_blocks and '\\n?' or ''
# strip leading spaces if lstrip_blocks is enabled
prefix_re = {}
if environment.lstrip_blocks:
# use '{%+' to manually disable lstrip_blocks behavior
no_lstrip_re = e('+')
# detect overlap between block and variable or comment strings
block_diff = c(r'^%s(.*)' % e(environment.block_start_string))
# make sure we don't mistake a block for a variable or a comment
m = block_diff.match(environment.comment_start_string)
no_lstrip_re += m and r'|%s' % e(m.group(1)) or ''
m = block_diff.match(environment.variable_start_string)
no_lstrip_re += m and r'|%s' % e(m.group(1)) or ''
# detect overlap between comment and variable strings
comment_diff = c(r'^%s(.*)' % e(environment.comment_start_string))
m = comment_diff.match(environment.variable_start_string)
no_variable_re = m and r'(?!%s)' % e(m.group(1)) or ''
lstrip_re = r'^[ \t]*'
block_prefix_re = r'%s%s(?!%s)|%s\+?' % (
lstrip_re,
e(environment.block_start_string),
no_lstrip_re,
e(environment.block_start_string),
)
comment_prefix_re = r'%s%s%s|%s\+?' % (
lstrip_re,
e(environment.comment_start_string),
no_variable_re,
e(environment.comment_start_string),
)
prefix_re['block'] = block_prefix_re
prefix_re['comment'] = comment_prefix_re
else:
block_prefix_re = '%s' % e(environment.block_start_string)
self.newline_sequence = environment.newline_sequence
self.keep_trailing_newline = environment.keep_trailing_newline
# global lexing rules
self.rules = {
'root': [
# directives
(c('(.*?)(?:%s)' % '|'.join(
[r'(?P<raw_begin>(?:\s*%s\-|%s)\s*raw\s*(?:\-%s\s*|%s))' % (
e(environment.block_start_string),
block_prefix_re,
e(environment.block_end_string),
e(environment.block_end_string)
)] + [
r'(?P<%s_begin>\s*%s\-|%s)' % (n, r, prefix_re.get(n,r))
for n, r in root_tag_rules
])), (TOKEN_DATA, '#bygroup'), '#bygroup'),
# data
(c('.+'), TOKEN_DATA, None)
],
# comments
TOKEN_COMMENT_BEGIN: [
(c(r'(.*?)((?:\-%s\s*|%s)%s)' % (
e(environment.comment_end_string),
e(environment.comment_end_string),
block_suffix_re
)), (TOKEN_COMMENT, TOKEN_COMMENT_END), '#pop'),
(c('(.)'), (Failure('Missing end of comment tag'),), None)
],
# blocks
TOKEN_BLOCK_BEGIN: [
(c('(?:\-%s\s*|%s)%s' % (
e(environment.block_end_string),
e(environment.block_end_string),
block_suffix_re
)), TOKEN_BLOCK_END, '#pop'),
] + tag_rules,
# variables
TOKEN_VARIABLE_BEGIN: [
(c('\-%s\s*|%s' % (
e(environment.variable_end_string),
e(environment.variable_end_string)
)), TOKEN_VARIABLE_END, '#pop')
] + tag_rules,
# raw block
TOKEN_RAW_BEGIN: [
(c('(.*?)((?:\s*%s\-|%s)\s*endraw\s*(?:\-%s\s*|%s%s))' % (
e(environment.block_start_string),
block_prefix_re,
e(environment.block_end_string),
e(environment.block_end_string),
block_suffix_re
)), (TOKEN_DATA, TOKEN_RAW_END), '#pop'),
(c('(.)'), (Failure('Missing end of raw directive'),), None)
],
# line statements
TOKEN_LINESTATEMENT_BEGIN: [
(c(r'\s*(\n|$)'), TOKEN_LINESTATEMENT_END, '#pop')
] + tag_rules,
# line comments
TOKEN_LINECOMMENT_BEGIN: [
(c(r'(.*?)()(?=\n|$)'), (TOKEN_LINECOMMENT,
TOKEN_LINECOMMENT_END), '#pop')
]
}
def _normalize_newlines(self, value):
"""Called for strings and template data to normalize it to unicode."""
return newline_re.sub(self.newline_sequence, value)
def tokenize(self, source, name=None, filename=None, state=None):
"""Calls tokeniter + tokenize and wraps it in a token stream.
"""
stream = self.tokeniter(source, name, filename, state)
return TokenStream(self.wrap(stream, name, filename), name, filename)
def wrap(self, stream, name=None, filename=None):
"""This is called with the stream as returned by `tokenize` and wraps
every token in a :class:`Token` and converts the value.
"""
for lineno, token, value in stream:
if token in ignored_tokens:
continue
elif token == 'linestatement_begin':
token = 'block_begin'
elif token == 'linestatement_end':
token = 'block_end'
# we are not interested in those tokens in the parser
elif token in ('raw_begin', 'raw_end'):
continue
elif token == 'data':
value = self._normalize_newlines(value)
elif token == 'keyword':
token = value
elif token == 'name':
value = str(value)
elif token == 'string':
# try to unescape string
try:
value = self._normalize_newlines(value[1:-1]) \
.encode('ascii', 'backslashreplace') \
.decode('unicode-escape')
except Exception as e:
msg = str(e).split(':')[-1].strip()
raise TemplateSyntaxError(msg, lineno, name, filename)
# if we can express it as bytestring (ascii only)
# we do that for support of semi broken APIs
# as datetime.datetime.strftime. On python 3 this
# call becomes a noop thanks to 2to3
try:
value = str(value)
except UnicodeError:
pass
elif token == 'integer':
value = int(value)
elif token == 'float':
value = float(value)
elif token == 'operator':
token = operators[value]
yield Token(lineno, token, value)
def tokeniter(self, source, name, filename=None, state=None):
"""This method tokenizes the text and returns the tokens in a
generator. Use this method if you just want to tokenize a template.
"""
source = text_type(source)
lines = source.splitlines()
if self.keep_trailing_newline and source:
for newline in ('\r\n', '\r', '\n'):
if source.endswith(newline):
lines.append('')
break
source = '\n'.join(lines)
pos = 0
lineno = 1
stack = ['root']
if state is not None and state != 'root':
assert state in ('variable', 'block'), 'invalid state'
stack.append(state + '_begin')
else:
state = 'root'
statetokens = self.rules[stack[-1]]
source_length = len(source)
balancing_stack = []
while 1:
# tokenizer loop
for regex, tokens, new_state in statetokens:
m = regex.match(source, pos)
# if no match we try again with the next rule
if m is None:
continue
# we only match blocks and variables if braces / parentheses
# are balanced. continue parsing with the lower rule which
# is the operator rule. do this only if the end tags look
# like operators
if balancing_stack and \
tokens in ('variable_end', 'block_end',
'linestatement_end'):
continue
# tuples support more options
if isinstance(tokens, tuple):
for idx, token in enumerate(tokens):
# failure group
if token.__class__ is Failure:
raise token(lineno, filename)
# bygroup is a bit more complex, in that case we
# yield for the current token the first named
# group that matched
elif token == '#bygroup':
for key, value in iteritems(m.groupdict()):
if value is not None:
yield lineno, key, value
lineno += value.count('\n')
break
else:
raise RuntimeError('%r wanted to resolve '
'the token dynamically'
' but no group matched'
% regex)
# normal group
else:
data = m.group(idx + 1)
if data or token not in ignore_if_empty:
yield lineno, token, data
lineno += data.count('\n')
# strings as token just are yielded as it.
else:
data = m.group()
# update brace/parentheses balance
if tokens == 'operator':
if data == '{':
balancing_stack.append('}')
elif data == '(':
balancing_stack.append(')')
elif data == '[':
balancing_stack.append(']')
elif data in ('}', ')', ']'):
if not balancing_stack:
raise TemplateSyntaxError('unexpected \'%s\'' %
data, lineno, name,
filename)
expected_op = balancing_stack.pop()
if expected_op != data:
raise TemplateSyntaxError('unexpected \'%s\', '
'expected \'%s\'' %
(data, expected_op),
lineno, name,
filename)
# yield items
if data or tokens not in ignore_if_empty:
yield lineno, tokens, data
lineno += data.count('\n')
# fetch new position into new variable so that we can check
# if there is a internal parsing error which would result
# in an infinite loop
pos2 = m.end()
# handle state changes
if new_state is not None:
# remove the uppermost state
if new_state == '#pop':
stack.pop()
# resolve the new state by group checking
elif new_state == '#bygroup':
for key, value in iteritems(m.groupdict()):
if value is not None:
stack.append(key)
break
else:
raise RuntimeError('%r wanted to resolve the '
'new state dynamically but'
' no group matched' %
regex)
# direct state name given
else:
stack.append(new_state)
statetokens = self.rules[stack[-1]]
# we are still at the same position and no stack change.
# this means a loop without break condition, avoid that and
# raise error
elif pos2 == pos:
raise RuntimeError('%r yielded empty string without '
'stack change' % regex)
# publish new function and start again
pos = pos2
break
# if loop terminated without break we haven't found a single match
# either we are at the end of the file or we have a problem
else:
# end of text
if pos >= source_length:
return
# something went wrong
raise TemplateSyntaxError('unexpected char %r at %d' %
(source[pos], pos), lineno,
name, filename)
-471
View File
@@ -1,471 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.loaders
~~~~~~~~~~~~~~
Jinja loader classes.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
import os
import sys
import weakref
from types import ModuleType
from os import path
from hashlib import sha1
from jinja2.exceptions import TemplateNotFound
from jinja2.utils import open_if_exists, internalcode
from jinja2._compat import string_types, iteritems
def split_template_path(template):
"""Split a path into segments and perform a sanity check. If it detects
'..' in the path it will raise a `TemplateNotFound` error.
"""
pieces = []
for piece in template.split('/'):
if path.sep in piece \
or (path.altsep and path.altsep in piece) or \
piece == path.pardir:
raise TemplateNotFound(template)
elif piece and piece != '.':
pieces.append(piece)
return pieces
class BaseLoader(object):
"""Baseclass for all loaders. Subclass this and override `get_source` to
implement a custom loading mechanism. The environment provides a
`get_template` method that calls the loader's `load` method to get the
:class:`Template` object.
A very basic example for a loader that looks up templates on the file
system could look like this::
from jinja2 import BaseLoader, TemplateNotFound
from os.path import join, exists, getmtime
class MyLoader(BaseLoader):
def __init__(self, path):
self.path = path
def get_source(self, environment, template):
path = join(self.path, template)
if not exists(path):
raise TemplateNotFound(template)
mtime = getmtime(path)
with file(path) as f:
source = f.read().decode('utf-8')
return source, path, lambda: mtime == getmtime(path)
"""
#: if set to `False` it indicates that the loader cannot provide access
#: to the source of templates.
#:
#: .. versionadded:: 2.4
has_source_access = True
def get_source(self, environment, template):
"""Get the template source, filename and reload helper for a template.
It's passed the environment and template name and has to return a
tuple in the form ``(source, filename, uptodate)`` or raise a
`TemplateNotFound` error if it can't locate the template.
The source part of the returned tuple must be the source of the
template as unicode string or a ASCII bytestring. The filename should
be the name of the file on the filesystem if it was loaded from there,
otherwise `None`. The filename is used by python for the tracebacks
if no loader extension is used.
The last item in the tuple is the `uptodate` function. If auto
reloading is enabled it's always called to check if the template
changed. No arguments are passed so the function must store the
old state somewhere (for example in a closure). If it returns `False`
the template will be reloaded.
"""
if not self.has_source_access:
raise RuntimeError('%s cannot provide access to the source' %
self.__class__.__name__)
raise TemplateNotFound(template)
def list_templates(self):
"""Iterates over all templates. If the loader does not support that
it should raise a :exc:`TypeError` which is the default behavior.
"""
raise TypeError('this loader cannot iterate over all templates')
@internalcode
def load(self, environment, name, globals=None):
"""Loads a template. This method looks up the template in the cache
or loads one by calling :meth:`get_source`. Subclasses should not
override this method as loaders working on collections of other
loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`)
will not call this method but `get_source` directly.
"""
code = None
if globals is None:
globals = {}
# first we try to get the source for this template together
# with the filename and the uptodate function.
source, filename, uptodate = self.get_source(environment, name)
# try to load the code from the bytecode cache if there is a
# bytecode cache configured.
bcc = environment.bytecode_cache
if bcc is not None:
bucket = bcc.get_bucket(environment, name, filename, source)
code = bucket.code
# if we don't have code so far (not cached, no longer up to
# date) etc. we compile the template
if code is None:
code = environment.compile(source, name, filename)
# if the bytecode cache is available and the bucket doesn't
# have a code so far, we give the bucket the new code and put
# it back to the bytecode cache.
if bcc is not None and bucket.code is None:
bucket.code = code
bcc.set_bucket(bucket)
return environment.template_class.from_code(environment, code,
globals, uptodate)
class FileSystemLoader(BaseLoader):
"""Loads templates from the file system. This loader can find templates
in folders on the file system and is the preferred way to load them.
The loader takes the path to the templates as string, or if multiple
locations are wanted a list of them which is then looked up in the
given order:
>>> loader = FileSystemLoader('/path/to/templates')
>>> loader = FileSystemLoader(['/path/to/templates', '/other/path'])
Per default the template encoding is ``'utf-8'`` which can be changed
by setting the `encoding` parameter to something else.
"""
def __init__(self, searchpath, encoding='utf-8'):
if isinstance(searchpath, string_types):
searchpath = [searchpath]
self.searchpath = list(searchpath)
self.encoding = encoding
def get_source(self, environment, template):
pieces = split_template_path(template)
for searchpath in self.searchpath:
filename = path.join(searchpath, *pieces)
f = open_if_exists(filename)
if f is None:
continue
try:
contents = f.read().decode(self.encoding)
finally:
f.close()
mtime = path.getmtime(filename)
def uptodate():
try:
return path.getmtime(filename) == mtime
except OSError:
return False
return contents, filename, uptodate
raise TemplateNotFound(template)
def list_templates(self):
found = set()
for searchpath in self.searchpath:
for dirpath, dirnames, filenames in os.walk(searchpath):
for filename in filenames:
template = os.path.join(dirpath, filename) \
[len(searchpath):].strip(os.path.sep) \
.replace(os.path.sep, '/')
if template[:2] == './':
template = template[2:]
if template not in found:
found.add(template)
return sorted(found)
class PackageLoader(BaseLoader):
"""Load templates from python eggs or packages. It is constructed with
the name of the python package and the path to the templates in that
package::
loader = PackageLoader('mypackage', 'views')
If the package path is not given, ``'templates'`` is assumed.
Per default the template encoding is ``'utf-8'`` which can be changed
by setting the `encoding` parameter to something else. Due to the nature
of eggs it's only possible to reload templates if the package was loaded
from the file system and not a zip file.
"""
def __init__(self, package_name, package_path='templates',
encoding='utf-8'):
from pkg_resources import DefaultProvider, ResourceManager, \
get_provider
provider = get_provider(package_name)
self.encoding = encoding
self.manager = ResourceManager()
self.filesystem_bound = isinstance(provider, DefaultProvider)
self.provider = provider
self.package_path = package_path
def get_source(self, environment, template):
pieces = split_template_path(template)
p = '/'.join((self.package_path,) + tuple(pieces))
if not self.provider.has_resource(p):
raise TemplateNotFound(template)
filename = uptodate = None
if self.filesystem_bound:
filename = self.provider.get_resource_filename(self.manager, p)
mtime = path.getmtime(filename)
def uptodate():
try:
return path.getmtime(filename) == mtime
except OSError:
return False
source = self.provider.get_resource_string(self.manager, p)
return source.decode(self.encoding), filename, uptodate
def list_templates(self):
path = self.package_path
if path[:2] == './':
path = path[2:]
elif path == '.':
path = ''
offset = len(path)
results = []
def _walk(path):
for filename in self.provider.resource_listdir(path):
fullname = path + '/' + filename
if self.provider.resource_isdir(fullname):
_walk(fullname)
else:
results.append(fullname[offset:].lstrip('/'))
_walk(path)
results.sort()
return results
class DictLoader(BaseLoader):
"""Loads a template from a python dict. It's passed a dict of unicode
strings bound to template names. This loader is useful for unittesting:
>>> loader = DictLoader({'index.html': 'source here'})
Because auto reloading is rarely useful this is disabled per default.
"""
def __init__(self, mapping):
self.mapping = mapping
def get_source(self, environment, template):
if template in self.mapping:
source = self.mapping[template]
return source, None, lambda: source == self.mapping.get(template)
raise TemplateNotFound(template)
def list_templates(self):
return sorted(self.mapping)
class FunctionLoader(BaseLoader):
"""A loader that is passed a function which does the loading. The
function becomes the name of the template passed and has to return either
an unicode string with the template source, a tuple in the form ``(source,
filename, uptodatefunc)`` or `None` if the template does not exist.
>>> def load_template(name):
... if name == 'index.html':
... return '...'
...
>>> loader = FunctionLoader(load_template)
The `uptodatefunc` is a function that is called if autoreload is enabled
and has to return `True` if the template is still up to date. For more
details have a look at :meth:`BaseLoader.get_source` which has the same
return value.
"""
def __init__(self, load_func):
self.load_func = load_func
def get_source(self, environment, template):
rv = self.load_func(template)
if rv is None:
raise TemplateNotFound(template)
elif isinstance(rv, string_types):
return rv, None, None
return rv
class PrefixLoader(BaseLoader):
"""A loader that is passed a dict of loaders where each loader is bound
to a prefix. The prefix is delimited from the template by a slash per
default, which can be changed by setting the `delimiter` argument to
something else::
loader = PrefixLoader({
'app1': PackageLoader('mypackage.app1'),
'app2': PackageLoader('mypackage.app2')
})
By loading ``'app1/index.html'`` the file from the app1 package is loaded,
by loading ``'app2/index.html'`` the file from the second.
"""
def __init__(self, mapping, delimiter='/'):
self.mapping = mapping
self.delimiter = delimiter
def get_loader(self, template):
try:
prefix, name = template.split(self.delimiter, 1)
loader = self.mapping[prefix]
except (ValueError, KeyError):
raise TemplateNotFound(template)
return loader, name
def get_source(self, environment, template):
loader, name = self.get_loader(template)
try:
return loader.get_source(environment, name)
except TemplateNotFound:
# re-raise the exception with the correct fileame here.
# (the one that includes the prefix)
raise TemplateNotFound(template)
@internalcode
def load(self, environment, name, globals=None):
loader, local_name = self.get_loader(name)
try:
return loader.load(environment, local_name)
except TemplateNotFound:
# re-raise the exception with the correct fileame here.
# (the one that includes the prefix)
raise TemplateNotFound(name)
def list_templates(self):
result = []
for prefix, loader in iteritems(self.mapping):
for template in loader.list_templates():
result.append(prefix + self.delimiter + template)
return result
class ChoiceLoader(BaseLoader):
"""This loader works like the `PrefixLoader` just that no prefix is
specified. If a template could not be found by one loader the next one
is tried.
>>> loader = ChoiceLoader([
... FileSystemLoader('/path/to/user/templates'),
... FileSystemLoader('/path/to/system/templates')
... ])
This is useful if you want to allow users to override builtin templates
from a different location.
"""
def __init__(self, loaders):
self.loaders = loaders
def get_source(self, environment, template):
for loader in self.loaders:
try:
return loader.get_source(environment, template)
except TemplateNotFound:
pass
raise TemplateNotFound(template)
@internalcode
def load(self, environment, name, globals=None):
for loader in self.loaders:
try:
return loader.load(environment, name, globals)
except TemplateNotFound:
pass
raise TemplateNotFound(name)
def list_templates(self):
found = set()
for loader in self.loaders:
found.update(loader.list_templates())
return sorted(found)
class _TemplateModule(ModuleType):
"""Like a normal module but with support for weak references"""
class ModuleLoader(BaseLoader):
"""This loader loads templates from precompiled templates.
Example usage:
>>> loader = ChoiceLoader([
... ModuleLoader('/path/to/compiled/templates'),
... FileSystemLoader('/path/to/templates')
... ])
Templates can be precompiled with :meth:`Environment.compile_templates`.
"""
has_source_access = False
def __init__(self, path):
package_name = '_jinja2_module_templates_%x' % id(self)
# create a fake module that looks for the templates in the
# path given.
mod = _TemplateModule(package_name)
if isinstance(path, string_types):
path = [path]
else:
path = list(path)
mod.__path__ = path
sys.modules[package_name] = weakref.proxy(mod,
lambda x: sys.modules.pop(package_name, None))
# the only strong reference, the sys.modules entry is weak
# so that the garbage collector can remove it once the
# loader that created it goes out of business.
self.module = mod
self.package_name = package_name
@staticmethod
def get_template_key(name):
return 'tmpl_' + sha1(name.encode('utf-8')).hexdigest()
@staticmethod
def get_module_filename(name):
return ModuleLoader.get_template_key(name) + '.py'
@internalcode
def load(self, environment, name, globals=None):
key = self.get_template_key(name)
module = '%s.%s' % (self.package_name, key)
mod = getattr(self.module, module, None)
if mod is None:
try:
mod = __import__(module, None, None, ['root'])
except ImportError:
raise TemplateNotFound(name)
# remove the entry from sys.modules, we only want the attribute
# on the module object we have stored on the loader.
sys.modules.pop(module, None)
return environment.template_class.from_module_dict(
environment, mod.__dict__, globals)
-234
View File
@@ -1,234 +0,0 @@
# -*- coding: utf-8 -*-
"""
markupsafe
~~~~~~~~~~
Implements a Markup string.
:copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import re
from ._compat import text_type, string_types, int_types, \
unichr, PY2
__all__ = ['Markup', 'soft_unicode', 'escape', 'escape_silent']
_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
_entity_re = re.compile(r'&([^;]+);')
class Markup(text_type):
r"""Marks a string as being safe for inclusion in HTML/XML output without
needing to be escaped. This implements the `__html__` interface a couple
of frameworks and web applications use. :class:`Markup` is a direct
subclass of `unicode` and provides all the methods of `unicode` just that
it escapes arguments passed and always returns `Markup`.
The `escape` function returns markup objects so that double escaping can't
happen.
The constructor of the :class:`Markup` class can be used for three
different things: When passed an unicode object it's assumed to be safe,
when passed an object with an HTML representation (has an `__html__`
method) that representation is used, otherwise the object passed is
converted into a unicode string and then assumed to be safe:
>>> Markup("Hello <em>World</em>!")
Markup(u'Hello <em>World</em>!')
>>> class Foo(object):
... def __html__(self):
... return '<a href="#">foo</a>'
...
>>> Markup(Foo())
Markup(u'<a href="#">foo</a>')
If you want object passed being always treated as unsafe you can use the
:meth:`escape` classmethod to create a :class:`Markup` object:
>>> Markup.escape("Hello <em>World</em>!")
Markup(u'Hello &lt;em&gt;World&lt;/em&gt;!')
Operations on a markup string are markup aware which means that all
arguments are passed through the :func:`escape` function:
>>> em = Markup("<em>%s</em>")
>>> em % "foo & bar"
Markup(u'<em>foo &amp; bar</em>')
>>> strong = Markup("<strong>%(text)s</strong>")
>>> strong % {'text': '<blink>hacker here</blink>'}
Markup(u'<strong>&lt;blink&gt;hacker here&lt;/blink&gt;</strong>')
>>> Markup("<em>Hello</em> ") + "<foo>"
Markup(u'<em>Hello</em> &lt;foo&gt;')
"""
__slots__ = ()
def __new__(cls, base=u'', encoding=None, errors='strict'):
if hasattr(base, '__html__'):
base = base.__html__()
if encoding is None:
return text_type.__new__(cls, base)
return text_type.__new__(cls, base, encoding, errors)
def __html__(self):
return self
def __add__(self, other):
if isinstance(other, string_types) or hasattr(other, '__html__'):
return self.__class__(super(Markup, self).__add__(self.escape(other)))
return NotImplemented
def __radd__(self, other):
if hasattr(other, '__html__') or isinstance(other, string_types):
return self.escape(other).__add__(self)
return NotImplemented
def __mul__(self, num):
if isinstance(num, int_types):
return self.__class__(text_type.__mul__(self, num))
return NotImplemented
__rmul__ = __mul__
def __mod__(self, arg):
if isinstance(arg, tuple):
arg = tuple(_MarkupEscapeHelper(x, self.escape) for x in arg)
else:
arg = _MarkupEscapeHelper(arg, self.escape)
return self.__class__(text_type.__mod__(self, arg))
def __repr__(self):
return '%s(%s)' % (
self.__class__.__name__,
text_type.__repr__(self)
)
def join(self, seq):
return self.__class__(text_type.join(self, map(self.escape, seq)))
join.__doc__ = text_type.join.__doc__
def split(self, *args, **kwargs):
return list(map(self.__class__, text_type.split(self, *args, **kwargs)))
split.__doc__ = text_type.split.__doc__
def rsplit(self, *args, **kwargs):
return list(map(self.__class__, text_type.rsplit(self, *args, **kwargs)))
rsplit.__doc__ = text_type.rsplit.__doc__
def splitlines(self, *args, **kwargs):
return list(map(self.__class__, text_type.splitlines(self, *args, **kwargs)))
splitlines.__doc__ = text_type.splitlines.__doc__
def unescape(self):
r"""Unescape markup again into an text_type string. This also resolves
known HTML4 and XHTML entities:
>>> Markup("Main &raquo; <em>About</em>").unescape()
u'Main \xbb <em>About</em>'
"""
from _constants import HTML_ENTITIES
def handle_match(m):
name = m.group(1)
if name in HTML_ENTITIES:
return unichr(HTML_ENTITIES[name])
try:
if name[:2] in ('#x', '#X'):
return unichr(int(name[2:], 16))
elif name.startswith('#'):
return unichr(int(name[1:]))
except ValueError:
pass
return u''
return _entity_re.sub(handle_match, text_type(self))
def striptags(self):
r"""Unescape markup into an text_type string and strip all tags. This
also resolves known HTML4 and XHTML entities. Whitespace is
normalized to one:
>>> Markup("Main &raquo; <em>About</em>").striptags()
u'Main \xbb About'
"""
stripped = u' '.join(_striptags_re.sub('', self).split())
return Markup(stripped).unescape()
@classmethod
def escape(cls, s):
"""Escape the string. Works like :func:`escape` with the difference
that for subclasses of :class:`Markup` this function would return the
correct subclass.
"""
rv = escape(s)
if rv.__class__ is not cls:
return cls(rv)
return rv
def make_wrapper(name):
orig = getattr(text_type, name)
def func(self, *args, **kwargs):
args = _escape_argspec(list(args), enumerate(args), self.escape)
#_escape_argspec(kwargs, kwargs.iteritems(), None)
return self.__class__(orig(self, *args, **kwargs))
func.__name__ = orig.__name__
func.__doc__ = orig.__doc__
return func
for method in '__getitem__', 'capitalize', \
'title', 'lower', 'upper', 'replace', 'ljust', \
'rjust', 'lstrip', 'rstrip', 'center', 'strip', \
'translate', 'expandtabs', 'swapcase', 'zfill':
locals()[method] = make_wrapper(method)
# new in python 2.5
if hasattr(text_type, 'partition'):
def partition(self, sep):
return tuple(map(self.__class__,
text_type.partition(self, self.escape(sep))))
def rpartition(self, sep):
return tuple(map(self.__class__,
text_type.rpartition(self, self.escape(sep))))
# new in python 2.6
if hasattr(text_type, 'format'):
format = make_wrapper('format')
# not in python 3
if hasattr(text_type, '__getslice__'):
__getslice__ = make_wrapper('__getslice__')
del method, make_wrapper
def _escape_argspec(obj, iterable, escape):
"""Helper for various string-wrapped functions."""
for key, value in iterable:
if hasattr(value, '__html__') or isinstance(value, string_types):
obj[key] = escape(value)
return obj
class _MarkupEscapeHelper(object):
"""Helper for Markup.__mod__"""
def __init__(self, obj, escape):
self.obj = obj
self.escape = escape
__getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x], s.escape)
__unicode__ = __str__ = lambda s: text_type(s.escape(s.obj))
__repr__ = lambda s: str(s.escape(repr(s.obj)))
__int__ = lambda s: int(s.obj)
__float__ = lambda s: float(s.obj)
# we have to import it down here as the speedups and native
# modules imports the markup type which is define above.
try:
from _speedups import escape, escape_silent, soft_unicode
except ImportError:
from ._native import escape, escape_silent, soft_unicode
if not PY2:
soft_str = soft_unicode
__all__.append('soft_str')
-24
View File
@@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
"""
markupsafe._compat
~~~~~~~~~~~~~~~~~~
Compatibility module for different Python versions.
:copyright: (c) 2013 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import sys
PY2 = sys.version_info[0] == 2
if not PY2:
text_type = str
string_types = (str,)
unichr = chr
int_types = (int,)
else:
text_type = unicode
string_types = (str, unicode)
unichr = unichr
int_types = (int, long)
-267
View File
@@ -1,267 +0,0 @@
# -*- coding: utf-8 -*-
"""
markupsafe._constants
~~~~~~~~~~~~~~~~~~~~~
Highlevel implementation of the Markup string.
:copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
HTML_ENTITIES = {
'AElig': 198,
'Aacute': 193,
'Acirc': 194,
'Agrave': 192,
'Alpha': 913,
'Aring': 197,
'Atilde': 195,
'Auml': 196,
'Beta': 914,
'Ccedil': 199,
'Chi': 935,
'Dagger': 8225,
'Delta': 916,
'ETH': 208,
'Eacute': 201,
'Ecirc': 202,
'Egrave': 200,
'Epsilon': 917,
'Eta': 919,
'Euml': 203,
'Gamma': 915,
'Iacute': 205,
'Icirc': 206,
'Igrave': 204,
'Iota': 921,
'Iuml': 207,
'Kappa': 922,
'Lambda': 923,
'Mu': 924,
'Ntilde': 209,
'Nu': 925,
'OElig': 338,
'Oacute': 211,
'Ocirc': 212,
'Ograve': 210,
'Omega': 937,
'Omicron': 927,
'Oslash': 216,
'Otilde': 213,
'Ouml': 214,
'Phi': 934,
'Pi': 928,
'Prime': 8243,
'Psi': 936,
'Rho': 929,
'Scaron': 352,
'Sigma': 931,
'THORN': 222,
'Tau': 932,
'Theta': 920,
'Uacute': 218,
'Ucirc': 219,
'Ugrave': 217,
'Upsilon': 933,
'Uuml': 220,
'Xi': 926,
'Yacute': 221,
'Yuml': 376,
'Zeta': 918,
'aacute': 225,
'acirc': 226,
'acute': 180,
'aelig': 230,
'agrave': 224,
'alefsym': 8501,
'alpha': 945,
'amp': 38,
'and': 8743,
'ang': 8736,
'apos': 39,
'aring': 229,
'asymp': 8776,
'atilde': 227,
'auml': 228,
'bdquo': 8222,
'beta': 946,
'brvbar': 166,
'bull': 8226,
'cap': 8745,
'ccedil': 231,
'cedil': 184,
'cent': 162,
'chi': 967,
'circ': 710,
'clubs': 9827,
'cong': 8773,
'copy': 169,
'crarr': 8629,
'cup': 8746,
'curren': 164,
'dArr': 8659,
'dagger': 8224,
'darr': 8595,
'deg': 176,
'delta': 948,
'diams': 9830,
'divide': 247,
'eacute': 233,
'ecirc': 234,
'egrave': 232,
'empty': 8709,
'emsp': 8195,
'ensp': 8194,
'epsilon': 949,
'equiv': 8801,
'eta': 951,
'eth': 240,
'euml': 235,
'euro': 8364,
'exist': 8707,
'fnof': 402,
'forall': 8704,
'frac12': 189,
'frac14': 188,
'frac34': 190,
'frasl': 8260,
'gamma': 947,
'ge': 8805,
'gt': 62,
'hArr': 8660,
'harr': 8596,
'hearts': 9829,
'hellip': 8230,
'iacute': 237,
'icirc': 238,
'iexcl': 161,
'igrave': 236,
'image': 8465,
'infin': 8734,
'int': 8747,
'iota': 953,
'iquest': 191,
'isin': 8712,
'iuml': 239,
'kappa': 954,
'lArr': 8656,
'lambda': 955,
'lang': 9001,
'laquo': 171,
'larr': 8592,
'lceil': 8968,
'ldquo': 8220,
'le': 8804,
'lfloor': 8970,
'lowast': 8727,
'loz': 9674,
'lrm': 8206,
'lsaquo': 8249,
'lsquo': 8216,
'lt': 60,
'macr': 175,
'mdash': 8212,
'micro': 181,
'middot': 183,
'minus': 8722,
'mu': 956,
'nabla': 8711,
'nbsp': 160,
'ndash': 8211,
'ne': 8800,
'ni': 8715,
'not': 172,
'notin': 8713,
'nsub': 8836,
'ntilde': 241,
'nu': 957,
'oacute': 243,
'ocirc': 244,
'oelig': 339,
'ograve': 242,
'oline': 8254,
'omega': 969,
'omicron': 959,
'oplus': 8853,
'or': 8744,
'ordf': 170,
'ordm': 186,
'oslash': 248,
'otilde': 245,
'otimes': 8855,
'ouml': 246,
'para': 182,
'part': 8706,
'permil': 8240,
'perp': 8869,
'phi': 966,
'pi': 960,
'piv': 982,
'plusmn': 177,
'pound': 163,
'prime': 8242,
'prod': 8719,
'prop': 8733,
'psi': 968,
'quot': 34,
'rArr': 8658,
'radic': 8730,
'rang': 9002,
'raquo': 187,
'rarr': 8594,
'rceil': 8969,
'rdquo': 8221,
'real': 8476,
'reg': 174,
'rfloor': 8971,
'rho': 961,
'rlm': 8207,
'rsaquo': 8250,
'rsquo': 8217,
'sbquo': 8218,
'scaron': 353,
'sdot': 8901,
'sect': 167,
'shy': 173,
'sigma': 963,
'sigmaf': 962,
'sim': 8764,
'spades': 9824,
'sub': 8834,
'sube': 8838,
'sum': 8721,
'sup': 8835,
'sup1': 185,
'sup2': 178,
'sup3': 179,
'supe': 8839,
'szlig': 223,
'tau': 964,
'there4': 8756,
'theta': 952,
'thetasym': 977,
'thinsp': 8201,
'thorn': 254,
'tilde': 732,
'times': 215,
'trade': 8482,
'uArr': 8657,
'uacute': 250,
'uarr': 8593,
'ucirc': 251,
'ugrave': 249,
'uml': 168,
'upsih': 978,
'upsilon': 965,
'uuml': 252,
'weierp': 8472,
'xi': 958,
'yacute': 253,
'yen': 165,
'yuml': 255,
'zeta': 950,
'zwj': 8205,
'zwnj': 8204
}
-45
View File
@@ -1,45 +0,0 @@
# -*- coding: utf-8 -*-
"""
markupsafe._native
~~~~~~~~~~~~~~~~~~
Native Python implementation the C module is not compiled.
:copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from ._compat import text_type
def escape(s):
"""Convert the characters &, <, >, ' and " in string s to HTML-safe
sequences. Use this if you need to display text that might contain
such characters in HTML. Marks return value as markup string.
"""
if hasattr(s, '__html__'):
return s.__html__()
return Markup(text_type(s)
.replace('&', '&amp;')
.replace('>', '&gt;')
.replace('<', '&lt;')
.replace("'", '&#39;')
.replace('"', '&#34;')
)
def escape_silent(s):
"""Like :func:`escape` but converts `None` into an empty
markup string.
"""
if s is None:
return Markup()
return escape(s)
def soft_unicode(s):
"""Make a string unicode if it isn't already. That way a markup
string is not converted back to unicode.
"""
if not isinstance(s, text_type):
s = text_type(s)
return s
-103
View File
@@ -1,103 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.meta
~~~~~~~~~~~
This module implements various functions that exposes information about
templates that might be interesting for various kinds of applications.
:copyright: (c) 2010 by the Jinja Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from jinja2 import nodes
from jinja2.compiler import CodeGenerator
from jinja2._compat import string_types
class TrackingCodeGenerator(CodeGenerator):
"""We abuse the code generator for introspection."""
def __init__(self, environment):
CodeGenerator.__init__(self, environment, '<introspection>',
'<introspection>')
self.undeclared_identifiers = set()
def write(self, x):
"""Don't write."""
def pull_locals(self, frame):
"""Remember all undeclared identifiers."""
self.undeclared_identifiers.update(frame.identifiers.undeclared)
def find_undeclared_variables(ast):
"""Returns a set of all variables in the AST that will be looked up from
the context at runtime. Because at compile time it's not known which
variables will be used depending on the path the execution takes at
runtime, all variables are returned.
>>> from jinja2 import Environment, meta
>>> env = Environment()
>>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
>>> meta.find_undeclared_variables(ast)
set(['bar'])
.. admonition:: Implementation
Internally the code generator is used for finding undeclared variables.
This is good to know because the code generator might raise a
:exc:`TemplateAssertionError` during compilation and as a matter of
fact this function can currently raise that exception as well.
"""
codegen = TrackingCodeGenerator(ast.environment)
codegen.visit(ast)
return codegen.undeclared_identifiers
def find_referenced_templates(ast):
"""Finds all the referenced templates from the AST. This will return an
iterator over all the hardcoded template extensions, inclusions and
imports. If dynamic inheritance or inclusion is used, `None` will be
yielded.
>>> from jinja2 import Environment, meta
>>> env = Environment()
>>> ast = env.parse('{% extends "layout.html" %}{% include helper %}')
>>> list(meta.find_referenced_templates(ast))
['layout.html', None]
This function is useful for dependency tracking. For example if you want
to rebuild parts of the website after a layout template has changed.
"""
for node in ast.find_all((nodes.Extends, nodes.FromImport, nodes.Import,
nodes.Include)):
if not isinstance(node.template, nodes.Const):
# a tuple with some non consts in there
if isinstance(node.template, (nodes.Tuple, nodes.List)):
for template_name in node.template.items:
# something const, only yield the strings and ignore
# non-string consts that really just make no sense
if isinstance(template_name, nodes.Const):
if isinstance(template_name.value, string_types):
yield template_name.value
# something dynamic in there
else:
yield None
# something dynamic we don't know about here
else:
yield None
continue
# constant is a basestring, direct template name
if isinstance(node.template.value, string_types):
yield node.template.value
# a tuple or list (latter *should* not happen) made of consts,
# yield the consts that are strings. We could warn here for
# non string values
elif isinstance(node, nodes.Include) and \
isinstance(node.template.value, (tuple, list)):
for template_name in node.template.value:
if isinstance(template_name, string_types):
yield template_name
# something else we don't care about, we could warn here
else:
yield None
-914
View File
@@ -1,914 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.nodes
~~~~~~~~~~~~
This module implements additional nodes derived from the ast base node.
It also provides some node tree helper functions like `in_lineno` and
`get_nodes` used by the parser and translator in order to normalize
python and jinja nodes.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
import operator
from collections import deque
from jinja2.utils import Markup
from jinja2._compat import next, izip, with_metaclass, text_type, \
method_type, function_type
#: the types we support for context functions
_context_function_types = (function_type, method_type)
_binop_to_func = {
'*': operator.mul,
'/': operator.truediv,
'//': operator.floordiv,
'**': operator.pow,
'%': operator.mod,
'+': operator.add,
'-': operator.sub
}
_uaop_to_func = {
'not': operator.not_,
'+': operator.pos,
'-': operator.neg
}
_cmpop_to_func = {
'eq': operator.eq,
'ne': operator.ne,
'gt': operator.gt,
'gteq': operator.ge,
'lt': operator.lt,
'lteq': operator.le,
'in': lambda a, b: a in b,
'notin': lambda a, b: a not in b
}
class Impossible(Exception):
"""Raised if the node could not perform a requested action."""
class NodeType(type):
"""A metaclass for nodes that handles the field and attribute
inheritance. fields and attributes from the parent class are
automatically forwarded to the child."""
def __new__(cls, name, bases, d):
for attr in 'fields', 'attributes':
storage = []
storage.extend(getattr(bases[0], attr, ()))
storage.extend(d.get(attr, ()))
assert len(bases) == 1, 'multiple inheritance not allowed'
assert len(storage) == len(set(storage)), 'layout conflict'
d[attr] = tuple(storage)
d.setdefault('abstract', False)
return type.__new__(cls, name, bases, d)
class EvalContext(object):
"""Holds evaluation time information. Custom attributes can be attached
to it in extensions.
"""
def __init__(self, environment, template_name=None):
self.environment = environment
if callable(environment.autoescape):
self.autoescape = environment.autoescape(template_name)
else:
self.autoescape = environment.autoescape
self.volatile = False
def save(self):
return self.__dict__.copy()
def revert(self, old):
self.__dict__.clear()
self.__dict__.update(old)
def get_eval_context(node, ctx):
if ctx is None:
if node.environment is None:
raise RuntimeError('if no eval context is passed, the '
'node must have an attached '
'environment.')
return EvalContext(node.environment)
return ctx
class Node(with_metaclass(NodeType, object)):
"""Baseclass for all Jinja2 nodes. There are a number of nodes available
of different types. There are four major types:
- :class:`Stmt`: statements
- :class:`Expr`: expressions
- :class:`Helper`: helper nodes
- :class:`Template`: the outermost wrapper node
All nodes have fields and attributes. Fields may be other nodes, lists,
or arbitrary values. Fields are passed to the constructor as regular
positional arguments, attributes as keyword arguments. Each node has
two attributes: `lineno` (the line number of the node) and `environment`.
The `environment` attribute is set at the end of the parsing process for
all nodes automatically.
"""
fields = ()
attributes = ('lineno', 'environment')
abstract = True
def __init__(self, *fields, **attributes):
if self.abstract:
raise TypeError('abstract nodes are not instanciable')
if fields:
if len(fields) != len(self.fields):
if not self.fields:
raise TypeError('%r takes 0 arguments' %
self.__class__.__name__)
raise TypeError('%r takes 0 or %d argument%s' % (
self.__class__.__name__,
len(self.fields),
len(self.fields) != 1 and 's' or ''
))
for name, arg in izip(self.fields, fields):
setattr(self, name, arg)
for attr in self.attributes:
setattr(self, attr, attributes.pop(attr, None))
if attributes:
raise TypeError('unknown attribute %r' %
next(iter(attributes)))
def iter_fields(self, exclude=None, only=None):
"""This method iterates over all fields that are defined and yields
``(key, value)`` tuples. Per default all fields are returned, but
it's possible to limit that to some fields by providing the `only`
parameter or to exclude some using the `exclude` parameter. Both
should be sets or tuples of field names.
"""
for name in self.fields:
if (exclude is only is None) or \
(exclude is not None and name not in exclude) or \
(only is not None and name in only):
try:
yield name, getattr(self, name)
except AttributeError:
pass
def iter_child_nodes(self, exclude=None, only=None):
"""Iterates over all direct child nodes of the node. This iterates
over all fields and yields the values of they are nodes. If the value
of a field is a list all the nodes in that list are returned.
"""
for field, item in self.iter_fields(exclude, only):
if isinstance(item, list):
for n in item:
if isinstance(n, Node):
yield n
elif isinstance(item, Node):
yield item
def find(self, node_type):
"""Find the first node of a given type. If no such node exists the
return value is `None`.
"""
for result in self.find_all(node_type):
return result
def find_all(self, node_type):
"""Find all the nodes of a given type. If the type is a tuple,
the check is performed for any of the tuple items.
"""
for child in self.iter_child_nodes():
if isinstance(child, node_type):
yield child
for result in child.find_all(node_type):
yield result
def set_ctx(self, ctx):
"""Reset the context of a node and all child nodes. Per default the
parser will all generate nodes that have a 'load' context as it's the
most common one. This method is used in the parser to set assignment
targets and other nodes to a store context.
"""
todo = deque([self])
while todo:
node = todo.popleft()
if 'ctx' in node.fields:
node.ctx = ctx
todo.extend(node.iter_child_nodes())
return self
def set_lineno(self, lineno, override=False):
"""Set the line numbers of the node and children."""
todo = deque([self])
while todo:
node = todo.popleft()
if 'lineno' in node.attributes:
if node.lineno is None or override:
node.lineno = lineno
todo.extend(node.iter_child_nodes())
return self
def set_environment(self, environment):
"""Set the environment for all nodes."""
todo = deque([self])
while todo:
node = todo.popleft()
node.environment = environment
todo.extend(node.iter_child_nodes())
return self
def __eq__(self, other):
return type(self) is type(other) and \
tuple(self.iter_fields()) == tuple(other.iter_fields())
def __ne__(self, other):
return not self.__eq__(other)
# Restore Python 2 hashing behavior on Python 3
__hash__ = object.__hash__
def __repr__(self):
return '%s(%s)' % (
self.__class__.__name__,
', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
arg in self.fields)
)
class Stmt(Node):
"""Base node for all statements."""
abstract = True
class Helper(Node):
"""Nodes that exist in a specific context only."""
abstract = True
class Template(Node):
"""Node that represents a template. This must be the outermost node that
is passed to the compiler.
"""
fields = ('body',)
class Output(Stmt):
"""A node that holds multiple expressions which are then printed out.
This is used both for the `print` statement and the regular template data.
"""
fields = ('nodes',)
class Extends(Stmt):
"""Represents an extends statement."""
fields = ('template',)
class For(Stmt):
"""The for loop. `target` is the target for the iteration (usually a
:class:`Name` or :class:`Tuple`), `iter` the iterable. `body` is a list
of nodes that are used as loop-body, and `else_` a list of nodes for the
`else` block. If no else node exists it has to be an empty list.
For filtered nodes an expression can be stored as `test`, otherwise `None`.
"""
fields = ('target', 'iter', 'body', 'else_', 'test', 'recursive')
class If(Stmt):
"""If `test` is true, `body` is rendered, else `else_`."""
fields = ('test', 'body', 'else_')
class Macro(Stmt):
"""A macro definition. `name` is the name of the macro, `args` a list of
arguments and `defaults` a list of defaults if there are any. `body` is
a list of nodes for the macro body.
"""
fields = ('name', 'args', 'defaults', 'body')
class CallBlock(Stmt):
"""Like a macro without a name but a call instead. `call` is called with
the unnamed macro as `caller` argument this node holds.
"""
fields = ('call', 'args', 'defaults', 'body')
class FilterBlock(Stmt):
"""Node for filter sections."""
fields = ('body', 'filter')
class Block(Stmt):
"""A node that represents a block."""
fields = ('name', 'body', 'scoped')
class Include(Stmt):
"""A node that represents the include tag."""
fields = ('template', 'with_context', 'ignore_missing')
class Import(Stmt):
"""A node that represents the import tag."""
fields = ('template', 'target', 'with_context')
class FromImport(Stmt):
"""A node that represents the from import tag. It's important to not
pass unsafe names to the name attribute. The compiler translates the
attribute lookups directly into getattr calls and does *not* use the
subscript callback of the interface. As exported variables may not
start with double underscores (which the parser asserts) this is not a
problem for regular Jinja code, but if this node is used in an extension
extra care must be taken.
The list of names may contain tuples if aliases are wanted.
"""
fields = ('template', 'names', 'with_context')
class ExprStmt(Stmt):
"""A statement that evaluates an expression and discards the result."""
fields = ('node',)
class Assign(Stmt):
"""Assigns an expression to a target."""
fields = ('target', 'node')
class Expr(Node):
"""Baseclass for all expressions."""
abstract = True
def as_const(self, eval_ctx=None):
"""Return the value of the expression as constant or raise
:exc:`Impossible` if this was not possible.
An :class:`EvalContext` can be provided, if none is given
a default context is created which requires the nodes to have
an attached environment.
.. versionchanged:: 2.4
the `eval_ctx` parameter was added.
"""
raise Impossible()
def can_assign(self):
"""Check if it's possible to assign something to this node."""
return False
class BinExpr(Expr):
"""Baseclass for all binary expressions."""
fields = ('left', 'right')
operator = None
abstract = True
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
# intercepted operators cannot be folded at compile time
if self.environment.sandboxed and \
self.operator in self.environment.intercepted_binops:
raise Impossible()
f = _binop_to_func[self.operator]
try:
return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx))
except Exception:
raise Impossible()
class UnaryExpr(Expr):
"""Baseclass for all unary expressions."""
fields = ('node',)
operator = None
abstract = True
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
# intercepted operators cannot be folded at compile time
if self.environment.sandboxed and \
self.operator in self.environment.intercepted_unops:
raise Impossible()
f = _uaop_to_func[self.operator]
try:
return f(self.node.as_const(eval_ctx))
except Exception:
raise Impossible()
class Name(Expr):
"""Looks up a name or stores a value in a name.
The `ctx` of the node can be one of the following values:
- `store`: store a value in the name
- `load`: load that name
- `param`: like `store` but if the name was defined as function parameter.
"""
fields = ('name', 'ctx')
def can_assign(self):
return self.name not in ('true', 'false', 'none',
'True', 'False', 'None')
class Literal(Expr):
"""Baseclass for literals."""
abstract = True
class Const(Literal):
"""All constant values. The parser will return this node for simple
constants such as ``42`` or ``"foo"`` but it can be used to store more
complex values such as lists too. Only constants with a safe
representation (objects where ``eval(repr(x)) == x`` is true).
"""
fields = ('value',)
def as_const(self, eval_ctx=None):
return self.value
@classmethod
def from_untrusted(cls, value, lineno=None, environment=None):
"""Return a const object if the value is representable as
constant value in the generated code, otherwise it will raise
an `Impossible` exception.
"""
from .compiler import has_safe_repr
if not has_safe_repr(value):
raise Impossible()
return cls(value, lineno=lineno, environment=environment)
class TemplateData(Literal):
"""A constant template string."""
fields = ('data',)
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
if eval_ctx.volatile:
raise Impossible()
if eval_ctx.autoescape:
return Markup(self.data)
return self.data
class Tuple(Literal):
"""For loop unpacking and some other things like multiple arguments
for subscripts. Like for :class:`Name` `ctx` specifies if the tuple
is used for loading the names or storing.
"""
fields = ('items', 'ctx')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
return tuple(x.as_const(eval_ctx) for x in self.items)
def can_assign(self):
for item in self.items:
if not item.can_assign():
return False
return True
class List(Literal):
"""Any list literal such as ``[1, 2, 3]``"""
fields = ('items',)
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
return [x.as_const(eval_ctx) for x in self.items]
class Dict(Literal):
"""Any dict literal such as ``{1: 2, 3: 4}``. The items must be a list of
:class:`Pair` nodes.
"""
fields = ('items',)
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
return dict(x.as_const(eval_ctx) for x in self.items)
class Pair(Helper):
"""A key, value pair for dicts."""
fields = ('key', 'value')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
class Keyword(Helper):
"""A key, value pair for keyword arguments where key is a string."""
fields = ('key', 'value')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
return self.key, self.value.as_const(eval_ctx)
class CondExpr(Expr):
"""A conditional expression (inline if expression). (``{{
foo if bar else baz }}``)
"""
fields = ('test', 'expr1', 'expr2')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
if self.test.as_const(eval_ctx):
return self.expr1.as_const(eval_ctx)
# if we evaluate to an undefined object, we better do that at runtime
if self.expr2 is None:
raise Impossible()
return self.expr2.as_const(eval_ctx)
class Filter(Expr):
"""This node applies a filter on an expression. `name` is the name of
the filter, the rest of the fields are the same as for :class:`Call`.
If the `node` of a filter is `None` the contents of the last buffer are
filtered. Buffers are created by macros and filter blocks.
"""
fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
if eval_ctx.volatile or self.node is None:
raise Impossible()
# we have to be careful here because we call filter_ below.
# if this variable would be called filter, 2to3 would wrap the
# call in a list beause it is assuming we are talking about the
# builtin filter function here which no longer returns a list in
# python 3. because of that, do not rename filter_ to filter!
filter_ = self.environment.filters.get(self.name)
if filter_ is None or getattr(filter_, 'contextfilter', False):
raise Impossible()
obj = self.node.as_const(eval_ctx)
args = [x.as_const(eval_ctx) for x in self.args]
if getattr(filter_, 'evalcontextfilter', False):
args.insert(0, eval_ctx)
elif getattr(filter_, 'environmentfilter', False):
args.insert(0, self.environment)
kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs)
if self.dyn_args is not None:
try:
args.extend(self.dyn_args.as_const(eval_ctx))
except Exception:
raise Impossible()
if self.dyn_kwargs is not None:
try:
kwargs.update(self.dyn_kwargs.as_const(eval_ctx))
except Exception:
raise Impossible()
try:
return filter_(obj, *args, **kwargs)
except Exception:
raise Impossible()
class Test(Expr):
"""Applies a test on an expression. `name` is the name of the test, the
rest of the fields are the same as for :class:`Call`.
"""
fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
class Call(Expr):
"""Calls an expression. `args` is a list of arguments, `kwargs` a list
of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args`
and `dyn_kwargs` has to be either `None` or a node that is used as
node for dynamic positional (``*args``) or keyword (``**kwargs``)
arguments.
"""
fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
if eval_ctx.volatile:
raise Impossible()
obj = self.node.as_const(eval_ctx)
# don't evaluate context functions
args = [x.as_const(eval_ctx) for x in self.args]
if isinstance(obj, _context_function_types):
if getattr(obj, 'contextfunction', False):
raise Impossible()
elif getattr(obj, 'evalcontextfunction', False):
args.insert(0, eval_ctx)
elif getattr(obj, 'environmentfunction', False):
args.insert(0, self.environment)
kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs)
if self.dyn_args is not None:
try:
args.extend(self.dyn_args.as_const(eval_ctx))
except Exception:
raise Impossible()
if self.dyn_kwargs is not None:
try:
kwargs.update(self.dyn_kwargs.as_const(eval_ctx))
except Exception:
raise Impossible()
try:
return obj(*args, **kwargs)
except Exception:
raise Impossible()
class Getitem(Expr):
"""Get an attribute or item from an expression and prefer the item."""
fields = ('node', 'arg', 'ctx')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
if self.ctx != 'load':
raise Impossible()
try:
return self.environment.getitem(self.node.as_const(eval_ctx),
self.arg.as_const(eval_ctx))
except Exception:
raise Impossible()
def can_assign(self):
return False
class Getattr(Expr):
"""Get an attribute or item from an expression that is a ascii-only
bytestring and prefer the attribute.
"""
fields = ('node', 'attr', 'ctx')
def as_const(self, eval_ctx=None):
if self.ctx != 'load':
raise Impossible()
try:
eval_ctx = get_eval_context(self, eval_ctx)
return self.environment.getattr(self.node.as_const(eval_ctx),
self.attr)
except Exception:
raise Impossible()
def can_assign(self):
return False
class Slice(Expr):
"""Represents a slice object. This must only be used as argument for
:class:`Subscript`.
"""
fields = ('start', 'stop', 'step')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
def const(obj):
if obj is None:
return None
return obj.as_const(eval_ctx)
return slice(const(self.start), const(self.stop), const(self.step))
class Concat(Expr):
"""Concatenates the list of expressions provided after converting them to
unicode.
"""
fields = ('nodes',)
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
return ''.join(text_type(x.as_const(eval_ctx)) for x in self.nodes)
class Compare(Expr):
"""Compares an expression with some other expressions. `ops` must be a
list of :class:`Operand`\s.
"""
fields = ('expr', 'ops')
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
result = value = self.expr.as_const(eval_ctx)
try:
for op in self.ops:
new_value = op.expr.as_const(eval_ctx)
result = _cmpop_to_func[op.op](value, new_value)
value = new_value
except Exception:
raise Impossible()
return result
class Operand(Helper):
"""Holds an operator and an expression."""
fields = ('op', 'expr')
if __debug__:
Operand.__doc__ += '\nThe following operators are available: ' + \
', '.join(sorted('``%s``' % x for x in set(_binop_to_func) |
set(_uaop_to_func) | set(_cmpop_to_func)))
class Mul(BinExpr):
"""Multiplies the left with the right node."""
operator = '*'
class Div(BinExpr):
"""Divides the left by the right node."""
operator = '/'
class FloorDiv(BinExpr):
"""Divides the left by the right node and truncates conver the
result into an integer by truncating.
"""
operator = '//'
class Add(BinExpr):
"""Add the left to the right node."""
operator = '+'
class Sub(BinExpr):
"""Substract the right from the left node."""
operator = '-'
class Mod(BinExpr):
"""Left modulo right."""
operator = '%'
class Pow(BinExpr):
"""Left to the power of right."""
operator = '**'
class And(BinExpr):
"""Short circuited AND."""
operator = 'and'
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)
class Or(BinExpr):
"""Short circuited OR."""
operator = 'or'
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)
class Not(UnaryExpr):
"""Negate the expression."""
operator = 'not'
class Neg(UnaryExpr):
"""Make the expression negative."""
operator = '-'
class Pos(UnaryExpr):
"""Make the expression positive (noop for most expressions)"""
operator = '+'
# Helpers for extensions
class EnvironmentAttribute(Expr):
"""Loads an attribute from the environment object. This is useful for
extensions that want to call a callback stored on the environment.
"""
fields = ('name',)
class ExtensionAttribute(Expr):
"""Returns the attribute of an extension bound to the environment.
The identifier is the identifier of the :class:`Extension`.
This node is usually constructed by calling the
:meth:`~jinja2.ext.Extension.attr` method on an extension.
"""
fields = ('identifier', 'name')
class ImportedName(Expr):
"""If created with an import name the import name is returned on node
access. For example ``ImportedName('cgi.escape')`` returns the `escape`
function from the cgi module on evaluation. Imports are optimized by the
compiler so there is no need to assign them to local variables.
"""
fields = ('importname',)
class InternalName(Expr):
"""An internal name in the compiler. You cannot create these nodes
yourself but the parser provides a
:meth:`~jinja2.parser.Parser.free_identifier` method that creates
a new identifier for you. This identifier is not available from the
template and is not threated specially by the compiler.
"""
fields = ('name',)
def __init__(self):
raise TypeError('Can\'t create internal names. Use the '
'`free_identifier` method on a parser.')
class MarkSafe(Expr):
"""Mark the wrapped expression as safe (wrap it as `Markup`)."""
fields = ('expr',)
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
return Markup(self.expr.as_const(eval_ctx))
class MarkSafeIfAutoescape(Expr):
"""Mark the wrapped expression as safe (wrap it as `Markup`) but
only if autoescaping is active.
.. versionadded:: 2.5
"""
fields = ('expr',)
def as_const(self, eval_ctx=None):
eval_ctx = get_eval_context(self, eval_ctx)
if eval_ctx.volatile:
raise Impossible()
expr = self.expr.as_const(eval_ctx)
if eval_ctx.autoescape:
return Markup(expr)
return expr
class ContextReference(Expr):
"""Returns the current template context. It can be used like a
:class:`Name` node, with a ``'load'`` ctx and will return the
current :class:`~jinja2.runtime.Context` object.
Here an example that assigns the current template name to a
variable named `foo`::
Assign(Name('foo', ctx='store'),
Getattr(ContextReference(), 'name'))
"""
class Continue(Stmt):
"""Continue a loop."""
class Break(Stmt):
"""Break a loop."""
class Scope(Stmt):
"""An artificial scope."""
fields = ('body',)
class EvalContextModifier(Stmt):
"""Modifies the eval context. For each option that should be modified,
a :class:`Keyword` has to be added to the :attr:`options` list.
Example to change the `autoescape` setting::
EvalContextModifier(options=[Keyword('autoescape', Const(True))])
"""
fields = ('options',)
class ScopedEvalContextModifier(EvalContextModifier):
"""Modifies the eval context and reverts it later. Works exactly like
:class:`EvalContextModifier` but will only modify the
:class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
"""
fields = ('body',)
# make sure nobody creates custom nodes
def _failing_new(*args, **kwargs):
raise TypeError('can\'t create custom node types')
NodeType.__new__ = staticmethod(_failing_new); del _failing_new
-68
View File
@@ -1,68 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.optimizer
~~~~~~~~~~~~~~~~
The jinja optimizer is currently trying to constant fold a few expressions
and modify the AST in place so that it should be easier to evaluate it.
Because the AST does not contain all the scoping information and the
compiler has to find that out, we cannot do all the optimizations we
want. For example loop unrolling doesn't work because unrolled loops would
have a different scoping.
The solution would be a second syntax tree that has the scoping rules stored.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD.
"""
from jinja2 import nodes
from jinja2.visitor import NodeTransformer
def optimize(node, environment):
"""The context hint can be used to perform an static optimization
based on the context given."""
optimizer = Optimizer(environment)
return optimizer.visit(node)
class Optimizer(NodeTransformer):
def __init__(self, environment):
self.environment = environment
def visit_If(self, node):
"""Eliminate dead code."""
# do not optimize ifs that have a block inside so that it doesn't
# break super().
if node.find(nodes.Block) is not None:
return self.generic_visit(node)
try:
val = self.visit(node.test).as_const()
except nodes.Impossible:
return self.generic_visit(node)
if val:
body = node.body
else:
body = node.else_
result = []
for node in body:
result.extend(self.visit_list(node))
return result
def fold(self, node):
"""Do constant folding."""
node = self.generic_visit(node)
try:
return nodes.Const.from_untrusted(node.as_const(),
lineno=node.lineno,
environment=self.environment)
except nodes.Impossible:
return node
visit_Add = visit_Sub = visit_Mul = visit_Div = visit_FloorDiv = \
visit_Pow = visit_Mod = visit_And = visit_Or = visit_Pos = visit_Neg = \
visit_Not = visit_Compare = visit_Getitem = visit_Getattr = visit_Call = \
visit_Filter = visit_Test = visit_CondExpr = fold
del fold
-895
View File
@@ -1,895 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.parser
~~~~~~~~~~~~~
Implements the template parser.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
from jinja2 import nodes
from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
from jinja2.lexer import describe_token, describe_token_expr
from jinja2._compat import next, imap
#: statements that callinto
_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
'macro', 'include', 'from', 'import',
'set'])
_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq'])
class Parser(object):
"""This is the central parsing class Jinja2 uses. It's passed to
extensions and can be used to parse expressions or statements.
"""
def __init__(self, environment, source, name=None, filename=None,
state=None):
self.environment = environment
self.stream = environment._tokenize(source, name, filename, state)
self.name = name
self.filename = filename
self.closed = False
self.extensions = {}
for extension in environment.iter_extensions():
for tag in extension.tags:
self.extensions[tag] = extension.parse
self._last_identifier = 0
self._tag_stack = []
self._end_token_stack = []
def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
"""Convenience method that raises `exc` with the message, passed
line number or last line number as well as the current name and
filename.
"""
if lineno is None:
lineno = self.stream.current.lineno
raise exc(msg, lineno, self.name, self.filename)
def _fail_ut_eof(self, name, end_token_stack, lineno):
expected = []
for exprs in end_token_stack:
expected.extend(imap(describe_token_expr, exprs))
if end_token_stack:
currently_looking = ' or '.join(
"'%s'" % describe_token_expr(expr)
for expr in end_token_stack[-1])
else:
currently_looking = None
if name is None:
message = ['Unexpected end of template.']
else:
message = ['Encountered unknown tag \'%s\'.' % name]
if currently_looking:
if name is not None and name in expected:
message.append('You probably made a nesting mistake. Jinja '
'is expecting this tag, but currently looking '
'for %s.' % currently_looking)
else:
message.append('Jinja was looking for the following tags: '
'%s.' % currently_looking)
if self._tag_stack:
message.append('The innermost block that needs to be '
'closed is \'%s\'.' % self._tag_stack[-1])
self.fail(' '.join(message), lineno)
def fail_unknown_tag(self, name, lineno=None):
"""Called if the parser encounters an unknown tag. Tries to fail
with a human readable error message that could help to identify
the problem.
"""
return self._fail_ut_eof(name, self._end_token_stack, lineno)
def fail_eof(self, end_tokens=None, lineno=None):
"""Like fail_unknown_tag but for end of template situations."""
stack = list(self._end_token_stack)
if end_tokens is not None:
stack.append(end_tokens)
return self._fail_ut_eof(None, stack, lineno)
def is_tuple_end(self, extra_end_rules=None):
"""Are we at the end of a tuple?"""
if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
return True
elif extra_end_rules is not None:
return self.stream.current.test_any(extra_end_rules)
return False
def free_identifier(self, lineno=None):
"""Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
self._last_identifier += 1
rv = object.__new__(nodes.InternalName)
nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
return rv
def parse_statement(self):
"""Parse a single statement."""
token = self.stream.current
if token.type != 'name':
self.fail('tag name expected', token.lineno)
self._tag_stack.append(token.value)
pop_tag = True
try:
if token.value in _statement_keywords:
return getattr(self, 'parse_' + self.stream.current.value)()
if token.value == 'call':
return self.parse_call_block()
if token.value == 'filter':
return self.parse_filter_block()
ext = self.extensions.get(token.value)
if ext is not None:
return ext(self)
# did not work out, remove the token we pushed by accident
# from the stack so that the unknown tag fail function can
# produce a proper error message.
self._tag_stack.pop()
pop_tag = False
self.fail_unknown_tag(token.value, token.lineno)
finally:
if pop_tag:
self._tag_stack.pop()
def parse_statements(self, end_tokens, drop_needle=False):
"""Parse multiple statements into a list until one of the end tokens
is reached. This is used to parse the body of statements as it also
parses template data if appropriate. The parser checks first if the
current token is a colon and skips it if there is one. Then it checks
for the block end and parses until if one of the `end_tokens` is
reached. Per default the active token in the stream at the end of
the call is the matched end token. If this is not wanted `drop_needle`
can be set to `True` and the end token is removed.
"""
# the first token may be a colon for python compatibility
self.stream.skip_if('colon')
# in the future it would be possible to add whole code sections
# by adding some sort of end of statement token and parsing those here.
self.stream.expect('block_end')
result = self.subparse(end_tokens)
# we reached the end of the template too early, the subparser
# does not check for this, so we do that now
if self.stream.current.type == 'eof':
self.fail_eof(end_tokens)
if drop_needle:
next(self.stream)
return result
def parse_set(self):
"""Parse an assign statement."""
lineno = next(self.stream).lineno
target = self.parse_assign_target()
self.stream.expect('assign')
expr = self.parse_tuple()
return nodes.Assign(target, expr, lineno=lineno)
def parse_for(self):
"""Parse a for loop."""
lineno = self.stream.expect('name:for').lineno
target = self.parse_assign_target(extra_end_rules=('name:in',))
self.stream.expect('name:in')
iter = self.parse_tuple(with_condexpr=False,
extra_end_rules=('name:recursive',))
test = None
if self.stream.skip_if('name:if'):
test = self.parse_expression()
recursive = self.stream.skip_if('name:recursive')
body = self.parse_statements(('name:endfor', 'name:else'))
if next(self.stream).value == 'endfor':
else_ = []
else:
else_ = self.parse_statements(('name:endfor',), drop_needle=True)
return nodes.For(target, iter, body, else_, test,
recursive, lineno=lineno)
def parse_if(self):
"""Parse an if construct."""
node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
while 1:
node.test = self.parse_tuple(with_condexpr=False)
node.body = self.parse_statements(('name:elif', 'name:else',
'name:endif'))
token = next(self.stream)
if token.test('name:elif'):
new_node = nodes.If(lineno=self.stream.current.lineno)
node.else_ = [new_node]
node = new_node
continue
elif token.test('name:else'):
node.else_ = self.parse_statements(('name:endif',),
drop_needle=True)
else:
node.else_ = []
break
return result
def parse_block(self):
node = nodes.Block(lineno=next(self.stream).lineno)
node.name = self.stream.expect('name').value
node.scoped = self.stream.skip_if('name:scoped')
# common problem people encounter when switching from django
# to jinja. we do not support hyphens in block names, so let's
# raise a nicer error message in that case.
if self.stream.current.type == 'sub':
self.fail('Block names in Jinja have to be valid Python '
'identifiers and may not contain hyphens, use an '
'underscore instead.')
node.body = self.parse_statements(('name:endblock',), drop_needle=True)
self.stream.skip_if('name:' + node.name)
return node
def parse_extends(self):
node = nodes.Extends(lineno=next(self.stream).lineno)
node.template = self.parse_expression()
return node
def parse_import_context(self, node, default):
if self.stream.current.test_any('name:with', 'name:without') and \
self.stream.look().test('name:context'):
node.with_context = next(self.stream).value == 'with'
self.stream.skip()
else:
node.with_context = default
return node
def parse_include(self):
node = nodes.Include(lineno=next(self.stream).lineno)
node.template = self.parse_expression()
if self.stream.current.test('name:ignore') and \
self.stream.look().test('name:missing'):
node.ignore_missing = True
self.stream.skip(2)
else:
node.ignore_missing = False
return self.parse_import_context(node, True)
def parse_import(self):
node = nodes.Import(lineno=next(self.stream).lineno)
node.template = self.parse_expression()
self.stream.expect('name:as')
node.target = self.parse_assign_target(name_only=True).name
return self.parse_import_context(node, False)
def parse_from(self):
node = nodes.FromImport(lineno=next(self.stream).lineno)
node.template = self.parse_expression()
self.stream.expect('name:import')
node.names = []
def parse_context():
if self.stream.current.value in ('with', 'without') and \
self.stream.look().test('name:context'):
node.with_context = next(self.stream).value == 'with'
self.stream.skip()
return True
return False
while 1:
if node.names:
self.stream.expect('comma')
if self.stream.current.type == 'name':
if parse_context():
break
target = self.parse_assign_target(name_only=True)
if target.name.startswith('_'):
self.fail('names starting with an underline can not '
'be imported', target.lineno,
exc=TemplateAssertionError)
if self.stream.skip_if('name:as'):
alias = self.parse_assign_target(name_only=True)
node.names.append((target.name, alias.name))
else:
node.names.append(target.name)
if parse_context() or self.stream.current.type != 'comma':
break
else:
break
if not hasattr(node, 'with_context'):
node.with_context = False
self.stream.skip_if('comma')
return node
def parse_signature(self, node):
node.args = args = []
node.defaults = defaults = []
self.stream.expect('lparen')
while self.stream.current.type != 'rparen':
if args:
self.stream.expect('comma')
arg = self.parse_assign_target(name_only=True)
arg.set_ctx('param')
if self.stream.skip_if('assign'):
defaults.append(self.parse_expression())
args.append(arg)
self.stream.expect('rparen')
def parse_call_block(self):
node = nodes.CallBlock(lineno=next(self.stream).lineno)
if self.stream.current.type == 'lparen':
self.parse_signature(node)
else:
node.args = []
node.defaults = []
node.call = self.parse_expression()
if not isinstance(node.call, nodes.Call):
self.fail('expected call', node.lineno)
node.body = self.parse_statements(('name:endcall',), drop_needle=True)
return node
def parse_filter_block(self):
node = nodes.FilterBlock(lineno=next(self.stream).lineno)
node.filter = self.parse_filter(None, start_inline=True)
node.body = self.parse_statements(('name:endfilter',),
drop_needle=True)
return node
def parse_macro(self):
node = nodes.Macro(lineno=next(self.stream).lineno)
node.name = self.parse_assign_target(name_only=True).name
self.parse_signature(node)
node.body = self.parse_statements(('name:endmacro',),
drop_needle=True)
return node
def parse_print(self):
node = nodes.Output(lineno=next(self.stream).lineno)
node.nodes = []
while self.stream.current.type != 'block_end':
if node.nodes:
self.stream.expect('comma')
node.nodes.append(self.parse_expression())
return node
def parse_assign_target(self, with_tuple=True, name_only=False,
extra_end_rules=None):
"""Parse an assignment target. As Jinja2 allows assignments to
tuples, this function can parse all allowed assignment targets. Per
default assignments to tuples are parsed, that can be disable however
by setting `with_tuple` to `False`. If only assignments to names are
wanted `name_only` can be set to `True`. The `extra_end_rules`
parameter is forwarded to the tuple parsing function.
"""
if name_only:
token = self.stream.expect('name')
target = nodes.Name(token.value, 'store', lineno=token.lineno)
else:
if with_tuple:
target = self.parse_tuple(simplified=True,
extra_end_rules=extra_end_rules)
else:
target = self.parse_primary()
target.set_ctx('store')
if not target.can_assign():
self.fail('can\'t assign to %r' % target.__class__.
__name__.lower(), target.lineno)
return target
def parse_expression(self, with_condexpr=True):
"""Parse an expression. Per default all expressions are parsed, if
the optional `with_condexpr` parameter is set to `False` conditional
expressions are not parsed.
"""
if with_condexpr:
return self.parse_condexpr()
return self.parse_or()
def parse_condexpr(self):
lineno = self.stream.current.lineno
expr1 = self.parse_or()
while self.stream.skip_if('name:if'):
expr2 = self.parse_or()
if self.stream.skip_if('name:else'):
expr3 = self.parse_condexpr()
else:
expr3 = None
expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
lineno = self.stream.current.lineno
return expr1
def parse_or(self):
lineno = self.stream.current.lineno
left = self.parse_and()
while self.stream.skip_if('name:or'):
right = self.parse_and()
left = nodes.Or(left, right, lineno=lineno)
lineno = self.stream.current.lineno
return left
def parse_and(self):
lineno = self.stream.current.lineno
left = self.parse_not()
while self.stream.skip_if('name:and'):
right = self.parse_not()
left = nodes.And(left, right, lineno=lineno)
lineno = self.stream.current.lineno
return left
def parse_not(self):
if self.stream.current.test('name:not'):
lineno = next(self.stream).lineno
return nodes.Not(self.parse_not(), lineno=lineno)
return self.parse_compare()
def parse_compare(self):
lineno = self.stream.current.lineno
expr = self.parse_add()
ops = []
while 1:
token_type = self.stream.current.type
if token_type in _compare_operators:
next(self.stream)
ops.append(nodes.Operand(token_type, self.parse_add()))
elif self.stream.skip_if('name:in'):
ops.append(nodes.Operand('in', self.parse_add()))
elif self.stream.current.test('name:not') and \
self.stream.look().test('name:in'):
self.stream.skip(2)
ops.append(nodes.Operand('notin', self.parse_add()))
else:
break
lineno = self.stream.current.lineno
if not ops:
return expr
return nodes.Compare(expr, ops, lineno=lineno)
def parse_add(self):
lineno = self.stream.current.lineno
left = self.parse_sub()
while self.stream.current.type == 'add':
next(self.stream)
right = self.parse_sub()
left = nodes.Add(left, right, lineno=lineno)
lineno = self.stream.current.lineno
return left
def parse_sub(self):
lineno = self.stream.current.lineno
left = self.parse_concat()
while self.stream.current.type == 'sub':
next(self.stream)
right = self.parse_concat()
left = nodes.Sub(left, right, lineno=lineno)
lineno = self.stream.current.lineno
return left
def parse_concat(self):
lineno = self.stream.current.lineno
args = [self.parse_mul()]
while self.stream.current.type == 'tilde':
next(self.stream)
args.append(self.parse_mul())
if len(args) == 1:
return args[0]
return nodes.Concat(args, lineno=lineno)
def parse_mul(self):
lineno = self.stream.current.lineno
left = self.parse_div()
while self.stream.current.type == 'mul':
next(self.stream)
right = self.parse_div()
left = nodes.Mul(left, right, lineno=lineno)
lineno = self.stream.current.lineno
return left
def parse_div(self):
lineno = self.stream.current.lineno
left = self.parse_floordiv()
while self.stream.current.type == 'div':
next(self.stream)
right = self.parse_floordiv()
left = nodes.Div(left, right, lineno=lineno)
lineno = self.stream.current.lineno
return left
def parse_floordiv(self):
lineno = self.stream.current.lineno
left = self.parse_mod()
while self.stream.current.type == 'floordiv':
next(self.stream)
right = self.parse_mod()
left = nodes.FloorDiv(left, right, lineno=lineno)
lineno = self.stream.current.lineno
return left
def parse_mod(self):
lineno = self.stream.current.lineno
left = self.parse_pow()
while self.stream.current.type == 'mod':
next(self.stream)
right = self.parse_pow()
left = nodes.Mod(left, right, lineno=lineno)
lineno = self.stream.current.lineno
return left
def parse_pow(self):
lineno = self.stream.current.lineno
left = self.parse_unary()
while self.stream.current.type == 'pow':
next(self.stream)
right = self.parse_unary()
left = nodes.Pow(left, right, lineno=lineno)
lineno = self.stream.current.lineno
return left
def parse_unary(self, with_filter=True):
token_type = self.stream.current.type
lineno = self.stream.current.lineno
if token_type == 'sub':
next(self.stream)
node = nodes.Neg(self.parse_unary(False), lineno=lineno)
elif token_type == 'add':
next(self.stream)
node = nodes.Pos(self.parse_unary(False), lineno=lineno)
else:
node = self.parse_primary()
node = self.parse_postfix(node)
if with_filter:
node = self.parse_filter_expr(node)
return node
def parse_primary(self):
token = self.stream.current
if token.type == 'name':
if token.value in ('true', 'false', 'True', 'False'):
node = nodes.Const(token.value in ('true', 'True'),
lineno=token.lineno)
elif token.value in ('none', 'None'):
node = nodes.Const(None, lineno=token.lineno)
else:
node = nodes.Name(token.value, 'load', lineno=token.lineno)
next(self.stream)
elif token.type == 'string':
next(self.stream)
buf = [token.value]
lineno = token.lineno
while self.stream.current.type == 'string':
buf.append(self.stream.current.value)
next(self.stream)
node = nodes.Const(''.join(buf), lineno=lineno)
elif token.type in ('integer', 'float'):
next(self.stream)
node = nodes.Const(token.value, lineno=token.lineno)
elif token.type == 'lparen':
next(self.stream)
node = self.parse_tuple(explicit_parentheses=True)
self.stream.expect('rparen')
elif token.type == 'lbracket':
node = self.parse_list()
elif token.type == 'lbrace':
node = self.parse_dict()
else:
self.fail("unexpected '%s'" % describe_token(token), token.lineno)
return node
def parse_tuple(self, simplified=False, with_condexpr=True,
extra_end_rules=None, explicit_parentheses=False):
"""Works like `parse_expression` but if multiple expressions are
delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
This method could also return a regular expression instead of a tuple
if no commas where found.
The default parsing mode is a full tuple. If `simplified` is `True`
only names and literals are parsed. The `no_condexpr` parameter is
forwarded to :meth:`parse_expression`.
Because tuples do not require delimiters and may end in a bogus comma
an extra hint is needed that marks the end of a tuple. For example
for loops support tuples between `for` and `in`. In that case the
`extra_end_rules` is set to ``['name:in']``.
`explicit_parentheses` is true if the parsing was triggered by an
expression in parentheses. This is used to figure out if an empty
tuple is a valid expression or not.
"""
lineno = self.stream.current.lineno
if simplified:
parse = self.parse_primary
elif with_condexpr:
parse = self.parse_expression
else:
parse = lambda: self.parse_expression(with_condexpr=False)
args = []
is_tuple = False
while 1:
if args:
self.stream.expect('comma')
if self.is_tuple_end(extra_end_rules):
break
args.append(parse())
if self.stream.current.type == 'comma':
is_tuple = True
else:
break
lineno = self.stream.current.lineno
if not is_tuple:
if args:
return args[0]
# if we don't have explicit parentheses, an empty tuple is
# not a valid expression. This would mean nothing (literally
# nothing) in the spot of an expression would be an empty
# tuple.
if not explicit_parentheses:
self.fail('Expected an expression, got \'%s\'' %
describe_token(self.stream.current))
return nodes.Tuple(args, 'load', lineno=lineno)
def parse_list(self):
token = self.stream.expect('lbracket')
items = []
while self.stream.current.type != 'rbracket':
if items:
self.stream.expect('comma')
if self.stream.current.type == 'rbracket':
break
items.append(self.parse_expression())
self.stream.expect('rbracket')
return nodes.List(items, lineno=token.lineno)
def parse_dict(self):
token = self.stream.expect('lbrace')
items = []
while self.stream.current.type != 'rbrace':
if items:
self.stream.expect('comma')
if self.stream.current.type == 'rbrace':
break
key = self.parse_expression()
self.stream.expect('colon')
value = self.parse_expression()
items.append(nodes.Pair(key, value, lineno=key.lineno))
self.stream.expect('rbrace')
return nodes.Dict(items, lineno=token.lineno)
def parse_postfix(self, node):
while 1:
token_type = self.stream.current.type
if token_type == 'dot' or token_type == 'lbracket':
node = self.parse_subscript(node)
# calls are valid both after postfix expressions (getattr
# and getitem) as well as filters and tests
elif token_type == 'lparen':
node = self.parse_call(node)
else:
break
return node
def parse_filter_expr(self, node):
while 1:
token_type = self.stream.current.type
if token_type == 'pipe':
node = self.parse_filter(node)
elif token_type == 'name' and self.stream.current.value == 'is':
node = self.parse_test(node)
# calls are valid both after postfix expressions (getattr
# and getitem) as well as filters and tests
elif token_type == 'lparen':
node = self.parse_call(node)
else:
break
return node
def parse_subscript(self, node):
token = next(self.stream)
if token.type == 'dot':
attr_token = self.stream.current
next(self.stream)
if attr_token.type == 'name':
return nodes.Getattr(node, attr_token.value, 'load',
lineno=token.lineno)
elif attr_token.type != 'integer':
self.fail('expected name or number', attr_token.lineno)
arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
if token.type == 'lbracket':
args = []
while self.stream.current.type != 'rbracket':
if args:
self.stream.expect('comma')
args.append(self.parse_subscribed())
self.stream.expect('rbracket')
if len(args) == 1:
arg = args[0]
else:
arg = nodes.Tuple(args, 'load', lineno=token.lineno)
return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
self.fail('expected subscript expression', self.lineno)
def parse_subscribed(self):
lineno = self.stream.current.lineno
if self.stream.current.type == 'colon':
next(self.stream)
args = [None]
else:
node = self.parse_expression()
if self.stream.current.type != 'colon':
return node
next(self.stream)
args = [node]
if self.stream.current.type == 'colon':
args.append(None)
elif self.stream.current.type not in ('rbracket', 'comma'):
args.append(self.parse_expression())
else:
args.append(None)
if self.stream.current.type == 'colon':
next(self.stream)
if self.stream.current.type not in ('rbracket', 'comma'):
args.append(self.parse_expression())
else:
args.append(None)
else:
args.append(None)
return nodes.Slice(lineno=lineno, *args)
def parse_call(self, node):
token = self.stream.expect('lparen')
args = []
kwargs = []
dyn_args = dyn_kwargs = None
require_comma = False
def ensure(expr):
if not expr:
self.fail('invalid syntax for function call expression',
token.lineno)
while self.stream.current.type != 'rparen':
if require_comma:
self.stream.expect('comma')
# support for trailing comma
if self.stream.current.type == 'rparen':
break
if self.stream.current.type == 'mul':
ensure(dyn_args is None and dyn_kwargs is None)
next(self.stream)
dyn_args = self.parse_expression()
elif self.stream.current.type == 'pow':
ensure(dyn_kwargs is None)
next(self.stream)
dyn_kwargs = self.parse_expression()
else:
ensure(dyn_args is None and dyn_kwargs is None)
if self.stream.current.type == 'name' and \
self.stream.look().type == 'assign':
key = self.stream.current.value
self.stream.skip(2)
value = self.parse_expression()
kwargs.append(nodes.Keyword(key, value,
lineno=value.lineno))
else:
ensure(not kwargs)
args.append(self.parse_expression())
require_comma = True
self.stream.expect('rparen')
if node is None:
return args, kwargs, dyn_args, dyn_kwargs
return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
lineno=token.lineno)
def parse_filter(self, node, start_inline=False):
while self.stream.current.type == 'pipe' or start_inline:
if not start_inline:
next(self.stream)
token = self.stream.expect('name')
name = token.value
while self.stream.current.type == 'dot':
next(self.stream)
name += '.' + self.stream.expect('name').value
if self.stream.current.type == 'lparen':
args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
else:
args = []
kwargs = []
dyn_args = dyn_kwargs = None
node = nodes.Filter(node, name, args, kwargs, dyn_args,
dyn_kwargs, lineno=token.lineno)
start_inline = False
return node
def parse_test(self, node):
token = next(self.stream)
if self.stream.current.test('name:not'):
next(self.stream)
negated = True
else:
negated = False
name = self.stream.expect('name').value
while self.stream.current.type == 'dot':
next(self.stream)
name += '.' + self.stream.expect('name').value
dyn_args = dyn_kwargs = None
kwargs = []
if self.stream.current.type == 'lparen':
args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
elif self.stream.current.type in ('name', 'string', 'integer',
'float', 'lparen', 'lbracket',
'lbrace') and not \
self.stream.current.test_any('name:else', 'name:or',
'name:and'):
if self.stream.current.test('name:is'):
self.fail('You cannot chain multiple tests with is')
args = [self.parse_expression()]
else:
args = []
node = nodes.Test(node, name, args, kwargs, dyn_args,
dyn_kwargs, lineno=token.lineno)
if negated:
node = nodes.Not(node, lineno=token.lineno)
return node
def subparse(self, end_tokens=None):
body = []
data_buffer = []
add_data = data_buffer.append
if end_tokens is not None:
self._end_token_stack.append(end_tokens)
def flush_data():
if data_buffer:
lineno = data_buffer[0].lineno
body.append(nodes.Output(data_buffer[:], lineno=lineno))
del data_buffer[:]
try:
while self.stream:
token = self.stream.current
if token.type == 'data':
if token.value:
add_data(nodes.TemplateData(token.value,
lineno=token.lineno))
next(self.stream)
elif token.type == 'variable_begin':
next(self.stream)
add_data(self.parse_tuple(with_condexpr=True))
self.stream.expect('variable_end')
elif token.type == 'block_begin':
flush_data()
next(self.stream)
if end_tokens is not None and \
self.stream.current.test_any(*end_tokens):
return body
rv = self.parse_statement()
if isinstance(rv, list):
body.extend(rv)
else:
body.append(rv)
self.stream.expect('block_end')
else:
raise AssertionError('internal parsing error')
flush_data()
finally:
if end_tokens is not None:
self._end_token_stack.pop()
return body
def parse(self):
"""Parse the whole template into a `Template` node."""
result = nodes.Template(self.subparse(), lineno=1)
result.set_environment(self.environment)
return result
-581
View File
@@ -1,581 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.runtime
~~~~~~~~~~~~~~
Runtime helpers.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD.
"""
from itertools import chain
from jinja2.nodes import EvalContext, _context_function_types
from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \
internalcode, object_type_repr
from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
TemplateNotFound
from jinja2._compat import next, imap, text_type, iteritems, \
implements_iterator, implements_to_string, string_types, PY2
# these variables are exported to the template runtime
__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
'TemplateRuntimeError', 'missing', 'concat', 'escape',
'markup_join', 'unicode_join', 'to_string', 'identity',
'TemplateNotFound']
#: the name of the function that is used to convert something into
#: a string. We can just use the text type here.
to_string = text_type
#: the identity function. Useful for certain things in the environment
identity = lambda x: x
_last_iteration = object()
def markup_join(seq):
"""Concatenation that escapes if necessary and converts to unicode."""
buf = []
iterator = imap(soft_unicode, seq)
for arg in iterator:
buf.append(arg)
if hasattr(arg, '__html__'):
return Markup(u'').join(chain(buf, iterator))
return concat(buf)
def unicode_join(seq):
"""Simple args to unicode conversion and concatenation."""
return concat(imap(text_type, seq))
def new_context(environment, template_name, blocks, vars=None,
shared=None, globals=None, locals=None):
"""Internal helper to for context creation."""
if vars is None:
vars = {}
if shared:
parent = vars
else:
parent = dict(globals or (), **vars)
if locals:
# if the parent is shared a copy should be created because
# we don't want to modify the dict passed
if shared:
parent = dict(parent)
for key, value in iteritems(locals):
if key[:2] == 'l_' and value is not missing:
parent[key[2:]] = value
return Context(environment, parent, template_name, blocks)
class TemplateReference(object):
"""The `self` in templates."""
def __init__(self, context):
self.__context = context
def __getitem__(self, name):
blocks = self.__context.blocks[name]
return BlockReference(name, self.__context, blocks, 0)
def __repr__(self):
return '<%s %r>' % (
self.__class__.__name__,
self.__context.name
)
class Context(object):
"""The template context holds the variables of a template. It stores the
values passed to the template and also the names the template exports.
Creating instances is neither supported nor useful as it's created
automatically at various stages of the template evaluation and should not
be created by hand.
The context is immutable. Modifications on :attr:`parent` **must not**
happen and modifications on :attr:`vars` are allowed from generated
template code only. Template filters and global functions marked as
:func:`contextfunction`\s get the active context passed as first argument
and are allowed to access the context read-only.
The template context supports read only dict operations (`get`,
`keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
`__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
method that doesn't fail with a `KeyError` but returns an
:class:`Undefined` object for missing variables.
"""
__slots__ = ('parent', 'vars', 'environment', 'eval_ctx', 'exported_vars',
'name', 'blocks', '__weakref__')
def __init__(self, environment, parent, name, blocks):
self.parent = parent
self.vars = {}
self.environment = environment
self.eval_ctx = EvalContext(self.environment, name)
self.exported_vars = set()
self.name = name
# create the initial mapping of blocks. Whenever template inheritance
# takes place the runtime will update this mapping with the new blocks
# from the template.
self.blocks = dict((k, [v]) for k, v in iteritems(blocks))
def super(self, name, current):
"""Render a parent block."""
try:
blocks = self.blocks[name]
index = blocks.index(current) + 1
blocks[index]
except LookupError:
return self.environment.undefined('there is no parent block '
'called %r.' % name,
name='super')
return BlockReference(name, self, blocks, index)
def get(self, key, default=None):
"""Returns an item from the template context, if it doesn't exist
`default` is returned.
"""
try:
return self[key]
except KeyError:
return default
def resolve(self, key):
"""Looks up a variable like `__getitem__` or `get` but returns an
:class:`Undefined` object with the name of the name looked up.
"""
if key in self.vars:
return self.vars[key]
if key in self.parent:
return self.parent[key]
return self.environment.undefined(name=key)
def get_exported(self):
"""Get a new dict with the exported variables."""
return dict((k, self.vars[k]) for k in self.exported_vars)
def get_all(self):
"""Return a copy of the complete context as dict including the
exported variables.
"""
return dict(self.parent, **self.vars)
@internalcode
def call(__self, __obj, *args, **kwargs):
"""Call the callable with the arguments and keyword arguments
provided but inject the active context or environment as first
argument if the callable is a :func:`contextfunction` or
:func:`environmentfunction`.
"""
if __debug__:
__traceback_hide__ = True
# Allow callable classes to take a context
fn = __obj.__call__
for fn_type in ('contextfunction',
'evalcontextfunction',
'environmentfunction'):
if hasattr(fn, fn_type):
__obj = fn
break
if isinstance(__obj, _context_function_types):
if getattr(__obj, 'contextfunction', 0):
args = (__self,) + args
elif getattr(__obj, 'evalcontextfunction', 0):
args = (__self.eval_ctx,) + args
elif getattr(__obj, 'environmentfunction', 0):
args = (__self.environment,) + args
try:
return __obj(*args, **kwargs)
except StopIteration:
return __self.environment.undefined('value was undefined because '
'a callable raised a '
'StopIteration exception')
def derived(self, locals=None):
"""Internal helper function to create a derived context."""
context = new_context(self.environment, self.name, {},
self.parent, True, None, locals)
context.vars.update(self.vars)
context.eval_ctx = self.eval_ctx
context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks))
return context
def _all(meth):
proxy = lambda self: getattr(self.get_all(), meth)()
proxy.__doc__ = getattr(dict, meth).__doc__
proxy.__name__ = meth
return proxy
keys = _all('keys')
values = _all('values')
items = _all('items')
# not available on python 3
if PY2:
iterkeys = _all('iterkeys')
itervalues = _all('itervalues')
iteritems = _all('iteritems')
del _all
def __contains__(self, name):
return name in self.vars or name in self.parent
def __getitem__(self, key):
"""Lookup a variable or raise `KeyError` if the variable is
undefined.
"""
item = self.resolve(key)
if isinstance(item, Undefined):
raise KeyError(key)
return item
def __repr__(self):
return '<%s %s of %r>' % (
self.__class__.__name__,
repr(self.get_all()),
self.name
)
# register the context as mapping if possible
try:
from collections import Mapping
Mapping.register(Context)
except ImportError:
pass
class BlockReference(object):
"""One block on a template reference."""
def __init__(self, name, context, stack, depth):
self.name = name
self._context = context
self._stack = stack
self._depth = depth
@property
def super(self):
"""Super the block."""
if self._depth + 1 >= len(self._stack):
return self._context.environment. \
undefined('there is no parent block called %r.' %
self.name, name='super')
return BlockReference(self.name, self._context, self._stack,
self._depth + 1)
@internalcode
def __call__(self):
rv = concat(self._stack[self._depth](self._context))
if self._context.eval_ctx.autoescape:
rv = Markup(rv)
return rv
class LoopContext(object):
"""A loop context for dynamic iteration."""
def __init__(self, iterable, recurse=None, depth0=0):
self._iterator = iter(iterable)
self._recurse = recurse
self._after = self._safe_next()
self.index0 = -1
self.depth0 = depth0
# try to get the length of the iterable early. This must be done
# here because there are some broken iterators around where there
# __len__ is the number of iterations left (i'm looking at your
# listreverseiterator!).
try:
self._length = len(iterable)
except (TypeError, AttributeError):
self._length = None
def cycle(self, *args):
"""Cycles among the arguments with the current loop index."""
if not args:
raise TypeError('no items for cycling given')
return args[self.index0 % len(args)]
first = property(lambda x: x.index0 == 0)
last = property(lambda x: x._after is _last_iteration)
index = property(lambda x: x.index0 + 1)
revindex = property(lambda x: x.length - x.index0)
revindex0 = property(lambda x: x.length - x.index)
depth = property(lambda x: x.depth0 + 1)
def __len__(self):
return self.length
def __iter__(self):
return LoopContextIterator(self)
def _safe_next(self):
try:
return next(self._iterator)
except StopIteration:
return _last_iteration
@internalcode
def loop(self, iterable):
if self._recurse is None:
raise TypeError('Tried to call non recursive loop. Maybe you '
"forgot the 'recursive' modifier.")
return self._recurse(iterable, self._recurse, self.depth0 + 1)
# a nifty trick to enhance the error message if someone tried to call
# the the loop without or with too many arguments.
__call__ = loop
del loop
@property
def length(self):
if self._length is None:
# if was not possible to get the length of the iterator when
# the loop context was created (ie: iterating over a generator)
# we have to convert the iterable into a sequence and use the
# length of that.
iterable = tuple(self._iterator)
self._iterator = iter(iterable)
self._length = len(iterable) + self.index0 + 1
return self._length
def __repr__(self):
return '<%s %r/%r>' % (
self.__class__.__name__,
self.index,
self.length
)
@implements_iterator
class LoopContextIterator(object):
"""The iterator for a loop context."""
__slots__ = ('context',)
def __init__(self, context):
self.context = context
def __iter__(self):
return self
def __next__(self):
ctx = self.context
ctx.index0 += 1
if ctx._after is _last_iteration:
raise StopIteration()
next_elem = ctx._after
ctx._after = ctx._safe_next()
return next_elem, ctx
class Macro(object):
"""Wraps a macro function."""
def __init__(self, environment, func, name, arguments, defaults,
catch_kwargs, catch_varargs, caller):
self._environment = environment
self._func = func
self._argument_count = len(arguments)
self.name = name
self.arguments = arguments
self.defaults = defaults
self.catch_kwargs = catch_kwargs
self.catch_varargs = catch_varargs
self.caller = caller
@internalcode
def __call__(self, *args, **kwargs):
# try to consume the positional arguments
arguments = list(args[:self._argument_count])
off = len(arguments)
# if the number of arguments consumed is not the number of
# arguments expected we start filling in keyword arguments
# and defaults.
if off != self._argument_count:
for idx, name in enumerate(self.arguments[len(arguments):]):
try:
value = kwargs.pop(name)
except KeyError:
try:
value = self.defaults[idx - self._argument_count + off]
except IndexError:
value = self._environment.undefined(
'parameter %r was not provided' % name, name=name)
arguments.append(value)
# it's important that the order of these arguments does not change
# if not also changed in the compiler's `function_scoping` method.
# the order is caller, keyword arguments, positional arguments!
if self.caller:
caller = kwargs.pop('caller', None)
if caller is None:
caller = self._environment.undefined('No caller defined',
name='caller')
arguments.append(caller)
if self.catch_kwargs:
arguments.append(kwargs)
elif kwargs:
raise TypeError('macro %r takes no keyword argument %r' %
(self.name, next(iter(kwargs))))
if self.catch_varargs:
arguments.append(args[self._argument_count:])
elif len(args) > self._argument_count:
raise TypeError('macro %r takes not more than %d argument(s)' %
(self.name, len(self.arguments)))
return self._func(*arguments)
def __repr__(self):
return '<%s %s>' % (
self.__class__.__name__,
self.name is None and 'anonymous' or repr(self.name)
)
@implements_to_string
class Undefined(object):
"""The default undefined type. This undefined type can be printed and
iterated over, but every other access will raise an :exc:`UndefinedError`:
>>> foo = Undefined(name='foo')
>>> str(foo)
''
>>> not foo
True
>>> foo + 42
Traceback (most recent call last):
...
UndefinedError: 'foo' is undefined
"""
__slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
'_undefined_exception')
def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
self._undefined_hint = hint
self._undefined_obj = obj
self._undefined_name = name
self._undefined_exception = exc
@internalcode
def _fail_with_undefined_error(self, *args, **kwargs):
"""Regular callback function for undefined objects that raises an
`UndefinedError` on call.
"""
if self._undefined_hint is None:
if self._undefined_obj is missing:
hint = '%r is undefined' % self._undefined_name
elif not isinstance(self._undefined_name, string_types):
hint = '%s has no element %r' % (
object_type_repr(self._undefined_obj),
self._undefined_name
)
else:
hint = '%r has no attribute %r' % (
object_type_repr(self._undefined_obj),
self._undefined_name
)
else:
hint = self._undefined_hint
raise self._undefined_exception(hint)
@internalcode
def __getattr__(self, name):
if name[:2] == '__':
raise AttributeError(name)
return self._fail_with_undefined_error()
__add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
__truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
__mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
__getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \
__float__ = __complex__ = __pow__ = __rpow__ = \
_fail_with_undefined_error
def __eq__(self, other):
return type(self) is type(other)
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return id(type(self))
def __str__(self):
return u''
def __len__(self):
return 0
def __iter__(self):
if 0:
yield None
def __nonzero__(self):
return False
def __repr__(self):
return 'Undefined'
@implements_to_string
class DebugUndefined(Undefined):
"""An undefined that returns the debug info when printed.
>>> foo = DebugUndefined(name='foo')
>>> str(foo)
'{{ foo }}'
>>> not foo
True
>>> foo + 42
Traceback (most recent call last):
...
UndefinedError: 'foo' is undefined
"""
__slots__ = ()
def __str__(self):
if self._undefined_hint is None:
if self._undefined_obj is missing:
return u'{{ %s }}' % self._undefined_name
return '{{ no such element: %s[%r] }}' % (
object_type_repr(self._undefined_obj),
self._undefined_name
)
return u'{{ undefined value printed: %s }}' % self._undefined_hint
@implements_to_string
class StrictUndefined(Undefined):
"""An undefined that barks on print and iteration as well as boolean
tests and all kinds of comparisons. In other words: you can do nothing
with it except checking if it's defined using the `defined` test.
>>> foo = StrictUndefined(name='foo')
>>> str(foo)
Traceback (most recent call last):
...
UndefinedError: 'foo' is undefined
>>> not foo
Traceback (most recent call last):
...
UndefinedError: 'foo' is undefined
>>> foo + 42
Traceback (most recent call last):
...
UndefinedError: 'foo' is undefined
"""
__slots__ = ()
__iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \
__ne__ = __bool__ = __hash__ = \
Undefined._fail_with_undefined_error
# remove remaining slots attributes, after the metaclass did the magic they
# are unneeded and irritating as they contain wrong data for the subclasses.
del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__
-368
View File
@@ -1,368 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.sandbox
~~~~~~~~~~~~~~
Adds a sandbox layer to Jinja as it was the default behavior in the old
Jinja 1 releases. This sandbox is slightly different from Jinja 1 as the
default behavior is easier to use.
The behavior can be changed by subclassing the environment.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD.
"""
import operator
from jinja2.environment import Environment
from jinja2.exceptions import SecurityError
from jinja2._compat import string_types, function_type, method_type, \
traceback_type, code_type, frame_type, generator_type, PY2
#: maximum number of items a range may produce
MAX_RANGE = 100000
#: attributes of function objects that are considered unsafe.
UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
'func_defaults', 'func_globals'])
#: unsafe method attributes. function attributes are unsafe for methods too
UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
#: unsafe generator attirbutes.
UNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code'])
# On versions > python 2 the special attributes on functions are gone,
# but they remain on methods and generators for whatever reason.
if not PY2:
UNSAFE_FUNCTION_ATTRIBUTES = set()
import warnings
# make sure we don't warn in python 2.6 about stuff we don't care about
warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
module='jinja2.sandbox')
from collections import deque
_mutable_set_types = (set,)
_mutable_mapping_types = (dict,)
_mutable_sequence_types = (list,)
# on python 2.x we can register the user collection types
try:
from UserDict import UserDict, DictMixin
from UserList import UserList
_mutable_mapping_types += (UserDict, DictMixin)
_mutable_set_types += (UserList,)
except ImportError:
pass
# if sets is still available, register the mutable set from there as well
try:
from sets import Set
_mutable_set_types += (Set,)
except ImportError:
pass
#: register Python 2.6 abstract base classes
try:
from collections import MutableSet, MutableMapping, MutableSequence
_mutable_set_types += (MutableSet,)
_mutable_mapping_types += (MutableMapping,)
_mutable_sequence_types += (MutableSequence,)
except ImportError:
pass
_mutable_spec = (
(_mutable_set_types, frozenset([
'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
'symmetric_difference_update', 'update'
])),
(_mutable_mapping_types, frozenset([
'clear', 'pop', 'popitem', 'setdefault', 'update'
])),
(_mutable_sequence_types, frozenset([
'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
])),
(deque, frozenset([
'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
'popleft', 'remove', 'rotate'
]))
)
def safe_range(*args):
"""A range that can't generate ranges with a length of more than
MAX_RANGE items.
"""
rng = range(*args)
if len(rng) > MAX_RANGE:
raise OverflowError('range too big, maximum size for range is %d' %
MAX_RANGE)
return rng
def unsafe(f):
"""Marks a function or method as unsafe.
::
@unsafe
def delete(self):
pass
"""
f.unsafe_callable = True
return f
def is_internal_attribute(obj, attr):
"""Test if the attribute given is an internal python attribute. For
example this function returns `True` for the `func_code` attribute of
python objects. This is useful if the environment method
:meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
>>> from jinja2.sandbox import is_internal_attribute
>>> is_internal_attribute(lambda: None, "func_code")
True
>>> is_internal_attribute((lambda x:x).func_code, 'co_code')
True
>>> is_internal_attribute(str, "upper")
False
"""
if isinstance(obj, function_type):
if attr in UNSAFE_FUNCTION_ATTRIBUTES:
return True
elif isinstance(obj, method_type):
if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
attr in UNSAFE_METHOD_ATTRIBUTES:
return True
elif isinstance(obj, type):
if attr == 'mro':
return True
elif isinstance(obj, (code_type, traceback_type, frame_type)):
return True
elif isinstance(obj, generator_type):
if attr in UNSAFE_GENERATOR_ATTRIBUTES:
return True
return attr.startswith('__')
def modifies_known_mutable(obj, attr):
"""This function checks if an attribute on a builtin mutable object
(list, dict, set or deque) would modify it if called. It also supports
the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
with Python 2.6 onwards the abstract base classes `MutableSet`,
`MutableMapping`, and `MutableSequence`.
>>> modifies_known_mutable({}, "clear")
True
>>> modifies_known_mutable({}, "keys")
False
>>> modifies_known_mutable([], "append")
True
>>> modifies_known_mutable([], "index")
False
If called with an unsupported object (such as unicode) `False` is
returned.
>>> modifies_known_mutable("foo", "upper")
False
"""
for typespec, unsafe in _mutable_spec:
if isinstance(obj, typespec):
return attr in unsafe
return False
class SandboxedEnvironment(Environment):
"""The sandboxed environment. It works like the regular environment but
tells the compiler to generate sandboxed code. Additionally subclasses of
this environment may override the methods that tell the runtime what
attributes or functions are safe to access.
If the template tries to access insecure code a :exc:`SecurityError` is
raised. However also other exceptions may occour during the rendering so
the caller has to ensure that all exceptions are catched.
"""
sandboxed = True
#: default callback table for the binary operators. A copy of this is
#: available on each instance of a sandboxed environment as
#: :attr:`binop_table`
default_binop_table = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv,
'//': operator.floordiv,
'**': operator.pow,
'%': operator.mod
}
#: default callback table for the unary operators. A copy of this is
#: available on each instance of a sandboxed environment as
#: :attr:`unop_table`
default_unop_table = {
'+': operator.pos,
'-': operator.neg
}
#: a set of binary operators that should be intercepted. Each operator
#: that is added to this set (empty by default) is delegated to the
#: :meth:`call_binop` method that will perform the operator. The default
#: operator callback is specified by :attr:`binop_table`.
#:
#: The following binary operators are interceptable:
#: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
#:
#: The default operation form the operator table corresponds to the
#: builtin function. Intercepted calls are always slower than the native
#: operator call, so make sure only to intercept the ones you are
#: interested in.
#:
#: .. versionadded:: 2.6
intercepted_binops = frozenset()
#: a set of unary operators that should be intercepted. Each operator
#: that is added to this set (empty by default) is delegated to the
#: :meth:`call_unop` method that will perform the operator. The default
#: operator callback is specified by :attr:`unop_table`.
#:
#: The following unary operators are interceptable: ``+``, ``-``
#:
#: The default operation form the operator table corresponds to the
#: builtin function. Intercepted calls are always slower than the native
#: operator call, so make sure only to intercept the ones you are
#: interested in.
#:
#: .. versionadded:: 2.6
intercepted_unops = frozenset()
def intercept_unop(self, operator):
"""Called during template compilation with the name of a unary
operator to check if it should be intercepted at runtime. If this
method returns `True`, :meth:`call_unop` is excuted for this unary
operator. The default implementation of :meth:`call_unop` will use
the :attr:`unop_table` dictionary to perform the operator with the
same logic as the builtin one.
The following unary operators are interceptable: ``+`` and ``-``
Intercepted calls are always slower than the native operator call,
so make sure only to intercept the ones you are interested in.
.. versionadded:: 2.6
"""
return False
def __init__(self, *args, **kwargs):
Environment.__init__(self, *args, **kwargs)
self.globals['range'] = safe_range
self.binop_table = self.default_binop_table.copy()
self.unop_table = self.default_unop_table.copy()
def is_safe_attribute(self, obj, attr, value):
"""The sandboxed environment will call this method to check if the
attribute of an object is safe to access. Per default all attributes
starting with an underscore are considered private as well as the
special attributes of internal python objects as returned by the
:func:`is_internal_attribute` function.
"""
return not (attr.startswith('_') or is_internal_attribute(obj, attr))
def is_safe_callable(self, obj):
"""Check if an object is safely callable. Per default a function is
considered safe unless the `unsafe_callable` attribute exists and is
True. Override this method to alter the behavior, but this won't
affect the `unsafe` decorator from this module.
"""
return not (getattr(obj, 'unsafe_callable', False) or
getattr(obj, 'alters_data', False))
def call_binop(self, context, operator, left, right):
"""For intercepted binary operator calls (:meth:`intercepted_binops`)
this function is executed instead of the builtin operator. This can
be used to fine tune the behavior of certain operators.
.. versionadded:: 2.6
"""
return self.binop_table[operator](left, right)
def call_unop(self, context, operator, arg):
"""For intercepted unary operator calls (:meth:`intercepted_unops`)
this function is executed instead of the builtin operator. This can
be used to fine tune the behavior of certain operators.
.. versionadded:: 2.6
"""
return self.unop_table[operator](arg)
def getitem(self, obj, argument):
"""Subscribe an object from sandboxed code."""
try:
return obj[argument]
except (TypeError, LookupError):
if isinstance(argument, string_types):
try:
attr = str(argument)
except Exception:
pass
else:
try:
value = getattr(obj, attr)
except AttributeError:
pass
else:
if self.is_safe_attribute(obj, argument, value):
return value
return self.unsafe_undefined(obj, argument)
return self.undefined(obj=obj, name=argument)
def getattr(self, obj, attribute):
"""Subscribe an object from sandboxed code and prefer the
attribute. The attribute passed *must* be a bytestring.
"""
try:
value = getattr(obj, attribute)
except AttributeError:
try:
return obj[attribute]
except (TypeError, LookupError):
pass
else:
if self.is_safe_attribute(obj, attribute, value):
return value
return self.unsafe_undefined(obj, attribute)
return self.undefined(obj=obj, name=attribute)
def unsafe_undefined(self, obj, attribute):
"""Return an undefined object for unsafe attributes."""
return self.undefined('access to attribute %r of %r '
'object is unsafe.' % (
attribute,
obj.__class__.__name__
), name=attribute, obj=obj, exc=SecurityError)
def call(__self, __context, __obj, *args, **kwargs):
"""Call an object from sandboxed code."""
# the double prefixes are to avoid double keyword argument
# errors when proxying the call.
if not __self.is_safe_callable(__obj):
raise SecurityError('%r is not safely callable' % (__obj,))
return __context.call(__obj, *args, **kwargs)
class ImmutableSandboxedEnvironment(SandboxedEnvironment):
"""Works exactly like the regular `SandboxedEnvironment` but does not
permit modifications on the builtin mutable objects `list`, `set`, and
`dict` by using the :func:`modifies_known_mutable` function.
"""
def is_safe_attribute(self, obj, attr, value):
if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
return False
return not modifies_known_mutable(obj, attr)
-149
View File
@@ -1,149 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.tests
~~~~~~~~~~~~
Jinja test functions. Used with the "is" operator.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
import re
from jinja2.runtime import Undefined
from jinja2._compat import text_type, string_types, mapping_types
number_re = re.compile(r'^-?\d+(\.\d+)?$')
regex_type = type(number_re)
test_callable = callable
def test_odd(value):
"""Return true if the variable is odd."""
return value % 2 == 1
def test_even(value):
"""Return true if the variable is even."""
return value % 2 == 0
def test_divisibleby(value, num):
"""Check if a variable is divisible by a number."""
return value % num == 0
def test_defined(value):
"""Return true if the variable is defined:
.. sourcecode:: jinja
{% if variable is defined %}
value of variable: {{ variable }}
{% else %}
variable is not defined
{% endif %}
See the :func:`default` filter for a simple way to set undefined
variables.
"""
return not isinstance(value, Undefined)
def test_undefined(value):
"""Like :func:`defined` but the other way round."""
return isinstance(value, Undefined)
def test_none(value):
"""Return true if the variable is none."""
return value is None
def test_lower(value):
"""Return true if the variable is lowercased."""
return text_type(value).islower()
def test_upper(value):
"""Return true if the variable is uppercased."""
return text_type(value).isupper()
def test_string(value):
"""Return true if the object is a string."""
return isinstance(value, string_types)
def test_mapping(value):
"""Return true if the object is a mapping (dict etc.).
.. versionadded:: 2.6
"""
return isinstance(value, mapping_types)
def test_number(value):
"""Return true if the variable is a number."""
return isinstance(value, (int, float, complex))
def test_sequence(value):
"""Return true if the variable is a sequence. Sequences are variables
that are iterable.
"""
try:
len(value)
value.__getitem__
except:
return False
return True
def test_sameas(value, other):
"""Check if an object points to the same memory address than another
object:
.. sourcecode:: jinja
{% if foo.attribute is sameas false %}
the foo attribute really is the `False` singleton
{% endif %}
"""
return value is other
def test_iterable(value):
"""Check if it's possible to iterate over an object."""
try:
iter(value)
except TypeError:
return False
return True
def test_escaped(value):
"""Check if the value is escaped."""
return hasattr(value, '__html__')
TESTS = {
'odd': test_odd,
'even': test_even,
'divisibleby': test_divisibleby,
'defined': test_defined,
'undefined': test_undefined,
'none': test_none,
'lower': test_lower,
'upper': test_upper,
'string': test_string,
'mapping': test_mapping,
'number': test_number,
'sequence': test_sequence,
'iterable': test_iterable,
'callable': test_callable,
'sameas': test_sameas,
'escaped': test_escaped
}
-520
View File
@@ -1,520 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.utils
~~~~~~~~~~~~
Utility functions.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
import re
import errno
from collections import deque
from jinja2._compat import text_type, string_types, implements_iterator, \
allocate_lock, url_quote
_word_split_re = re.compile(r'(\s+)')
_punctuation_re = re.compile(
'^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
'|'.join(map(re.escape, ('(', '<', '&lt;'))),
'|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
)
)
_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
_entity_re = re.compile(r'&([^;]+);')
_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
_digits = '0123456789'
# special singleton representing missing values for the runtime
missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
# internal code
internal_code = set()
concat = u''.join
def contextfunction(f):
"""This decorator can be used to mark a function or method context callable.
A context callable is passed the active :class:`Context` as first argument when
called from the template. This is useful if a function wants to get access
to the context or functions provided on the context object. For example
a function that returns a sorted list of template variables the current
template exports could look like this::
@contextfunction
def get_exported_names(context):
return sorted(context.exported_vars)
"""
f.contextfunction = True
return f
def evalcontextfunction(f):
"""This decorator can be used to mark a function or method as an eval
context callable. This is similar to the :func:`contextfunction`
but instead of passing the context, an evaluation context object is
passed. For more information about the eval context, see
:ref:`eval-context`.
.. versionadded:: 2.4
"""
f.evalcontextfunction = True
return f
def environmentfunction(f):
"""This decorator can be used to mark a function or method as environment
callable. This decorator works exactly like the :func:`contextfunction`
decorator just that the first argument is the active :class:`Environment`
and not context.
"""
f.environmentfunction = True
return f
def internalcode(f):
"""Marks the function as internally used"""
internal_code.add(f.__code__)
return f
def is_undefined(obj):
"""Check if the object passed is undefined. This does nothing more than
performing an instance check against :class:`Undefined` but looks nicer.
This can be used for custom filters or tests that want to react to
undefined variables. For example a custom default filter can look like
this::
def default(var, default=''):
if is_undefined(var):
return default
return var
"""
from jinja2.runtime import Undefined
return isinstance(obj, Undefined)
def consume(iterable):
"""Consumes an iterable without doing anything with it."""
for event in iterable:
pass
def clear_caches():
"""Jinja2 keeps internal caches for environments and lexers. These are
used so that Jinja2 doesn't have to recreate environments and lexers all
the time. Normally you don't have to care about that but if you are
messuring memory consumption you may want to clean the caches.
"""
from jinja2.environment import _spontaneous_environments
from jinja2.lexer import _lexer_cache
_spontaneous_environments.clear()
_lexer_cache.clear()
def import_string(import_name, silent=False):
"""Imports an object based on a string. This is useful if you want to
use import paths as endpoints or something similar. An import path can
be specified either in dotted notation (``xml.sax.saxutils.escape``)
or with a colon as object delimiter (``xml.sax.saxutils:escape``).
If the `silent` is True the return value will be `None` if the import
fails.
:return: imported object
"""
try:
if ':' in import_name:
module, obj = import_name.split(':', 1)
elif '.' in import_name:
items = import_name.split('.')
module = '.'.join(items[:-1])
obj = items[-1]
else:
return __import__(import_name)
return getattr(__import__(module, None, None, [obj]), obj)
except (ImportError, AttributeError):
if not silent:
raise
def open_if_exists(filename, mode='rb'):
"""Returns a file descriptor for the filename if that file exists,
otherwise `None`.
"""
try:
return open(filename, mode)
except IOError as e:
if e.errno not in (errno.ENOENT, errno.EISDIR):
raise
def object_type_repr(obj):
"""Returns the name of the object's type. For some recognized
singletons the name of the object is returned instead. (For
example for `None` and `Ellipsis`).
"""
if obj is None:
return 'None'
elif obj is Ellipsis:
return 'Ellipsis'
# __builtin__ in 2.x, builtins in 3.x
if obj.__class__.__module__ in ('__builtin__', 'builtins'):
name = obj.__class__.__name__
else:
name = obj.__class__.__module__ + '.' + obj.__class__.__name__
return '%s object' % name
def pformat(obj, verbose=False):
"""Prettyprint an object. Either use the `pretty` library or the
builtin `pprint`.
"""
try:
from pretty import pretty
return pretty(obj, verbose=verbose)
except ImportError:
from pprint import pformat
return pformat(obj)
def urlize(text, trim_url_limit=None, nofollow=False):
"""Converts any URLs in text into clickable links. Works on http://,
https:// and www. links. Links can have trailing punctuation (periods,
commas, close-parens) and leading punctuation (opening parens) and
it'll still do the right thing.
If trim_url_limit is not None, the URLs in link text will be limited
to trim_url_limit characters.
If nofollow is True, the URLs in link text will get a rel="nofollow"
attribute.
"""
trim_url = lambda x, limit=trim_url_limit: limit is not None \
and (x[:limit] + (len(x) >=limit and '...'
or '')) or x
words = _word_split_re.split(text_type(escape(text)))
nofollow_attr = nofollow and ' rel="nofollow"' or ''
for i, word in enumerate(words):
match = _punctuation_re.match(word)
if match:
lead, middle, trail = match.groups()
if middle.startswith('www.') or (
'@' not in middle and
not middle.startswith('http://') and
not middle.startswith('https://') and
len(middle) > 0 and
middle[0] in _letters + _digits and (
middle.endswith('.org') or
middle.endswith('.net') or
middle.endswith('.com')
)):
middle = '<a href="http://%s"%s>%s</a>' % (middle,
nofollow_attr, trim_url(middle))
if middle.startswith('http://') or \
middle.startswith('https://'):
middle = '<a href="%s"%s>%s</a>' % (middle,
nofollow_attr, trim_url(middle))
if '@' in middle and not middle.startswith('www.') and \
not ':' in middle and _simple_email_re.match(middle):
middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
if lead + middle + trail != word:
words[i] = lead + middle + trail
return u''.join(words)
def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
"""Generate some lorem impsum for the template."""
from jinja2.constants import LOREM_IPSUM_WORDS
from random import choice, randrange
words = LOREM_IPSUM_WORDS.split()
result = []
for _ in range(n):
next_capitalized = True
last_comma = last_fullstop = 0
word = None
last = None
p = []
# each paragraph contains out of 20 to 100 words.
for idx, _ in enumerate(range(randrange(min, max))):
while True:
word = choice(words)
if word != last:
last = word
break
if next_capitalized:
word = word.capitalize()
next_capitalized = False
# add commas
if idx - randrange(3, 8) > last_comma:
last_comma = idx
last_fullstop += 2
word += ','
# add end of sentences
if idx - randrange(10, 20) > last_fullstop:
last_comma = last_fullstop = idx
word += '.'
next_capitalized = True
p.append(word)
# ensure that the paragraph ends with a dot.
p = u' '.join(p)
if p.endswith(','):
p = p[:-1] + '.'
elif not p.endswith('.'):
p += '.'
result.append(p)
if not html:
return u'\n\n'.join(result)
return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
def unicode_urlencode(obj, charset='utf-8'):
"""URL escapes a single bytestring or unicode string with the
given charset if applicable to URL safe quoting under all rules
that need to be considered under all supported Python versions.
If non strings are provided they are converted to their unicode
representation first.
"""
if not isinstance(obj, string_types):
obj = text_type(obj)
if isinstance(obj, text_type):
obj = obj.encode(charset)
return text_type(url_quote(obj))
class LRUCache(object):
"""A simple LRU Cache implementation."""
# this is fast for small capacities (something below 1000) but doesn't
# scale. But as long as it's only used as storage for templates this
# won't do any harm.
def __init__(self, capacity):
self.capacity = capacity
self._mapping = {}
self._queue = deque()
self._postinit()
def _postinit(self):
# alias all queue methods for faster lookup
self._popleft = self._queue.popleft
self._pop = self._queue.pop
self._remove = self._queue.remove
self._wlock = allocate_lock()
self._append = self._queue.append
def __getstate__(self):
return {
'capacity': self.capacity,
'_mapping': self._mapping,
'_queue': self._queue
}
def __setstate__(self, d):
self.__dict__.update(d)
self._postinit()
def __getnewargs__(self):
return (self.capacity,)
def copy(self):
"""Return a shallow copy of the instance."""
rv = self.__class__(self.capacity)
rv._mapping.update(self._mapping)
rv._queue = deque(self._queue)
return rv
def get(self, key, default=None):
"""Return an item from the cache dict or `default`"""
try:
return self[key]
except KeyError:
return default
def setdefault(self, key, default=None):
"""Set `default` if the key is not in the cache otherwise
leave unchanged. Return the value of this key.
"""
self._wlock.acquire()
try:
try:
return self[key]
except KeyError:
self[key] = default
return default
finally:
self._wlock.release()
def clear(self):
"""Clear the cache."""
self._wlock.acquire()
try:
self._mapping.clear()
self._queue.clear()
finally:
self._wlock.release()
def __contains__(self, key):
"""Check if a key exists in this cache."""
return key in self._mapping
def __len__(self):
"""Return the current size of the cache."""
return len(self._mapping)
def __repr__(self):
return '<%s %r>' % (
self.__class__.__name__,
self._mapping
)
def __getitem__(self, key):
"""Get an item from the cache. Moves the item up so that it has the
highest priority then.
Raise a `KeyError` if it does not exist.
"""
self._wlock.acquire()
try:
rv = self._mapping[key]
if self._queue[-1] != key:
try:
self._remove(key)
except ValueError:
# if something removed the key from the container
# when we read, ignore the ValueError that we would
# get otherwise.
pass
self._append(key)
return rv
finally:
self._wlock.release()
def __setitem__(self, key, value):
"""Sets the value for an item. Moves the item up so that it
has the highest priority then.
"""
self._wlock.acquire()
try:
if key in self._mapping:
self._remove(key)
elif len(self._mapping) == self.capacity:
del self._mapping[self._popleft()]
self._append(key)
self._mapping[key] = value
finally:
self._wlock.release()
def __delitem__(self, key):
"""Remove an item from the cache dict.
Raise a `KeyError` if it does not exist.
"""
self._wlock.acquire()
try:
del self._mapping[key]
try:
self._remove(key)
except ValueError:
# __getitem__ is not locked, it might happen
pass
finally:
self._wlock.release()
def items(self):
"""Return a list of items."""
result = [(key, self._mapping[key]) for key in list(self._queue)]
result.reverse()
return result
def iteritems(self):
"""Iterate over all items."""
return iter(self.items())
def values(self):
"""Return a list of all values."""
return [x[1] for x in self.items()]
def itervalue(self):
"""Iterate over all values."""
return iter(self.values())
def keys(self):
"""Return a list of all keys ordered by most recent usage."""
return list(self)
def iterkeys(self):
"""Iterate over all keys in the cache dict, ordered by
the most recent usage.
"""
return reversed(tuple(self._queue))
__iter__ = iterkeys
def __reversed__(self):
"""Iterate over the values in the cache dict, oldest items
coming first.
"""
return iter(tuple(self._queue))
__copy__ = copy
# register the LRU cache as mutable mapping if possible
try:
from collections import MutableMapping
MutableMapping.register(LRUCache)
except ImportError:
pass
@implements_iterator
class Cycler(object):
"""A cycle helper for templates."""
def __init__(self, *items):
if not items:
raise RuntimeError('at least one item has to be provided')
self.items = items
self.reset()
def reset(self):
"""Resets the cycle."""
self.pos = 0
@property
def current(self):
"""Returns the current item."""
return self.items[self.pos]
def __next__(self):
"""Goes one item ahead and returns it."""
rv = self.current
self.pos = (self.pos + 1) % len(self.items)
return rv
class Joiner(object):
"""A joining helper for templates."""
def __init__(self, sep=u', '):
self.sep = sep
self.used = False
def __call__(self):
if not self.used:
self.used = True
return u''
return self.sep
# Imported here because that's where it was in the past
from .markupsafe import Markup, escape, soft_unicode
-87
View File
@@ -1,87 +0,0 @@
# -*- coding: utf-8 -*-
"""
jinja2.visitor
~~~~~~~~~~~~~~
This module implements a visitor for the nodes.
:copyright: (c) 2010 by the Jinja Team.
:license: BSD.
"""
from jinja2.nodes import Node
class NodeVisitor(object):
"""Walks the abstract syntax tree and call visitor functions for every
node found. The visitor functions may return values which will be
forwarded by the `visit` method.
Per default the visitor functions for the nodes are ``'visit_'`` +
class name of the node. So a `TryFinally` node visit function would
be `visit_TryFinally`. This behavior can be changed by overriding
the `get_visitor` function. If no visitor function exists for a node
(return value `None`) the `generic_visit` visitor is used instead.
"""
def get_visitor(self, node):
"""Return the visitor function for this node or `None` if no visitor
exists for this node. In that case the generic visit function is
used instead.
"""
method = 'visit_' + node.__class__.__name__
return getattr(self, method, None)
def visit(self, node, *args, **kwargs):
"""Visit a node."""
f = self.get_visitor(node)
if f is not None:
return f(node, *args, **kwargs)
return self.generic_visit(node, *args, **kwargs)
def generic_visit(self, node, *args, **kwargs):
"""Called if no explicit visitor function exists for a node."""
for node in node.iter_child_nodes():
self.visit(node, *args, **kwargs)
class NodeTransformer(NodeVisitor):
"""Walks the abstract syntax tree and allows modifications of nodes.
The `NodeTransformer` will walk the AST and use the return value of the
visitor functions to replace or remove the old node. If the return
value of the visitor function is `None` the node will be removed
from the previous location otherwise it's replaced with the return
value. The return value may be the original node in which case no
replacement takes place.
"""
def generic_visit(self, node, *args, **kwargs):
for field, old_value in node.iter_fields():
if isinstance(old_value, list):
new_values = []
for value in old_value:
if isinstance(value, Node):
value = self.visit(value, *args, **kwargs)
if value is None:
continue
elif not isinstance(value, Node):
new_values.extend(value)
continue
new_values.append(value)
old_value[:] = new_values
elif isinstance(old_value, Node):
new_node = self.visit(old_value, *args, **kwargs)
if new_node is None:
delattr(node, field)
else:
setattr(node, field, new_node)
return node
def visit_list(self, node, *args, **kwargs):
"""As transformers may return lists in some places this method
can be used to enforce a list as return value.
"""
rv = self.visit(node, *args, **kwargs)
if not isinstance(rv, list):
rv = [rv]
return rv
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -2
View File
@@ -24,8 +24,7 @@ if(WIN32 AND NOT MINGW)
endif(WIN32 AND NOT MINGW)
ocv_warnings_disable(CMAKE_C_FLAGS -Wno-implicit-function-declaration -Wno-uninitialized -Wmissing-prototypes
-Wno-unused-but-set-parameter -Wmissing-declarations -Wunused -Wshadow
-Wsign-compare -Wstrict-overflow)
-Wno-unused-but-set-parameter -Wmissing-declarations -Wunused -Wshadow -Wsign-compare)
ocv_warnings_disable(CMAKE_C_FLAGS -Wunused-parameter) # clang
ocv_warnings_disable(CMAKE_C_FLAGS /wd4013 /wd4018 /wd4101 /wd4244 /wd4267 /wd4715) # vs2005
+1
View File
@@ -842,6 +842,7 @@ static int jas_cmshapmat_apply(jas_cmpxform_t *pxform, jas_cmreal_t *in,
*dst++ = a2;
}
} else {
assert(0);
while (--cnt >= 0) {
a0 = *src++;
src++;
+2 -5
View File
@@ -345,7 +345,6 @@ jas_stream_t *jas_stream_tmpfile()
{
jas_stream_t *stream;
jas_stream_fileobj_t *obj;
char *tmpname;
if (!(stream = jas_stream_create())) {
return 0;
@@ -366,12 +365,10 @@ jas_stream_t *jas_stream_tmpfile()
#ifdef _WIN32
/* Choose a file name. */
tmpname = tempnam(NULL, NULL);
strcpy(obj->pathname, tmpname);
free(tmpname);
tmpnam(obj->pathname);
/* Open the underlying file. */
if ((obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY | O_TEMPORARY | _O_SHORT_LIVED,
if ((obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY,
JAS_STREAM_PERMS)) < 0) {
jas_stream_destroy(stream);
return 0;
-14
View File
@@ -9,19 +9,6 @@ ocv_include_directories(${CMAKE_CURRENT_SOURCE_DIR})
file(GLOB lib_srcs *.c)
file(GLOB lib_hdrs *.h)
if(ANDROID OR IOS OR APPLE)
ocv_list_filterout(lib_srcs jmemansi.c)
else()
ocv_list_filterout(lib_srcs jmemnobs.c)
endif()
if(WINRT)
add_definitions(-DNO_GETENV)
get_directory_property( DirDefs COMPILE_DEFINITIONS )
message(STATUS "Adding NO_GETENV to compiler definitions for WINRT:")
message(STATUS " COMPILE_DEFINITIONS = ${DirDefs}")
endif()
# ----------------------------------------------------------------------------------
# Define the library target:
# ----------------------------------------------------------------------------------
@@ -40,7 +27,6 @@ endif()
ocv_warnings_disable(CMAKE_C_FLAGS -Wcast-align -Wshadow -Wunused)
ocv_warnings_disable(CMAKE_C_FLAGS -Wunused-parameter) # clang
ocv_warnings_disable(CMAKE_C_FLAGS /wd4013 /wd4244 /wd4267) # vs2005
set_target_properties(${JPEG_LIBRARY}
PROPERTIES OUTPUT_NAME ${JPEG_LIBRARY}
+178 -143
View File
@@ -1,20 +1,24 @@
The Independent JPEG Group's JPEG software
==========================================
README for release 9 of 13-Jan-2013
===================================
README for release 6b of 27-Mar-1998
====================================
This distribution contains the ninth public release of the Independent JPEG
This distribution contains the sixth public release of the Independent JPEG
Group's free JPEG software. You are welcome to redistribute this software and
to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,
Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,
Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,
and other members of the Independent JPEG Group.
Serious users of this software (particularly those incorporating it into
larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to
our electronic mailing list. Mailing list members are notified of updates
and have a chance to participate in technical discussions, etc.
IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee
(also known as JPEG, together with ITU-T SG16).
This software is the work of Tom Lane, Philip Gladstone, Jim Boucher,
Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi,
Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG
Group.
IJG is not affiliated with the official ISO JPEG standards committee.
DOCUMENTATION ROADMAP
@@ -26,27 +30,27 @@ OVERVIEW General description of JPEG and the IJG software.
LEGAL ISSUES Copyright, lack of warranty, terms of distribution.
REFERENCES Where to learn more about JPEG.
ARCHIVE LOCATIONS Where to find newer versions of this software.
ACKNOWLEDGMENTS Special thanks.
RELATED SOFTWARE Other stuff you should get.
FILE FORMAT WARS Software *not* to get.
TO DO Plans for future IJG releases.
Other documentation files in the distribution are:
User documentation:
install.txt How to configure and install the IJG software.
usage.txt Usage instructions for cjpeg, djpeg, jpegtran,
install.doc How to configure and install the IJG software.
usage.doc Usage instructions for cjpeg, djpeg, jpegtran,
rdjpgcom, and wrjpgcom.
*.1 Unix-style man pages for programs (same info as usage.txt).
wizard.txt Advanced usage instructions for JPEG wizards only.
*.1 Unix-style man pages for programs (same info as usage.doc).
wizard.doc Advanced usage instructions for JPEG wizards only.
change.log Version-to-version change highlights.
Programmer and internal documentation:
libjpeg.txt How to use the JPEG library in your own programs.
libjpeg.doc How to use the JPEG library in your own programs.
example.c Sample code for calling the JPEG library.
structure.txt Overview of the JPEG library's internal structure.
filelist.txt Road map of IJG files.
coderules.txt Coding style rules --- please read if you contribute code.
structure.doc Overview of the JPEG library's internal structure.
filelist.doc Road map of IJG files.
coderules.doc Coding style rules --- please read if you contribute code.
Please read at least the files install.txt and usage.txt. Some information
Please read at least the files install.doc and usage.doc. Useful information
can also be found in the JPEG FAQ (Frequently Asked Questions) article. See
ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
@@ -58,15 +62,24 @@ the order listed) before diving into the code.
OVERVIEW
========
This package contains C software to implement JPEG image encoding, decoding,
and transcoding. JPEG (pronounced "jay-peg") is a standardized compression
method for full-color and gray-scale images.
This package contains C software to implement JPEG image compression and
decompression. JPEG (pronounced "jay-peg") is a standardized compression
method for full-color and gray-scale images. JPEG is intended for compressing
"real-world" scenes; line drawings, cartoons and other non-realistic images
are not its strong suit. JPEG is lossy, meaning that the output image is not
exactly identical to the input image. Hence you must not use JPEG if you
have to have identical output bits. However, on typical photographic images,
very good compression levels can be obtained with no visible change, and
remarkably high compression levels are possible if you can tolerate a
low-quality image. For more details, see the references, or just experiment
with various compression settings.
This software implements JPEG baseline, extended-sequential, and progressive
compression processes. Provision is made for supporting all variants of these
processes, although some uncommon parameter settings aren't implemented yet.
We have made no provision for supporting the hierarchical or lossless
processes defined in the standard.
For legal reasons, we are not distributing code for the arithmetic-coding
variants of JPEG; see LEGAL ISSUES. We have made no provision for supporting
the hierarchical or lossless processes defined in the standard.
We provide a set of library routines for reading and writing JPEG image files,
plus two sample applications "cjpeg" and "djpeg", which use the library to
@@ -78,11 +91,10 @@ considerable functionality beyond the bare JPEG coding/decoding capability;
for example, the color quantization modules are not strictly part of JPEG
decoding, but they are essential for output to colormapped file formats or
colormapped displays. These extra functions can be compiled out of the
library if not required for a particular application.
We have also included "jpegtran", a utility for lossless transcoding between
different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
applications for inserting and extracting textual comments in JFIF files.
library if not required for a particular application. We have also included
"jpegtran", a utility for lossless transcoding between different JPEG
processes, and "rdjpgcom" and "wrjpgcom", two simple applications for
inserting and extracting textual comments in JFIF files.
The emphasis in designing this software has been on achieving portability and
flexibility, while also making it fast enough to be useful. In particular,
@@ -115,7 +127,7 @@ with respect to this software, its quality, accuracy, merchantability, or
fitness for a particular purpose. This software is provided "AS IS", and you,
its user, assume the entire risk as to its quality and accuracy.
This software is copyright (C) 1991-2013, Thomas G. Lane, Guido Vollbeding.
This software is copyright (C) 1991-1998, Thomas G. Lane.
All Rights Reserved except as specified below.
Permission is hereby granted to use, copy, modify, and distribute this
@@ -146,11 +158,29 @@ commercial products, provided that all warranty or liability claims are
assumed by the product vendor.
ansi2knr.c is included in this distribution by permission of L. Peter Deutsch,
sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA.
ansi2knr.c is NOT covered by the above copyright and conditions, but instead
by the usual distribution terms of the Free Software Foundation; principally,
that you must include source code if you redistribute it. (See the file
ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part
of any program generated from the IJG code, this does not limit you more than
the foregoing paragraphs do.
The Unix configuration script "configure" was produced with GNU Autoconf.
It is copyright by the Free Software Foundation but is freely distributable.
The same holds for its supporting scripts (config.guess, config.sub,
ltmain.sh). Another support script, install-sh, is copyright by X Consortium
but is also freely distributable.
ltconfig, ltmain.sh). Another support script, install-sh, is copyright
by M.I.T. but is also freely distributable.
It appears that the arithmetic coding option of the JPEG spec is covered by
patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot
legally be used without obtaining one or more licenses. For this reason,
support for arithmetic coding has been removed from the free JPEG software.
(Since arithmetic coding provides only a marginal gain over the unpatented
Huffman mode, it is unlikely that very many implementations will support it.)
So far as we are aware, there are no patent restrictions on the remaining
code.
The IJG distribution formerly included code to read and write GIF files.
To avoid entanglement with the Unisys LZW patent, GIF reading support has
@@ -168,7 +198,7 @@ We are required to state that
REFERENCES
==========
We recommend reading one or more of these references before trying to
We highly recommend reading one or more of these references before trying to
understand the innards of the JPEG software.
The best short technical introduction to the JPEG compression algorithm is
@@ -177,7 +207,7 @@ The best short technical introduction to the JPEG compression algorithm is
(Adjacent articles in that issue discuss MPEG motion picture compression,
applications of JPEG, and related topics.) If you don't have the CACM issue
handy, a PostScript file containing a revised version of Wallace's article is
available at http://www.ijg.org/files/wallace.ps.gz. The file (actually
available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz. The file (actually
a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
omits the sample images that appeared in CACM, but it includes corrections
and some added material. Note: the Wallace article is copyright ACM and IEEE,
@@ -192,71 +222,82 @@ code but don't know much about data compression in general. The book's JPEG
sample code is far from industrial-strength, but when you are ready to look
at a full implementation, you've got one here...
The best currently available description of JPEG is the textbook "JPEG Still
Image Data Compression Standard" by William B. Pennebaker and Joan L.
Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG
standards (DIS 10918-1 and draft DIS 10918-2).
Although this is by far the most detailed and comprehensive exposition of
JPEG publicly available, we point out that it is still missing an explanation
of the most essential properties and algorithms of the underlying DCT
technology.
If you think that you know about DCT-based JPEG after reading this book,
then you are in delusion. The real fundamentals and corresponding potential
of DCT-based JPEG are not publicly known so far, and that is the reason for
all the mistaken developments taking place in the image coding domain.
The best full description of JPEG is the textbook "JPEG Still Image Data
Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published
by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp.
The book includes the complete text of the ISO JPEG standards (DIS 10918-1
and draft DIS 10918-2). This is by far the most complete exposition of JPEG
in existence, and we highly recommend it.
The original JPEG standard is divided into two parts, Part 1 being the actual
specification, while Part 2 covers compliance testing methods. Part 1 is
titled "Digital Compression and Coding of Continuous-tone Still Images,
The JPEG standard itself is not available electronically; you must order a
paper copy through ISO or ITU. (Unless you feel a need to own a certified
official copy, we recommend buying the Pennebaker and Mitchell book instead;
it's much cheaper and includes a great deal of useful explanatory material.)
In the USA, copies of the standard may be ordered from ANSI Sales at (212)
642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI
doesn't take credit card orders, but Global does.) It's not cheap: as of
1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7%
shipping/handling. The standard is divided into two parts, Part 1 being the
actual specification, while Part 2 covers compliance testing methods. Part 1
is titled "Digital Compression and Coding of Continuous-tone Still Images,
Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of
Continuous-tone Still Images, Part 2: Compliance testing" and has document
numbers ISO/IEC IS 10918-2, ITU-T T.83.
IJG JPEG 8 introduced an implementation of the JPEG SmartScale extension
which is specified in two documents: A contributed document at ITU and ISO
with title "ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced
Image Coding", April 2006, Geneva, Switzerland. The latest version of this
document is Revision 3. And a contributed document ISO/IEC JTC1/SC29/WG1 N
5799 with title "Evolution of JPEG", June/July 2011, Berlin, Germany.
IJG JPEG 9 introduces a reversible color transform for improved lossless
compression which is described in a contributed document ISO/IEC JTC1/SC29/
WG1 N 6080 with title "JPEG 9 Lossless Coding", June/July 2012, Paris,
France.
Some extensions to the original JPEG standard are defined in JPEG Part 3,
a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84. IJG
currently does not support any Part 3 extensions.
The JPEG standard does not specify all details of an interchangeable file
format. For the omitted details we follow the "JFIF" conventions, revision
1.02. JFIF 1.02 has been adopted as an Ecma International Technical Report
and thus received a formal publication status. It is available as a free
download in PDF format from
http://www.ecma-international.org/publications/techreports/E-TR-098.htm.
A PostScript version of the JFIF document is available at
http://www.ijg.org/files/jfif.ps.gz. There is also a plain text version at
http://www.ijg.org/files/jfif.txt.gz, but it is missing the figures.
1.02. A copy of the JFIF spec is available from:
Literature Department
C-Cube Microsystems, Inc.
1778 McCarthy Blvd.
Milpitas, CA 95035
phone (408) 944-6300, fax (408) 944-6314
A PostScript version of this document is available by FTP at
ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz. There is also a plain text
version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing
the figures.
The TIFF 6.0 file format specification can be obtained by FTP from
ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme
found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
(Compression tag 7). Copies of this Note can be obtained from
http://www.ijg.org/files/. It is expected that the next revision
(Compression tag 7). Copies of this Note can be obtained from ftp.sgi.com or
from ftp://ftp.uu.net/graphics/jpeg/. It is expected that the next revision
of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
Although IJG's own code does not support TIFF/JPEG, the free libtiff library
uses our library to implement TIFF/JPEG per the Note.
uses our library to implement TIFF/JPEG per the Note. libtiff is available
from ftp://ftp.sgi.com/graphics/tiff/.
ARCHIVE LOCATIONS
=================
The "official" archive site for this software is www.ijg.org.
The most recent released version can always be found there in
directory "files". This particular version will be archived as
http://www.ijg.org/files/jpegsrc.v9.tar.gz, and in Windows-compatible
"zip" archive format as http://www.ijg.org/files/jpegsr9.zip.
The "official" archive site for this software is ftp.uu.net (Internet
address 192.48.96.9). The most recent released version can always be found
there in directory graphics/jpeg. This particular version will be archived
as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz. If you don't have
direct Internet access, UUNET's archives are also available via UUCP; contact
help@uunet.uu.net for information on retrieving files that way.
The JPEG FAQ (Frequently Asked Questions) article is a source of some
general information about JPEG.
Numerous Internet sites maintain copies of the UUNET files. However, only
ftp.uu.net is guaranteed to have the latest official version.
You can also obtain this software in DOS-compatible "zip" archive format from
the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or
on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12
"JPEG Tools". Again, these versions may sometimes lag behind the ftp.uu.net
release.
The JPEG FAQ (Frequently Asked Questions) article is a useful source of
general information about JPEG. It is updated constantly and therefore is
not included in this distribution. The FAQ is posted every two weeks to
Usenet newsgroups comp.graphics.misc, news.answers, and other groups.
It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
and other news.answers archive sites, including the official news.answers
archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
@@ -266,85 +307,79 @@ with body
send usenet/news.answers/jpeg-faq/part2
ACKNOWLEDGMENTS
===============
RELATED SOFTWARE
================
Thank to Juergen Bruder for providing me with a copy of the common DCT
algorithm article, only to find out that I had come to the same result
in a more direct and comprehensible way with a more generative approach.
Numerous viewing and image manipulation programs now support JPEG. (Quite a
few of them use this library to do so.) The JPEG FAQ described above lists
some of the more popular free and shareware viewers, and tells where to
obtain them on Internet.
Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the
ITU JPEG (Study Group 16) meeting in Geneva, Switzerland.
If you are on a Unix machine, we highly recommend Jef Poskanzer's free
PBMPLUS software, which provides many useful operations on PPM-format image
files. In particular, it can convert PPM images to and from a wide range of
other formats, thus making cjpeg/djpeg considerably more useful. The latest
version is distributed by the NetPBM group, and is available from numerous
sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/.
Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is;
you are likely to have difficulty making it work on any non-Unix machine.
Thank to Thomas Wiegand and Gary Sullivan for inviting me to the
Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland.
Thank to Thomas Richter and Daniel Lee for inviting me to the
ISO/IEC JTC1/SC29/WG1 (also known as JPEG, together with ITU-T SG16)
meeting in Berlin, Germany.
Thank to John Korejwa and Massimo Ballerini for inviting me to
fruitful consultations in Boston, MA and Milan, Italy.
Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther
Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel
for corresponding business development.
Thank to Nico Zschach and Dirk Stelling of the technical support team
at the Digital Images company in Halle for providing me with extra
equipment for configuration tests.
Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful
communication about JPEG configuration in Sigma Photo Pro software.
Thank to Andrew Finkenstadt for hosting the ijg.org site.
Last but not least special thank to Thomas G. Lane for the original
design and development of this singular software package.
A different free JPEG implementation, written by the PVRG group at Stanford,
is available from ftp://havefun.stanford.edu/pub/jpeg/. This program
is designed for research and experimentation rather than production use;
it is slower, harder to use, and less portable than the IJG code, but it
is easier to read and modify. Also, the PVRG code supports lossless JPEG,
which we do not. (On the other hand, it doesn't do progressive JPEG.)
FILE FORMAT WARS
================
The ISO/IEC JTC1/SC29/WG1 standards committee (also known as JPEG, together
with ITU-T SG16) currently promotes different formats containing the name
"JPEG" which is misleading because these formats are incompatible with
original DCT-based JPEG and are based on faulty technologies.
IJG therefore does not and will not support such momentary mistakes
(see REFERENCES).
There exist also distributions under the name "OpenJPEG" promoting such
kind of formats which is misleading because they don't support original
JPEG images.
We have no sympathy for the promotion of inferior formats. Indeed, one of
the original reasons for developing this free software was to help force
convergence on common, interoperable format standards for JPEG files.
Don't use an incompatible file format!
(In any case, our decoder will remain capable of reading existing JPEG
image files indefinitely.)
Some JPEG programs produce files that are not compatible with our library.
The root of the problem is that the ISO JPEG committee failed to specify a
concrete file format. Some vendors "filled in the blanks" on their own,
creating proprietary formats that no one else could read. (For example, none
of the early commercial JPEG implementations for the Macintosh were able to
exchange compressed files.)
Furthermore, the ISO committee pretends to be "responsible for the popular
JPEG" in their public reports which is not true because they don't respond to
actual requirements for the maintenance of the original JPEG specification.
The file format we have adopted is called JFIF (see REFERENCES). This format
has been agreed to by a number of major commercial JPEG vendors, and it has
become the de facto standard. JFIF is a minimal or "low end" representation.
We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF
Technical Note #2) for "high end" applications that need to record a lot of
additional data about an image. TIFF/JPEG is fairly new and not yet widely
supported, unfortunately.
There are currently different distributions in circulation containing the
name "libjpeg" which is misleading because they don't have the features and
are incompatible with formats supported by actual IJG libjpeg distributions.
One of those fakes is released by members of the ISO committee and just uses
the name of libjpeg for misdirection of people, similar to the abuse of the
name JPEG as described above, while having nothing in common with actual IJG
libjpeg distributions.
The other one claims to be a "derivative" or "fork" of the original libjpeg
and violates the license conditions as described under LEGAL ISSUES above.
We have no sympathy for the release of misleading and illegal distributions
derived from obsolete code bases.
Don't use an obsolete code base!
The upcoming JPEG Part 3 standard defines a file format called SPIFF.
SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should
be able to read the most common variant of SPIFF. SPIFF has some technical
advantages over JFIF, but its major claim to fame is simply that it is an
official standard rather than an informal one. At this point it is unclear
whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto
standard. IJG intends to support SPIFF once the standard is frozen, but we
have not decided whether it should become our default output format or not.
(In any case, our decoder will remain capable of reading JFIF indefinitely.)
Various proprietary file formats incorporating JPEG compression also exist.
We have little or no sympathy for the existence of these formats. Indeed,
one of the original reasons for developing this free software was to help
force convergence on common, open format standards for JPEG files. Don't
use a proprietary file format!
TO DO
=====
Version 9 is the second release of a new generation JPEG standard
to overcome the limitations of the original JPEG specification.
More features are being prepared for coming releases...
The major thrust for v7 will probably be improvement of visual quality.
The current method for scaling the quantization tables is known not to be
very good at low Q values. We also intend to investigate block boundary
smoothing, "poor man's variable quantization", and other means of improving
quality-vs-file-size performance without sacrificing compatibility.
Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.
In future versions, we are considering supporting some of the upcoming JPEG
Part 3 extensions --- principally, variable quantization and the SPIFF file
format.
As always, speeding things up is of great interest.
Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net.
-382
View File
@@ -1,382 +0,0 @@
CHANGE LOG for Independent JPEG Group's JPEG software
Version 9 13-Jan-2013
----------------------
Add cjpeg -rgb1 option to create an RGB JPEG file, and insert
a simple reversible color transform into the processing which
significantly improves the compression.
The recommended command for lossless coding of RGB images is now
cjpeg -rgb1 -block 1 -arithmetic.
As said, this option improves the compression significantly, but
the files are not compatible with JPEG decoders prior to IJG v9
due to the included color transform.
The used color transform and marker signaling is compatible with
other JPEG standards (e.g., JPEG-LS part 2).
Remove the automatic de-ANSI-fication support (Automake 1.12).
Thank also to Nitin A Kamble for suggestion.
Add remark for jpeg_mem_dest() in jdatadst.c.
Thank to Elie-Gregoire Khoury for the hint.
Support files with invalid component identifiers (created
by Adobe PDF). Thank to Robin Watts for the suggestion.
Adapt full buffer case in jcmainct.c for use with scaled DCT.
Thank to Sergii Biloshytskyi for the suggestion.
Add type identifier for declaration of noreturn functions.
Thank to Brett L. Moore for the suggestion.
Correct argument type in format string, avoid compiler warnings.
Thank to Vincent Torri for hint.
Add missing #include directives in configuration checks, avoid
configuration errors. Thank to John Spencer for the hint.
Version 8d 15-Jan-2012
-----------------------
Add cjpeg -rgb option to create RGB JPEG files.
Using this switch suppresses the conversion from RGB
colorspace input to the default YCbCr JPEG colorspace.
This feature allows true lossless JPEG coding of RGB color images.
The recommended command for this purpose is currently
cjpeg -rgb -block 1 -arithmetic.
SmartScale capable decoder (introduced with IJG JPEG 8) required.
Thank to Michael Koch for the initial suggestion.
Add option to disable the region adjustment in the transupp crop code.
Thank to Jeffrey Friedl for the suggestion.
Thank to Richard Jones and Edd Dawson for various minor corrections.
Thank to Akim Demaille for configure.ac cleanup.
Version 8c 16-Jan-2011
-----------------------
Add option to compression library and cjpeg (-block N) to use
different DCT block size.
All N from 1 to 16 are possible. Default is 8 (baseline format).
Larger values produce higher compression,
smaller values produce higher quality.
SmartScale capable decoder (introduced with IJG JPEG 8) required.
Version 8b 16-May-2010
-----------------------
Repair problem in new memory source manager with corrupt JPEG data.
Thank to Ted Campbell and Samuel Chun for the report.
Repair problem in Makefile.am test target.
Thank to anonymous user for the report.
Support MinGW installation with automatic configure.
Thank to Volker Grabsch for the suggestion.
Version 8a 28-Feb-2010
-----------------------
Writing tables-only datastreams via jpeg_write_tables works again.
Support 32-bit BMPs (RGB image with Alpha channel) for read in cjpeg.
Thank to Brett Blackham for the suggestion.
Improve accuracy in floating point IDCT calculation.
Thank to Robert Hooke for the hint.
Version 8 10-Jan-2010
----------------------
jpegtran now supports the same -scale option as djpeg for "lossless" resize.
An implementation of the JPEG SmartScale extension is required for this
feature. A (draft) specification of the JPEG SmartScale extension is
available as a contributed document at ITU and ISO. Revision 2 or later
of the document is required (latest document version is Revision 3).
The SmartScale extension will enable more features beside lossless resize
in future implementations, as described in the document (new compression
options).
Add sanity check in BMP reader module to avoid cjpeg crash for empty input
image (thank to Isaev Ildar of ISP RAS, Moscow, RU for reporting this error).
Add data source and destination managers for read from and write to
memory buffers. New API functions jpeg_mem_src and jpeg_mem_dest.
Thank to Roberto Boni from Italy for the suggestion.
Version 7 27-Jun-2009
----------------------
New scaled DCTs implemented.
djpeg now supports scalings N/8 with all N from 1 to 16.
cjpeg now supports scalings 8/N with all N from 1 to 16.
Scaled DCTs with size larger than 8 are now also used for resolving the
common 2x2 chroma subsampling case without additional spatial resampling.
Separate spatial resampling for those kind of files is now only necessary
for N>8 scaling cases.
Furthermore, separate scaled DCT functions are provided for direct resolving
of the common asymmetric subsampling cases (2x1 and 1x2) without additional
spatial resampling.
cjpeg -quality option has been extended for support of separate quality
settings for luminance and chrominance (or in general, for every provided
quantization table slot).
New API function jpeg_default_qtables() and q_scale_factor array in library.
Added -nosmooth option to cjpeg, complementary to djpeg.
New variable "do_fancy_downsampling" in library, complement to fancy
upsampling. Fancy upsampling now uses direct DCT scaling with sizes
larger than 8. The old method is not reversible and has been removed.
Support arithmetic entropy encoding and decoding.
Added files jaricom.c, jcarith.c, jdarith.c.
Straighten the file structure:
Removed files jidctred.c, jcphuff.c, jchuff.h, jdphuff.c, jdhuff.h.
jpegtran has a new "lossless" cropping feature.
Implement -perfect option in jpegtran, new API function
jtransform_perfect_transform() in transupp. (DP 204_perfect.dpatch)
Better error messages for jpegtran fopen failure.
(DP 203_jpegtran_errmsg.dpatch)
Fix byte order issue with 16bit PPM/PGM files in rdppm.c/wrppm.c:
according to Netpbm, the de facto standard implementation of the PNM formats,
the most significant byte is first. (DP 203_rdppm.dpatch)
Add -raw option to rdjpgcom not to mangle the output.
(DP 205_rdjpgcom_raw.dpatch)
Make rdjpgcom locale aware. (DP 201_rdjpgcom_locale.dpatch)
Add extern "C" to jpeglib.h.
This avoids the need to put extern "C" { ... } around #include "jpeglib.h"
in your C++ application. Defining the symbol DONT_USE_EXTERN_C in the
configuration prevents this. (DP 202_jpeglib.h_c++.dpatch)
Version 6b 27-Mar-1998
-----------------------
jpegtran has new features for lossless image transformations (rotation
and flipping) as well as "lossless" reduction to grayscale.
jpegtran now copies comments by default; it has a -copy switch to enable
copying all APPn blocks as well, or to suppress comments. (Formerly it
always suppressed comments and APPn blocks.) jpegtran now also preserves
JFIF version and resolution information.
New decompressor library feature: COM and APPn markers found in the input
file can be saved in memory for later use by the application. (Before,
you had to code this up yourself with a custom marker processor.)
There is an unused field "void * client_data" now in compress and decompress
parameter structs; this may be useful in some applications.
JFIF version number information is now saved by the decoder and accepted by
the encoder. jpegtran uses this to copy the source file's version number,
to ensure "jpegtran -copy all" won't create bogus files that contain JFXX
extensions but claim to be version 1.01. Applications that generate their
own JFXX extension markers also (finally) have a supported way to cause the
encoder to emit JFIF version number 1.02.
djpeg's trace mode reports JFIF 1.02 thumbnail images as such, rather
than as unknown APP0 markers.
In -verbose mode, djpeg and rdjpgcom will try to print the contents of
APP12 markers as text. Some digital cameras store useful text information
in APP12 markers.
Handling of truncated data streams is more robust: blocks beyond the one in
which the error occurs will be output as uniform gray, or left unchanged
if decoding a progressive JPEG. The appearance no longer depends on the
Huffman tables being used.
Huffman tables are checked for validity much more carefully than before.
To avoid the Unisys LZW patent, djpeg's GIF output capability has been
changed to produce "uncompressed GIFs", and cjpeg's GIF input capability
has been removed altogether. We're not happy about it either, but there
seems to be no good alternative.
The configure script now supports building libjpeg as a shared library
on many flavors of Unix (all the ones that GNU libtool knows how to
build shared libraries for). Use "./configure --enable-shared" to
try this out.
New jconfig file and makefiles for Microsoft Visual C++ and Developer Studio.
Also, a jconfig file and a build script for Metrowerks CodeWarrior
on Apple Macintosh. makefile.dj has been updated for DJGPP v2, and there
are miscellaneous other minor improvements in the makefiles.
jmemmac.c now knows how to create temporary files following Mac System 7
conventions.
djpeg's -map switch is now able to read raw-format PPM files reliably.
cjpeg -progressive -restart no longer generates any unnecessary DRI markers.
Multiple calls to jpeg_simple_progression for a single JPEG object
no longer leak memory.
Version 6a 7-Feb-96
--------------------
Library initialization sequence modified to detect version mismatches
and struct field packing mismatches between library and calling application.
This change requires applications to be recompiled, but does not require
any application source code change.
All routine declarations changed to the style "GLOBAL(type) name ...",
that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the
routine's return type as an argument. This makes it possible to add
Microsoft-style linkage keywords to all the routines by changing just
these macros. Note that any application code that was using these macros
will have to be changed.
DCT coefficient quantization tables are now stored in normal array order
rather than zigzag order. Application code that calls jpeg_add_quant_table,
or otherwise manipulates quantization tables directly, will need to be
changed. If you need to make such code work with either older or newer
versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is
recommended.
djpeg's trace capability now dumps DQT tables in natural order, not zigzag
order. This allows the trace output to be made into a "-qtables" file
more easily.
New system-dependent memory manager module for use on Apple Macintosh.
Fix bug in cjpeg's -smooth option: last one or two scanlines would be
duplicates of the prior line unless the image height mod 16 was 1 or 2.
Repair minor problems in VMS, BCC, MC6 makefiles.
New configure script based on latest GNU Autoconf.
Correct the list of include files needed by MetroWerks C for ccommand().
Numerous small documentation updates.
Version 6 2-Aug-95
-------------------
Progressive JPEG support: library can read and write full progressive JPEG
files. A "buffered image" mode supports incremental decoding for on-the-fly
display of progressive images. Simply recompiling an existing IJG-v5-based
decoder with v6 should allow it to read progressive files, though of course
without any special progressive display.
New "jpegtran" application performs lossless transcoding between different
JPEG formats; primarily, it can be used to convert baseline to progressive
JPEG and vice versa. In support of jpegtran, the library now allows lossless
reading and writing of JPEG files as DCT coefficient arrays. This ability
may be of use in other applications.
Notes for programmers:
* We changed jpeg_start_decompress() to be able to suspend; this makes all
decoding modes available to suspending-input applications. However,
existing applications that use suspending input will need to be changed
to check the return value from jpeg_start_decompress(). You don't need to
do anything if you don't use a suspending data source.
* We changed the interface to the virtual array routines: access_virt_array
routines now take a count of the number of rows to access this time. The
last parameter to request_virt_array routines is now interpreted as the
maximum number of rows that may be accessed at once, but not necessarily
the height of every access.
Version 5b 15-Mar-95
---------------------
Correct bugs with grayscale images having v_samp_factor > 1.
jpeg_write_raw_data() now supports output suspension.
Correct bugs in "configure" script for case of compiling in
a directory other than the one containing the source files.
Repair bug in jquant1.c: sometimes didn't use as many colors as it could.
Borland C makefile and jconfig file work under either MS-DOS or OS/2.
Miscellaneous improvements to documentation.
Version 5a 7-Dec-94
--------------------
Changed color conversion roundoff behavior so that grayscale values are
represented exactly. (This causes test image files to change.)
Make ordered dither use 16x16 instead of 4x4 pattern for a small quality
improvement.
New configure script based on latest GNU Autoconf.
Fix configure script to handle CFLAGS correctly.
Rename *.auto files to *.cfg, so that configure script still works if
file names have been truncated for DOS.
Fix bug in rdbmp.c: didn't allow for extra data between header and image.
Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data.
Fix several bugs in rdrle.c.
NEED_SHORT_EXTERNAL_NAMES option was broken.
Revise jerror.h/jerror.c for more flexibility in message table.
Repair oversight in jmemname.c NO_MKTEMP case: file could be there
but unreadable.
Version 5 24-Sep-94
--------------------
Version 5 represents a nearly complete redesign and rewrite of the IJG
software. Major user-visible changes include:
* Automatic configuration simplifies installation for most Unix systems.
* A range of speed vs. image quality tradeoffs are supported.
This includes resizing of an image during decompression: scaling down
by a factor of 1/2, 1/4, or 1/8 is handled very efficiently.
* New programs rdjpgcom and wrjpgcom allow insertion and extraction
of text comments in a JPEG file.
The application programmer's interface to the library has changed completely.
Notable improvements include:
* We have eliminated the use of callback routines for handling the
uncompressed image data. The application now sees the library as a
set of routines that it calls to read or write image data on a
scanline-by-scanline basis.
* The application image data is represented in a conventional interleaved-
pixel format, rather than as a separate array for each color channel.
This can save a copying step in many programs.
* The handling of compressed data has been cleaned up: the application can
supply routines to source or sink the compressed data. It is possible to
suspend processing on source/sink buffer overrun, although this is not
supported in all operating modes.
* All static state has been eliminated from the library, so that multiple
instances of compression or decompression can be active concurrently.
* JPEG abbreviated datastream formats are supported, ie, quantization and
Huffman tables can be stored separately from the image data.
* And not only that, but the documentation of the library has improved
considerably!
The last widely used release before the version 5 rewrite was version 4A of
18-Feb-93. Change logs before that point have been discarded, since they
are not of much interest after the rewrite.
-153
View File
@@ -1,153 +0,0 @@
/*
* jaricom.c
*
* Developed 1997-2011 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains probability estimation tables for common use in
* arithmetic entropy encoding and decoding routines.
*
* This data represents Table D.3 in the JPEG spec (D.2 in the draft),
* ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81, and Table 24
* in the JBIG spec, ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* The following #define specifies the packing of the four components
* into the compact INT32 representation.
* Note that this formula must match the actual arithmetic encoder
* and decoder implementation. The implementation has to be changed
* if this formula is changed.
* The current organization is leaned on Markus Kuhn's JBIG
* implementation (jbig_tab.c).
*/
#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b)
const INT32 jpeg_aritab[113+1] = {
/*
* Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS
*/
V( 0, 0x5a1d, 1, 1, 1 ),
V( 1, 0x2586, 14, 2, 0 ),
V( 2, 0x1114, 16, 3, 0 ),
V( 3, 0x080b, 18, 4, 0 ),
V( 4, 0x03d8, 20, 5, 0 ),
V( 5, 0x01da, 23, 6, 0 ),
V( 6, 0x00e5, 25, 7, 0 ),
V( 7, 0x006f, 28, 8, 0 ),
V( 8, 0x0036, 30, 9, 0 ),
V( 9, 0x001a, 33, 10, 0 ),
V( 10, 0x000d, 35, 11, 0 ),
V( 11, 0x0006, 9, 12, 0 ),
V( 12, 0x0003, 10, 13, 0 ),
V( 13, 0x0001, 12, 13, 0 ),
V( 14, 0x5a7f, 15, 15, 1 ),
V( 15, 0x3f25, 36, 16, 0 ),
V( 16, 0x2cf2, 38, 17, 0 ),
V( 17, 0x207c, 39, 18, 0 ),
V( 18, 0x17b9, 40, 19, 0 ),
V( 19, 0x1182, 42, 20, 0 ),
V( 20, 0x0cef, 43, 21, 0 ),
V( 21, 0x09a1, 45, 22, 0 ),
V( 22, 0x072f, 46, 23, 0 ),
V( 23, 0x055c, 48, 24, 0 ),
V( 24, 0x0406, 49, 25, 0 ),
V( 25, 0x0303, 51, 26, 0 ),
V( 26, 0x0240, 52, 27, 0 ),
V( 27, 0x01b1, 54, 28, 0 ),
V( 28, 0x0144, 56, 29, 0 ),
V( 29, 0x00f5, 57, 30, 0 ),
V( 30, 0x00b7, 59, 31, 0 ),
V( 31, 0x008a, 60, 32, 0 ),
V( 32, 0x0068, 62, 33, 0 ),
V( 33, 0x004e, 63, 34, 0 ),
V( 34, 0x003b, 32, 35, 0 ),
V( 35, 0x002c, 33, 9, 0 ),
V( 36, 0x5ae1, 37, 37, 1 ),
V( 37, 0x484c, 64, 38, 0 ),
V( 38, 0x3a0d, 65, 39, 0 ),
V( 39, 0x2ef1, 67, 40, 0 ),
V( 40, 0x261f, 68, 41, 0 ),
V( 41, 0x1f33, 69, 42, 0 ),
V( 42, 0x19a8, 70, 43, 0 ),
V( 43, 0x1518, 72, 44, 0 ),
V( 44, 0x1177, 73, 45, 0 ),
V( 45, 0x0e74, 74, 46, 0 ),
V( 46, 0x0bfb, 75, 47, 0 ),
V( 47, 0x09f8, 77, 48, 0 ),
V( 48, 0x0861, 78, 49, 0 ),
V( 49, 0x0706, 79, 50, 0 ),
V( 50, 0x05cd, 48, 51, 0 ),
V( 51, 0x04de, 50, 52, 0 ),
V( 52, 0x040f, 50, 53, 0 ),
V( 53, 0x0363, 51, 54, 0 ),
V( 54, 0x02d4, 52, 55, 0 ),
V( 55, 0x025c, 53, 56, 0 ),
V( 56, 0x01f8, 54, 57, 0 ),
V( 57, 0x01a4, 55, 58, 0 ),
V( 58, 0x0160, 56, 59, 0 ),
V( 59, 0x0125, 57, 60, 0 ),
V( 60, 0x00f6, 58, 61, 0 ),
V( 61, 0x00cb, 59, 62, 0 ),
V( 62, 0x00ab, 61, 63, 0 ),
V( 63, 0x008f, 61, 32, 0 ),
V( 64, 0x5b12, 65, 65, 1 ),
V( 65, 0x4d04, 80, 66, 0 ),
V( 66, 0x412c, 81, 67, 0 ),
V( 67, 0x37d8, 82, 68, 0 ),
V( 68, 0x2fe8, 83, 69, 0 ),
V( 69, 0x293c, 84, 70, 0 ),
V( 70, 0x2379, 86, 71, 0 ),
V( 71, 0x1edf, 87, 72, 0 ),
V( 72, 0x1aa9, 87, 73, 0 ),
V( 73, 0x174e, 72, 74, 0 ),
V( 74, 0x1424, 72, 75, 0 ),
V( 75, 0x119c, 74, 76, 0 ),
V( 76, 0x0f6b, 74, 77, 0 ),
V( 77, 0x0d51, 75, 78, 0 ),
V( 78, 0x0bb6, 77, 79, 0 ),
V( 79, 0x0a40, 77, 48, 0 ),
V( 80, 0x5832, 80, 81, 1 ),
V( 81, 0x4d1c, 88, 82, 0 ),
V( 82, 0x438e, 89, 83, 0 ),
V( 83, 0x3bdd, 90, 84, 0 ),
V( 84, 0x34ee, 91, 85, 0 ),
V( 85, 0x2eae, 92, 86, 0 ),
V( 86, 0x299a, 93, 87, 0 ),
V( 87, 0x2516, 86, 71, 0 ),
V( 88, 0x5570, 88, 89, 1 ),
V( 89, 0x4ca9, 95, 90, 0 ),
V( 90, 0x44d9, 96, 91, 0 ),
V( 91, 0x3e22, 97, 92, 0 ),
V( 92, 0x3824, 99, 93, 0 ),
V( 93, 0x32b4, 99, 94, 0 ),
V( 94, 0x2e17, 93, 86, 0 ),
V( 95, 0x56a8, 95, 96, 1 ),
V( 96, 0x4f46, 101, 97, 0 ),
V( 97, 0x47e5, 102, 98, 0 ),
V( 98, 0x41cf, 103, 99, 0 ),
V( 99, 0x3c3d, 104, 100, 0 ),
V( 100, 0x375e, 99, 93, 0 ),
V( 101, 0x5231, 105, 102, 0 ),
V( 102, 0x4c0f, 106, 103, 0 ),
V( 103, 0x4639, 107, 104, 0 ),
V( 104, 0x415e, 103, 99, 0 ),
V( 105, 0x5627, 105, 106, 1 ),
V( 106, 0x50e7, 108, 107, 0 ),
V( 107, 0x4b85, 109, 103, 0 ),
V( 108, 0x5597, 110, 109, 0 ),
V( 109, 0x504f, 111, 107, 0 ),
V( 110, 0x5a10, 110, 111, 1 ),
V( 111, 0x5522, 112, 109, 0 ),
V( 112, 0x59eb, 112, 111, 1 ),
/*
* This last entry is used for fixed probability estimate of 0.5
* as suggested in Section 10.3 Table 5 of ITU-T Rec. T.851.
*/
V( 113, 0x5a1d, 113, 113, 0 )
};
+7 -15
View File
@@ -2,7 +2,6 @@
* jcapimin.c
*
* Copyright (C) 1994-1998, Thomas G. Lane.
* Modified 2003-2010 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
@@ -38,7 +37,7 @@ jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
if (structsize != SIZEOF(struct jpeg_compress_struct))
ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
(int) SIZEOF(struct jpeg_compress_struct), (int) structsize);
(int) SIZEOF(struct jpeg_compress_struct), (int) structsize);
/* For debugging purposes, we zero the whole master structure.
* But the application has already set the err pointer, and may have set
@@ -64,21 +63,14 @@ jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
cinfo->comp_info = NULL;
for (i = 0; i < NUM_QUANT_TBLS; i++) {
for (i = 0; i < NUM_QUANT_TBLS; i++)
cinfo->quant_tbl_ptrs[i] = NULL;
cinfo->q_scale_factor[i] = 100;
}
for (i = 0; i < NUM_HUFF_TBLS; i++) {
cinfo->dc_huff_tbl_ptrs[i] = NULL;
cinfo->ac_huff_tbl_ptrs[i] = NULL;
}
/* Must do it here for emit_dqt in case jpeg_write_tables is used */
cinfo->block_size = DCTSIZE;
cinfo->natural_order = jpeg_natural_order;
cinfo->lim_Se = DCTSIZE2-1;
cinfo->script_space = NULL;
cinfo->input_gamma = 1.0; /* in case application forgets */
@@ -169,15 +161,15 @@ jpeg_finish_compress (j_compress_ptr cinfo)
(*cinfo->master->prepare_for_pass) (cinfo);
for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) {
if (cinfo->progress != NULL) {
cinfo->progress->pass_counter = (long) iMCU_row;
cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows;
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
cinfo->progress->pass_counter = (long) iMCU_row;
cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows;
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
}
/* We bypass the main controller and invoke coef controller directly;
* all work is being done from the coefficient buffer.
*/
if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL))
ERREXIT(cinfo, JERR_CANT_SUSPEND);
ERREXIT(cinfo, JERR_CANT_SUSPEND);
}
(*cinfo->master->finish_pass) (cinfo);
}
@@ -198,7 +190,7 @@ jpeg_finish_compress (j_compress_ptr cinfo)
GLOBAL(void)
jpeg_write_marker (j_compress_ptr cinfo, int marker,
const JOCTET *dataptr, unsigned int datalen)
const JOCTET *dataptr, unsigned int datalen)
{
JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val));
+2 -2
View File
@@ -75,7 +75,7 @@ jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
GLOBAL(JDIMENSION)
jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
JDIMENSION num_lines)
JDIMENSION num_lines)
{
JDIMENSION row_ctr, rows_left;
@@ -118,7 +118,7 @@ jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
GLOBAL(JDIMENSION)
jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
JDIMENSION num_lines)
JDIMENSION num_lines)
{
JDIMENSION lines_per_iMCU_row;
-943
View File
@@ -1,943 +0,0 @@
/*
* jcarith.c
*
* Developed 1997-2012 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains portable arithmetic entropy encoding routines for JPEG
* (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
*
* Both sequential and progressive modes are supported in this single module.
*
* Suspension is not currently supported in this module.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Expanded entropy encoder object for arithmetic encoding. */
typedef struct {
struct jpeg_entropy_encoder pub; /* public fields */
INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */
INT32 a; /* A register, normalized size of coding interval */
INT32 sc; /* counter for stacked 0xFF values which might overflow */
INT32 zc; /* counter for pending 0x00 output values which might *
* be discarded at the end ("Pacman" termination) */
int ct; /* bit shift counter, determines when next byte will be written */
int buffer; /* buffer for most recent output byte != 0xFF */
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
unsigned int restarts_to_go; /* MCUs left in this restart interval */
int next_restart_num; /* next restart number to write (0-7) */
/* Pointers to statistics areas (these workspaces have image lifespan) */
unsigned char * dc_stats[NUM_ARITH_TBLS];
unsigned char * ac_stats[NUM_ARITH_TBLS];
/* Statistics bin for coding with fixed probability 0.5 */
unsigned char fixed_bin[4];
} arith_entropy_encoder;
typedef arith_entropy_encoder * arith_entropy_ptr;
/* The following two definitions specify the allocation chunk size
* for the statistics area.
* According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
* 49 statistics bins for DC, and 245 statistics bins for AC coding.
*
* We use a compact representation with 1 byte per statistics bin,
* thus the numbers directly represent byte sizes.
* This 1 byte per statistics bin contains the meaning of the MPS
* (more probable symbol) in the highest bit (mask 0x80), and the
* index into the probability estimation state machine table
* in the lower bits (mask 0x7F).
*/
#define DC_STAT_BINS 64
#define AC_STAT_BINS 256
/* NOTE: Uncomment the following #define if you want to use the
* given formula for calculating the AC conditioning parameter Kx
* for spectral selection progressive coding in section G.1.3.2
* of the spec (Kx = Kmin + SRL (8 + Se - Kmin) 4).
* Although the spec and P&M authors claim that this "has proven
* to give good results for 8 bit precision samples", I'm not
* convinced yet that this is really beneficial.
* Early tests gave only very marginal compression enhancements
* (a few - around 5 or so - bytes even for very large files),
* which would turn out rather negative if we'd suppress the
* DAC (Define Arithmetic Conditioning) marker segments for
* the default parameters in the future.
* Note that currently the marker writing module emits 12-byte
* DAC segments for a full-component scan in a color image.
* This is not worth worrying about IMHO. However, since the
* spec defines the default values to be used if the tables
* are omitted (unlike Huffman tables, which are required
* anyway), one might optimize this behaviour in the future,
* and then it would be disadvantageous to use custom tables if
* they don't provide sufficient gain to exceed the DAC size.
*
* On the other hand, I'd consider it as a reasonable result
* that the conditioning has no significant influence on the
* compression performance. This means that the basic
* statistical model is already rather stable.
*
* Thus, at the moment, we use the default conditioning values
* anyway, and do not use the custom formula.
*
#define CALCULATE_SPECTRAL_CONDITIONING
*/
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
* We assume that int right shift is unsigned if INT32 right shift is,
* which should be safe.
*/
#ifdef RIGHT_SHIFT_IS_UNSIGNED
#define ISHIFT_TEMPS int ishift_temp;
#define IRIGHT_SHIFT(x,shft) \
((ishift_temp = (x)) < 0 ? \
(ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
(ishift_temp >> (shft)))
#else
#define ISHIFT_TEMPS
#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
#endif
LOCAL(void)
emit_byte (int val, j_compress_ptr cinfo)
/* Write next output byte; we do not support suspension in this module. */
{
struct jpeg_destination_mgr * dest = cinfo->dest;
*dest->next_output_byte++ = (JOCTET) val;
if (--dest->free_in_buffer == 0)
if (! (*dest->empty_output_buffer) (cinfo))
ERREXIT(cinfo, JERR_CANT_SUSPEND);
}
/*
* Finish up at the end of an arithmetic-compressed scan.
*/
METHODDEF(void)
finish_pass (j_compress_ptr cinfo)
{
arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
INT32 temp;
/* Section D.1.8: Termination of encoding */
/* Find the e->c in the coding interval with the largest
* number of trailing zero bits */
if ((temp = (e->a - 1 + e->c) & 0xFFFF0000L) < e->c)
e->c = temp + 0x8000L;
else
e->c = temp;
/* Send remaining bytes to output */
e->c <<= e->ct;
if (e->c & 0xF8000000L) {
/* One final overflow has to be handled */
if (e->buffer >= 0) {
if (e->zc)
do emit_byte(0x00, cinfo);
while (--e->zc);
emit_byte(e->buffer + 1, cinfo);
if (e->buffer + 1 == 0xFF)
emit_byte(0x00, cinfo);
}
e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */
e->sc = 0;
} else {
if (e->buffer == 0)
++e->zc;
else if (e->buffer >= 0) {
if (e->zc)
do emit_byte(0x00, cinfo);
while (--e->zc);
emit_byte(e->buffer, cinfo);
}
if (e->sc) {
if (e->zc)
do emit_byte(0x00, cinfo);
while (--e->zc);
do {
emit_byte(0xFF, cinfo);
emit_byte(0x00, cinfo);
} while (--e->sc);
}
}
/* Output final bytes only if they are not 0x00 */
if (e->c & 0x7FFF800L) {
if (e->zc) /* output final pending zero bytes */
do emit_byte(0x00, cinfo);
while (--e->zc);
emit_byte((e->c >> 19) & 0xFF, cinfo);
if (((e->c >> 19) & 0xFF) == 0xFF)
emit_byte(0x00, cinfo);
if (e->c & 0x7F800L) {
emit_byte((e->c >> 11) & 0xFF, cinfo);
if (((e->c >> 11) & 0xFF) == 0xFF)
emit_byte(0x00, cinfo);
}
}
}
/*
* The core arithmetic encoding routine (common in JPEG and JBIG).
* This needs to go as fast as possible.
* Machine-dependent optimization facilities
* are not utilized in this portable implementation.
* However, this code should be fairly efficient and
* may be a good base for further optimizations anyway.
*
* Parameter 'val' to be encoded may be 0 or 1 (binary decision).
*
* Note: I've added full "Pacman" termination support to the
* byte output routines, which is equivalent to the optional
* Discard_final_zeros procedure (Figure D.15) in the spec.
* Thus, we always produce the shortest possible output
* stream compliant to the spec (no trailing zero bytes,
* except for FF stuffing).
*
* I've also introduced a new scheme for accessing
* the probability estimation state machine table,
* derived from Markus Kuhn's JBIG implementation.
*/
LOCAL(void)
arith_encode (j_compress_ptr cinfo, unsigned char *st, int val)
{
register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
register unsigned char nl, nm;
register INT32 qe, temp;
register int sv;
/* Fetch values from our compact representation of Table D.3(D.2):
* Qe values and probability estimation state machine
*/
sv = *st;
qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */
nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */
nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */
/* Encode & estimation procedures per sections D.1.4 & D.1.5 */
e->a -= qe;
if (val != (sv >> 7)) {
/* Encode the less probable symbol */
if (e->a >= qe) {
/* If the interval size (qe) for the less probable symbol (LPS)
* is larger than the interval size for the MPS, then exchange
* the two symbols for coding efficiency, otherwise code the LPS
* as usual: */
e->c += e->a;
e->a = qe;
}
*st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */
} else {
/* Encode the more probable symbol */
if (e->a >= 0x8000L)
return; /* A >= 0x8000 -> ready, no renormalization required */
if (e->a < qe) {
/* If the interval size (qe) for the less probable symbol (LPS)
* is larger than the interval size for the MPS, then exchange
* the two symbols for coding efficiency: */
e->c += e->a;
e->a = qe;
}
*st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */
}
/* Renormalization & data output per section D.1.6 */
do {
e->a <<= 1;
e->c <<= 1;
if (--e->ct == 0) {
/* Another byte is ready for output */
temp = e->c >> 19;
if (temp > 0xFF) {
/* Handle overflow over all stacked 0xFF bytes */
if (e->buffer >= 0) {
if (e->zc)
do emit_byte(0x00, cinfo);
while (--e->zc);
emit_byte(e->buffer + 1, cinfo);
if (e->buffer + 1 == 0xFF)
emit_byte(0x00, cinfo);
}
e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */
e->sc = 0;
/* Note: The 3 spacer bits in the C register guarantee
* that the new buffer byte can't be 0xFF here
* (see page 160 in the P&M JPEG book). */
e->buffer = temp & 0xFF; /* new output byte, might overflow later */
} else if (temp == 0xFF) {
++e->sc; /* stack 0xFF byte (which might overflow later) */
} else {
/* Output all stacked 0xFF bytes, they will not overflow any more */
if (e->buffer == 0)
++e->zc;
else if (e->buffer >= 0) {
if (e->zc)
do emit_byte(0x00, cinfo);
while (--e->zc);
emit_byte(e->buffer, cinfo);
}
if (e->sc) {
if (e->zc)
do emit_byte(0x00, cinfo);
while (--e->zc);
do {
emit_byte(0xFF, cinfo);
emit_byte(0x00, cinfo);
} while (--e->sc);
}
e->buffer = temp & 0xFF; /* new output byte (can still overflow) */
}
e->c &= 0x7FFFFL;
e->ct += 8;
}
} while (e->a < 0x8000L);
}
/*
* Emit a restart marker & resynchronize predictions.
*/
LOCAL(void)
emit_restart (j_compress_ptr cinfo, int restart_num)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
int ci;
jpeg_component_info * compptr;
finish_pass(cinfo);
emit_byte(0xFF, cinfo);
emit_byte(JPEG_RST0 + restart_num, cinfo);
/* Re-initialize statistics areas */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* DC needs no table for refinement scan */
if (cinfo->Ss == 0 && cinfo->Ah == 0) {
MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
/* Reset DC predictions to 0 */
entropy->last_dc_val[ci] = 0;
entropy->dc_context[ci] = 0;
}
/* AC needs no table when not present */
if (cinfo->Se) {
MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
}
}
/* Reset arithmetic encoding variables */
entropy->c = 0;
entropy->a = 0x10000L;
entropy->sc = 0;
entropy->zc = 0;
entropy->ct = 11;
entropy->buffer = -1; /* empty */
}
/*
* MCU encoding for DC initial scan (either spectral selection,
* or first pass of successive approximation).
*/
METHODDEF(boolean)
encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
JBLOCKROW block;
unsigned char *st;
int blkn, ci, tbl;
int v, v2, m;
ISHIFT_TEMPS
/* Emit restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
emit_restart(cinfo, entropy->next_restart_num);
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
/* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn];
ci = cinfo->MCU_membership[blkn];
tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
/* Compute the DC value after the required point transform by Al.
* This is simply an arithmetic right shift.
*/
m = IRIGHT_SHIFT((int) ((*block)[0]), cinfo->Al);
/* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
/* Table F.4: Point to statistics bin S0 for DC coefficient coding */
st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
/* Figure F.4: Encode_DC_DIFF */
if ((v = m - entropy->last_dc_val[ci]) == 0) {
arith_encode(cinfo, st, 0);
entropy->dc_context[ci] = 0; /* zero diff category */
} else {
entropy->last_dc_val[ci] = m;
arith_encode(cinfo, st, 1);
/* Figure F.6: Encoding nonzero value v */
/* Figure F.7: Encoding the sign of v */
if (v > 0) {
arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */
st += 2; /* Table F.4: SP = S0 + 2 */
entropy->dc_context[ci] = 4; /* small positive diff category */
} else {
v = -v;
arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */
st += 3; /* Table F.4: SN = S0 + 3 */
entropy->dc_context[ci] = 8; /* small negative diff category */
}
/* Figure F.8: Encoding the magnitude category of v */
m = 0;
if (v -= 1) {
arith_encode(cinfo, st, 1);
m = 1;
v2 = v;
st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
while (v2 >>= 1) {
arith_encode(cinfo, st, 1);
m <<= 1;
st += 1;
}
}
arith_encode(cinfo, st, 0);
/* Section F.1.4.4.1.2: Establish dc_context conditioning category */
if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
entropy->dc_context[ci] = 0; /* zero diff category */
else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
entropy->dc_context[ci] += 8; /* large diff category */
/* Figure F.9: Encoding the magnitude bit pattern of v */
st += 14;
while (m >>= 1)
arith_encode(cinfo, st, (m & v) ? 1 : 0);
}
}
return TRUE;
}
/*
* MCU encoding for AC initial scan (either spectral selection,
* or first pass of successive approximation).
*/
METHODDEF(boolean)
encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
JBLOCKROW block;
unsigned char *st;
int tbl, k, ke;
int v, v2, m;
const int * natural_order;
/* Emit restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
emit_restart(cinfo, entropy->next_restart_num);
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
natural_order = cinfo->natural_order;
/* Encode the MCU data block */
block = MCU_data[0];
tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
/* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
/* Establish EOB (end-of-block) index */
ke = cinfo->Se;
do {
/* We must apply the point transform by Al. For AC coefficients this
* is an integer division with rounding towards 0. To do this portably
* in C, we shift after obtaining the absolute value.
*/
if ((v = (*block)[natural_order[ke]]) >= 0) {
if (v >>= cinfo->Al) break;
} else {
v = -v;
if (v >>= cinfo->Al) break;
}
} while (--ke);
/* Figure F.5: Encode_AC_Coefficients */
for (k = cinfo->Ss - 1; k < ke;) {
st = entropy->ac_stats[tbl] + 3 * k;
arith_encode(cinfo, st, 0); /* EOB decision */
for (;;) {
if ((v = (*block)[natural_order[++k]]) >= 0) {
if (v >>= cinfo->Al) {
arith_encode(cinfo, st + 1, 1);
arith_encode(cinfo, entropy->fixed_bin, 0);
break;
}
} else {
v = -v;
if (v >>= cinfo->Al) {
arith_encode(cinfo, st + 1, 1);
arith_encode(cinfo, entropy->fixed_bin, 1);
break;
}
}
arith_encode(cinfo, st + 1, 0);
st += 3;
}
st += 2;
/* Figure F.8: Encoding the magnitude category of v */
m = 0;
if (v -= 1) {
arith_encode(cinfo, st, 1);
m = 1;
v2 = v;
if (v2 >>= 1) {
arith_encode(cinfo, st, 1);
m <<= 1;
st = entropy->ac_stats[tbl] +
(k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
while (v2 >>= 1) {
arith_encode(cinfo, st, 1);
m <<= 1;
st += 1;
}
}
}
arith_encode(cinfo, st, 0);
/* Figure F.9: Encoding the magnitude bit pattern of v */
st += 14;
while (m >>= 1)
arith_encode(cinfo, st, (m & v) ? 1 : 0);
}
/* Encode EOB decision only if k < cinfo->Se */
if (k < cinfo->Se) {
st = entropy->ac_stats[tbl] + 3 * k;
arith_encode(cinfo, st, 1);
}
return TRUE;
}
/*
* MCU encoding for DC successive approximation refinement scan.
*/
METHODDEF(boolean)
encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
unsigned char *st;
int Al, blkn;
/* Emit restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
emit_restart(cinfo, entropy->next_restart_num);
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
st = entropy->fixed_bin; /* use fixed probability estimation */
Al = cinfo->Al;
/* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
/* We simply emit the Al'th bit of the DC coefficient value. */
arith_encode(cinfo, st, (MCU_data[blkn][0][0] >> Al) & 1);
}
return TRUE;
}
/*
* MCU encoding for AC successive approximation refinement scan.
*/
METHODDEF(boolean)
encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
JBLOCKROW block;
unsigned char *st;
int tbl, k, ke, kex;
int v;
const int * natural_order;
/* Emit restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
emit_restart(cinfo, entropy->next_restart_num);
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
natural_order = cinfo->natural_order;
/* Encode the MCU data block */
block = MCU_data[0];
tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
/* Section G.1.3.3: Encoding of AC coefficients */
/* Establish EOB (end-of-block) index */
ke = cinfo->Se;
do {
/* We must apply the point transform by Al. For AC coefficients this
* is an integer division with rounding towards 0. To do this portably
* in C, we shift after obtaining the absolute value.
*/
if ((v = (*block)[natural_order[ke]]) >= 0) {
if (v >>= cinfo->Al) break;
} else {
v = -v;
if (v >>= cinfo->Al) break;
}
} while (--ke);
/* Establish EOBx (previous stage end-of-block) index */
for (kex = ke; kex > 0; kex--)
if ((v = (*block)[natural_order[kex]]) >= 0) {
if (v >>= cinfo->Ah) break;
} else {
v = -v;
if (v >>= cinfo->Ah) break;
}
/* Figure G.10: Encode_AC_Coefficients_SA */
for (k = cinfo->Ss - 1; k < ke;) {
st = entropy->ac_stats[tbl] + 3 * k;
if (k >= kex)
arith_encode(cinfo, st, 0); /* EOB decision */
for (;;) {
if ((v = (*block)[natural_order[++k]]) >= 0) {
if (v >>= cinfo->Al) {
if (v >> 1) /* previously nonzero coef */
arith_encode(cinfo, st + 2, (v & 1));
else { /* newly nonzero coef */
arith_encode(cinfo, st + 1, 1);
arith_encode(cinfo, entropy->fixed_bin, 0);
}
break;
}
} else {
v = -v;
if (v >>= cinfo->Al) {
if (v >> 1) /* previously nonzero coef */
arith_encode(cinfo, st + 2, (v & 1));
else { /* newly nonzero coef */
arith_encode(cinfo, st + 1, 1);
arith_encode(cinfo, entropy->fixed_bin, 1);
}
break;
}
}
arith_encode(cinfo, st + 1, 0);
st += 3;
}
}
/* Encode EOB decision only if k < cinfo->Se */
if (k < cinfo->Se) {
st = entropy->ac_stats[tbl] + 3 * k;
arith_encode(cinfo, st, 1);
}
return TRUE;
}
/*
* Encode and output one MCU's worth of arithmetic-compressed coefficients.
*/
METHODDEF(boolean)
encode_mcu (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
jpeg_component_info * compptr;
JBLOCKROW block;
unsigned char *st;
int blkn, ci, tbl, k, ke;
int v, v2, m;
const int * natural_order;
/* Emit restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
emit_restart(cinfo, entropy->next_restart_num);
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
natural_order = cinfo->natural_order;
/* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn];
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
/* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
tbl = compptr->dc_tbl_no;
/* Table F.4: Point to statistics bin S0 for DC coefficient coding */
st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
/* Figure F.4: Encode_DC_DIFF */
if ((v = (*block)[0] - entropy->last_dc_val[ci]) == 0) {
arith_encode(cinfo, st, 0);
entropy->dc_context[ci] = 0; /* zero diff category */
} else {
entropy->last_dc_val[ci] = (*block)[0];
arith_encode(cinfo, st, 1);
/* Figure F.6: Encoding nonzero value v */
/* Figure F.7: Encoding the sign of v */
if (v > 0) {
arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */
st += 2; /* Table F.4: SP = S0 + 2 */
entropy->dc_context[ci] = 4; /* small positive diff category */
} else {
v = -v;
arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */
st += 3; /* Table F.4: SN = S0 + 3 */
entropy->dc_context[ci] = 8; /* small negative diff category */
}
/* Figure F.8: Encoding the magnitude category of v */
m = 0;
if (v -= 1) {
arith_encode(cinfo, st, 1);
m = 1;
v2 = v;
st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
while (v2 >>= 1) {
arith_encode(cinfo, st, 1);
m <<= 1;
st += 1;
}
}
arith_encode(cinfo, st, 0);
/* Section F.1.4.4.1.2: Establish dc_context conditioning category */
if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
entropy->dc_context[ci] = 0; /* zero diff category */
else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
entropy->dc_context[ci] += 8; /* large diff category */
/* Figure F.9: Encoding the magnitude bit pattern of v */
st += 14;
while (m >>= 1)
arith_encode(cinfo, st, (m & v) ? 1 : 0);
}
/* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
if ((ke = cinfo->lim_Se) == 0) continue;
tbl = compptr->ac_tbl_no;
/* Establish EOB (end-of-block) index */
do {
if ((*block)[natural_order[ke]]) break;
} while (--ke);
/* Figure F.5: Encode_AC_Coefficients */
for (k = 0; k < ke;) {
st = entropy->ac_stats[tbl] + 3 * k;
arith_encode(cinfo, st, 0); /* EOB decision */
while ((v = (*block)[natural_order[++k]]) == 0) {
arith_encode(cinfo, st + 1, 0);
st += 3;
}
arith_encode(cinfo, st + 1, 1);
/* Figure F.6: Encoding nonzero value v */
/* Figure F.7: Encoding the sign of v */
if (v > 0) {
arith_encode(cinfo, entropy->fixed_bin, 0);
} else {
v = -v;
arith_encode(cinfo, entropy->fixed_bin, 1);
}
st += 2;
/* Figure F.8: Encoding the magnitude category of v */
m = 0;
if (v -= 1) {
arith_encode(cinfo, st, 1);
m = 1;
v2 = v;
if (v2 >>= 1) {
arith_encode(cinfo, st, 1);
m <<= 1;
st = entropy->ac_stats[tbl] +
(k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
while (v2 >>= 1) {
arith_encode(cinfo, st, 1);
m <<= 1;
st += 1;
}
}
}
arith_encode(cinfo, st, 0);
/* Figure F.9: Encoding the magnitude bit pattern of v */
st += 14;
while (m >>= 1)
arith_encode(cinfo, st, (m & v) ? 1 : 0);
}
/* Encode EOB decision only if k < cinfo->lim_Se */
if (k < cinfo->lim_Se) {
st = entropy->ac_stats[tbl] + 3 * k;
arith_encode(cinfo, st, 1);
}
}
return TRUE;
}
/*
* Initialize for an arithmetic-compressed scan.
*/
METHODDEF(void)
start_pass (j_compress_ptr cinfo, boolean gather_statistics)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
int ci, tbl;
jpeg_component_info * compptr;
if (gather_statistics)
/* Make sure to avoid that in the master control logic!
* We are fully adaptive here and need no extra
* statistics gathering pass!
*/
ERREXIT(cinfo, JERR_NOT_COMPILED);
/* We assume jcmaster.c already validated the progressive scan parameters. */
/* Select execution routines */
if (cinfo->progressive_mode) {
if (cinfo->Ah == 0) {
if (cinfo->Ss == 0)
entropy->pub.encode_mcu = encode_mcu_DC_first;
else
entropy->pub.encode_mcu = encode_mcu_AC_first;
} else {
if (cinfo->Ss == 0)
entropy->pub.encode_mcu = encode_mcu_DC_refine;
else
entropy->pub.encode_mcu = encode_mcu_AC_refine;
}
} else
entropy->pub.encode_mcu = encode_mcu;
/* Allocate & initialize requested statistics areas */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* DC needs no table for refinement scan */
if (cinfo->Ss == 0 && cinfo->Ah == 0) {
tbl = compptr->dc_tbl_no;
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
if (entropy->dc_stats[tbl] == NULL)
entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
/* Initialize DC predictions to 0 */
entropy->last_dc_val[ci] = 0;
entropy->dc_context[ci] = 0;
}
/* AC needs no table when not present */
if (cinfo->Se) {
tbl = compptr->ac_tbl_no;
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
if (entropy->ac_stats[tbl] == NULL)
entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
#ifdef CALCULATE_SPECTRAL_CONDITIONING
if (cinfo->progressive_mode)
/* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */
cinfo->arith_ac_K[tbl] = cinfo->Ss + ((8 + cinfo->Se - cinfo->Ss) >> 4);
#endif
}
}
/* Initialize arithmetic encoding variables */
entropy->c = 0;
entropy->a = 0x10000L;
entropy->sc = 0;
entropy->zc = 0;
entropy->ct = 11;
entropy->buffer = -1; /* empty */
/* Initialize restart stuff */
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num = 0;
}
/*
* Module initialization routine for arithmetic entropy encoding.
*/
GLOBAL(void)
jinit_arith_encoder (j_compress_ptr cinfo)
{
arith_entropy_ptr entropy;
int i;
entropy = (arith_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(arith_entropy_encoder));
cinfo->entropy = &entropy->pub;
entropy->pub.start_pass = start_pass;
entropy->pub.finish_pass = finish_pass;
/* Mark tables unallocated */
for (i = 0; i < NUM_ARITH_TBLS; i++) {
entropy->dc_stats[i] = NULL;
entropy->ac_stats[i] = NULL;
}
/* Initialize index for fixed probability estimation */
entropy->fixed_bin[0] = 113;
}
+80 -85
View File
@@ -2,7 +2,6 @@
* jccoefct.c
*
* Copyright (C) 1994-1997, Thomas G. Lane.
* Modified 2003-2011 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
@@ -150,13 +149,12 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
int blkn, bi, ci, yindex, yoffset, blockcnt;
JDIMENSION ypos, xpos;
jpeg_component_info *compptr;
forward_DCT_ptr forward_DCT;
/* Loop to write as much as one whole iMCU row */
for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
yoffset++) {
for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col;
MCU_col_num++) {
MCU_col_num++) {
/* Determine where data comes from in input_buf and do the DCT thing.
* Each call on forward_DCT processes a horizontal row of DCT blocks
* as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
@@ -168,48 +166,46 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
*/
blkn = 0;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
forward_DCT = cinfo->fdct->forward_DCT[compptr->component_index];
blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
: compptr->last_col_width;
xpos = MCU_col_num * compptr->MCU_sample_width;
ypos = yoffset * compptr->DCT_v_scaled_size;
/* ypos == (yoffset+yindex) * DCTSIZE */
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (coef->iMCU_row_num < last_iMCU_row ||
yoffset+yindex < compptr->last_row_height) {
(*forward_DCT) (cinfo, compptr,
input_buf[compptr->component_index],
coef->MCU_buffer[blkn],
ypos, xpos, (JDIMENSION) blockcnt);
if (blockcnt < compptr->MCU_width) {
/* Create some dummy blocks at the right edge of the image. */
FMEMZERO((void FAR *) coef->MCU_buffer[blkn + blockcnt],
(compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK));
for (bi = blockcnt; bi < compptr->MCU_width; bi++) {
coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0];
}
}
} else {
/* Create a row of dummy blocks at the bottom of the image. */
FMEMZERO((void FAR *) coef->MCU_buffer[blkn],
compptr->MCU_width * SIZEOF(JBLOCK));
for (bi = 0; bi < compptr->MCU_width; bi++) {
coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0];
}
compptr = cinfo->cur_comp_info[ci];
blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
: compptr->last_col_width;
xpos = MCU_col_num * compptr->MCU_sample_width;
ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (coef->iMCU_row_num < last_iMCU_row ||
yoffset+yindex < compptr->last_row_height) {
(*cinfo->fdct->forward_DCT) (cinfo, compptr,
input_buf[compptr->component_index],
coef->MCU_buffer[blkn],
ypos, xpos, (JDIMENSION) blockcnt);
if (blockcnt < compptr->MCU_width) {
/* Create some dummy blocks at the right edge of the image. */
jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt],
(compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK));
for (bi = blockcnt; bi < compptr->MCU_width; bi++) {
coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0];
}
blkn += compptr->MCU_width;
ypos += compptr->DCT_v_scaled_size;
}
} else {
/* Create a row of dummy blocks at the bottom of the image. */
jzero_far((void FAR *) coef->MCU_buffer[blkn],
compptr->MCU_width * SIZEOF(JBLOCK));
for (bi = 0; bi < compptr->MCU_width; bi++) {
coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0];
}
}
blkn += compptr->MCU_width;
ypos += DCTSIZE;
}
}
/* Try to write the MCU. In event of a suspension failure, we will
* re-DCT the MCU on restart (a bit inefficient, could be fixed...)
*/
if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
/* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset;
coef->mcu_ctr = MCU_col_num;
return FALSE;
/* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset;
coef->mcu_ctr = MCU_col_num;
return FALSE;
}
}
/* Completed an MCU row, but perhaps not an iMCU row */
@@ -256,7 +252,6 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
jpeg_component_info *compptr;
JBLOCKARRAY buffer;
JBLOCKROW thisblockrow, lastblockrow;
forward_DCT_ptr forward_DCT;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -279,23 +274,23 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
ndummy = (int) (blocks_across % h_samp_factor);
if (ndummy > 0)
ndummy = h_samp_factor - ndummy;
forward_DCT = cinfo->fdct->forward_DCT[ci];
/* Perform DCT for all non-dummy blocks in this iMCU row. Each call
* on forward_DCT processes a complete horizontal row of DCT blocks.
*/
for (block_row = 0; block_row < block_rows; block_row++) {
thisblockrow = buffer[block_row];
(*forward_DCT) (cinfo, compptr, input_buf[ci], thisblockrow,
(JDIMENSION) (block_row * compptr->DCT_v_scaled_size),
(JDIMENSION) 0, blocks_across);
(*cinfo->fdct->forward_DCT) (cinfo, compptr,
input_buf[ci], thisblockrow,
(JDIMENSION) (block_row * DCTSIZE),
(JDIMENSION) 0, blocks_across);
if (ndummy > 0) {
/* Create dummy blocks at the right edge of the image. */
thisblockrow += blocks_across; /* => first dummy block */
FMEMZERO((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));
lastDC = thisblockrow[-1][0];
for (bi = 0; bi < ndummy; bi++) {
thisblockrow[bi][0] = lastDC;
}
/* Create dummy blocks at the right edge of the image. */
thisblockrow += blocks_across; /* => first dummy block */
jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));
lastDC = thisblockrow[-1][0];
for (bi = 0; bi < ndummy; bi++) {
thisblockrow[bi][0] = lastDC;
}
}
}
/* If at end of image, create dummy block rows as needed.
@@ -307,19 +302,19 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
blocks_across += ndummy; /* include lower right corner */
MCUs_across = blocks_across / h_samp_factor;
for (block_row = block_rows; block_row < compptr->v_samp_factor;
block_row++) {
thisblockrow = buffer[block_row];
lastblockrow = buffer[block_row-1];
FMEMZERO((void FAR *) thisblockrow,
(size_t) (blocks_across * SIZEOF(JBLOCK)));
for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {
lastDC = lastblockrow[h_samp_factor-1][0];
for (bi = 0; bi < h_samp_factor; bi++) {
thisblockrow[bi][0] = lastDC;
}
thisblockrow += h_samp_factor; /* advance to next MCU in row */
lastblockrow += h_samp_factor;
}
block_row++) {
thisblockrow = buffer[block_row];
lastblockrow = buffer[block_row-1];
jzero_far((void FAR *) thisblockrow,
(size_t) (blocks_across * SIZEOF(JBLOCK)));
for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {
lastDC = lastblockrow[h_samp_factor-1][0];
for (bi = 0; bi < h_samp_factor; bi++) {
thisblockrow[bi][0] = lastDC;
}
thisblockrow += h_samp_factor; /* advance to next MCU in row */
lastblockrow += h_samp_factor;
}
}
}
}
@@ -369,25 +364,25 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
yoffset++) {
for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
MCU_col_num++) {
MCU_col_num++) {
/* Construct list of pointers to DCT blocks belonging to this MCU */
blkn = 0; /* index of current DCT block within MCU */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
start_col = MCU_col_num * compptr->MCU_width;
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
coef->MCU_buffer[blkn++] = buffer_ptr++;
}
}
compptr = cinfo->cur_comp_info[ci];
start_col = MCU_col_num * compptr->MCU_width;
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
coef->MCU_buffer[blkn++] = buffer_ptr++;
}
}
}
/* Try to write the MCU. */
if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
/* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset;
coef->mcu_ctr = MCU_col_num;
return FALSE;
/* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset;
coef->mcu_ctr = MCU_col_num;
return FALSE;
}
}
/* Completed an MCU row, but perhaps not an iMCU row */
@@ -413,7 +408,7 @@ jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_coef_controller));
SIZEOF(my_coef_controller));
cinfo->coef = (struct jpeg_c_coef_controller *) coef;
coef->pub.start_pass = start_pass_coef;
@@ -426,14 +421,14 @@ jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
jpeg_component_info *compptr;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
ci++, compptr++) {
coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
(JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor),
(JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor),
(JDIMENSION) compptr->v_samp_factor);
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
(JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor),
(JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor),
(JDIMENSION) compptr->v_samp_factor);
}
#else
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
@@ -445,7 +440,7 @@ jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
buffer = (JBLOCKROW)
(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
coef->MCU_buffer[i] = buffer + i;
}
+53 -135
View File
@@ -2,7 +2,6 @@
* jccolor.c
*
* Copyright (C) 1991-1996, Thomas G. Lane.
* Modified 2011-2012 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
@@ -93,7 +92,7 @@ rgb_ycc_start (j_compress_ptr cinfo)
/* Allocate and fill in the conversion tables. */
cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(TABLE_SIZE * SIZEOF(INT32)));
(TABLE_SIZE * SIZEOF(INT32)));
for (i = 0; i <= MAXJSAMPLE; i++) {
rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i;
@@ -129,12 +128,12 @@ rgb_ycc_start (j_compress_ptr cinfo)
METHODDEF(void)
rgb_ycc_convert (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
register INT32 * ctab = cconvert->rgb_ycc_tab;
register int r, g, b;
register INT32 * ctab = cconvert->rgb_ycc_tab;
register JSAMPROW inptr;
register JSAMPROW outptr0, outptr1, outptr2;
register JDIMENSION col;
@@ -150,6 +149,7 @@ rgb_ycc_convert (j_compress_ptr cinfo,
r = GETJSAMPLE(inptr[RGB_RED]);
g = GETJSAMPLE(inptr[RGB_GREEN]);
b = GETJSAMPLE(inptr[RGB_BLUE]);
inptr += RGB_PIXELSIZE;
/* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
* must be too; we do not need an explicit range-limiting operation.
* Hence the value being shifted is never negative, and we don't
@@ -157,17 +157,16 @@ rgb_ycc_convert (j_compress_ptr cinfo,
*/
/* Y */
outptr0[col] = (JSAMPLE)
((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
>> SCALEBITS);
((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
>> SCALEBITS);
/* Cb */
outptr1[col] = (JSAMPLE)
((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
>> SCALEBITS);
((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
>> SCALEBITS);
/* Cr */
outptr2[col] = (JSAMPLE)
((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
>> SCALEBITS);
inptr += RGB_PIXELSIZE;
((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
>> SCALEBITS);
}
}
}
@@ -185,12 +184,12 @@ rgb_ycc_convert (j_compress_ptr cinfo,
METHODDEF(void)
rgb_gray_convert (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
register INT32 * ctab = cconvert->rgb_ycc_tab;
register int r, g, b;
register INT32 * ctab = cconvert->rgb_ycc_tab;
register JSAMPROW inptr;
register JSAMPROW outptr;
register JDIMENSION col;
@@ -198,16 +197,17 @@ rgb_gray_convert (j_compress_ptr cinfo,
while (--num_rows >= 0) {
inptr = *input_buf++;
outptr = output_buf[0][output_row++];
outptr = output_buf[0][output_row];
output_row++;
for (col = 0; col < num_cols; col++) {
r = GETJSAMPLE(inptr[RGB_RED]);
g = GETJSAMPLE(inptr[RGB_GREEN]);
b = GETJSAMPLE(inptr[RGB_BLUE]);
inptr += RGB_PIXELSIZE;
/* Y */
outptr[col] = (JSAMPLE)
((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
>> SCALEBITS);
inptr += RGB_PIXELSIZE;
((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
>> SCALEBITS);
}
}
}
@@ -223,12 +223,12 @@ rgb_gray_convert (j_compress_ptr cinfo,
METHODDEF(void)
cmyk_ycck_convert (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
register INT32 * ctab = cconvert->rgb_ycc_tab;
register int r, g, b;
register INT32 * ctab = cconvert->rgb_ycc_tab;
register JSAMPROW inptr;
register JSAMPROW outptr0, outptr1, outptr2, outptr3;
register JDIMENSION col;
@@ -247,6 +247,7 @@ cmyk_ycck_convert (j_compress_ptr cinfo,
b = MAXJSAMPLE - GETJSAMPLE(inptr[2]);
/* K passes through as-is */
outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */
inptr += 4;
/* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
* must be too; we do not need an explicit range-limiting operation.
* Hence the value being shifted is never negative, and we don't
@@ -254,56 +255,16 @@ cmyk_ycck_convert (j_compress_ptr cinfo,
*/
/* Y */
outptr0[col] = (JSAMPLE)
((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
>> SCALEBITS);
((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
>> SCALEBITS);
/* Cb */
outptr1[col] = (JSAMPLE)
((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
>> SCALEBITS);
((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
>> SCALEBITS);
/* Cr */
outptr2[col] = (JSAMPLE)
((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
>> SCALEBITS);
inptr += 4;
}
}
}
/*
* Convert some rows of samples to the JPEG colorspace.
* [R,G,B] to [R-G,G,B-G] conversion with modulo calculation
* (forward reversible color transform).
*/
METHODDEF(void)
rgb_rgb1_convert (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
{
register int r, g, b;
register JSAMPROW inptr;
register JSAMPROW outptr0, outptr1, outptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
while (--num_rows >= 0) {
inptr = *input_buf++;
outptr0 = output_buf[0][output_row];
outptr1 = output_buf[1][output_row];
outptr2 = output_buf[2][output_row];
output_row++;
for (col = 0; col < num_cols; col++) {
r = GETJSAMPLE(inptr[RGB_RED]);
g = GETJSAMPLE(inptr[RGB_GREEN]);
b = GETJSAMPLE(inptr[RGB_BLUE]);
/* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD
* (modulo) operator is equivalent to the bitmask operator AND.
*/
outptr0[col] = (JSAMPLE) ((r - g + CENTERJSAMPLE) & MAXJSAMPLE);
outptr1[col] = (JSAMPLE) g;
outptr2[col] = (JSAMPLE) ((b - g + CENTERJSAMPLE) & MAXJSAMPLE);
inptr += RGB_PIXELSIZE;
((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
>> SCALEBITS);
}
}
}
@@ -317,18 +278,19 @@ rgb_rgb1_convert (j_compress_ptr cinfo,
METHODDEF(void)
grayscale_convert (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
{
int instride = cinfo->input_components;
register JSAMPROW inptr;
register JSAMPROW outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
int instride = cinfo->input_components;
while (--num_rows >= 0) {
inptr = *input_buf++;
outptr = output_buf[0][output_row++];
outptr = output_buf[0][output_row];
output_row++;
for (col = 0; col < num_cols; col++) {
outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */
inptr += instride;
@@ -337,39 +299,6 @@ grayscale_convert (j_compress_ptr cinfo,
}
/*
* Convert some rows of samples to the JPEG colorspace.
* No colorspace conversion, but change from interleaved
* to separate-planes representation.
*/
METHODDEF(void)
rgb_convert (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
{
register JSAMPROW inptr;
register JSAMPROW outptr0, outptr1, outptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
while (--num_rows >= 0) {
inptr = *input_buf++;
outptr0 = output_buf[0][output_row];
outptr1 = output_buf[1][output_row];
outptr2 = output_buf[2][output_row];
output_row++;
for (col = 0; col < num_cols; col++) {
/* We can dispense with GETJSAMPLE() here */
outptr0[col] = inptr[RGB_RED];
outptr1[col] = inptr[RGB_GREEN];
outptr2[col] = inptr[RGB_BLUE];
inptr += RGB_PIXELSIZE;
}
}
}
/*
* Convert some rows of samples to the JPEG colorspace.
* This version handles multi-component colorspaces without conversion.
@@ -378,24 +307,24 @@ rgb_convert (j_compress_ptr cinfo,
METHODDEF(void)
null_convert (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows)
{
int ci;
register int nc = cinfo->num_components;
register JSAMPROW inptr;
register JSAMPROW outptr;
register JDIMENSION col;
register int ci;
int nc = cinfo->num_components;
JDIMENSION num_cols = cinfo->image_width;
while (--num_rows >= 0) {
/* It seems fastest to make a separate pass for each component. */
for (ci = 0; ci < nc; ci++) {
inptr = input_buf[0] + ci;
inptr = *input_buf;
outptr = output_buf[ci][output_row];
for (col = 0; col < num_cols; col++) {
*outptr++ = *inptr; /* don't need GETJSAMPLE() here */
inptr += nc;
outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */
inptr += nc;
}
}
input_buf++;
@@ -426,8 +355,8 @@ jinit_color_converter (j_compress_ptr cinfo)
cconvert = (my_cconvert_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_color_converter));
cinfo->cconvert = &cconvert->pub;
SIZEOF(my_color_converter));
cinfo->cconvert = (struct jpeg_color_converter *) cconvert;
/* set start_pass to null method until we find out differently */
cconvert->pub.start_pass = null_method;
@@ -439,9 +368,11 @@ jinit_color_converter (j_compress_ptr cinfo)
break;
case JCS_RGB:
#if RGB_PIXELSIZE != 3
if (cinfo->input_components != RGB_PIXELSIZE)
ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
break;
#endif /* else share code with YCbCr */
case JCS_YCbCr:
if (cinfo->input_components != 3)
@@ -460,41 +391,28 @@ jinit_color_converter (j_compress_ptr cinfo)
break;
}
/* Support color transform only for RGB colorspace */
if (cinfo->color_transform && cinfo->jpeg_color_space != JCS_RGB)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
/* Check num_components, set conversion method based on requested space */
switch (cinfo->jpeg_color_space) {
case JCS_GRAYSCALE:
if (cinfo->num_components != 1)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_GRAYSCALE ||
cinfo->in_color_space == JCS_YCbCr)
if (cinfo->in_color_space == JCS_GRAYSCALE)
cconvert->pub.color_convert = grayscale_convert;
else if (cinfo->in_color_space == JCS_RGB) {
cconvert->pub.start_pass = rgb_ycc_start;
cconvert->pub.color_convert = rgb_gray_convert;
} else
} else if (cinfo->in_color_space == JCS_YCbCr)
cconvert->pub.color_convert = grayscale_convert;
else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_RGB:
if (cinfo->num_components != 3)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_RGB) {
switch (cinfo->color_transform) {
case JCT_NONE:
cconvert->pub.color_convert = rgb_convert;
break;
case JCT_SUBTRACT_GREEN:
cconvert->pub.color_convert = rgb_rgb1_convert;
break;
default:
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
}
} else
if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3)
cconvert->pub.color_convert = null_convert;
else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
@@ -533,7 +451,7 @@ jinit_color_converter (j_compress_ptr cinfo)
default: /* allow null conversion of JCS_UNKNOWN */
if (cinfo->jpeg_color_space != cinfo->in_color_space ||
cinfo->num_components != cinfo->input_components)
cinfo->num_components != cinfo->input_components)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cconvert->pub.color_convert = null_convert;
break;
+262 -357
View File
@@ -23,7 +23,7 @@ typedef struct {
struct jpeg_forward_dct pub; /* public fields */
/* Pointer to the DCT routine actually in use */
forward_DCT_method_ptr do_dct[MAX_COMPONENTS];
forward_DCT_method_ptr do_dct;
/* The actual post-DCT divisors --- not identical to the quant table
* entries, because of scaling (especially for an unnormalized DCT).
@@ -33,7 +33,7 @@ typedef struct {
#ifdef DCT_FLOAT_SUPPORTED
/* Same as above for the floating-point case. */
float_DCT_method_ptr do_float_dct[MAX_COMPONENTS];
float_DCT_method_ptr do_float_dct;
FAST_FLOAT * float_divisors[NUM_QUANT_TBLS];
#endif
} my_fdct_controller;
@@ -41,132 +41,6 @@ typedef struct {
typedef my_fdct_controller * my_fdct_ptr;
/* The current scaled-DCT routines require ISLOW-style divisor tables,
* so be sure to compile that code if either ISLOW or SCALING is requested.
*/
#ifdef DCT_ISLOW_SUPPORTED
#define PROVIDE_ISLOW_TABLES
#else
#ifdef DCT_SCALING_SUPPORTED
#define PROVIDE_ISLOW_TABLES
#endif
#endif
/*
* Perform forward DCT on one or more blocks of a component.
*
* The input samples are taken from the sample_data[] array starting at
* position start_row/start_col, and moving to the right for any additional
* blocks. The quantized coefficients are returned in coef_blocks[].
*/
METHODDEF(void)
forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks)
/* This version is used for integer DCT implementations. */
{
/* This routine is heavily used, so it's worth coding it tightly. */
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
forward_DCT_method_ptr do_dct = fdct->do_dct[compptr->component_index];
DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no];
DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */
JDIMENSION bi;
sample_data += start_row; /* fold in the vertical offset once */
for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {
/* Perform the DCT */
(*do_dct) (workspace, sample_data, start_col);
/* Quantize/descale the coefficients, and store into coef_blocks[] */
{ register DCTELEM temp, qval;
register int i;
register JCOEFPTR output_ptr = coef_blocks[bi];
for (i = 0; i < DCTSIZE2; i++) {
qval = divisors[i];
temp = workspace[i];
/* Divide the coefficient value by qval, ensuring proper rounding.
* Since C does not specify the direction of rounding for negative
* quotients, we have to force the dividend positive for portability.
*
* In most files, at least half of the output values will be zero
* (at default quantization settings, more like three-quarters...)
* so we should ensure that this case is fast. On many machines,
* a comparison is enough cheaper than a divide to make a special test
* a win. Since both inputs will be nonnegative, we need only test
* for a < b to discover whether a/b is 0.
* If your machine's division is fast enough, define FAST_DIVIDE.
*/
#ifdef FAST_DIVIDE
#define DIVIDE_BY(a,b) a /= b
#else
#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0
#endif
if (temp < 0) {
temp = -temp;
temp += qval>>1; /* for rounding */
DIVIDE_BY(temp, qval);
temp = -temp;
} else {
temp += qval>>1; /* for rounding */
DIVIDE_BY(temp, qval);
}
output_ptr[i] = (JCOEF) temp;
}
}
}
}
#ifdef DCT_FLOAT_SUPPORTED
METHODDEF(void)
forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks)
/* This version is used for floating-point DCT implementations. */
{
/* This routine is heavily used, so it's worth coding it tightly. */
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
float_DCT_method_ptr do_dct = fdct->do_float_dct[compptr->component_index];
FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no];
FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */
JDIMENSION bi;
sample_data += start_row; /* fold in the vertical offset once */
for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {
/* Perform the DCT */
(*do_dct) (workspace, sample_data, start_col);
/* Quantize/descale the coefficients, and store into coef_blocks[] */
{ register FAST_FLOAT temp;
register int i;
register JCOEFPTR output_ptr = coef_blocks[bi];
for (i = 0; i < DCTSIZE2; i++) {
/* Apply the quantization and scaling factor */
temp = workspace[i] * divisors[i];
/* Round to nearest integer.
* Since C does not specify the direction of rounding for negative
* quotients, we have to force the dividend positive for portability.
* The maximum coefficient size is +-16K (for 12-bit data), so this
* code should work for either 16-bit or 32-bit ints.
*/
output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384);
}
}
}
}
#endif /* DCT_FLOAT_SUPPORTED */
/*
* Initialize for a processing pass.
* Verify that all referenced Q-tables are present, and set up
@@ -182,270 +56,108 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
int ci, qtblno, i;
jpeg_component_info *compptr;
int method = 0;
JQUANT_TBL * qtbl;
DCTELEM * dtbl;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Select the proper DCT routine for this component's scaling */
switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) {
#ifdef DCT_SCALING_SUPPORTED
case ((1 << 8) + 1):
fdct->do_dct[ci] = jpeg_fdct_1x1;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((2 << 8) + 2):
fdct->do_dct[ci] = jpeg_fdct_2x2;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((3 << 8) + 3):
fdct->do_dct[ci] = jpeg_fdct_3x3;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((4 << 8) + 4):
fdct->do_dct[ci] = jpeg_fdct_4x4;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((5 << 8) + 5):
fdct->do_dct[ci] = jpeg_fdct_5x5;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((6 << 8) + 6):
fdct->do_dct[ci] = jpeg_fdct_6x6;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((7 << 8) + 7):
fdct->do_dct[ci] = jpeg_fdct_7x7;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((9 << 8) + 9):
fdct->do_dct[ci] = jpeg_fdct_9x9;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((10 << 8) + 10):
fdct->do_dct[ci] = jpeg_fdct_10x10;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((11 << 8) + 11):
fdct->do_dct[ci] = jpeg_fdct_11x11;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((12 << 8) + 12):
fdct->do_dct[ci] = jpeg_fdct_12x12;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((13 << 8) + 13):
fdct->do_dct[ci] = jpeg_fdct_13x13;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((14 << 8) + 14):
fdct->do_dct[ci] = jpeg_fdct_14x14;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((15 << 8) + 15):
fdct->do_dct[ci] = jpeg_fdct_15x15;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((16 << 8) + 16):
fdct->do_dct[ci] = jpeg_fdct_16x16;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((16 << 8) + 8):
fdct->do_dct[ci] = jpeg_fdct_16x8;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((14 << 8) + 7):
fdct->do_dct[ci] = jpeg_fdct_14x7;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((12 << 8) + 6):
fdct->do_dct[ci] = jpeg_fdct_12x6;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((10 << 8) + 5):
fdct->do_dct[ci] = jpeg_fdct_10x5;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((8 << 8) + 4):
fdct->do_dct[ci] = jpeg_fdct_8x4;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((6 << 8) + 3):
fdct->do_dct[ci] = jpeg_fdct_6x3;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((4 << 8) + 2):
fdct->do_dct[ci] = jpeg_fdct_4x2;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((2 << 8) + 1):
fdct->do_dct[ci] = jpeg_fdct_2x1;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((8 << 8) + 16):
fdct->do_dct[ci] = jpeg_fdct_8x16;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((7 << 8) + 14):
fdct->do_dct[ci] = jpeg_fdct_7x14;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((6 << 8) + 12):
fdct->do_dct[ci] = jpeg_fdct_6x12;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((5 << 8) + 10):
fdct->do_dct[ci] = jpeg_fdct_5x10;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((4 << 8) + 8):
fdct->do_dct[ci] = jpeg_fdct_4x8;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((3 << 8) + 6):
fdct->do_dct[ci] = jpeg_fdct_3x6;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((2 << 8) + 4):
fdct->do_dct[ci] = jpeg_fdct_2x4;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
case ((1 << 8) + 2):
fdct->do_dct[ci] = jpeg_fdct_1x2;
method = JDCT_ISLOW; /* jfdctint uses islow-style table */
break;
#endif
case ((DCTSIZE << 8) + DCTSIZE):
switch (cinfo->dct_method) {
#ifdef DCT_ISLOW_SUPPORTED
case JDCT_ISLOW:
fdct->do_dct[ci] = jpeg_fdct_islow;
method = JDCT_ISLOW;
break;
#endif
#ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST:
fdct->do_dct[ci] = jpeg_fdct_ifast;
method = JDCT_IFAST;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
fdct->do_float_dct[ci] = jpeg_fdct_float;
method = JDCT_FLOAT;
break;
#endif
default:
ERREXIT(cinfo, JERR_NOT_COMPILED);
break;
}
break;
default:
ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size);
break;
}
qtblno = compptr->quant_tbl_no;
/* Make sure specified quantization table is present */
if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
cinfo->quant_tbl_ptrs[qtblno] == NULL)
cinfo->quant_tbl_ptrs[qtblno] == NULL)
ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
qtbl = cinfo->quant_tbl_ptrs[qtblno];
/* Compute divisors for this quant table */
/* We may do this more than once for same table, but it's not a big deal */
switch (method) {
#ifdef PROVIDE_ISLOW_TABLES
switch (cinfo->dct_method) {
#ifdef DCT_ISLOW_SUPPORTED
case JDCT_ISLOW:
/* For LL&M IDCT method, divisors are equal to raw quantization
* coefficients multiplied by 8 (to counteract scaling).
*/
if (fdct->divisors[qtblno] == NULL) {
fdct->divisors[qtblno] = (DCTELEM *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
DCTSIZE2 * SIZEOF(DCTELEM));
fdct->divisors[qtblno] = (DCTELEM *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
DCTSIZE2 * SIZEOF(DCTELEM));
}
dtbl = fdct->divisors[qtblno];
for (i = 0; i < DCTSIZE2; i++) {
dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3;
dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3;
}
fdct->pub.forward_DCT[ci] = forward_DCT;
break;
#endif
#ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST:
{
/* For AA&N IDCT method, divisors are equal to quantization
* coefficients scaled by scalefactor[row]*scalefactor[col], where
* scalefactor[0] = 1
* scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
* We apply a further scale factor of 8.
*/
/* For AA&N IDCT method, divisors are equal to quantization
* coefficients scaled by scalefactor[row]*scalefactor[col], where
* scalefactor[0] = 1
* scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
* We apply a further scale factor of 8.
*/
#define CONST_BITS 14
static const INT16 aanscales[DCTSIZE2] = {
/* precomputed values scaled up by 14 bits */
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
};
SHIFT_TEMPS
static const INT16 aanscales[DCTSIZE2] = {
/* precomputed values scaled up by 14 bits */
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
};
SHIFT_TEMPS
if (fdct->divisors[qtblno] == NULL) {
fdct->divisors[qtblno] = (DCTELEM *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
DCTSIZE2 * SIZEOF(DCTELEM));
}
dtbl = fdct->divisors[qtblno];
for (i = 0; i < DCTSIZE2; i++) {
dtbl[i] = (DCTELEM)
DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
(INT32) aanscales[i]),
CONST_BITS-3);
}
if (fdct->divisors[qtblno] == NULL) {
fdct->divisors[qtblno] = (DCTELEM *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
DCTSIZE2 * SIZEOF(DCTELEM));
}
dtbl = fdct->divisors[qtblno];
for (i = 0; i < DCTSIZE2; i++) {
dtbl[i] = (DCTELEM)
DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
(INT32) aanscales[i]),
CONST_BITS-3);
}
}
fdct->pub.forward_DCT[ci] = forward_DCT;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
{
/* For float AA&N IDCT method, divisors are equal to quantization
* coefficients scaled by scalefactor[row]*scalefactor[col], where
* scalefactor[0] = 1
* scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
* We apply a further scale factor of 8.
* What's actually stored is 1/divisor so that the inner loop can
* use a multiplication rather than a division.
*/
FAST_FLOAT * fdtbl;
int row, col;
static const double aanscalefactor[DCTSIZE] = {
1.0, 1.387039845, 1.306562965, 1.175875602,
1.0, 0.785694958, 0.541196100, 0.275899379
};
/* For float AA&N IDCT method, divisors are equal to quantization
* coefficients scaled by scalefactor[row]*scalefactor[col], where
* scalefactor[0] = 1
* scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
* We apply a further scale factor of 8.
* What's actually stored is 1/divisor so that the inner loop can
* use a multiplication rather than a division.
*/
FAST_FLOAT * fdtbl;
int row, col;
static const double aanscalefactor[DCTSIZE] = {
1.0, 1.387039845, 1.306562965, 1.175875602,
1.0, 0.785694958, 0.541196100, 0.275899379
};
if (fdct->float_divisors[qtblno] == NULL) {
fdct->float_divisors[qtblno] = (FAST_FLOAT *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
DCTSIZE2 * SIZEOF(FAST_FLOAT));
}
fdtbl = fdct->float_divisors[qtblno];
i = 0;
for (row = 0; row < DCTSIZE; row++) {
for (col = 0; col < DCTSIZE; col++) {
fdtbl[i] = (FAST_FLOAT)
(1.0 / (((double) qtbl->quantval[i] *
aanscalefactor[row] * aanscalefactor[col] * 8.0)));
i++;
}
}
if (fdct->float_divisors[qtblno] == NULL) {
fdct->float_divisors[qtblno] = (FAST_FLOAT *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
DCTSIZE2 * SIZEOF(FAST_FLOAT));
}
fdtbl = fdct->float_divisors[qtblno];
i = 0;
for (row = 0; row < DCTSIZE; row++) {
for (col = 0; col < DCTSIZE; col++) {
fdtbl[i] = (FAST_FLOAT)
(1.0 / (((double) qtbl->quantval[i] *
aanscalefactor[row] * aanscalefactor[col] * 8.0)));
i++;
}
}
}
fdct->pub.forward_DCT[ci] = forward_DCT_float;
break;
#endif
default:
@@ -456,6 +168,175 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
}
/*
* Perform forward DCT on one or more blocks of a component.
*
* The input samples are taken from the sample_data[] array starting at
* position start_row/start_col, and moving to the right for any additional
* blocks. The quantized coefficients are returned in coef_blocks[].
*/
METHODDEF(void)
forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks)
/* This version is used for integer DCT implementations. */
{
/* This routine is heavily used, so it's worth coding it tightly. */
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
forward_DCT_method_ptr do_dct = fdct->do_dct;
DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no];
DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */
JDIMENSION bi;
sample_data += start_row; /* fold in the vertical offset once */
for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) {
/* Load data into workspace, applying unsigned->signed conversion */
{ register DCTELEM *workspaceptr;
register JSAMPROW elemptr;
register int elemr;
workspaceptr = workspace;
for (elemr = 0; elemr < DCTSIZE; elemr++) {
elemptr = sample_data[elemr] + start_col;
#if DCTSIZE == 8 /* unroll the inner loop */
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
#else
{ register int elemc;
for (elemc = DCTSIZE; elemc > 0; elemc--) {
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
}
}
#endif
}
}
/* Perform the DCT */
(*do_dct) (workspace);
/* Quantize/descale the coefficients, and store into coef_blocks[] */
{ register DCTELEM temp, qval;
register int i;
register JCOEFPTR output_ptr = coef_blocks[bi];
for (i = 0; i < DCTSIZE2; i++) {
qval = divisors[i];
temp = workspace[i];
/* Divide the coefficient value by qval, ensuring proper rounding.
* Since C does not specify the direction of rounding for negative
* quotients, we have to force the dividend positive for portability.
*
* In most files, at least half of the output values will be zero
* (at default quantization settings, more like three-quarters...)
* so we should ensure that this case is fast. On many machines,
* a comparison is enough cheaper than a divide to make a special test
* a win. Since both inputs will be nonnegative, we need only test
* for a < b to discover whether a/b is 0.
* If your machine's division is fast enough, define FAST_DIVIDE.
*/
#ifdef FAST_DIVIDE
#define DIVIDE_BY(a,b) a /= b
#else
#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0
#endif
if (temp < 0) {
temp = -temp;
temp += qval>>1; /* for rounding */
DIVIDE_BY(temp, qval);
temp = -temp;
} else {
temp += qval>>1; /* for rounding */
DIVIDE_BY(temp, qval);
}
output_ptr[i] = (JCOEF) temp;
}
}
}
}
#ifdef DCT_FLOAT_SUPPORTED
METHODDEF(void)
forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks)
/* This version is used for floating-point DCT implementations. */
{
/* This routine is heavily used, so it's worth coding it tightly. */
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
float_DCT_method_ptr do_dct = fdct->do_float_dct;
FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no];
FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */
JDIMENSION bi;
sample_data += start_row; /* fold in the vertical offset once */
for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) {
/* Load data into workspace, applying unsigned->signed conversion */
{ register FAST_FLOAT *workspaceptr;
register JSAMPROW elemptr;
register int elemr;
workspaceptr = workspace;
for (elemr = 0; elemr < DCTSIZE; elemr++) {
elemptr = sample_data[elemr] + start_col;
#if DCTSIZE == 8 /* unroll the inner loop */
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
#else
{ register int elemc;
for (elemc = DCTSIZE; elemc > 0; elemc--) {
*workspaceptr++ = (FAST_FLOAT)
(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
}
}
#endif
}
}
/* Perform the DCT */
(*do_dct) (workspace);
/* Quantize/descale the coefficients, and store into coef_blocks[] */
{ register FAST_FLOAT temp;
register int i;
register JCOEFPTR output_ptr = coef_blocks[bi];
for (i = 0; i < DCTSIZE2; i++) {
/* Apply the quantization and scaling factor */
temp = workspace[i] * divisors[i];
/* Round to nearest integer.
* Since C does not specify the direction of rounding for negative
* quotients, we have to force the dividend positive for portability.
* The maximum coefficient size is +-16K (for 12-bit data), so this
* code should work for either 16-bit or 32-bit ints.
*/
output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384);
}
}
}
}
#endif /* DCT_FLOAT_SUPPORTED */
/*
* Initialize FDCT manager.
*/
@@ -468,10 +349,34 @@ jinit_forward_dct (j_compress_ptr cinfo)
fdct = (my_fdct_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_fdct_controller));
SIZEOF(my_fdct_controller));
cinfo->fdct = (struct jpeg_forward_dct *) fdct;
fdct->pub.start_pass = start_pass_fdctmgr;
switch (cinfo->dct_method) {
#ifdef DCT_ISLOW_SUPPORTED
case JDCT_ISLOW:
fdct->pub.forward_DCT = forward_DCT;
fdct->do_dct = jpeg_fdct_islow;
break;
#endif
#ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST:
fdct->pub.forward_DCT = forward_DCT;
fdct->do_dct = jpeg_fdct_ifast;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
fdct->pub.forward_DCT = forward_DCT_float;
fdct->do_float_dct = jpeg_fdct_float;
break;
#endif
default:
ERREXIT(cinfo, JERR_NOT_COMPILED);
break;
}
/* Mark divisor tables unallocated */
for (i = 0; i < NUM_QUANT_TBLS; i++) {
fdct->divisors[i] = NULL;
+210 -877
View File
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
/*
* jchuff.h
*
* Copyright (C) 1991-1997, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains declarations for Huffman entropy encoding routines
* that are shared between the sequential encoder (jchuff.c) and the
* progressive encoder (jcphuff.c). No other modules need to see these.
*/
/* The legal range of a DCT coefficient is
* -1024 .. +1023 for 8-bit data;
* -16384 .. +16383 for 12-bit data.
* Hence the magnitude should always fit in 10 or 14 bits respectively.
*/
#if BITS_IN_JSAMPLE == 8
#define MAX_COEF_BITS 10
#else
#define MAX_COEF_BITS 14
#endif
/* Derived data constructed for each Huffman table */
typedef struct {
unsigned int ehufco[256]; /* code for each symbol */
char ehufsi[256]; /* length of code for each symbol */
/* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */
} c_derived_tbl;
/* Short forms of external names for systems with brain-damaged linkers. */
#ifdef NEED_SHORT_EXTERNAL_NAMES
#define jpeg_make_c_derived_tbl jMkCDerived
#define jpeg_gen_optimal_table jGenOptTbl
#endif /* NEED_SHORT_EXTERNAL_NAMES */
/* Expand a Huffman table definition into the derived format */
EXTERN(void) jpeg_make_c_derived_tbl
JPP((j_compress_ptr cinfo, boolean isDC, int tblno,
c_derived_tbl ** pdtbl));
/* Generate an optimal table definition given the specified counts */
EXTERN(void) jpeg_gen_optimal_table
JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]));
+12 -5
View File
@@ -41,15 +41,22 @@ jinit_compress_master (j_compress_ptr cinfo)
/* Forward DCT */
jinit_forward_dct(cinfo);
/* Entropy encoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code)
jinit_arith_encoder(cinfo);
else {
jinit_huff_encoder(cinfo);
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->progressive_mode) {
#ifdef C_PROGRESSIVE_SUPPORTED
jinit_phuff_encoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_huff_encoder(cinfo);
}
/* Need a full-image coefficient buffer in any multi-pass mode. */
jinit_c_coef_controller(cinfo,
(boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding));
(boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding));
jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
jinit_marker_writer(cinfo);
+90 -94
View File
@@ -2,12 +2,11 @@
* jcmainct.c
*
* Copyright (C) 1994-1996, Thomas G. Lane.
* Modified 2003-2012 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the main buffer controller for compression.
* The main buffer lies between the pre-processor and the JPEG
* This file contains the main_ptr buffer controller for compression.
* The main_ptr buffer lies between the pre-processor and the JPEG
* compressor proper; it holds downsampled data in the JPEG colorspace.
*/
@@ -53,12 +52,12 @@ typedef my_main_controller * my_main_ptr;
/* Forward declarations */
METHODDEF(void) process_data_simple_main
JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
#ifdef FULL_MAIN_BUFFER_SUPPORTED
METHODDEF(void) process_data_buffer_main
JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
#endif
@@ -69,32 +68,32 @@ METHODDEF(void) process_data_buffer_main
METHODDEF(void)
start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
{
my_main_ptr mainp = (my_main_ptr) cinfo->main;
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
/* Do nothing in raw-data mode. */
if (cinfo->raw_data_in)
return;
mainp->cur_iMCU_row = 0; /* initialize counters */
mainp->rowgroup_ctr = 0;
mainp->suspended = FALSE;
mainp->pass_mode = pass_mode; /* save mode for use by process_data */
main_ptr->cur_iMCU_row = 0; /* initialize counters */
main_ptr->rowgroup_ctr = 0;
main_ptr->suspended = FALSE;
main_ptr->pass_mode = pass_mode; /* save mode for use by process_data */
switch (pass_mode) {
case JBUF_PASS_THRU:
#ifdef FULL_MAIN_BUFFER_SUPPORTED
if (mainp->whole_image[0] != NULL)
if (main_ptr->whole_image[0] != NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
#endif
mainp->pub.process_data = process_data_simple_main;
main_ptr->pub.process_data = process_data_simple_main;
break;
#ifdef FULL_MAIN_BUFFER_SUPPORTED
case JBUF_SAVE_SOURCE:
case JBUF_CRANK_DEST:
case JBUF_SAVE_AND_PASS:
if (mainp->whole_image[0] == NULL)
if (main_ptr->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
mainp->pub.process_data = process_data_buffer_main;
main_ptr->pub.process_data = process_data_buffer_main;
break;
#endif
default:
@@ -112,49 +111,49 @@ start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
METHODDEF(void)
process_data_simple_main (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail)
JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail)
{
my_main_ptr mainp = (my_main_ptr) cinfo->main;
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
while (mainp->cur_iMCU_row < cinfo->total_iMCU_rows) {
/* Read input data if we haven't filled the main buffer yet */
if (mainp->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)
while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
/* Read input data if we haven't filled the main_ptr buffer yet */
if (main_ptr->rowgroup_ctr < DCTSIZE)
(*cinfo->prep->pre_process_data) (cinfo,
input_buf, in_row_ctr, in_rows_avail,
mainp->buffer, &mainp->rowgroup_ctr,
(JDIMENSION) cinfo->min_DCT_v_scaled_size);
input_buf, in_row_ctr, in_rows_avail,
main_ptr->buffer, &main_ptr->rowgroup_ctr,
(JDIMENSION) DCTSIZE);
/* If we don't have a full iMCU row buffered, return to application for
* more data. Note that preprocessor will always pad to fill the iMCU row
* at the bottom of the image.
*/
if (mainp->rowgroup_ctr != (JDIMENSION) cinfo->min_DCT_v_scaled_size)
if (main_ptr->rowgroup_ctr != DCTSIZE)
return;
/* Send the completed row to the compressor */
if (! (*cinfo->coef->compress_data) (cinfo, mainp->buffer)) {
if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
/* If compressor did not consume the whole row, then we must need to
* suspend processing and return to the application. In this situation
* we pretend we didn't yet consume the last input row; otherwise, if
* it happened to be the last row of the image, the application would
* think we were done.
*/
if (! mainp->suspended) {
(*in_row_ctr)--;
mainp->suspended = TRUE;
if (! main_ptr->suspended) {
(*in_row_ctr)--;
main_ptr->suspended = TRUE;
}
return;
}
/* We did finish the row. Undo our little suspension hack if a previous
* call suspended; then mark the main buffer empty.
* call suspended; then mark the main_ptr buffer empty.
*/
if (mainp->suspended) {
if (main_ptr->suspended) {
(*in_row_ctr)++;
mainp->suspended = FALSE;
main_ptr->suspended = FALSE;
}
mainp->rowgroup_ctr = 0;
mainp->cur_iMCU_row++;
main_ptr->rowgroup_ctr = 0;
main_ptr->cur_iMCU_row++;
}
}
@@ -168,30 +167,28 @@ process_data_simple_main (j_compress_ptr cinfo,
METHODDEF(void)
process_data_buffer_main (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail)
JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail)
{
my_main_ptr mainp = (my_main_ptr) cinfo->main;
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
int ci;
jpeg_component_info *compptr;
boolean writing = (mainp->pass_mode != JBUF_CRANK_DEST);
boolean writing = (main_ptr->pass_mode != JBUF_CRANK_DEST);
while (mainp->cur_iMCU_row < cinfo->total_iMCU_rows) {
while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
/* Realign the virtual buffers if at the start of an iMCU row. */
if (mainp->rowgroup_ctr == 0) {
if (main_ptr->rowgroup_ctr == 0) {
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
mainp->buffer[ci] = (*cinfo->mem->access_virt_sarray)
((j_common_ptr) cinfo, mainp->whole_image[ci], mainp->cur_iMCU_row *
((JDIMENSION) (compptr->v_samp_factor * cinfo->min_DCT_v_scaled_size)),
(JDIMENSION) (compptr->v_samp_factor * cinfo->min_DCT_v_scaled_size),
writing);
ci++, compptr++) {
main_ptr->buffer[ci] = (*cinfo->mem->access_virt_sarray)
((j_common_ptr) cinfo, main_ptr->whole_image[ci],
main_ptr->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
(JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing);
}
/* In a read pass, pretend we just read some source data. */
if (! writing) {
*in_row_ctr += (JDIMENSION)
(cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size);
mainp->rowgroup_ctr = (JDIMENSION) cinfo->min_DCT_v_scaled_size;
*in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE;
main_ptr->rowgroup_ctr = DCTSIZE;
}
}
@@ -199,41 +196,41 @@ process_data_buffer_main (j_compress_ptr cinfo,
/* Note: preprocessor will pad if necessary to fill the last iMCU row. */
if (writing) {
(*cinfo->prep->pre_process_data) (cinfo,
input_buf, in_row_ctr, in_rows_avail,
mainp->buffer, &mainp->rowgroup_ctr,
(JDIMENSION) cinfo->min_DCT_v_scaled_size);
input_buf, in_row_ctr, in_rows_avail,
main_ptr->buffer, &main_ptr->rowgroup_ctr,
(JDIMENSION) DCTSIZE);
/* Return to application if we need more data to fill the iMCU row. */
if (mainp->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)
return;
if (main_ptr->rowgroup_ctr < DCTSIZE)
return;
}
/* Emit data, unless this is a sink-only pass. */
if (mainp->pass_mode != JBUF_SAVE_SOURCE) {
if (! (*cinfo->coef->compress_data) (cinfo, mainp->buffer)) {
/* If compressor did not consume the whole row, then we must need to
* suspend processing and return to the application. In this situation
* we pretend we didn't yet consume the last input row; otherwise, if
* it happened to be the last row of the image, the application would
* think we were done.
*/
if (! mainp->suspended) {
(*in_row_ctr)--;
mainp->suspended = TRUE;
}
return;
if (main_ptr->pass_mode != JBUF_SAVE_SOURCE) {
if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
/* If compressor did not consume the whole row, then we must need to
* suspend processing and return to the application. In this situation
* we pretend we didn't yet consume the last input row; otherwise, if
* it happened to be the last row of the image, the application would
* think we were done.
*/
if (! main_ptr->suspended) {
(*in_row_ctr)--;
main_ptr->suspended = TRUE;
}
return;
}
/* We did finish the row. Undo our little suspension hack if a previous
* call suspended; then mark the main buffer empty.
* call suspended; then mark the main_ptr buffer empty.
*/
if (mainp->suspended) {
(*in_row_ctr)++;
mainp->suspended = FALSE;
if (main_ptr->suspended) {
(*in_row_ctr)++;
main_ptr->suspended = FALSE;
}
}
/* If get here, we are done with this iMCU row. Mark buffer empty. */
mainp->rowgroup_ctr = 0;
mainp->cur_iMCU_row++;
main_ptr->rowgroup_ctr = 0;
main_ptr->cur_iMCU_row++;
}
}
@@ -241,21 +238,21 @@ process_data_buffer_main (j_compress_ptr cinfo,
/*
* Initialize main buffer controller.
* Initialize main_ptr buffer controller.
*/
GLOBAL(void)
jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
{
my_main_ptr mainp;
my_main_ptr main_ptr;
int ci;
jpeg_component_info *compptr;
mainp = (my_main_ptr)
main_ptr = (my_main_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_main_controller));
cinfo->main = &mainp->pub;
mainp->pub.start_pass = start_pass_main;
SIZEOF(my_main_controller));
cinfo->main = (struct jpeg_c_main_controller *) main_ptr;
main_ptr->pub.start_pass = start_pass_main;
/* We don't need to create a buffer in raw-data mode. */
if (cinfo->raw_data_in)
@@ -269,29 +266,28 @@ jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
/* Allocate a full-image virtual array for each component */
/* Note we pad the bottom to a multiple of the iMCU height */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
mainp->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size),
((JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor)) *
((JDIMENSION) cinfo->min_DCT_v_scaled_size),
(JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));
ci++, compptr++) {
main_ptr->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
compptr->width_in_blocks * DCTSIZE,
(JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor) * DCTSIZE,
(JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
}
#else
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
#endif
} else {
#ifdef FULL_MAIN_BUFFER_SUPPORTED
mainp->whole_image[0] = NULL; /* flag for no virtual arrays */
main_ptr->whole_image[0] = NULL; /* flag for no virtual arrays */
#endif
/* Allocate a strip buffer for each component */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
mainp->buffer[ci] = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE,
compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size),
(JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));
ci++, compptr++) {
main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE,
compptr->width_in_blocks * DCTSIZE,
(JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
}
}
}
+59 -114
View File
@@ -2,7 +2,6 @@
* jcmarker.c
*
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2003-2012 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
@@ -73,7 +72,6 @@ typedef enum { /* JPEG marker codes */
M_APP15 = 0xef,
M_JPG0 = 0xf0,
M_JPG8 = 0xf8,
M_JPG13 = 0xfd,
M_COM = 0xfe,
@@ -155,24 +153,23 @@ emit_dqt (j_compress_ptr cinfo, int index)
ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index);
prec = 0;
for (i = 0; i <= cinfo->lim_Se; i++) {
if (qtbl->quantval[cinfo->natural_order[i]] > 255)
for (i = 0; i < DCTSIZE2; i++) {
if (qtbl->quantval[i] > 255)
prec = 1;
}
if (! qtbl->sent_table) {
emit_marker(cinfo, M_DQT);
emit_2bytes(cinfo,
prec ? cinfo->lim_Se * 2 + 2 + 1 + 2 : cinfo->lim_Se + 1 + 1 + 2);
emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2);
emit_byte(cinfo, index + (prec<<4));
for (i = 0; i <= cinfo->lim_Se; i++) {
for (i = 0; i < DCTSIZE2; i++) {
/* The table entries must be emitted in zigzag order. */
unsigned int qval = qtbl->quantval[cinfo->natural_order[i]];
unsigned int qval = qtbl->quantval[jpeg_natural_order[i]];
if (prec)
emit_byte(cinfo, (int) (qval >> 8));
emit_byte(cinfo, (int) (qval >> 8));
emit_byte(cinfo, (int) (qval & 0xFF));
}
@@ -238,32 +235,26 @@ emit_dac (j_compress_ptr cinfo)
for (i = 0; i < cinfo->comps_in_scan; i++) {
compptr = cinfo->cur_comp_info[i];
/* DC needs no table for refinement scan */
if (cinfo->Ss == 0 && cinfo->Ah == 0)
dc_in_use[compptr->dc_tbl_no] = 1;
/* AC needs no table when not present */
if (cinfo->Se)
ac_in_use[compptr->ac_tbl_no] = 1;
dc_in_use[compptr->dc_tbl_no] = 1;
ac_in_use[compptr->ac_tbl_no] = 1;
}
length = 0;
for (i = 0; i < NUM_ARITH_TBLS; i++)
length += dc_in_use[i] + ac_in_use[i];
if (length) {
emit_marker(cinfo, M_DAC);
emit_marker(cinfo, M_DAC);
emit_2bytes(cinfo, length*2 + 2);
emit_2bytes(cinfo, length*2 + 2);
for (i = 0; i < NUM_ARITH_TBLS; i++) {
if (dc_in_use[i]) {
emit_byte(cinfo, i);
emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
}
if (ac_in_use[i]) {
emit_byte(cinfo, i + 0x10);
emit_byte(cinfo, cinfo->arith_ac_K[i]);
}
for (i = 0; i < NUM_ARITH_TBLS; i++) {
if (dc_in_use[i]) {
emit_byte(cinfo, i);
emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
}
if (ac_in_use[i]) {
emit_byte(cinfo, i + 0x10);
emit_byte(cinfo, cinfo->arith_ac_K[i]);
}
}
#endif /* C_ARITH_CODING_SUPPORTED */
@@ -282,37 +273,6 @@ emit_dri (j_compress_ptr cinfo)
}
LOCAL(void)
emit_lse_ict (j_compress_ptr cinfo)
/* Emit an LSE inverse color transform specification marker */
{
/* Support only 1 transform */
if (cinfo->color_transform != JCT_SUBTRACT_GREEN ||
cinfo->num_components < 3)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
emit_marker(cinfo, M_JPG8);
emit_2bytes(cinfo, 24); /* fixed length */
emit_byte(cinfo, 0x0D); /* ID inverse transform specification */
emit_2bytes(cinfo, MAXJSAMPLE); /* MAXTRANS */
emit_byte(cinfo, 3); /* Nt=3 */
emit_byte(cinfo, cinfo->comp_info[1].component_id);
emit_byte(cinfo, cinfo->comp_info[0].component_id);
emit_byte(cinfo, cinfo->comp_info[2].component_id);
emit_byte(cinfo, 0x80); /* F1: CENTER1=1, NORM1=0 */
emit_2bytes(cinfo, 0); /* A(1,1)=0 */
emit_2bytes(cinfo, 0); /* A(1,2)=0 */
emit_byte(cinfo, 0); /* F2: CENTER2=0, NORM2=0 */
emit_2bytes(cinfo, 1); /* A(2,1)=1 */
emit_2bytes(cinfo, 0); /* A(2,2)=0 */
emit_byte(cinfo, 0); /* F3: CENTER3=0, NORM3=0 */
emit_2bytes(cinfo, 1); /* A(3,1)=1 */
emit_2bytes(cinfo, 0); /* A(3,2)=0 */
}
LOCAL(void)
emit_sof (j_compress_ptr cinfo, JPEG_MARKER code)
/* Emit a SOF marker */
@@ -325,13 +285,13 @@ emit_sof (j_compress_ptr cinfo, JPEG_MARKER code)
emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
/* Make sure image isn't bigger than SOF field can handle */
if ((long) cinfo->jpeg_height > 65535L ||
(long) cinfo->jpeg_width > 65535L)
if ((long) cinfo->image_height > 65535L ||
(long) cinfo->image_width > 65535L)
ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);
emit_byte(cinfo, cinfo->data_precision);
emit_2bytes(cinfo, (int) cinfo->jpeg_height);
emit_2bytes(cinfo, (int) cinfo->jpeg_width);
emit_2bytes(cinfo, (int) cinfo->image_height);
emit_2bytes(cinfo, (int) cinfo->image_width);
emit_byte(cinfo, cinfo->num_components);
@@ -360,16 +320,22 @@ emit_sos (j_compress_ptr cinfo)
for (i = 0; i < cinfo->comps_in_scan; i++) {
compptr = cinfo->cur_comp_info[i];
emit_byte(cinfo, compptr->component_id);
/* We emit 0 for unused field(s); this is recommended by the P&M text
* but does not seem to be specified in the standard.
*/
/* DC needs no table for refinement scan */
td = cinfo->Ss == 0 && cinfo->Ah == 0 ? compptr->dc_tbl_no : 0;
/* AC needs no table when not present */
ta = cinfo->Se ? compptr->ac_tbl_no : 0;
td = compptr->dc_tbl_no;
ta = compptr->ac_tbl_no;
if (cinfo->progressive_mode) {
/* Progressive mode: only DC or only AC tables are used in one scan;
* furthermore, Huffman coding of DC refinement uses no table at all.
* We emit 0 for unused field(s); this is recommended by the P&M text
* but does not seem to be specified in the standard.
*/
if (cinfo->Ss == 0) {
ta = 0; /* DC scan */
if (cinfo->Ah != 0 && !cinfo->arith_code)
td = 0; /* no DC table either */
} else {
td = 0; /* AC scan */
}
}
emit_byte(cinfo, (td << 4) + ta);
}
@@ -379,22 +345,6 @@ emit_sos (j_compress_ptr cinfo)
}
LOCAL(void)
emit_pseudo_sos (j_compress_ptr cinfo)
/* Emit a pseudo SOS marker */
{
emit_marker(cinfo, M_SOS);
emit_2bytes(cinfo, 2 + 1 + 3); /* length */
emit_byte(cinfo, 0); /* Ns */
emit_byte(cinfo, 0); /* Ss */
emit_byte(cinfo, cinfo->block_size * cinfo->block_size - 1); /* Se */
emit_byte(cinfo, 0); /* Ah/Al */
}
LOCAL(void)
emit_jfif_app0 (j_compress_ptr cinfo)
/* Emit a JFIF-compliant APP0 marker */
@@ -534,8 +484,7 @@ write_file_header (j_compress_ptr cinfo)
/*
* Write frame header.
* This consists of DQT and SOFn markers,
* a conditional LSE marker and a conditional pseudo SOS marker.
* This consists of DQT and SOFn markers.
* Note that we do not emit the SOF until we have emitted the DQT(s).
* This avoids compatibility problems with incorrect implementations that
* try to error-check the quant table numbers as soon as they see the SOF.
@@ -562,14 +511,14 @@ write_frame_header (j_compress_ptr cinfo)
* Note we assume that Huffman table numbers won't be changed later.
*/
if (cinfo->arith_code || cinfo->progressive_mode ||
cinfo->data_precision != 8 || cinfo->block_size != DCTSIZE) {
cinfo->data_precision != 8) {
is_baseline = FALSE;
} else {
is_baseline = TRUE;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
ci++, compptr++) {
if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1)
is_baseline = FALSE;
is_baseline = FALSE;
}
if (prec && is_baseline) {
is_baseline = FALSE;
@@ -580,10 +529,7 @@ write_frame_header (j_compress_ptr cinfo)
/* Emit the proper SOF marker */
if (cinfo->arith_code) {
if (cinfo->progressive_mode)
emit_sof(cinfo, M_SOF10); /* SOF code for progressive arithmetic */
else
emit_sof(cinfo, M_SOF9); /* SOF code for sequential arithmetic */
emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */
} else {
if (cinfo->progressive_mode)
emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
@@ -592,14 +538,6 @@ write_frame_header (j_compress_ptr cinfo)
else
emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */
}
/* Check to emit LSE inverse color transform specification marker */
if (cinfo->color_transform)
emit_lse_ict(cinfo);
/* Check to emit pseudo SOS marker */
if (cinfo->progressive_mode && cinfo->block_size != DCTSIZE)
emit_pseudo_sos(cinfo);
}
@@ -628,12 +566,19 @@ write_scan_header (j_compress_ptr cinfo)
*/
for (i = 0; i < cinfo->comps_in_scan; i++) {
compptr = cinfo->cur_comp_info[i];
/* DC needs no table for refinement scan */
if (cinfo->Ss == 0 && cinfo->Ah == 0)
if (cinfo->progressive_mode) {
/* Progressive mode: only DC or only AC tables are used in one scan */
if (cinfo->Ss == 0) {
if (cinfo->Ah == 0) /* DC needs no table for refinement scan */
emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
/* AC needs no table when not present */
if (cinfo->Se)
emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
} else {
emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
}
} else {
/* Sequential mode: need both DC and AC tables */
emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
}
}
}
@@ -682,9 +627,9 @@ write_tables_only (j_compress_ptr cinfo)
if (! cinfo->arith_code) {
for (i = 0; i < NUM_HUFF_TBLS; i++) {
if (cinfo->dc_huff_tbl_ptrs[i] != NULL)
emit_dht(cinfo, i, FALSE);
emit_dht(cinfo, i, FALSE);
if (cinfo->ac_huff_tbl_ptrs[i] != NULL)
emit_dht(cinfo, i, TRUE);
emit_dht(cinfo, i, TRUE);
}
}
@@ -704,8 +649,8 @@ jinit_marker_writer (j_compress_ptr cinfo)
/* Create the subobject */
marker = (my_marker_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_marker_writer));
cinfo->marker = &marker->pub;
SIZEOF(my_marker_writer));
cinfo->marker = (struct jpeg_marker_writer *) marker;
/* Initialize method pointers */
marker->pub.write_file_header = write_file_header;
marker->pub.write_frame_header = write_frame_header;
+82 -350
View File
@@ -2,7 +2,6 @@
* jcmaster.c
*
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2003-2011 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
@@ -20,9 +19,9 @@
/* Private state */
typedef enum {
main_pass, /* input data, also do first output step */
huff_opt_pass, /* Huffman code optimization pass */
output_pass /* data output pass */
main_pass, /* input data, also do first output step */
huff_opt_pass, /* Huffman code optimization pass */
output_pass /* data output pass */
} c_pass_type;
typedef struct {
@@ -43,220 +42,23 @@ typedef my_comp_master * my_master_ptr;
* Support routines that do various essential calculations.
*/
/*
* Compute JPEG image dimensions and related values.
* NOTE: this is exported for possible use by application.
* Hence it mustn't do anything that can't be done twice.
*/
GLOBAL(void)
jpeg_calc_jpeg_dimensions (j_compress_ptr cinfo)
LOCAL(void)
initial_setup (j_compress_ptr cinfo)
/* Do computations that are needed before master selection phase */
{
#ifdef DCT_SCALING_SUPPORTED
/* Sanity check on input image dimensions to prevent overflow in
* following calculation.
* We do check jpeg_width and jpeg_height in initial_setup below,
* but image_width and image_height can come from arbitrary data,
* and we need some space for multiplication by block_size.
*/
if (((long) cinfo->image_width >> 24) || ((long) cinfo->image_height >> 24))
ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
/* Compute actual JPEG image dimensions and DCT scaling choices. */
if (cinfo->scale_num >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/1 scaling */
cinfo->jpeg_width = cinfo->image_width * cinfo->block_size;
cinfo->jpeg_height = cinfo->image_height * cinfo->block_size;
cinfo->min_DCT_h_scaled_size = 1;
cinfo->min_DCT_v_scaled_size = 1;
} else if (cinfo->scale_num * 2 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/2 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 2L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 2L);
cinfo->min_DCT_h_scaled_size = 2;
cinfo->min_DCT_v_scaled_size = 2;
} else if (cinfo->scale_num * 3 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/3 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 3L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 3L);
cinfo->min_DCT_h_scaled_size = 3;
cinfo->min_DCT_v_scaled_size = 3;
} else if (cinfo->scale_num * 4 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/4 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 4L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 4L);
cinfo->min_DCT_h_scaled_size = 4;
cinfo->min_DCT_v_scaled_size = 4;
} else if (cinfo->scale_num * 5 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/5 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 5L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 5L);
cinfo->min_DCT_h_scaled_size = 5;
cinfo->min_DCT_v_scaled_size = 5;
} else if (cinfo->scale_num * 6 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/6 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 6L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 6L);
cinfo->min_DCT_h_scaled_size = 6;
cinfo->min_DCT_v_scaled_size = 6;
} else if (cinfo->scale_num * 7 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/7 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 7L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 7L);
cinfo->min_DCT_h_scaled_size = 7;
cinfo->min_DCT_v_scaled_size = 7;
} else if (cinfo->scale_num * 8 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/8 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 8L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 8L);
cinfo->min_DCT_h_scaled_size = 8;
cinfo->min_DCT_v_scaled_size = 8;
} else if (cinfo->scale_num * 9 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/9 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 9L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 9L);
cinfo->min_DCT_h_scaled_size = 9;
cinfo->min_DCT_v_scaled_size = 9;
} else if (cinfo->scale_num * 10 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/10 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 10L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 10L);
cinfo->min_DCT_h_scaled_size = 10;
cinfo->min_DCT_v_scaled_size = 10;
} else if (cinfo->scale_num * 11 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/11 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 11L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 11L);
cinfo->min_DCT_h_scaled_size = 11;
cinfo->min_DCT_v_scaled_size = 11;
} else if (cinfo->scale_num * 12 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/12 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 12L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 12L);
cinfo->min_DCT_h_scaled_size = 12;
cinfo->min_DCT_v_scaled_size = 12;
} else if (cinfo->scale_num * 13 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/13 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 13L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 13L);
cinfo->min_DCT_h_scaled_size = 13;
cinfo->min_DCT_v_scaled_size = 13;
} else if (cinfo->scale_num * 14 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/14 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 14L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 14L);
cinfo->min_DCT_h_scaled_size = 14;
cinfo->min_DCT_v_scaled_size = 14;
} else if (cinfo->scale_num * 15 >= cinfo->scale_denom * cinfo->block_size) {
/* Provide block_size/15 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 15L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 15L);
cinfo->min_DCT_h_scaled_size = 15;
cinfo->min_DCT_v_scaled_size = 15;
} else {
/* Provide block_size/16 scaling */
cinfo->jpeg_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 16L);
cinfo->jpeg_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 16L);
cinfo->min_DCT_h_scaled_size = 16;
cinfo->min_DCT_v_scaled_size = 16;
}
#else /* !DCT_SCALING_SUPPORTED */
/* Hardwire it to "no scaling" */
cinfo->jpeg_width = cinfo->image_width;
cinfo->jpeg_height = cinfo->image_height;
cinfo->min_DCT_h_scaled_size = DCTSIZE;
cinfo->min_DCT_v_scaled_size = DCTSIZE;
#endif /* DCT_SCALING_SUPPORTED */
}
LOCAL(void)
jpeg_calc_trans_dimensions (j_compress_ptr cinfo)
{
if (cinfo->min_DCT_h_scaled_size != cinfo->min_DCT_v_scaled_size)
ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
cinfo->min_DCT_h_scaled_size, cinfo->min_DCT_v_scaled_size);
cinfo->block_size = cinfo->min_DCT_h_scaled_size;
}
LOCAL(void)
initial_setup (j_compress_ptr cinfo, boolean transcode_only)
/* Do computations that are needed before master selection phase */
{
int ci, ssize;
int ci;
jpeg_component_info *compptr;
long samplesperrow;
JDIMENSION jd_samplesperrow;
if (transcode_only)
jpeg_calc_trans_dimensions(cinfo);
else
jpeg_calc_jpeg_dimensions(cinfo);
/* Sanity check on block_size */
if (cinfo->block_size < 1 || cinfo->block_size > 16)
ERREXIT2(cinfo, JERR_BAD_DCTSIZE, cinfo->block_size, cinfo->block_size);
/* Derive natural_order from block_size */
switch (cinfo->block_size) {
case 2: cinfo->natural_order = jpeg_natural_order2; break;
case 3: cinfo->natural_order = jpeg_natural_order3; break;
case 4: cinfo->natural_order = jpeg_natural_order4; break;
case 5: cinfo->natural_order = jpeg_natural_order5; break;
case 6: cinfo->natural_order = jpeg_natural_order6; break;
case 7: cinfo->natural_order = jpeg_natural_order7; break;
default: cinfo->natural_order = jpeg_natural_order; break;
}
/* Derive lim_Se from block_size */
cinfo->lim_Se = cinfo->block_size < DCTSIZE ?
cinfo->block_size * cinfo->block_size - 1 : DCTSIZE2-1;
/* Sanity check on image dimensions */
if (cinfo->jpeg_height <= 0 || cinfo->jpeg_width <= 0 ||
cinfo->num_components <= 0 || cinfo->input_components <= 0)
if (cinfo->image_height <= 0 || cinfo->image_width <= 0
|| cinfo->num_components <= 0 || cinfo->input_components <= 0)
ERREXIT(cinfo, JERR_EMPTY_IMAGE);
/* Make sure image isn't bigger than I can handle */
if ((long) cinfo->jpeg_height > (long) JPEG_MAX_DIMENSION ||
(long) cinfo->jpeg_width > (long) JPEG_MAX_DIMENSION)
if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
(long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
/* Width of an input scanline must be representable as JDIMENSION. */
@@ -272,7 +74,7 @@ initial_setup (j_compress_ptr cinfo, boolean transcode_only)
/* Check that number of components won't exceed internal array sizes */
if (cinfo->num_components > MAX_COMPONENTS)
ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
MAX_COMPONENTS);
MAX_COMPONENTS);
/* Compute maximum sampling factors; check factor validity */
cinfo->max_h_samp_factor = 1;
@@ -280,12 +82,12 @@ initial_setup (j_compress_ptr cinfo, boolean transcode_only)
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
ERREXIT(cinfo, JERR_BAD_SAMPLING);
cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
compptr->h_samp_factor);
compptr->h_samp_factor);
cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
compptr->v_samp_factor);
compptr->v_samp_factor);
}
/* Compute dimensions of components */
@@ -293,52 +95,22 @@ initial_setup (j_compress_ptr cinfo, boolean transcode_only)
ci++, compptr++) {
/* Fill in the correct component_index value; don't rely on application */
compptr->component_index = ci;
/* In selecting the actual DCT scaling for each component, we try to
* scale down the chroma components via DCT scaling rather than downsampling.
* This saves time if the downsampler gets to use 1:1 scaling.
* Note this code adapts subsampling ratios which are powers of 2.
*/
ssize = 1;
#ifdef DCT_SCALING_SUPPORTED
while (cinfo->min_DCT_h_scaled_size * ssize <=
(cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
(cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) {
ssize = ssize * 2;
}
#endif
compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;
ssize = 1;
#ifdef DCT_SCALING_SUPPORTED
while (cinfo->min_DCT_v_scaled_size * ssize <=
(cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
(cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) {
ssize = ssize * 2;
}
#endif
compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;
/* We don't support DCT ratios larger than 2. */
if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)
compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;
else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)
compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;
/* For compression, we never do DCT scaling. */
compptr->DCT_scaled_size = DCTSIZE;
/* Size in DCT blocks */
compptr->width_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->jpeg_width * (long) compptr->h_samp_factor,
(long) (cinfo->max_h_samp_factor * cinfo->block_size));
jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
(long) (cinfo->max_h_samp_factor * DCTSIZE));
compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->jpeg_height * (long) compptr->v_samp_factor,
(long) (cinfo->max_v_samp_factor * cinfo->block_size));
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
(long) (cinfo->max_v_samp_factor * DCTSIZE));
/* Size in samples */
compptr->downsampled_width = (JDIMENSION)
jdiv_round_up((long) cinfo->jpeg_width *
(long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),
(long) (cinfo->max_h_samp_factor * cinfo->block_size));
jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
(long) cinfo->max_h_samp_factor);
compptr->downsampled_height = (JDIMENSION)
jdiv_round_up((long) cinfo->jpeg_height *
(long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),
(long) (cinfo->max_v_samp_factor * cinfo->block_size));
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
(long) cinfo->max_v_samp_factor);
/* Mark component needed (this flag isn't actually used for compression) */
compptr->component_needed = TRUE;
}
@@ -347,8 +119,8 @@ initial_setup (j_compress_ptr cinfo, boolean transcode_only)
* main controller will call coefficient controller).
*/
cinfo->total_iMCU_rows = (JDIMENSION)
jdiv_round_up((long) cinfo->jpeg_height,
(long) (cinfo->max_v_samp_factor * cinfo->block_size));
jdiv_round_up((long) cinfo->image_height,
(long) (cinfo->max_v_samp_factor*DCTSIZE));
}
@@ -383,7 +155,7 @@ validate_script (j_compress_ptr cinfo)
last_bitpos_ptr = & last_bitpos[0][0];
for (ci = 0; ci < cinfo->num_components; ci++)
for (coefi = 0; coefi < DCTSIZE2; coefi++)
*last_bitpos_ptr++ = -1;
*last_bitpos_ptr++ = -1;
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
@@ -401,10 +173,10 @@ validate_script (j_compress_ptr cinfo)
for (ci = 0; ci < ncomps; ci++) {
thisi = scanptr->component_index[ci];
if (thisi < 0 || thisi >= cinfo->num_components)
ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
/* Components must appear in SOF order within each scan */
if (ci > 0 && thisi <= scanptr->component_index[ci-1])
ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
}
/* Validate progression parameters */
Ss = scanptr->Ss;
@@ -426,43 +198,43 @@ validate_script (j_compress_ptr cinfo)
#define MAX_AH_AL 13
#endif
if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 ||
Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
if (Ss == 0) {
if (Se != 0) /* DC and AC together not OK */
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
if (Se != 0) /* DC and AC together not OK */
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
} else {
if (ncomps != 1) /* AC scans must be for only one component */
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
if (ncomps != 1) /* AC scans must be for only one component */
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
}
for (ci = 0; ci < ncomps; ci++) {
last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0];
if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */
last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0];
if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
for (coefi = Ss; coefi <= Se; coefi++) {
if (last_bitpos_ptr[coefi] < 0) {
/* first scan of this coefficient */
if (Ah != 0)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
for (coefi = Ss; coefi <= Se; coefi++) {
if (last_bitpos_ptr[coefi] < 0) {
/* first scan of this coefficient */
if (Ah != 0)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
} else {
/* not first scan */
if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
}
last_bitpos_ptr[coefi] = Al;
}
} else {
/* not first scan */
if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
}
last_bitpos_ptr[coefi] = Al;
}
}
#endif
} else {
/* For sequential JPEG, all progression parameters must be these: */
if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
/* Make sure components are not sent twice */
for (ci = 0; ci < ncomps; ci++) {
thisi = scanptr->component_index[ci];
if (component_sent[thisi])
ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
component_sent[thisi] = TRUE;
thisi = scanptr->component_index[ci];
if (component_sent[thisi])
ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
component_sent[thisi] = TRUE;
}
}
}
@@ -477,50 +249,17 @@ validate_script (j_compress_ptr cinfo)
*/
for (ci = 0; ci < cinfo->num_components; ci++) {
if (last_bitpos[ci][0] < 0)
ERREXIT(cinfo, JERR_MISSING_DATA);
ERREXIT(cinfo, JERR_MISSING_DATA);
}
#endif
} else {
for (ci = 0; ci < cinfo->num_components; ci++) {
if (! component_sent[ci])
ERREXIT(cinfo, JERR_MISSING_DATA);
ERREXIT(cinfo, JERR_MISSING_DATA);
}
}
}
LOCAL(void)
reduce_script (j_compress_ptr cinfo)
/* Adapt scan script for use with reduced block size;
* assume that script has been validated before.
*/
{
jpeg_scan_info * scanptr;
int idxout, idxin;
/* Circumvent const declaration for this function */
scanptr = (jpeg_scan_info *) cinfo->scan_info;
idxout = 0;
for (idxin = 0; idxin < cinfo->num_scans; idxin++) {
/* After skipping, idxout becomes smaller than idxin */
if (idxin != idxout)
/* Copy rest of data;
* note we stay in given chunk of allocated memory.
*/
scanptr[idxout] = scanptr[idxin];
if (scanptr[idxout].Ss > cinfo->lim_Se)
/* Entire scan out of range - skip this entry */
continue;
if (scanptr[idxout].Se > cinfo->lim_Se)
/* Limit scan to end of block */
scanptr[idxout].Se = cinfo->lim_Se;
idxout++;
}
cinfo->num_scans = idxout;
}
#endif /* C_MULTISCAN_FILES_SUPPORTED */
@@ -539,15 +278,12 @@ select_scan_parameters (j_compress_ptr cinfo)
cinfo->comps_in_scan = scanptr->comps_in_scan;
for (ci = 0; ci < scanptr->comps_in_scan; ci++) {
cinfo->cur_comp_info[ci] =
&cinfo->comp_info[scanptr->component_index[ci]];
}
if (cinfo->progressive_mode) {
cinfo->Ss = scanptr->Ss;
cinfo->Se = scanptr->Se;
cinfo->Ah = scanptr->Ah;
cinfo->Al = scanptr->Al;
return;
&cinfo->comp_info[scanptr->component_index[ci]];
}
cinfo->Ss = scanptr->Ss;
cinfo->Se = scanptr->Se;
cinfo->Ah = scanptr->Ah;
cinfo->Al = scanptr->Al;
}
else
#endif
@@ -555,16 +291,16 @@ select_scan_parameters (j_compress_ptr cinfo)
/* Prepare for single sequential-JPEG scan containing all components */
if (cinfo->num_components > MAX_COMPS_IN_SCAN)
ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
MAX_COMPS_IN_SCAN);
MAX_COMPS_IN_SCAN);
cinfo->comps_in_scan = cinfo->num_components;
for (ci = 0; ci < cinfo->num_components; ci++) {
cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];
}
cinfo->Ss = 0;
cinfo->Se = DCTSIZE2-1;
cinfo->Ah = 0;
cinfo->Al = 0;
}
cinfo->Ss = 0;
cinfo->Se = cinfo->block_size * cinfo->block_size - 1;
cinfo->Ah = 0;
cinfo->Al = 0;
}
@@ -589,7 +325,7 @@ per_scan_setup (j_compress_ptr cinfo)
compptr->MCU_width = 1;
compptr->MCU_height = 1;
compptr->MCU_blocks = 1;
compptr->MCU_sample_width = compptr->DCT_h_scaled_size;
compptr->MCU_sample_width = DCTSIZE;
compptr->last_col_width = 1;
/* For noninterleaved scans, it is convenient to define last_row_height
* as the number of block rows present in the last iMCU row.
@@ -607,15 +343,15 @@ per_scan_setup (j_compress_ptr cinfo)
/* Interleaved (multi-component) scan */
if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
MAX_COMPS_IN_SCAN);
MAX_COMPS_IN_SCAN);
/* Overall image size in MCUs */
cinfo->MCUs_per_row = (JDIMENSION)
jdiv_round_up((long) cinfo->jpeg_width,
(long) (cinfo->max_h_samp_factor * cinfo->block_size));
jdiv_round_up((long) cinfo->image_width,
(long) (cinfo->max_h_samp_factor*DCTSIZE));
cinfo->MCU_rows_in_scan = (JDIMENSION)
jdiv_round_up((long) cinfo->jpeg_height,
(long) (cinfo->max_v_samp_factor * cinfo->block_size));
jdiv_round_up((long) cinfo->image_height,
(long) (cinfo->max_v_samp_factor*DCTSIZE));
cinfo->blocks_in_MCU = 0;
@@ -625,7 +361,7 @@ per_scan_setup (j_compress_ptr cinfo)
compptr->MCU_width = compptr->h_samp_factor;
compptr->MCU_height = compptr->v_samp_factor;
compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size;
compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE;
/* Figure number of non-dummy blocks in last MCU column & row */
tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
if (tmp == 0) tmp = compptr->MCU_width;
@@ -636,9 +372,9 @@ per_scan_setup (j_compress_ptr cinfo)
/* Prepare array describing MCU composition */
mcublks = compptr->MCU_blocks;
if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU)
ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
while (mcublks-- > 0) {
cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
}
}
@@ -681,8 +417,8 @@ prepare_for_pass (j_compress_ptr cinfo)
(*cinfo->fdct->start_pass) (cinfo);
(*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding);
(*cinfo->coef->start_pass) (cinfo,
(master->total_passes > 1 ?
JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
(master->total_passes > 1 ?
JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
(*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
if (cinfo->optimize_coding) {
/* No immediate data output; postpone writing frame/scan headers */
@@ -697,7 +433,7 @@ prepare_for_pass (j_compress_ptr cinfo)
/* Do Huffman optimization for a scan after the first one. */
select_scan_parameters(cinfo);
per_scan_setup(cinfo);
if (cinfo->Ss != 0 || cinfo->Ah == 0) {
if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code) {
(*cinfo->entropy->start_pass) (cinfo, TRUE);
(*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
master->pub.call_pass_startup = FALSE;
@@ -810,7 +546,7 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
master = (my_master_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_comp_master));
SIZEOF(my_comp_master));
cinfo->master = (struct jpeg_comp_master *) master;
master->pub.prepare_for_pass = prepare_for_pass;
master->pub.pass_startup = pass_startup;
@@ -818,13 +554,11 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
master->pub.is_last_pass = FALSE;
/* Validate parameters, determine derived values */
initial_setup(cinfo, transcode_only);
initial_setup(cinfo);
if (cinfo->scan_info != NULL) {
#ifdef C_MULTISCAN_FILES_SUPPORTED
validate_script(cinfo);
if (cinfo->block_size < DCTSIZE)
reduce_script(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
@@ -833,10 +567,8 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
cinfo->num_scans = 1;
}
if ((cinfo->progressive_mode || cinfo->block_size < DCTSIZE) &&
!cinfo->arith_code) /* TEMPORARY HACK ??? */
/* assume default tables no good for progressive or downscale mode */
cinfo->optimize_coding = TRUE;
if (cinfo->progressive_mode) /* TEMPORARY HACK ??? */
cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */
/* Initialize my private state */
if (transcode_only) {
+11 -80
View File
@@ -1,83 +1,40 @@
/* jconfig.h. Generated automatically by configure. */
/* jconfig.cfg --- source file edited by configure script */
/* see jconfig.doc for explanations */
#define HAVE_PROTOTYPES
#define HAVE_UNSIGNED_CHAR
#define HAVE_UNSIGNED_SHORT
/* Define this if an ordinary "char" type is unsigned.
* If you're not sure, leaving it undefined will work at some cost in speed.
* If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal.
*/
/*#undef void*/
/*#undef const*/
#undef CHAR_IS_UNSIGNED
#if defined __MINGW__ || defined __MINGW32__ || (!defined WIN32 && !defined _WIN32)
/* Define this if your system has an ANSI-conforming <stddef.h> file.
*/
#define HAVE_STDDEF_H
/* Define this if your system has an ANSI-conforming <stdlib.h> file.
*/
#define HAVE_STDLIB_H
#endif
/* Define this if your system does not have an ANSI/SysV <string.h>,
* but does have a BSD-style <strings.h>.
*/
#undef NEED_BSD_STRINGS
/* Define this if your system does not provide typedef size_t in any of the
* ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
* <sys/types.h> instead.
*/
#undef NEED_SYS_TYPES_H
/* For 80x86 machines, you need to define NEED_FAR_POINTERS,
* unless you are using a large-data memory model or 80386 flat-memory mode.
* On less brain-damaged CPUs this symbol must not be defined.
* (Defining this symbol causes large data structures to be referenced through
* "far" pointers and to be allocated with a special version of malloc.)
*/
#undef NEED_FAR_POINTERS
/* Define this if your linker needs global names to be unique in less
* than the first 15 characters.
*/
#undef NEED_SHORT_EXTERNAL_NAMES
/* Although a real ANSI C compiler can deal perfectly well with pointers to
* unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
* and pseudo-ANSI compilers get confused. To keep one of these bozos happy,
* define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you
* actually get "missing structure definition" warnings or errors while
* compiling the JPEG code.
*/
/* Define this if you get warnings about undefined structures. */
#undef INCOMPLETE_TYPES_BROKEN
/* Define "boolean" as unsigned char, not int, on Windows systems.
*/
#ifdef _WIN32
#if defined WIN32 || defined _WIN32
/* Define "boolean" as unsigned char, not int, per Windows custom */
#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
typedef unsigned char boolean;
#endif
#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
#endif
/*
* The following options affect code selection within the JPEG library,
* but they don't need to be visible to applications using the library.
* To minimize application namespace pollution, the symbols won't be
* defined unless JPEG_INTERNALS has been defined.
*/
#ifdef JPEG_INTERNALS
/* Define this if your compiler implements ">>" on signed values as a logical
* (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift,
* which is the normal and rational definition.
*/
#undef RIGHT_SHIFT_IS_UNSIGNED
/* These are for configuring the JPEG memory manager. */
#define DEFAULT_MAX_MEM 1073741824 /*1Gb*/
#define DEFAULT_MAX_MEM 1073741824
#if !defined WIN32 && !defined _WIN32
#define INLINE __inline__
@@ -86,28 +43,14 @@ typedef unsigned char boolean;
#endif /* JPEG_INTERNALS */
/*
* The remaining options do not affect the JPEG library proper,
* but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c).
* Other applications can ignore these.
*/
#ifdef JPEG_CJPEG_DJPEG
/* These defines indicate which image (non-JPEG) file formats are allowed. */
#define BMP_SUPPORTED /* BMP image file format */
#define GIF_SUPPORTED /* GIF image file format */
#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
#undef RLE_SUPPORTED /* Utah RLE image file format */
#define TARGA_SUPPORTED /* Targa image file format */
/* Define this if you want to name both input and output files on the command
* line, rather than using stdout and optionally stdin. You MUST do this if
* your system can't cope with binary I/O to stdin/stdout. See comments at
* head of cjpeg.c or djpeg.c.
*/
#if defined WIN32 || defined _WIN32
#define TWO_FILE_COMMANDLINE /* optional */
#define USE_SETMODE /* Microsoft has setmode() */
@@ -115,22 +58,10 @@ typedef unsigned char boolean;
#undef TWO_FILE_COMMANDLINE
#endif
/* Define this if your system needs explicit cleanup of temporary files.
* This is crucial under MS-DOS, where the temporary "files" may be areas
* of extended memory; on most other systems it's not as important.
*/
#undef NEED_SIGNAL_CATCHER
/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb").
* This is necessary on systems that distinguish text files from binary files,
* and is harmless on most systems that don't. If you have one of the rare
* systems that complains about the "b" spec, define this symbol.
*/
#undef DONT_USE_B_MODE
/* Define this if you want percent-done progress reports from cjpeg/djpeg.
*/
/* Define this if you want percent-done progress reports from cjpeg/djpeg. */
#undef PROGRESS_REPORT
#endif /* JPEG_CJPEG_DJPEG */
+42 -69
View File
@@ -2,7 +2,6 @@
* jcparam.c
*
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2003-2012 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
@@ -22,8 +21,8 @@
GLOBAL(void)
jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
const unsigned int *basic_table,
int scale_factor, boolean force_baseline)
const unsigned int *basic_table,
int scale_factor, boolean force_baseline)
/* Define a quantization table equal to the basic_table times
* a scale factor (given as a percentage).
* If force_baseline is TRUE, the computed quantization table entries
@@ -61,61 +60,45 @@ jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
}
/* These are the sample quantization tables given in JPEG spec section K.1.
* The spec says that the values given produce "good" quality, and
* when divided by 2, "very good" quality.
*/
static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
GLOBAL(void)
jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
/* Set or change the 'quality' (quantization) setting, using default tables
* and straight percentage-scaling quality scales.
* This entry point allows different scalings for luminance and chrominance.
*/
{
/* Set up two quantization tables using the specified scaling */
jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
cinfo->q_scale_factor[0], force_baseline);
jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
cinfo->q_scale_factor[1], force_baseline);
}
GLOBAL(void)
jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
boolean force_baseline)
boolean force_baseline)
/* Set or change the 'quality' (quantization) setting, using default tables
* and a straight percentage-scaling quality scale. In most cases it's better
* to use jpeg_set_quality (below); this entry point is provided for
* applications that insist on a linear percentage scaling.
*/
{
/* These are the sample quantization tables given in JPEG spec section K.1.
* The spec says that the values given produce "good" quality, and
* when divided by 2, "very good" quality.
*/
static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
/* Set up two quantization tables using the specified scaling */
jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
scale_factor, force_baseline);
scale_factor, force_baseline);
jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
scale_factor, force_baseline);
scale_factor, force_baseline);
}
@@ -150,7 +133,7 @@ jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
/* Set or change the 'quality' (quantization) setting, using default tables.
* This is the standard quality-adjusting entry point for typical user
* interfaces; only those who want detailed control over quantization tables
* would use the preceding routines directly.
* would use the preceding three routines directly.
*/
{
/* Convert user 0-100 rating to percentage scaling */
@@ -167,7 +150,7 @@ jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
LOCAL(void)
add_huff_table (j_compress_ptr cinfo,
JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val)
JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val)
/* Define a Huffman table */
{
int nsymbols, len;
@@ -261,13 +244,13 @@ std_huff_tables (j_compress_ptr cinfo)
0xf9, 0xfa };
add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0],
bits_dc_luminance, val_dc_luminance);
bits_dc_luminance, val_dc_luminance);
add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0],
bits_ac_luminance, val_ac_luminance);
bits_ac_luminance, val_ac_luminance);
add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1],
bits_dc_chrominance, val_dc_chrominance);
bits_dc_chrominance, val_dc_chrominance);
add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1],
bits_ac_chrominance, val_ac_chrominance);
bits_ac_chrominance, val_ac_chrominance);
}
@@ -297,12 +280,10 @@ jpeg_set_defaults (j_compress_ptr cinfo)
if (cinfo->comp_info == NULL)
cinfo->comp_info = (jpeg_component_info *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
MAX_COMPONENTS * SIZEOF(jpeg_component_info));
MAX_COMPONENTS * SIZEOF(jpeg_component_info));
/* Initialize everything not dependent on the color space */
cinfo->scale_num = 1; /* 1:1 scaling */
cinfo->scale_denom = 1;
cinfo->data_precision = BITS_IN_JSAMPLE;
/* Set up two quantization tables using default quality of 75 */
jpeg_set_quality(cinfo, 75, TRUE);
@@ -339,9 +320,6 @@ jpeg_set_defaults (j_compress_ptr cinfo)
/* By default, use the simpler non-cosited sampling alignment */
cinfo->CCIR601_sampling = FALSE;
/* By default, apply fancy downsampling */
cinfo->do_fancy_downsampling = TRUE;
/* No input smoothing */
cinfo->smoothing_factor = 0;
@@ -367,9 +345,6 @@ jpeg_set_defaults (j_compress_ptr cinfo)
cinfo->X_density = 1; /* Pixel aspect ratio is square by default */
cinfo->Y_density = 1;
/* No color transform */
cinfo->color_transform = JCT_NONE;
/* Choose JPEG colorspace based on input space, set defaults accordingly */
jpeg_default_colorspace(cinfo);
@@ -451,9 +426,7 @@ jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */
cinfo->num_components = 3;
SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0);
SET_COMP(1, 0x47 /* 'G' */, 1,1, 0,
cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,
cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0);
SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0);
SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0);
break;
case JCS_YCbCr:
@@ -485,7 +458,7 @@ jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
cinfo->num_components = cinfo->input_components;
if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS)
ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
MAX_COMPONENTS);
MAX_COMPONENTS);
for (ci = 0; ci < cinfo->num_components; ci++) {
SET_COMP(ci, ci, 1,1, 0, 0,0);
}
@@ -500,7 +473,7 @@ jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
LOCAL(jpeg_scan_info *)
fill_a_scan (jpeg_scan_info * scanptr, int ci,
int Ss, int Se, int Ah, int Al)
int Ss, int Se, int Ah, int Al)
/* Support routine: generate one scan for specified component */
{
scanptr->comps_in_scan = 1;
@@ -515,7 +488,7 @@ fill_a_scan (jpeg_scan_info * scanptr, int ci,
LOCAL(jpeg_scan_info *)
fill_scans (jpeg_scan_info * scanptr, int ncomps,
int Ss, int Se, int Ah, int Al)
int Ss, int Se, int Ah, int Al)
/* Support routine: generate one scan for each component */
{
int ci;
@@ -594,7 +567,7 @@ jpeg_simple_progression (j_compress_ptr cinfo)
cinfo->script_space_size = MAX(nscans, 10);
cinfo->script_space = (jpeg_scan_info *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
cinfo->script_space_size * SIZEOF(jpeg_scan_info));
cinfo->script_space_size * SIZEOF(jpeg_scan_info));
}
scanptr = cinfo->script_space;
cinfo->scan_info = scanptr;
+833
View File
@@ -0,0 +1,833 @@
/*
* jcphuff.c
*
* Copyright (C) 1995-1997, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains Huffman entropy encoding routines for progressive JPEG.
*
* We do not support output suspension in this module, since the library
* currently does not allow multiple-scan files to be written with output
* suspension.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jchuff.h" /* Declarations shared with jchuff.c */
#ifdef C_PROGRESSIVE_SUPPORTED
/* Expanded entropy encoder object for progressive Huffman encoding. */
typedef struct {
struct jpeg_entropy_encoder pub; /* public fields */
/* Mode flag: TRUE for optimization, FALSE for actual data output */
boolean gather_statistics;
/* Bit-level coding status.
* next_output_byte/free_in_buffer are local copies of cinfo->dest fields.
*/
JOCTET * next_output_byte; /* => next byte to write in buffer */
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
INT32 put_buffer; /* current bit-accumulation buffer */
int put_bits; /* # of bits now in it */
j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */
/* Coding status for DC components */
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
/* Coding status for AC components */
int ac_tbl_no; /* the table number of the single component */
unsigned int EOBRUN; /* run length of EOBs */
unsigned int BE; /* # of buffered correction bits before MCU */
char * bit_buffer; /* buffer for correction bits (1 per char) */
/* packing correction bits tightly would save some space but cost time... */
unsigned int restarts_to_go; /* MCUs left in this restart interval */
int next_restart_num; /* next restart number to write (0-7) */
/* Pointers to derived tables (these workspaces have image lifespan).
* Since any one scan codes only DC or only AC, we only need one set
* of tables, not one for DC and one for AC.
*/
c_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
/* Statistics tables for optimization; again, one set is enough */
long * count_ptrs[NUM_HUFF_TBLS];
} phuff_entropy_encoder;
typedef phuff_entropy_encoder * phuff_entropy_ptr;
/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit
* buffer can hold. Larger sizes may slightly improve compression, but
* 1000 is already well into the realm of overkill.
* The minimum safe size is 64 bits.
*/
#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
* We assume that int right shift is unsigned if INT32 right shift is,
* which should be safe.
*/
#ifdef RIGHT_SHIFT_IS_UNSIGNED
#define ISHIFT_TEMPS int ishift_temp;
#define IRIGHT_SHIFT(x,shft) \
((ishift_temp = (x)) < 0 ? \
(ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
(ishift_temp >> (shft)))
#else
#define ISHIFT_TEMPS
#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
#endif
/* Forward declarations */
METHODDEF(boolean) encode_mcu_DC_first JPP((j_compress_ptr cinfo,
JBLOCKROW *MCU_data));
METHODDEF(boolean) encode_mcu_AC_first JPP((j_compress_ptr cinfo,
JBLOCKROW *MCU_data));
METHODDEF(boolean) encode_mcu_DC_refine JPP((j_compress_ptr cinfo,
JBLOCKROW *MCU_data));
METHODDEF(boolean) encode_mcu_AC_refine JPP((j_compress_ptr cinfo,
JBLOCKROW *MCU_data));
METHODDEF(void) finish_pass_phuff JPP((j_compress_ptr cinfo));
METHODDEF(void) finish_pass_gather_phuff JPP((j_compress_ptr cinfo));
/*
* Initialize for a Huffman-compressed scan using progressive JPEG.
*/
METHODDEF(void)
start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics)
{
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
boolean is_DC_band;
int ci, tbl;
jpeg_component_info * compptr;
entropy->cinfo = cinfo;
entropy->gather_statistics = gather_statistics;
is_DC_band = (cinfo->Ss == 0);
/* We assume jcmaster.c already validated the scan parameters. */
/* Select execution routines */
if (cinfo->Ah == 0) {
if (is_DC_band)
entropy->pub.encode_mcu = encode_mcu_DC_first;
else
entropy->pub.encode_mcu = encode_mcu_AC_first;
} else {
if (is_DC_band)
entropy->pub.encode_mcu = encode_mcu_DC_refine;
else {
entropy->pub.encode_mcu = encode_mcu_AC_refine;
/* AC refinement needs a correction bit buffer */
if (entropy->bit_buffer == NULL)
entropy->bit_buffer = (char *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
MAX_CORR_BITS * SIZEOF(char));
}
}
if (gather_statistics)
entropy->pub.finish_pass = finish_pass_gather_phuff;
else
entropy->pub.finish_pass = finish_pass_phuff;
/* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1
* for AC coefficients.
*/
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* Initialize DC predictions to 0 */
entropy->last_dc_val[ci] = 0;
/* Get table index */
if (is_DC_band) {
if (cinfo->Ah != 0) /* DC refinement needs no table */
continue;
tbl = compptr->dc_tbl_no;
} else {
entropy->ac_tbl_no = tbl = compptr->ac_tbl_no;
}
if (gather_statistics) {
/* Check for invalid table index */
/* (make_c_derived_tbl does this in the other path) */
if (tbl < 0 || tbl >= NUM_HUFF_TBLS)
ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
/* Allocate and zero the statistics tables */
/* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
if (entropy->count_ptrs[tbl] == NULL)
entropy->count_ptrs[tbl] = (long *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
257 * SIZEOF(long));
MEMZERO(entropy->count_ptrs[tbl], 257 * SIZEOF(long));
} else {
/* Compute derived values for Huffman table */
/* We may do this more than once for a table, but it's not expensive */
jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl,
& entropy->derived_tbls[tbl]);
}
}
/* Initialize AC stuff */
entropy->EOBRUN = 0;
entropy->BE = 0;
/* Initialize bit buffer to empty */
entropy->put_buffer = 0;
entropy->put_bits = 0;
/* Initialize restart stuff */
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num = 0;
}
/* Outputting bytes to the file.
* NB: these must be called only when actually outputting,
* that is, entropy->gather_statistics == FALSE.
*/
/* Emit a byte */
#define emit_byte(entropy,val) \
{ *(entropy)->next_output_byte++ = (JOCTET) (val); \
if (--(entropy)->free_in_buffer == 0) \
dump_buffer(entropy); }
LOCAL(void)
dump_buffer (phuff_entropy_ptr entropy)
/* Empty the output buffer; we do not support suspension in this module. */
{
struct jpeg_destination_mgr * dest = entropy->cinfo->dest;
if (! (*dest->empty_output_buffer) (entropy->cinfo))
ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);
/* After a successful buffer dump, must reset buffer pointers */
entropy->next_output_byte = dest->next_output_byte;
entropy->free_in_buffer = dest->free_in_buffer;
}
/* Outputting bits to the file */
/* Only the right 24 bits of put_buffer are used; the valid bits are
* left-justified in this part. At most 16 bits can be passed to emit_bits
* in one call, and we never retain more than 7 bits in put_buffer
* between calls, so 24 bits are sufficient.
*/
INLINE
LOCAL(void)
emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size)
/* Emit some bits, unless we are in gather mode */
{
/* This routine is heavily used, so it's worth coding tightly. */
register INT32 put_buffer = (INT32) code;
register int put_bits = entropy->put_bits;
/* if size is 0, caller used an invalid Huffman table entry */
if (size == 0)
ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
if (entropy->gather_statistics)
return; /* do nothing if we're only getting stats */
put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
put_bits += size; /* new number of bits in buffer */
put_buffer <<= 24 - put_bits; /* align incoming bits */
put_buffer |= entropy->put_buffer; /* and merge with old buffer contents */
while (put_bits >= 8) {
int c = (int) ((put_buffer >> 16) & 0xFF);
emit_byte(entropy, c);
if (c == 0xFF) { /* need to stuff a zero byte? */
emit_byte(entropy, 0);
}
put_buffer <<= 8;
put_bits -= 8;
}
entropy->put_buffer = put_buffer; /* update variables */
entropy->put_bits = put_bits;
}
LOCAL(void)
flush_bits (phuff_entropy_ptr entropy)
{
emit_bits(entropy, 0x7F, 7); /* fill any partial byte with ones */
entropy->put_buffer = 0; /* and reset bit-buffer to empty */
entropy->put_bits = 0;
}
/*
* Emit (or just count) a Huffman symbol.
*/
INLINE
LOCAL(void)
emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol)
{
if (entropy->gather_statistics)
entropy->count_ptrs[tbl_no][symbol]++;
else {
c_derived_tbl * tbl = entropy->derived_tbls[tbl_no];
emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
}
}
/*
* Emit bits from a correction bit buffer.
*/
LOCAL(void)
emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart,
unsigned int nbits)
{
if (entropy->gather_statistics)
return; /* no real work */
while (nbits > 0) {
emit_bits(entropy, (unsigned int) (*bufstart), 1);
bufstart++;
nbits--;
}
}
/*
* Emit any pending EOBRUN symbol.
*/
LOCAL(void)
emit_eobrun (phuff_entropy_ptr entropy)
{
register int temp, nbits;
if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */
temp = entropy->EOBRUN;
nbits = 0;
while ((temp >>= 1))
nbits++;
/* safety check: shouldn't happen given limited correction-bit buffer */
if (nbits > 14)
ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
emit_symbol(entropy, entropy->ac_tbl_no, nbits << 4);
if (nbits)
emit_bits(entropy, entropy->EOBRUN, nbits);
entropy->EOBRUN = 0;
/* Emit any buffered correction bits */
emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE);
entropy->BE = 0;
}
}
/*
* Emit a restart marker & resynchronize predictions.
*/
LOCAL(void)
emit_restart (phuff_entropy_ptr entropy, int restart_num)
{
int ci;
emit_eobrun(entropy);
if (! entropy->gather_statistics) {
flush_bits(entropy);
emit_byte(entropy, 0xFF);
emit_byte(entropy, JPEG_RST0 + restart_num);
}
if (entropy->cinfo->Ss == 0) {
/* Re-initialize DC predictions to 0 */
for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++)
entropy->last_dc_val[ci] = 0;
} else {
/* Re-initialize all AC-related fields to 0 */
entropy->EOBRUN = 0;
entropy->BE = 0;
}
}
/*
* MCU encoding for DC initial scan (either spectral selection,
* or first pass of successive approximation).
*/
METHODDEF(boolean)
encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
register int temp, temp2;
register int nbits;
int blkn, ci;
int Al = cinfo->Al;
JBLOCKROW block;
jpeg_component_info * compptr;
ISHIFT_TEMPS
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
/* Emit restart marker if needed */
if (cinfo->restart_interval)
if (entropy->restarts_to_go == 0)
emit_restart(entropy, entropy->next_restart_num);
/* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn];
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
/* Compute the DC value after the required point transform by Al.
* This is simply an arithmetic right shift.
*/
temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al);
/* DC differences are figured on the point-transformed values. */
temp = temp2 - entropy->last_dc_val[ci];
entropy->last_dc_val[ci] = temp2;
/* Encode the DC coefficient difference per section G.1.2.1 */
temp2 = temp;
if (temp < 0) {
temp = -temp; /* temp is abs value of input */
/* For a negative input, want temp2 = bitwise complement of abs(input) */
/* This code assumes we are on a two's complement machine */
temp2--;
}
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 0;
while (temp) {
nbits++;
temp >>= 1;
}
/* Check for out-of-range coefficient values.
* Since we're encoding a difference, the range limit is twice as much.
*/
if (nbits > MAX_COEF_BITS+1)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count/emit the Huffman-coded symbol for the number of bits */
emit_symbol(entropy, compptr->dc_tbl_no, nbits);
/* Emit that number of bits of the value, if positive, */
/* or the complement of its magnitude, if negative. */
if (nbits) /* emit_bits rejects calls with size 0 */
emit_bits(entropy, (unsigned int) temp2, nbits);
}
cinfo->dest->next_output_byte = entropy->next_output_byte;
cinfo->dest->free_in_buffer = entropy->free_in_buffer;
/* Update restart-interval state too */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
return TRUE;
}
/*
* MCU encoding for AC initial scan (either spectral selection,
* or first pass of successive approximation).
*/
METHODDEF(boolean)
encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
register int temp, temp2;
register int nbits;
register int r, k;
int Se = cinfo->Se;
int Al = cinfo->Al;
JBLOCKROW block;
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
/* Emit restart marker if needed */
if (cinfo->restart_interval)
if (entropy->restarts_to_go == 0)
emit_restart(entropy, entropy->next_restart_num);
/* Encode the MCU data block */
block = MCU_data[0];
/* Encode the AC coefficients per section G.1.2.2, fig. G.3 */
r = 0; /* r = run length of zeros */
for (k = cinfo->Ss; k <= Se; k++) {
if ((temp = (*block)[jpeg_natural_order[k]]) == 0) {
r++;
continue;
}
/* We must apply the point transform by Al. For AC coefficients this
* is an integer division with rounding towards 0. To do this portably
* in C, we shift after obtaining the absolute value; so the code is
* interwoven with finding the abs value (temp) and output bits (temp2).
*/
if (temp < 0) {
temp = -temp; /* temp is abs value of input */
temp >>= Al; /* apply the point transform */
/* For a negative coef, want temp2 = bitwise complement of abs(coef) */
temp2 = ~temp;
} else {
temp >>= Al; /* apply the point transform */
temp2 = temp;
}
/* Watch out for case that nonzero coef is zero after point transform */
if (temp == 0) {
r++;
continue;
}
/* Emit any pending EOBRUN */
if (entropy->EOBRUN > 0)
emit_eobrun(entropy);
/* if run length > 15, must emit special run-length-16 codes (0xF0) */
while (r > 15) {
emit_symbol(entropy, entropy->ac_tbl_no, 0xF0);
r -= 16;
}
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 1; /* there must be at least one 1 bit */
while ((temp >>= 1))
nbits++;
/* Check for out-of-range coefficient values */
if (nbits > MAX_COEF_BITS)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count/emit Huffman symbol for run length / number of bits */
emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits);
/* Emit that number of bits of the value, if positive, */
/* or the complement of its magnitude, if negative. */
emit_bits(entropy, (unsigned int) temp2, nbits);
r = 0; /* reset zero run length */
}
if (r > 0) { /* If there are trailing zeroes, */
entropy->EOBRUN++; /* count an EOB */
if (entropy->EOBRUN == 0x7FFF)
emit_eobrun(entropy); /* force it out to avoid overflow */
}
cinfo->dest->next_output_byte = entropy->next_output_byte;
cinfo->dest->free_in_buffer = entropy->free_in_buffer;
/* Update restart-interval state too */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
return TRUE;
}
/*
* MCU encoding for DC successive approximation refinement scan.
* Note: we assume such scans can be multi-component, although the spec
* is not very clear on the point.
*/
METHODDEF(boolean)
encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
register int temp;
int blkn;
int Al = cinfo->Al;
JBLOCKROW block;
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
/* Emit restart marker if needed */
if (cinfo->restart_interval)
if (entropy->restarts_to_go == 0)
emit_restart(entropy, entropy->next_restart_num);
/* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn];
/* We simply emit the Al'th bit of the DC coefficient value. */
temp = (*block)[0];
emit_bits(entropy, (unsigned int) (temp >> Al), 1);
}
cinfo->dest->next_output_byte = entropy->next_output_byte;
cinfo->dest->free_in_buffer = entropy->free_in_buffer;
/* Update restart-interval state too */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
return TRUE;
}
/*
* MCU encoding for AC successive approximation refinement scan.
*/
METHODDEF(boolean)
encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
register int temp;
register int r, k;
int EOB;
char *BR_buffer;
unsigned int BR;
int Se = cinfo->Se;
int Al = cinfo->Al;
JBLOCKROW block;
int absvalues[DCTSIZE2];
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
/* Emit restart marker if needed */
if (cinfo->restart_interval)
if (entropy->restarts_to_go == 0)
emit_restart(entropy, entropy->next_restart_num);
/* Encode the MCU data block */
block = MCU_data[0];
/* It is convenient to make a pre-pass to determine the transformed
* coefficients' absolute values and the EOB position.
*/
EOB = 0;
for (k = cinfo->Ss; k <= Se; k++) {
temp = (*block)[jpeg_natural_order[k]];
/* We must apply the point transform by Al. For AC coefficients this
* is an integer division with rounding towards 0. To do this portably
* in C, we shift after obtaining the absolute value.
*/
if (temp < 0)
temp = -temp; /* temp is abs value of input */
temp >>= Al; /* apply the point transform */
absvalues[k] = temp; /* save abs value for main pass */
if (temp == 1)
EOB = k; /* EOB = index of last newly-nonzero coef */
}
/* Encode the AC coefficients per section G.1.2.3, fig. G.7 */
r = 0; /* r = run length of zeros */
BR = 0; /* BR = count of buffered bits added now */
BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */
for (k = cinfo->Ss; k <= Se; k++) {
if ((temp = absvalues[k]) == 0) {
r++;
continue;
}
/* Emit any required ZRLs, but not if they can be folded into EOB */
while (r > 15 && k <= EOB) {
/* emit any pending EOBRUN and the BE correction bits */
emit_eobrun(entropy);
/* Emit ZRL */
emit_symbol(entropy, entropy->ac_tbl_no, 0xF0);
r -= 16;
/* Emit buffered correction bits that must be associated with ZRL */
emit_buffered_bits(entropy, BR_buffer, BR);
BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
BR = 0;
}
/* If the coef was previously nonzero, it only needs a correction bit.
* NOTE: a straight translation of the spec's figure G.7 would suggest
* that we also need to test r > 15. But if r > 15, we can only get here
* if k > EOB, which implies that this coefficient is not 1.
*/
if (temp > 1) {
/* The correction bit is the next bit of the absolute value. */
BR_buffer[BR++] = (char) (temp & 1);
continue;
}
/* Emit any pending EOBRUN and the BE correction bits */
emit_eobrun(entropy);
/* Count/emit Huffman symbol for run length / number of bits */
emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1);
/* Emit output bit for newly-nonzero coef */
temp = ((*block)[jpeg_natural_order[k]] < 0) ? 0 : 1;
emit_bits(entropy, (unsigned int) temp, 1);
/* Emit buffered correction bits that must be associated with this code */
emit_buffered_bits(entropy, BR_buffer, BR);
BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
BR = 0;
r = 0; /* reset zero run length */
}
if (r > 0 || BR > 0) { /* If there are trailing zeroes, */
entropy->EOBRUN++; /* count an EOB */
entropy->BE += BR; /* concat my correction bits to older ones */
/* We force out the EOB if we risk either:
* 1. overflow of the EOB counter;
* 2. overflow of the correction bit buffer during the next MCU.
*/
if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1))
emit_eobrun(entropy);
}
cinfo->dest->next_output_byte = entropy->next_output_byte;
cinfo->dest->free_in_buffer = entropy->free_in_buffer;
/* Update restart-interval state too */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0) {
entropy->restarts_to_go = cinfo->restart_interval;
entropy->next_restart_num++;
entropy->next_restart_num &= 7;
}
entropy->restarts_to_go--;
}
return TRUE;
}
/*
* Finish up at the end of a Huffman-compressed progressive scan.
*/
METHODDEF(void)
finish_pass_phuff (j_compress_ptr cinfo)
{
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
/* Flush out any buffered data */
emit_eobrun(entropy);
flush_bits(entropy);
cinfo->dest->next_output_byte = entropy->next_output_byte;
cinfo->dest->free_in_buffer = entropy->free_in_buffer;
}
/*
* Finish up a statistics-gathering pass and create the new Huffman tables.
*/
METHODDEF(void)
finish_pass_gather_phuff (j_compress_ptr cinfo)
{
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
boolean is_DC_band;
int ci, tbl;
jpeg_component_info * compptr;
JHUFF_TBL **htblptr;
boolean did[NUM_HUFF_TBLS];
/* Flush out buffered data (all we care about is counting the EOB symbol) */
emit_eobrun(entropy);
is_DC_band = (cinfo->Ss == 0);
/* It's important not to apply jpeg_gen_optimal_table more than once
* per table, because it clobbers the input frequency counts!
*/
MEMZERO(did, SIZEOF(did));
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
if (is_DC_band) {
if (cinfo->Ah != 0) /* DC refinement needs no table */
continue;
tbl = compptr->dc_tbl_no;
} else {
tbl = compptr->ac_tbl_no;
}
if (! did[tbl]) {
if (is_DC_band)
htblptr = & cinfo->dc_huff_tbl_ptrs[tbl];
else
htblptr = & cinfo->ac_huff_tbl_ptrs[tbl];
if (*htblptr == NULL)
*htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[tbl]);
did[tbl] = TRUE;
}
}
}
/*
* Module initialization routine for progressive Huffman entropy encoding.
*/
GLOBAL(void)
jinit_phuff_encoder (j_compress_ptr cinfo)
{
phuff_entropy_ptr entropy;
int i;
entropy = (phuff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(phuff_entropy_encoder));
cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
entropy->pub.start_pass = start_pass_phuff;
/* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) {
entropy->derived_tbls[i] = NULL;
entropy->count_ptrs[i] = NULL;
}
entropy->bit_buffer = NULL; /* needed only in AC refinement scan */
}
#endif /* C_PROGRESSIVE_SUPPORTED */
+58 -62
View File
@@ -104,13 +104,13 @@ start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
LOCAL(void)
expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols,
int input_rows, int output_rows)
int input_rows, int output_rows)
{
register int row;
for (row = input_rows; row < output_rows; row++) {
jcopy_sample_rows(image_data, input_rows-1, image_data, row,
1, num_cols);
1, num_cols);
}
}
@@ -126,10 +126,10 @@ expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols,
METHODDEF(void)
pre_process_data (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail,
JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail)
JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail,
JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail)
{
my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
int numrows, ci;
@@ -137,32 +137,32 @@ pre_process_data (j_compress_ptr cinfo,
jpeg_component_info * compptr;
while (*in_row_ctr < in_rows_avail &&
*out_row_group_ctr < out_row_groups_avail) {
*out_row_group_ctr < out_row_groups_avail) {
/* Do color conversion to fill the conversion buffer. */
inrows = in_rows_avail - *in_row_ctr;
numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
numrows = (int) MIN((JDIMENSION) numrows, inrows);
(*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
prep->color_buf,
(JDIMENSION) prep->next_buf_row,
numrows);
prep->color_buf,
(JDIMENSION) prep->next_buf_row,
numrows);
*in_row_ctr += numrows;
prep->next_buf_row += numrows;
prep->rows_to_go -= numrows;
/* If at bottom of image, pad to fill the conversion buffer. */
if (prep->rows_to_go == 0 &&
prep->next_buf_row < cinfo->max_v_samp_factor) {
prep->next_buf_row < cinfo->max_v_samp_factor) {
for (ci = 0; ci < cinfo->num_components; ci++) {
expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
prep->next_buf_row, cinfo->max_v_samp_factor);
expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
prep->next_buf_row, cinfo->max_v_samp_factor);
}
prep->next_buf_row = cinfo->max_v_samp_factor;
}
/* If we've filled the conversion buffer, empty it. */
if (prep->next_buf_row == cinfo->max_v_samp_factor) {
(*cinfo->downsample->downsample) (cinfo,
prep->color_buf, (JDIMENSION) 0,
output_buf, *out_row_group_ctr);
prep->color_buf, (JDIMENSION) 0,
output_buf, *out_row_group_ctr);
prep->next_buf_row = 0;
(*out_row_group_ctr)++;
}
@@ -170,15 +170,13 @@ pre_process_data (j_compress_ptr cinfo,
* Note we assume the caller is providing a one-iMCU-height output buffer!
*/
if (prep->rows_to_go == 0 &&
*out_row_group_ctr < out_row_groups_avail) {
*out_row_group_ctr < out_row_groups_avail) {
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
numrows = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
cinfo->min_DCT_v_scaled_size;
expand_bottom_edge(output_buf[ci],
compptr->width_in_blocks * compptr->DCT_h_scaled_size,
(int) (*out_row_group_ctr * numrows),
(int) (out_row_groups_avail * numrows));
ci++, compptr++) {
expand_bottom_edge(output_buf[ci],
compptr->width_in_blocks * DCTSIZE,
(int) (*out_row_group_ctr * compptr->v_samp_factor),
(int) (out_row_groups_avail * compptr->v_samp_factor));
}
*out_row_group_ctr = out_row_groups_avail;
break; /* can exit outer loop without test */
@@ -195,10 +193,10 @@ pre_process_data (j_compress_ptr cinfo,
METHODDEF(void)
pre_process_context (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail,
JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail)
JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail,
JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail)
{
my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
int numrows, ci;
@@ -212,19 +210,19 @@ pre_process_context (j_compress_ptr cinfo,
numrows = prep->next_buf_stop - prep->next_buf_row;
numrows = (int) MIN((JDIMENSION) numrows, inrows);
(*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
prep->color_buf,
(JDIMENSION) prep->next_buf_row,
numrows);
prep->color_buf,
(JDIMENSION) prep->next_buf_row,
numrows);
/* Pad at top of image, if first time through */
if (prep->rows_to_go == cinfo->image_height) {
for (ci = 0; ci < cinfo->num_components; ci++) {
int row;
for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
jcopy_sample_rows(prep->color_buf[ci], 0,
prep->color_buf[ci], -row,
1, cinfo->image_width);
}
}
for (ci = 0; ci < cinfo->num_components; ci++) {
int row;
for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
jcopy_sample_rows(prep->color_buf[ci], 0,
prep->color_buf[ci], -row,
1, cinfo->image_width);
}
}
}
*in_row_ctr += numrows;
prep->next_buf_row += numrows;
@@ -232,29 +230,29 @@ pre_process_context (j_compress_ptr cinfo,
} else {
/* Return for more data, unless we are at the bottom of the image. */
if (prep->rows_to_go != 0)
break;
break;
/* When at bottom of image, pad to fill the conversion buffer. */
if (prep->next_buf_row < prep->next_buf_stop) {
for (ci = 0; ci < cinfo->num_components; ci++) {
expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
prep->next_buf_row, prep->next_buf_stop);
}
prep->next_buf_row = prep->next_buf_stop;
for (ci = 0; ci < cinfo->num_components; ci++) {
expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
prep->next_buf_row, prep->next_buf_stop);
}
prep->next_buf_row = prep->next_buf_stop;
}
}
/* If we've gotten enough data, downsample a row group. */
if (prep->next_buf_row == prep->next_buf_stop) {
(*cinfo->downsample->downsample) (cinfo,
prep->color_buf,
(JDIMENSION) prep->this_row_group,
output_buf, *out_row_group_ctr);
prep->color_buf,
(JDIMENSION) prep->this_row_group,
output_buf, *out_row_group_ctr);
(*out_row_group_ctr)++;
/* Advance pointers with wraparound as necessary. */
prep->this_row_group += cinfo->max_v_samp_factor;
if (prep->this_row_group >= buf_height)
prep->this_row_group = 0;
prep->this_row_group = 0;
if (prep->next_buf_row >= buf_height)
prep->next_buf_row = 0;
prep->next_buf_row = 0;
prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor;
}
}
@@ -279,8 +277,8 @@ create_context_buffer (j_compress_ptr cinfo)
*/
fake_buffer = (JSAMPARRAY)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(cinfo->num_components * 5 * rgroup_height) *
SIZEOF(JSAMPROW));
(cinfo->num_components * 5 * rgroup_height) *
SIZEOF(JSAMPROW));
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -290,13 +288,12 @@ create_context_buffer (j_compress_ptr cinfo)
*/
true_buffer = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE,
(JDIMENSION) (((long) compptr->width_in_blocks *
cinfo->min_DCT_h_scaled_size *
cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE *
cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION) (3 * rgroup_height));
/* Copy true buffer row pointers into the middle of the fake row array */
MEMCOPY(fake_buffer + rgroup_height, true_buffer,
3 * rgroup_height * SIZEOF(JSAMPROW));
3 * rgroup_height * SIZEOF(JSAMPROW));
/* Fill in the above and below wraparound pointers */
for (i = 0; i < rgroup_height; i++) {
fake_buffer[i] = true_buffer[2 * rgroup_height + i];
@@ -326,7 +323,7 @@ jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
prep = (my_prep_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_prep_controller));
SIZEOF(my_prep_controller));
cinfo->prep = (struct jpeg_c_prep_controller *) prep;
prep->pub.start_pass = start_pass_prep;
@@ -346,13 +343,12 @@ jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
/* No context, just make it tall enough for one row group */
prep->pub.pre_process_data = pre_process_data;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
ci++, compptr++) {
prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE,
(JDIMENSION) (((long) compptr->width_in_blocks *
cinfo->min_DCT_h_scaled_size *
cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION) cinfo->max_v_samp_factor);
((j_common_ptr) cinfo, JPOOL_IMAGE,
(JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE *
cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION) cinfo->max_v_samp_factor);
}
}
}
+85 -111
View File
@@ -52,8 +52,8 @@
/* Pointer to routine to downsample a single component */
typedef JMETHOD(void, downsample1_ptr,
(j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data));
(j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data));
/* Private subobject */
@@ -62,15 +62,6 @@ typedef struct {
/* Downsampling method pointers, one per component */
downsample1_ptr methods[MAX_COMPONENTS];
/* Height of an output row group for each component. */
int rowgroup_height[MAX_COMPONENTS];
/* These arrays save pixel expansion factors so that int_downsample need not
* recompute them each time. They are unused for other downsampling methods.
*/
UINT8 h_expand[MAX_COMPONENTS];
UINT8 v_expand[MAX_COMPONENTS];
} my_downsampler;
typedef my_downsampler * my_downsample_ptr;
@@ -94,7 +85,7 @@ start_pass_downsample (j_compress_ptr cinfo)
LOCAL(void)
expand_right_edge (JSAMPARRAY image_data, int num_rows,
JDIMENSION input_cols, JDIMENSION output_cols)
JDIMENSION input_cols, JDIMENSION output_cols)
{
register JSAMPROW ptr;
register JSAMPLE pixval;
@@ -107,7 +98,7 @@ expand_right_edge (JSAMPARRAY image_data, int num_rows,
ptr = image_data[row] + input_cols;
pixval = ptr[-1]; /* don't need GETJSAMPLE() here */
for (count = numcols; count > 0; count--)
*ptr++ = pixval;
*ptr++ = pixval;
}
}
}
@@ -121,8 +112,8 @@ expand_right_edge (JSAMPARRAY image_data, int num_rows,
METHODDEF(void)
sep_downsample (j_compress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION in_row_index,
JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)
JSAMPIMAGE input_buf, JDIMENSION in_row_index,
JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)
{
my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
int ci;
@@ -132,8 +123,7 @@ sep_downsample (j_compress_ptr cinfo,
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
in_ptr = input_buf[ci] + in_row_index;
out_ptr = output_buf[ci] +
(out_row_group_index * downsample->rowgroup_height[ci]);
out_ptr = output_buf[ci] + (out_row_group_index * compptr->v_samp_factor);
(*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr);
}
}
@@ -148,17 +138,16 @@ sep_downsample (j_compress_ptr cinfo,
METHODDEF(void)
int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
JSAMPROW inptr, outptr;
INT32 outvalue;
h_expand = downsample->h_expand[compptr->component_index];
v_expand = downsample->v_expand[compptr->component_index];
h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor;
v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor;
numpix = h_expand * v_expand;
numpix2 = numpix/2;
@@ -167,24 +156,23 @@ int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
* efficient.
*/
expand_right_edge(input_data, cinfo->max_v_samp_factor,
cinfo->image_width, output_cols * h_expand);
cinfo->image_width, output_cols * h_expand);
inrow = outrow = 0;
while (inrow < cinfo->max_v_samp_factor) {
inrow = 0;
for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
outptr = output_data[outrow];
for (outcol = 0, outcol_h = 0; outcol < output_cols;
outcol++, outcol_h += h_expand) {
outcol++, outcol_h += h_expand) {
outvalue = 0;
for (v = 0; v < v_expand; v++) {
inptr = input_data[inrow+v] + outcol_h;
for (h = 0; h < h_expand; h++) {
outvalue += (INT32) GETJSAMPLE(*inptr++);
}
inptr = input_data[inrow+v] + outcol_h;
for (h = 0; h < h_expand; h++) {
outvalue += (INT32) GETJSAMPLE(*inptr++);
}
}
*outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);
}
inrow += v_expand;
outrow++;
}
}
@@ -197,14 +185,14 @@ int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
METHODDEF(void)
fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
/* Copy the data */
jcopy_sample_rows(input_data, 0, output_data, 0,
cinfo->max_v_samp_factor, cinfo->image_width);
cinfo->max_v_samp_factor, cinfo->image_width);
/* Edge-expand */
expand_right_edge(output_data, cinfo->max_v_samp_factor, cinfo->image_width,
compptr->width_in_blocks * compptr->DCT_h_scaled_size);
expand_right_edge(output_data, cinfo->max_v_samp_factor,
cinfo->image_width, compptr->width_in_blocks * DCTSIZE);
}
@@ -222,11 +210,11 @@ fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
METHODDEF(void)
h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
int inrow;
int outrow;
JDIMENSION outcol;
JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
register JSAMPROW inptr, outptr;
register int bias;
@@ -235,15 +223,15 @@ h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
* efficient.
*/
expand_right_edge(input_data, cinfo->max_v_samp_factor,
cinfo->image_width, output_cols * 2);
cinfo->image_width, output_cols * 2);
for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
outptr = output_data[inrow];
inptr = input_data[inrow];
for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
outptr = output_data[outrow];
inptr = input_data[outrow];
bias = 0; /* bias = 0,1,0,1,... for successive samples */
for (outcol = 0; outcol < output_cols; outcol++) {
*outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1])
+ bias) >> 1);
+ bias) >> 1);
bias ^= 1; /* 0=>1, 1=>0 */
inptr += 2;
}
@@ -259,11 +247,11 @@ h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
METHODDEF(void)
h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
int inrow, outrow;
JDIMENSION outcol;
JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
register JSAMPROW inptr0, inptr1, outptr;
register int bias;
@@ -272,23 +260,22 @@ h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
* efficient.
*/
expand_right_edge(input_data, cinfo->max_v_samp_factor,
cinfo->image_width, output_cols * 2);
cinfo->image_width, output_cols * 2);
inrow = outrow = 0;
while (inrow < cinfo->max_v_samp_factor) {
inrow = 0;
for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
outptr = output_data[outrow];
inptr0 = input_data[inrow];
inptr1 = input_data[inrow+1];
bias = 1; /* bias = 1,2,1,2,... for successive samples */
for (outcol = 0; outcol < output_cols; outcol++) {
*outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1])
+ bias) >> 2);
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1])
+ bias) >> 2);
bias ^= 3; /* 1=>2, 2=>1 */
inptr0 += 2; inptr1 += 2;
}
inrow += 2;
outrow++;
}
}
@@ -303,11 +290,11 @@ h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
METHODDEF(void)
h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
int inrow, outrow;
JDIMENSION colctr;
JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
INT32 membersum, neighsum, memberscale, neighscale;
@@ -316,7 +303,7 @@ h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
* efficient.
*/
expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
cinfo->image_width, output_cols * 2);
cinfo->image_width, output_cols * 2);
/* We don't bother to form the individual "smoothed" input pixel values;
* we can directly compute the output which is the average of the four
@@ -334,8 +321,8 @@ h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */
neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */
inrow = outrow = 0;
while (inrow < cinfo->max_v_samp_factor) {
inrow = 0;
for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
outptr = output_data[outrow];
inptr0 = input_data[inrow];
inptr1 = input_data[inrow+1];
@@ -344,14 +331,14 @@ h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
/* Special case for first column: pretend column -1 is same as column 0 */
membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);
neighsum += neighsum;
neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) +
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);
membersum = membersum * memberscale + neighsum * neighscale;
*outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
@@ -359,17 +346,17 @@ h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
for (colctr = output_cols - 2; colctr > 0; colctr--) {
/* sum of pixels directly mapped to this output element */
membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
/* sum of edge-neighbor pixels */
neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +
GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +
GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);
/* The edge-neighbors count twice as much as corner-neighbors */
neighsum += neighsum;
/* Add in the corner-neighbors */
neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) +
GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);
GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);
/* form final output scaled up by 2^16 */
membersum = membersum * memberscale + neighsum * neighscale;
/* round, descale and output it */
@@ -379,19 +366,18 @@ h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
/* Special case for last column */
membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +
GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +
GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);
neighsum += neighsum;
neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) +
GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);
GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);
membersum = membersum * memberscale + neighsum * neighscale;
*outptr = (JSAMPLE) ((membersum + 32768) >> 16);
inrow += 2;
outrow++;
}
}
@@ -404,11 +390,11 @@ h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
METHODDEF(void)
fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
int inrow;
int outrow;
JDIMENSION colctr;
JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
register JSAMPROW inptr, above_ptr, below_ptr, outptr;
INT32 membersum, neighsum, memberscale, neighscale;
int colsum, lastcolsum, nextcolsum;
@@ -418,7 +404,7 @@ fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
* efficient.
*/
expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
cinfo->image_width, output_cols);
cinfo->image_width, output_cols);
/* Each of the eight neighbor pixels contributes a fraction SF to the
* smoothed pixel, while the main pixel contributes (1-8*SF). In order
@@ -429,18 +415,18 @@ fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */
neighscale = cinfo->smoothing_factor * 64; /* scaled SF */
for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
outptr = output_data[inrow];
inptr = input_data[inrow];
above_ptr = input_data[inrow-1];
below_ptr = input_data[inrow+1];
for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
outptr = output_data[outrow];
inptr = input_data[outrow];
above_ptr = input_data[outrow-1];
below_ptr = input_data[outrow+1];
/* Special case for first column */
colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) +
GETJSAMPLE(*inptr);
GETJSAMPLE(*inptr);
membersum = GETJSAMPLE(*inptr++);
nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
GETJSAMPLE(*inptr);
GETJSAMPLE(*inptr);
neighsum = colsum + (colsum - membersum) + nextcolsum;
membersum = membersum * memberscale + neighsum * neighscale;
*outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
@@ -450,7 +436,7 @@ fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
membersum = GETJSAMPLE(*inptr++);
above_ptr++; below_ptr++;
nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
GETJSAMPLE(*inptr);
GETJSAMPLE(*inptr);
neighsum = lastcolsum + (colsum - membersum) + nextcolsum;
membersum = membersum * memberscale + neighsum * neighscale;
*outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
@@ -481,11 +467,10 @@ jinit_downsampler (j_compress_ptr cinfo)
int ci;
jpeg_component_info * compptr;
boolean smoothok = TRUE;
int h_in_group, v_in_group, h_out_group, v_out_group;
downsample = (my_downsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_downsampler));
SIZEOF(my_downsampler));
cinfo->downsample = (struct jpeg_downsampler *) downsample;
downsample->pub.start_pass = start_pass_downsample;
downsample->pub.downsample = sep_downsample;
@@ -497,43 +482,32 @@ jinit_downsampler (j_compress_ptr cinfo)
/* Verify we can handle the sampling factors, and set up method pointers */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Compute size of an "output group" for DCT scaling. This many samples
* are to be converted from max_h_samp_factor * max_v_samp_factor pixels.
*/
h_out_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) /
cinfo->min_DCT_h_scaled_size;
v_out_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
cinfo->min_DCT_v_scaled_size;
h_in_group = cinfo->max_h_samp_factor;
v_in_group = cinfo->max_v_samp_factor;
downsample->rowgroup_height[ci] = v_out_group; /* save for use later */
if (h_in_group == h_out_group && v_in_group == v_out_group) {
if (compptr->h_samp_factor == cinfo->max_h_samp_factor &&
compptr->v_samp_factor == cinfo->max_v_samp_factor) {
#ifdef INPUT_SMOOTHING_SUPPORTED
if (cinfo->smoothing_factor) {
downsample->methods[ci] = fullsize_smooth_downsample;
downsample->pub.need_context_rows = TRUE;
downsample->methods[ci] = fullsize_smooth_downsample;
downsample->pub.need_context_rows = TRUE;
} else
#endif
downsample->methods[ci] = fullsize_downsample;
} else if (h_in_group == h_out_group * 2 &&
v_in_group == v_out_group) {
downsample->methods[ci] = fullsize_downsample;
} else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
compptr->v_samp_factor == cinfo->max_v_samp_factor) {
smoothok = FALSE;
downsample->methods[ci] = h2v1_downsample;
} else if (h_in_group == h_out_group * 2 &&
v_in_group == v_out_group * 2) {
} else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) {
#ifdef INPUT_SMOOTHING_SUPPORTED
if (cinfo->smoothing_factor) {
downsample->methods[ci] = h2v2_smooth_downsample;
downsample->pub.need_context_rows = TRUE;
downsample->methods[ci] = h2v2_smooth_downsample;
downsample->pub.need_context_rows = TRUE;
} else
#endif
downsample->methods[ci] = h2v2_downsample;
} else if ((h_in_group % h_out_group) == 0 &&
(v_in_group % v_out_group) == 0) {
downsample->methods[ci] = h2v2_downsample;
} else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 &&
(cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) {
smoothok = FALSE;
downsample->methods[ci] = int_downsample;
downsample->h_expand[ci] = (UINT8) (h_in_group / h_out_group);
downsample->v_expand[ci] = (UINT8) (v_in_group / v_out_group);
} else
ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
}
+64 -61
View File
@@ -2,7 +2,6 @@
* jctrans.c
*
* Copyright (C) 1995-1998, Thomas G. Lane.
* Modified 2000-2012 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
@@ -18,9 +17,9 @@
/* Forward declarations */
LOCAL(void) transencode_master_selection
JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
LOCAL(void) transencode_coef_controller
JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
/*
@@ -62,7 +61,7 @@ jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
GLOBAL(void)
jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
j_compress_ptr dstinfo)
j_compress_ptr dstinfo)
{
JQUANT_TBL ** qtblptr;
jpeg_component_info *incomp, *outcomp;
@@ -77,18 +76,11 @@ jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
dstinfo->image_height = srcinfo->image_height;
dstinfo->input_components = srcinfo->num_components;
dstinfo->in_color_space = srcinfo->jpeg_color_space;
dstinfo->jpeg_width = srcinfo->output_width;
dstinfo->jpeg_height = srcinfo->output_height;
dstinfo->min_DCT_h_scaled_size = srcinfo->min_DCT_h_scaled_size;
dstinfo->min_DCT_v_scaled_size = srcinfo->min_DCT_v_scaled_size;
/* Initialize all parameters to default values */
jpeg_set_defaults(dstinfo);
/* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.
* Fix it to get the right header markers for the image colorspace.
* Note: Entropy table assignment in jpeg_set_colorspace depends
* on color_transform.
*/
dstinfo->color_transform = srcinfo->color_transform;
jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space);
dstinfo->data_precision = srcinfo->data_precision;
dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;
@@ -97,10 +89,10 @@ jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
if (srcinfo->quant_tbl_ptrs[tblno] != NULL) {
qtblptr = & dstinfo->quant_tbl_ptrs[tblno];
if (*qtblptr == NULL)
*qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo);
*qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo);
MEMCOPY((*qtblptr)->quantval,
srcinfo->quant_tbl_ptrs[tblno]->quantval,
SIZEOF((*qtblptr)->quantval));
srcinfo->quant_tbl_ptrs[tblno]->quantval,
SIZEOF((*qtblptr)->quantval));
(*qtblptr)->sent_table = FALSE;
}
}
@@ -110,7 +102,7 @@ jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
dstinfo->num_components = srcinfo->num_components;
if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS)
ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components,
MAX_COMPONENTS);
MAX_COMPONENTS);
for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info;
ci < dstinfo->num_components; ci++, incomp++, outcomp++) {
outcomp->component_id = incomp->component_id;
@@ -123,17 +115,17 @@ jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
*/
tblno = outcomp->quant_tbl_no;
if (tblno < 0 || tblno >= NUM_QUANT_TBLS ||
srcinfo->quant_tbl_ptrs[tblno] == NULL)
srcinfo->quant_tbl_ptrs[tblno] == NULL)
ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno);
slot_quant = srcinfo->quant_tbl_ptrs[tblno];
c_quant = incomp->quant_table;
if (c_quant != NULL) {
for (coefi = 0; coefi < DCTSIZE2; coefi++) {
if (c_quant->quantval[coefi] != slot_quant->quantval[coefi])
ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno);
if (c_quant->quantval[coefi] != slot_quant->quantval[coefi])
ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno);
}
}
/* Note: we do not copy the source's entropy table assignments;
/* Note: we do not copy the source's Huffman table assignments;
* instead we rely on jpeg_set_colorspace to have made a suitable choice.
*/
}
@@ -164,16 +156,27 @@ jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
LOCAL(void)
transencode_master_selection (j_compress_ptr cinfo,
jvirt_barray_ptr * coef_arrays)
jvirt_barray_ptr * coef_arrays)
{
/* Although we don't actually use input_components for transcoding,
* jcmaster.c's initial_setup will complain if input_components is 0.
*/
cinfo->input_components = 1;
/* Initialize master control (includes parameter checking/processing) */
jinit_c_master_control(cinfo, TRUE /* transcode only */);
/* Entropy encoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code)
jinit_arith_encoder(cinfo);
else {
jinit_huff_encoder(cinfo);
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->progressive_mode) {
#ifdef C_PROGRESSIVE_SUPPORTED
jinit_phuff_encoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_huff_encoder(cinfo);
}
/* We need a special coefficient buffer controller. */
@@ -298,44 +301,44 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
yoffset++) {
for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
MCU_col_num++) {
MCU_col_num++) {
/* Construct list of pointers to DCT blocks belonging to this MCU */
blkn = 0; /* index of current DCT block within MCU */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
start_col = MCU_col_num * compptr->MCU_width;
blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
: compptr->last_col_width;
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (coef->iMCU_row_num < last_iMCU_row ||
yindex+yoffset < compptr->last_row_height) {
/* Fill in pointers to real blocks in this row */
buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
for (xindex = 0; xindex < blockcnt; xindex++)
MCU_buffer[blkn++] = buffer_ptr++;
} else {
/* At bottom of image, need a whole row of dummy blocks */
xindex = 0;
}
/* Fill in any dummy blocks needed in this row.
* Dummy blocks are filled in the same way as in jccoefct.c:
* all zeroes in the AC entries, DC entries equal to previous
* block's DC value. The init routine has already zeroed the
* AC entries, so we need only set the DC entries correctly.
*/
for (; xindex < compptr->MCU_width; xindex++) {
MCU_buffer[blkn] = coef->dummy_buffer[blkn];
MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0];
blkn++;
}
}
compptr = cinfo->cur_comp_info[ci];
start_col = MCU_col_num * compptr->MCU_width;
blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
: compptr->last_col_width;
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (coef->iMCU_row_num < last_iMCU_row ||
yindex+yoffset < compptr->last_row_height) {
/* Fill in pointers to real blocks in this row */
buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
for (xindex = 0; xindex < blockcnt; xindex++)
MCU_buffer[blkn++] = buffer_ptr++;
} else {
/* At bottom of image, need a whole row of dummy blocks */
xindex = 0;
}
/* Fill in any dummy blocks needed in this row.
* Dummy blocks are filled in the same way as in jccoefct.c:
* all zeroes in the AC entries, DC entries equal to previous
* block's DC value. The init routine has already zeroed the
* AC entries, so we need only set the DC entries correctly.
*/
for (; xindex < compptr->MCU_width; xindex++) {
MCU_buffer[blkn] = coef->dummy_buffer[blkn];
MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0];
blkn++;
}
}
}
/* Try to write the MCU. */
if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) {
/* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset;
coef->mcu_ctr = MCU_col_num;
return FALSE;
/* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset;
coef->mcu_ctr = MCU_col_num;
return FALSE;
}
}
/* Completed an MCU row, but perhaps not an iMCU row */
@@ -358,7 +361,7 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
LOCAL(void)
transencode_coef_controller (j_compress_ptr cinfo,
jvirt_barray_ptr * coef_arrays)
jvirt_barray_ptr * coef_arrays)
{
my_coef_ptr coef;
JBLOCKROW buffer;
@@ -366,8 +369,8 @@ transencode_coef_controller (j_compress_ptr cinfo,
coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_coef_controller));
cinfo->coef = &coef->pub;
SIZEOF(my_coef_controller));
cinfo->coef = (struct jpeg_c_coef_controller *) coef;
coef->pub.start_pass = start_pass_coef;
coef->pub.compress_data = compress_output;
@@ -377,8 +380,8 @@ transencode_coef_controller (j_compress_ptr cinfo,
/* Allocate and pre-zero space for dummy DCT blocks. */
buffer = (JBLOCKROW)
(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
FMEMZERO((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
jzero_far((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
coef->dummy_buffer[i] = buffer + i;
}
+21 -22
View File
@@ -2,7 +2,6 @@
* jdapimin.c
*
* Copyright (C) 1994-1998, Thomas G. Lane.
* Modified 2009 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
@@ -38,7 +37,7 @@ jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
if (structsize != SIZEOF(struct jpeg_decompress_struct))
ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
(int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);
(int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);
/* For debugging purposes, we zero the whole master structure.
* But the application has already set the err pointer, and may have set
@@ -129,15 +128,15 @@ default_decompress_parms (j_decompress_ptr cinfo)
} else if (cinfo->saw_Adobe_marker) {
switch (cinfo->Adobe_transform) {
case 0:
cinfo->jpeg_color_space = JCS_RGB;
break;
cinfo->jpeg_color_space = JCS_RGB;
break;
case 1:
cinfo->jpeg_color_space = JCS_YCbCr;
break;
cinfo->jpeg_color_space = JCS_YCbCr;
break;
default:
WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
break;
WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
break;
}
} else {
/* Saw no special markers, try to guess from the component IDs */
@@ -146,12 +145,12 @@ default_decompress_parms (j_decompress_ptr cinfo)
int cid2 = cinfo->comp_info[2].component_id;
if (cid0 == 1 && cid1 == 2 && cid2 == 3)
cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
else {
TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
}
}
/* Always guess RGB is proper output colorspace. */
@@ -162,15 +161,15 @@ default_decompress_parms (j_decompress_ptr cinfo)
if (cinfo->saw_Adobe_marker) {
switch (cinfo->Adobe_transform) {
case 0:
cinfo->jpeg_color_space = JCS_CMYK;
break;
cinfo->jpeg_color_space = JCS_CMYK;
break;
case 2:
cinfo->jpeg_color_space = JCS_YCCK;
break;
cinfo->jpeg_color_space = JCS_YCCK;
break;
default:
WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */
break;
WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */
break;
}
} else {
/* No special markers, assume straight CMYK. */
@@ -186,8 +185,8 @@ default_decompress_parms (j_decompress_ptr cinfo)
}
/* Set defaults for other decompression parameters. */
cinfo->scale_num = cinfo->block_size; /* 1:1 scaling */
cinfo->scale_denom = cinfo->block_size;
cinfo->scale_num = 1; /* 1:1 scaling */
cinfo->scale_denom = 1;
cinfo->output_gamma = 1.0;
cinfo->buffered_image = FALSE;
cinfo->raw_data_out = FALSE;
+27 -27
View File
@@ -52,24 +52,24 @@ jpeg_start_decompress (j_decompress_ptr cinfo)
if (cinfo->inputctl->has_multiple_scans) {
#ifdef D_MULTISCAN_FILES_SUPPORTED
for (;;) {
int retcode;
/* Call progress monitor hook if present */
if (cinfo->progress != NULL)
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
/* Absorb some more input */
retcode = (*cinfo->inputctl->consume_input) (cinfo);
if (retcode == JPEG_SUSPENDED)
return FALSE;
if (retcode == JPEG_REACHED_EOI)
break;
/* Advance progress counter if appropriate */
if (cinfo->progress != NULL &&
(retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
/* jdmaster underestimated number of scans; ratchet up one scan */
cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
}
}
int retcode;
/* Call progress monitor hook if present */
if (cinfo->progress != NULL)
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
/* Absorb some more input */
retcode = (*cinfo->inputctl->consume_input) (cinfo);
if (retcode == JPEG_SUSPENDED)
return FALSE;
if (retcode == JPEG_REACHED_EOI)
break;
/* Advance progress counter if appropriate */
if (cinfo->progress != NULL &&
(retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
/* jdmaster underestimated number of scans; ratchet up one scan */
cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
}
}
}
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
@@ -108,16 +108,16 @@ output_pass_setup (j_decompress_ptr cinfo)
JDIMENSION last_scanline;
/* Call progress monitor hook if present */
if (cinfo->progress != NULL) {
cinfo->progress->pass_counter = (long) cinfo->output_scanline;
cinfo->progress->pass_limit = (long) cinfo->output_height;
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
cinfo->progress->pass_counter = (long) cinfo->output_scanline;
cinfo->progress->pass_limit = (long) cinfo->output_height;
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
}
/* Process some data */
last_scanline = cinfo->output_scanline;
(*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL,
&cinfo->output_scanline, (JDIMENSION) 0);
&cinfo->output_scanline, (JDIMENSION) 0);
if (cinfo->output_scanline == last_scanline)
return FALSE; /* No progress made, must suspend */
return FALSE; /* No progress made, must suspend */
}
/* Finish up dummy pass, and set up for another one */
(*cinfo->master->finish_output_pass) (cinfo);
@@ -150,7 +150,7 @@ output_pass_setup (j_decompress_ptr cinfo)
GLOBAL(JDIMENSION)
jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
JDIMENSION max_lines)
JDIMENSION max_lines)
{
JDIMENSION row_ctr;
@@ -183,7 +183,7 @@ jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
GLOBAL(JDIMENSION)
jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
JDIMENSION max_lines)
JDIMENSION max_lines)
{
JDIMENSION lines_per_iMCU_row;
@@ -202,7 +202,7 @@ jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
}
/* Verify that at least one iMCU row can be returned. */
lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size;
lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size;
if (max_lines < lines_per_iMCU_row)
ERREXIT(cinfo, JERR_BUFFER_SIZE);
@@ -264,7 +264,7 @@ jpeg_finish_output (j_decompress_ptr cinfo)
}
/* Read markers looking for SOS or EOI */
while (cinfo->input_scan_number <= cinfo->output_scan_number &&
! cinfo->inputctl->eoi_reached) {
! cinfo->inputctl->eoi_reached) {
if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
return FALSE; /* Suspend, come back later */
}
-782
View File
@@ -1,782 +0,0 @@
/*
* jdarith.c
*
* Developed 1997-2012 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains portable arithmetic entropy decoding routines for JPEG
* (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
*
* Both sequential and progressive modes are supported in this single module.
*
* Suspension is not currently supported in this module.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Expanded entropy decoder object for arithmetic decoding. */
typedef struct {
struct jpeg_entropy_decoder pub; /* public fields */
INT32 c; /* C register, base of coding interval + input bit buffer */
INT32 a; /* A register, normalized size of coding interval */
int ct; /* bit shift counter, # of bits left in bit buffer part of C */
/* init: ct = -16 */
/* run: ct = 0..7 */
/* error: ct = -1 */
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
unsigned int restarts_to_go; /* MCUs left in this restart interval */
/* Pointers to statistics areas (these workspaces have image lifespan) */
unsigned char * dc_stats[NUM_ARITH_TBLS];
unsigned char * ac_stats[NUM_ARITH_TBLS];
/* Statistics bin for coding with fixed probability 0.5 */
unsigned char fixed_bin[4];
} arith_entropy_decoder;
typedef arith_entropy_decoder * arith_entropy_ptr;
/* The following two definitions specify the allocation chunk size
* for the statistics area.
* According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
* 49 statistics bins for DC, and 245 statistics bins for AC coding.
*
* We use a compact representation with 1 byte per statistics bin,
* thus the numbers directly represent byte sizes.
* This 1 byte per statistics bin contains the meaning of the MPS
* (more probable symbol) in the highest bit (mask 0x80), and the
* index into the probability estimation state machine table
* in the lower bits (mask 0x7F).
*/
#define DC_STAT_BINS 64
#define AC_STAT_BINS 256
LOCAL(int)
get_byte (j_decompress_ptr cinfo)
/* Read next input byte; we do not support suspension in this module. */
{
struct jpeg_source_mgr * src = cinfo->src;
if (src->bytes_in_buffer == 0)
if (! (*src->fill_input_buffer) (cinfo))
ERREXIT(cinfo, JERR_CANT_SUSPEND);
src->bytes_in_buffer--;
return GETJOCTET(*src->next_input_byte++);
}
/*
* The core arithmetic decoding routine (common in JPEG and JBIG).
* This needs to go as fast as possible.
* Machine-dependent optimization facilities
* are not utilized in this portable implementation.
* However, this code should be fairly efficient and
* may be a good base for further optimizations anyway.
*
* Return value is 0 or 1 (binary decision).
*
* Note: I've changed the handling of the code base & bit
* buffer register C compared to other implementations
* based on the standards layout & procedures.
* While it also contains both the actual base of the
* coding interval (16 bits) and the next-bits buffer,
* the cut-point between these two parts is floating
* (instead of fixed) with the bit shift counter CT.
* Thus, we also need only one (variable instead of
* fixed size) shift for the LPS/MPS decision, and
* we can get away with any renormalization update
* of C (except for new data insertion, of course).
*
* I've also introduced a new scheme for accessing
* the probability estimation state machine table,
* derived from Markus Kuhn's JBIG implementation.
*/
LOCAL(int)
arith_decode (j_decompress_ptr cinfo, unsigned char *st)
{
register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
register unsigned char nl, nm;
register INT32 qe, temp;
register int sv, data;
/* Renormalization & data input per section D.2.6 */
while (e->a < 0x8000L) {
if (--e->ct < 0) {
/* Need to fetch next data byte */
if (cinfo->unread_marker)
data = 0; /* stuff zero data */
else {
data = get_byte(cinfo); /* read next input byte */
if (data == 0xFF) { /* zero stuff or marker code */
do data = get_byte(cinfo);
while (data == 0xFF); /* swallow extra 0xFF bytes */
if (data == 0)
data = 0xFF; /* discard stuffed zero byte */
else {
/* Note: Different from the Huffman decoder, hitting
* a marker while processing the compressed data
* segment is legal in arithmetic coding.
* The convention is to supply zero data
* then until decoding is complete.
*/
cinfo->unread_marker = data;
data = 0;
}
}
}
e->c = (e->c << 8) | data; /* insert data into C register */
if ((e->ct += 8) < 0) /* update bit shift counter */
/* Need more initial bytes */
if (++e->ct == 0)
/* Got 2 initial bytes -> re-init A and exit loop */
e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */
}
e->a <<= 1;
}
/* Fetch values from our compact representation of Table D.3(D.2):
* Qe values and probability estimation state machine
*/
sv = *st;
qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */
nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */
nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */
/* Decode & estimation procedures per sections D.2.4 & D.2.5 */
temp = e->a - qe;
e->a = temp;
temp <<= e->ct;
if (e->c >= temp) {
e->c -= temp;
/* Conditional LPS (less probable symbol) exchange */
if (e->a < qe) {
e->a = qe;
*st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */
} else {
e->a = qe;
*st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */
sv ^= 0x80; /* Exchange LPS/MPS */
}
} else if (e->a < 0x8000L) {
/* Conditional MPS (more probable symbol) exchange */
if (e->a < qe) {
*st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */
sv ^= 0x80; /* Exchange LPS/MPS */
} else {
*st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */
}
}
return sv >> 7;
}
/*
* Check for a restart marker & resynchronize decoder.
*/
LOCAL(void)
process_restart (j_decompress_ptr cinfo)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
int ci;
jpeg_component_info * compptr;
/* Advance past the RSTn marker */
if (! (*cinfo->marker->read_restart_marker) (cinfo))
ERREXIT(cinfo, JERR_CANT_SUSPEND);
/* Re-initialize statistics areas */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
/* Reset DC predictions to 0 */
entropy->last_dc_val[ci] = 0;
entropy->dc_context[ci] = 0;
}
if ((! cinfo->progressive_mode && cinfo->lim_Se) ||
(cinfo->progressive_mode && cinfo->Ss)) {
MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
}
}
/* Reset arithmetic decoding variables */
entropy->c = 0;
entropy->a = 0;
entropy->ct = -16; /* force reading 2 initial bytes to fill C */
/* Reset restart counter */
entropy->restarts_to_go = cinfo->restart_interval;
}
/*
* Arithmetic MCU decoding.
* Each of these routines decodes and returns one MCU's worth of
* arithmetic-compressed coefficients.
* The coefficients are reordered from zigzag order into natural array order,
* but are not dequantized.
*
* The i'th block of the MCU is stored into the block pointed to by
* MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
*/
/*
* MCU decoding for DC initial scan (either spectral selection,
* or first pass of successive approximation).
*/
METHODDEF(boolean)
decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
JBLOCKROW block;
unsigned char *st;
int blkn, ci, tbl, sign;
int v, m;
/* Process restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
process_restart(cinfo);
entropy->restarts_to_go--;
}
if (entropy->ct == -1) return TRUE; /* if error do nothing */
/* Outer loop handles each block in the MCU */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn];
ci = cinfo->MCU_membership[blkn];
tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
/* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
/* Table F.4: Point to statistics bin S0 for DC coefficient coding */
st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
/* Figure F.19: Decode_DC_DIFF */
if (arith_decode(cinfo, st) == 0)
entropy->dc_context[ci] = 0;
else {
/* Figure F.21: Decoding nonzero value v */
/* Figure F.22: Decoding the sign of v */
sign = arith_decode(cinfo, st + 1);
st += 2; st += sign;
/* Figure F.23: Decoding the magnitude category of v */
if ((m = arith_decode(cinfo, st)) != 0) {
st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
while (arith_decode(cinfo, st)) {
if ((m <<= 1) == 0x8000) {
WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
entropy->ct = -1; /* magnitude overflow */
return TRUE;
}
st += 1;
}
}
/* Section F.1.4.4.1.2: Establish dc_context conditioning category */
if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
entropy->dc_context[ci] = 0; /* zero diff category */
else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
else
entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */
v = m;
/* Figure F.24: Decoding the magnitude bit pattern of v */
st += 14;
while (m >>= 1)
if (arith_decode(cinfo, st)) v |= m;
v += 1; if (sign) v = -v;
entropy->last_dc_val[ci] += v;
}
/* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */
(*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al);
}
return TRUE;
}
/*
* MCU decoding for AC initial scan (either spectral selection,
* or first pass of successive approximation).
*/
METHODDEF(boolean)
decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
JBLOCKROW block;
unsigned char *st;
int tbl, sign, k;
int v, m;
const int * natural_order;
/* Process restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
process_restart(cinfo);
entropy->restarts_to_go--;
}
if (entropy->ct == -1) return TRUE; /* if error do nothing */
natural_order = cinfo->natural_order;
/* There is always only one block per MCU */
block = MCU_data[0];
tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
/* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
/* Figure F.20: Decode_AC_coefficients */
k = cinfo->Ss - 1;
do {
st = entropy->ac_stats[tbl] + 3 * k;
if (arith_decode(cinfo, st)) break; /* EOB flag */
for (;;) {
k++;
if (arith_decode(cinfo, st + 1)) break;
st += 3;
if (k >= cinfo->Se) {
WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
entropy->ct = -1; /* spectral overflow */
return TRUE;
}
}
/* Figure F.21: Decoding nonzero value v */
/* Figure F.22: Decoding the sign of v */
sign = arith_decode(cinfo, entropy->fixed_bin);
st += 2;
/* Figure F.23: Decoding the magnitude category of v */
if ((m = arith_decode(cinfo, st)) != 0) {
if (arith_decode(cinfo, st)) {
m <<= 1;
st = entropy->ac_stats[tbl] +
(k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
while (arith_decode(cinfo, st)) {
if ((m <<= 1) == 0x8000) {
WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
entropy->ct = -1; /* magnitude overflow */
return TRUE;
}
st += 1;
}
}
}
v = m;
/* Figure F.24: Decoding the magnitude bit pattern of v */
st += 14;
while (m >>= 1)
if (arith_decode(cinfo, st)) v |= m;
v += 1; if (sign) v = -v;
/* Scale and output coefficient in natural (dezigzagged) order */
(*block)[natural_order[k]] = (JCOEF) (v << cinfo->Al);
} while (k < cinfo->Se);
return TRUE;
}
/*
* MCU decoding for DC successive approximation refinement scan.
*/
METHODDEF(boolean)
decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
unsigned char *st;
int p1, blkn;
/* Process restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
process_restart(cinfo);
entropy->restarts_to_go--;
}
st = entropy->fixed_bin; /* use fixed probability estimation */
p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
/* Outer loop handles each block in the MCU */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
/* Encoded data is simply the next bit of the two's-complement DC value */
if (arith_decode(cinfo, st))
MCU_data[blkn][0][0] |= p1;
}
return TRUE;
}
/*
* MCU decoding for AC successive approximation refinement scan.
*/
METHODDEF(boolean)
decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
JBLOCKROW block;
JCOEFPTR thiscoef;
unsigned char *st;
int tbl, k, kex;
int p1, m1;
const int * natural_order;
/* Process restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
process_restart(cinfo);
entropy->restarts_to_go--;
}
if (entropy->ct == -1) return TRUE; /* if error do nothing */
natural_order = cinfo->natural_order;
/* There is always only one block per MCU */
block = MCU_data[0];
tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */
/* Establish EOBx (previous stage end-of-block) index */
kex = cinfo->Se;
do {
if ((*block)[natural_order[kex]]) break;
} while (--kex);
k = cinfo->Ss - 1;
do {
st = entropy->ac_stats[tbl] + 3 * k;
if (k >= kex)
if (arith_decode(cinfo, st)) break; /* EOB flag */
for (;;) {
thiscoef = *block + natural_order[++k];
if (*thiscoef) { /* previously nonzero coef */
if (arith_decode(cinfo, st + 2)) {
if (*thiscoef < 0)
*thiscoef += m1;
else
*thiscoef += p1;
}
break;
}
if (arith_decode(cinfo, st + 1)) { /* newly nonzero coef */
if (arith_decode(cinfo, entropy->fixed_bin))
*thiscoef = m1;
else
*thiscoef = p1;
break;
}
st += 3;
if (k >= cinfo->Se) {
WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
entropy->ct = -1; /* spectral overflow */
return TRUE;
}
}
} while (k < cinfo->Se);
return TRUE;
}
/*
* Decode one MCU's worth of arithmetic-compressed coefficients.
*/
METHODDEF(boolean)
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
jpeg_component_info * compptr;
JBLOCKROW block;
unsigned char *st;
int blkn, ci, tbl, sign, k;
int v, m;
const int * natural_order;
/* Process restart marker if needed */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
process_restart(cinfo);
entropy->restarts_to_go--;
}
if (entropy->ct == -1) return TRUE; /* if error do nothing */
natural_order = cinfo->natural_order;
/* Outer loop handles each block in the MCU */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn];
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
/* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
tbl = compptr->dc_tbl_no;
/* Table F.4: Point to statistics bin S0 for DC coefficient coding */
st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
/* Figure F.19: Decode_DC_DIFF */
if (arith_decode(cinfo, st) == 0)
entropy->dc_context[ci] = 0;
else {
/* Figure F.21: Decoding nonzero value v */
/* Figure F.22: Decoding the sign of v */
sign = arith_decode(cinfo, st + 1);
st += 2; st += sign;
/* Figure F.23: Decoding the magnitude category of v */
if ((m = arith_decode(cinfo, st)) != 0) {
st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
while (arith_decode(cinfo, st)) {
if ((m <<= 1) == 0x8000) {
WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
entropy->ct = -1; /* magnitude overflow */
return TRUE;
}
st += 1;
}
}
/* Section F.1.4.4.1.2: Establish dc_context conditioning category */
if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
entropy->dc_context[ci] = 0; /* zero diff category */
else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
else
entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */
v = m;
/* Figure F.24: Decoding the magnitude bit pattern of v */
st += 14;
while (m >>= 1)
if (arith_decode(cinfo, st)) v |= m;
v += 1; if (sign) v = -v;
entropy->last_dc_val[ci] += v;
}
(*block)[0] = (JCOEF) entropy->last_dc_val[ci];
/* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
if (cinfo->lim_Se == 0) continue;
tbl = compptr->ac_tbl_no;
k = 0;
/* Figure F.20: Decode_AC_coefficients */
do {
st = entropy->ac_stats[tbl] + 3 * k;
if (arith_decode(cinfo, st)) break; /* EOB flag */
for (;;) {
k++;
if (arith_decode(cinfo, st + 1)) break;
st += 3;
if (k >= cinfo->lim_Se) {
WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
entropy->ct = -1; /* spectral overflow */
return TRUE;
}
}
/* Figure F.21: Decoding nonzero value v */
/* Figure F.22: Decoding the sign of v */
sign = arith_decode(cinfo, entropy->fixed_bin);
st += 2;
/* Figure F.23: Decoding the magnitude category of v */
if ((m = arith_decode(cinfo, st)) != 0) {
if (arith_decode(cinfo, st)) {
m <<= 1;
st = entropy->ac_stats[tbl] +
(k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
while (arith_decode(cinfo, st)) {
if ((m <<= 1) == 0x8000) {
WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
entropy->ct = -1; /* magnitude overflow */
return TRUE;
}
st += 1;
}
}
}
v = m;
/* Figure F.24: Decoding the magnitude bit pattern of v */
st += 14;
while (m >>= 1)
if (arith_decode(cinfo, st)) v |= m;
v += 1; if (sign) v = -v;
(*block)[natural_order[k]] = (JCOEF) v;
} while (k < cinfo->lim_Se);
}
return TRUE;
}
/*
* Initialize for an arithmetic-compressed scan.
*/
METHODDEF(void)
start_pass (j_decompress_ptr cinfo)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
int ci, tbl;
jpeg_component_info * compptr;
if (cinfo->progressive_mode) {
/* Validate progressive scan parameters */
if (cinfo->Ss == 0) {
if (cinfo->Se != 0)
goto bad;
} else {
/* need not check Ss/Se < 0 since they came from unsigned bytes */
if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se)
goto bad;
/* AC scans may have only one component */
if (cinfo->comps_in_scan != 1)
goto bad;
}
if (cinfo->Ah != 0) {
/* Successive approximation refinement scan: must have Al = Ah-1. */
if (cinfo->Ah-1 != cinfo->Al)
goto bad;
}
if (cinfo->Al > 13) { /* need not check for < 0 */
bad:
ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
}
/* Update progression status, and verify that scan order is legal.
* Note that inter-scan inconsistencies are treated as warnings
* not fatal errors ... not clear if this is right way to behave.
*/
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;
int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];
if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
if (cinfo->Ah != expected)
WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
coef_bit_ptr[coefi] = cinfo->Al;
}
}
/* Select MCU decoding routine */
if (cinfo->Ah == 0) {
if (cinfo->Ss == 0)
entropy->pub.decode_mcu = decode_mcu_DC_first;
else
entropy->pub.decode_mcu = decode_mcu_AC_first;
} else {
if (cinfo->Ss == 0)
entropy->pub.decode_mcu = decode_mcu_DC_refine;
else
entropy->pub.decode_mcu = decode_mcu_AC_refine;
}
} else {
/* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
* This ought to be an error condition, but we make it a warning.
*/
if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||
(cinfo->Se < DCTSIZE2 && cinfo->Se != cinfo->lim_Se))
WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
/* Select MCU decoding routine */
entropy->pub.decode_mcu = decode_mcu;
}
/* Allocate & initialize requested statistics areas */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
tbl = compptr->dc_tbl_no;
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
if (entropy->dc_stats[tbl] == NULL)
entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
/* Initialize DC predictions to 0 */
entropy->last_dc_val[ci] = 0;
entropy->dc_context[ci] = 0;
}
if ((! cinfo->progressive_mode && cinfo->lim_Se) ||
(cinfo->progressive_mode && cinfo->Ss)) {
tbl = compptr->ac_tbl_no;
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
if (entropy->ac_stats[tbl] == NULL)
entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
}
}
/* Initialize arithmetic decoding variables */
entropy->c = 0;
entropy->a = 0;
entropy->ct = -16; /* force reading 2 initial bytes to fill C */
/* Initialize restart counter */
entropy->restarts_to_go = cinfo->restart_interval;
}
/*
* Module initialization routine for arithmetic entropy decoding.
*/
GLOBAL(void)
jinit_arith_decoder (j_decompress_ptr cinfo)
{
arith_entropy_ptr entropy;
int i;
entropy = (arith_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(arith_entropy_decoder));
cinfo->entropy = &entropy->pub;
entropy->pub.start_pass = start_pass;
/* Mark tables unallocated */
for (i = 0; i < NUM_ARITH_TBLS; i++) {
entropy->dc_stats[i] = NULL;
entropy->ac_stats[i] = NULL;
}
/* Initialize index for fixed probability estimation */
entropy->fixed_bin[0] = 113;
if (cinfo->progressive_mode) {
/* Create progression status table */
int *coef_bit_ptr, ci;
cinfo->coef_bits = (int (*)[DCTSIZE2])
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
cinfo->num_components*DCTSIZE2*SIZEOF(int));
coef_bit_ptr = & cinfo->coef_bits[0][0];
for (ci = 0; ci < cinfo->num_components; ci++)
for (i = 0; i < DCTSIZE2; i++)
*coef_bit_ptr++ = -1;
}
}
+5 -124
View File
@@ -2,14 +2,13 @@
* jdatadst.c
*
* Copyright (C) 1994-1996, Thomas G. Lane.
* Modified 2009-2012 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains compression data destination routines for the case of
* emitting JPEG data to memory or to a file (or any stdio stream).
* While these routines are sufficient for most applications,
* some will want to use a different destination manager.
* emitting JPEG data to a file (or any stdio stream). While these routines
* are sufficient for most applications, some will want to use a different
* destination manager.
* IMPORTANT: we assume that fwrite() will correctly transcribe an array of
* JOCTETs into 8-bit-wide elements on external storage. If char is wider
* than 8 bits on your machine, you may need to do some tweaking.
@@ -20,11 +19,6 @@
#include "jpeglib.h"
#include "jerror.h"
#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
extern void * malloc JPP((size_t size));
extern void free JPP((void *ptr));
#endif
/* Expanded data destination object for stdio output */
@@ -40,21 +34,6 @@ typedef my_destination_mgr * my_dest_ptr;
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
/* Expanded data destination object for memory output */
typedef struct {
struct jpeg_destination_mgr pub; /* public fields */
unsigned char ** outbuffer; /* target buffer */
unsigned long * outsize;
unsigned char * newbuffer; /* newly allocated buffer */
JOCTET * buffer; /* start of buffer */
size_t bufsize;
} my_mem_destination_mgr;
typedef my_mem_destination_mgr * my_mem_dest_ptr;
/*
* Initialize destination --- called by jpeg_start_compress
* before any data is actually written.
@@ -68,18 +47,12 @@ init_destination (j_compress_ptr cinfo)
/* Allocate the output buffer --- it will be released when done with image */
dest->buffer = (JOCTET *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
dest->pub.next_output_byte = dest->buffer;
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
}
METHODDEF(void)
init_mem_destination (j_compress_ptr cinfo)
{
/* no work necessary here */
}
/*
* Empty the output buffer --- called whenever buffer fills up.
@@ -119,36 +92,6 @@ empty_output_buffer (j_compress_ptr cinfo)
return TRUE;
}
METHODDEF(boolean)
empty_mem_output_buffer (j_compress_ptr cinfo)
{
size_t nextsize;
JOCTET * nextbuffer;
my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
/* Try to allocate new buffer with double size */
nextsize = dest->bufsize * 2;
nextbuffer = (JOCTET *) malloc(nextsize);
if (nextbuffer == NULL)
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
MEMCOPY(nextbuffer, dest->buffer, dest->bufsize);
if (dest->newbuffer != NULL)
free(dest->newbuffer);
dest->newbuffer = nextbuffer;
dest->pub.next_output_byte = nextbuffer + dest->bufsize;
dest->pub.free_in_buffer = dest->bufsize;
dest->buffer = nextbuffer;
dest->bufsize = nextsize;
return TRUE;
}
/*
* Terminate destination --- called by jpeg_finish_compress
@@ -176,15 +119,6 @@ term_destination (j_compress_ptr cinfo)
ERREXIT(cinfo, JERR_FILE_WRITE);
}
METHODDEF(void)
term_mem_destination (j_compress_ptr cinfo)
{
my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
*dest->outbuffer = dest->buffer;
*dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
}
/*
* Prepare for output to a stdio stream.
@@ -206,7 +140,7 @@ jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(my_destination_mgr));
SIZEOF(my_destination_mgr));
}
dest = (my_dest_ptr) cinfo->dest;
@@ -215,56 +149,3 @@ jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
dest->pub.term_destination = term_destination;
dest->outfile = outfile;
}
/*
* Prepare for output to a memory buffer.
* The caller may supply an own initial buffer with appropriate size.
* Otherwise, or when the actual data output exceeds the given size,
* the library adapts the buffer size as necessary.
* The standard library functions malloc/free are used for allocating
* larger memory, so the buffer is available to the application after
* finishing compression, and then the application is responsible for
* freeing the requested memory.
* Note: An initial buffer supplied by the caller is expected to be
* managed by the application. The library does not free such buffer
* when allocating a larger buffer.
*/
GLOBAL(void)
jpeg_mem_dest (j_compress_ptr cinfo,
unsigned char ** outbuffer, unsigned long * outsize)
{
my_mem_dest_ptr dest;
if (outbuffer == NULL || outsize == NULL) /* sanity check */
ERREXIT(cinfo, JERR_BUFFER_SIZE);
/* The destination object is made permanent so that multiple JPEG images
* can be written to the same buffer without re-executing jpeg_mem_dest.
*/
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(my_mem_destination_mgr));
}
dest = (my_mem_dest_ptr) cinfo->dest;
dest->pub.init_destination = init_mem_destination;
dest->pub.empty_output_buffer = empty_mem_output_buffer;
dest->pub.term_destination = term_mem_destination;
dest->outbuffer = outbuffer;
dest->outsize = outsize;
dest->newbuffer = NULL;
if (*outbuffer == NULL || *outsize == 0) {
/* Allocate initial buffer */
dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE);
if (dest->newbuffer == NULL)
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
*outsize = OUTPUT_BUF_SIZE;
}
dest->pub.next_output_byte = dest->buffer = *outbuffer;
dest->pub.free_in_buffer = dest->bufsize = *outsize;
}
+11 -74
View File
@@ -2,14 +2,13 @@
* jdatasrc.c
*
* Copyright (C) 1994-1996, Thomas G. Lane.
* Modified 2009-2011 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains decompression data source routines for the case of
* reading JPEG data from memory or from a file (or any stdio stream).
* While these routines are sufficient for most applications,
* some will want to use a different source manager.
* reading JPEG data from a file (or any stdio stream). While these routines
* are sufficient for most applications, some will want to use a different
* source manager.
* IMPORTANT: we assume that fread() will correctly transcribe an array of
* JOCTETs from 8-bit-wide elements on external storage. If char is wider
* than 8 bits on your machine, you may need to do some tweaking.
@@ -53,12 +52,6 @@ init_source (j_decompress_ptr cinfo)
src->start_of_file = TRUE;
}
METHODDEF(void)
init_mem_source (j_decompress_ptr cinfo)
{
/* no work necessary here */
}
/*
* Fill the input buffer --- called whenever buffer is emptied.
@@ -118,27 +111,6 @@ fill_input_buffer (j_decompress_ptr cinfo)
return TRUE;
}
METHODDEF(boolean)
fill_mem_input_buffer (j_decompress_ptr cinfo)
{
static const JOCTET mybuffer[4] = {
(JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0
};
/* The whole JPEG data is expected to reside in the supplied memory
* buffer, so any request for more data beyond the given buffer size
* is treated as an error.
*/
WARNMS(cinfo, JWRN_JPEG_EOF);
/* Insert a fake EOI marker */
cinfo->src->next_input_byte = mybuffer;
cinfo->src->bytes_in_buffer = 2;
return TRUE;
}
/*
* Skip data --- used to skip over a potentially large amount of
@@ -155,22 +127,22 @@ fill_mem_input_buffer (j_decompress_ptr cinfo)
METHODDEF(void)
skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
struct jpeg_source_mgr * src = cinfo->src;
my_src_ptr src = (my_src_ptr) cinfo->src;
/* Just a dumb implementation for now. Could use fseek() except
* it doesn't work on pipes. Not clear that being smart is worth
* any trouble anyway --- large skips are infrequent.
*/
if (num_bytes > 0) {
while (num_bytes > (long) src->bytes_in_buffer) {
num_bytes -= (long) src->bytes_in_buffer;
(void) (*src->fill_input_buffer) (cinfo);
while (num_bytes > (long) src->pub.bytes_in_buffer) {
num_bytes -= (long) src->pub.bytes_in_buffer;
(void) fill_input_buffer(cinfo);
/* note we assume that fill_input_buffer will never return FALSE,
* so suspension need not be handled.
*/
}
src->next_input_byte += (size_t) num_bytes;
src->bytes_in_buffer -= (size_t) num_bytes;
src->pub.next_input_byte += (size_t) num_bytes;
src->pub.bytes_in_buffer -= (size_t) num_bytes;
}
}
@@ -221,11 +193,11 @@ jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
if (cinfo->src == NULL) { /* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(my_source_mgr));
SIZEOF(my_source_mgr));
src = (my_src_ptr) cinfo->src;
src->buffer = (JOCTET *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
INPUT_BUF_SIZE * SIZEOF(JOCTET));
INPUT_BUF_SIZE * SIZEOF(JOCTET));
}
src = (my_src_ptr) cinfo->src;
@@ -238,38 +210,3 @@ jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
src->pub.next_input_byte = NULL; /* until buffer loaded */
}
/*
* Prepare for input from a supplied memory buffer.
* The buffer must contain the whole JPEG data.
*/
GLOBAL(void)
jpeg_mem_src (j_decompress_ptr cinfo,
unsigned char * inbuffer, unsigned long insize)
{
struct jpeg_source_mgr * src;
if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */
ERREXIT(cinfo, JERR_INPUT_EMPTY);
/* The source object is made permanent so that a series of JPEG images
* can be read from the same buffer by calling jpeg_mem_src only before
* the first one.
*/
if (cinfo->src == NULL) { /* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(struct jpeg_source_mgr));
}
src = cinfo->src;
src->init_source = init_mem_source;
src->fill_input_buffer = fill_mem_input_buffer;
src->skip_input_data = skip_input_data;
src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->term_source = term_source;
src->bytes_in_buffer = (size_t) insize;
src->next_input_byte = (JOCTET *) inbuffer;
}

Some files were not shown because too many files have changed in this diff Show More