Completely refactored the TurboJPEG C API so that it uses pixel formats instead of the clunky pixel size + flags combination to define the pixel size and component order.  tjCompress2() and tjTransform() can also now grow the JPEG buffer as needed, which can allow programs to save memory by not pre-allocating the "worst-case" buffer size calculated by TJBUFSIZE().  Converted API documentation to Doxygen.  There is no legacy code remaining, so the refactored version of the library has been re-licensed under a BSD-style license.


git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@616 632fc199-4ca6-4c93-a231-07263d6284db
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d569b2b..c8cd090 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -170,7 +170,7 @@
   add_dependencies(jpeg-static simd)
 endif()
 
-set(TURBOJPEG_SOURCES turbojpegl.c transupp.c)
+set(TURBOJPEG_SOURCES turbojpegl.c transupp.c jdatadst-tj.c jdatasrc-tj.c)
 if(WITH_JAVA)
   set(TURBOJPEG_SOURCES ${TURBOJPEG_SOURCES} turbojpeg-jni.c)
   include_directories(${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
@@ -185,7 +185,7 @@
 set_target_properties(turbojpeg PROPERTIES LINK_INTERFACE_LIBRARIES "")
 
 add_library(turbojpeg-static STATIC ${JPEG_SOURCES} ${SIMD_OBJS}
-  turbojpegl.c transupp.c)
+  turbojpegl.c transupp.c jdatadst-tj.c jdatasrc-tj.c)
 if(NOT MSVC)
   set_target_properties(turbojpeg-static PROPERTIES OUTPUT_NAME turbojpeg)
 endif()
diff --git a/ChangeLog.txt b/ChangeLog.txt
index bedfb4d..e1cee84 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -35,6 +35,11 @@
 conversion routines to accelerate JPEG decoding on ARM Linux platforms that
 have NEON instructions.
 
+[11] Refactored the TurboJPEG C API so that it uses pixel formats to define the
+size and component order of the uncompressed source/destination images as well
+as uses the libjpeg memory source and destination managers.  The latter allows
+the TurboJPEG compressor to grow the JPEG buffer as necessary.
+
 
 1.1.1
 =====
diff --git a/Makefile.am b/Makefile.am
index b6c93d5..9237233 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,7 +35,7 @@
 endif
 
 libturbojpeg_la_SOURCES = $(libjpeg_la_SOURCES) turbojpegl.c turbojpeg.h \
-	transupp.c transupp.h
+	transupp.c transupp.h jdatadst-tj.c jdatasrc-tj.c
 
 SUBDIRS = java
 
diff --git a/doc/html/annotated.html b/doc/html/annotated.html
new file mode 100644
index 0000000..78d47fb
--- /dev/null
+++ b/doc/html/annotated.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: Data Structures</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li><a href="modules.html"><span>Modules</span></a></li>
+      <li class="current"><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+  <div id="navrow2" class="tabs2">
+    <ul class="tablist">
+      <li class="current"><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li><a href="classes.html"><span>Data&#160;Structure&#160;Index</span></a></li>
+      <li><a href="functions.html"><span>Data&#160;Fields</span></a></li>
+    </ul>
+  </div>
+</div>
+<div class="header">
+  <div class="headertitle">
+<div class="title">Data Structures</div>  </div>
+</div>
+<div class="contents">
+<div class="textblock">Here are the data structures with brief descriptions:</div><table>
+  <tr><td class="indexkey"><a class="el" href="structtjregion.html">tjregion</a></td><td class="indexvalue">Cropping region </td></tr>
+  <tr><td class="indexkey"><a class="el" href="structtjscalingfactor.html">tjscalingfactor</a></td><td class="indexvalue">Scaling factor </td></tr>
+  <tr><td class="indexkey"><a class="el" href="structtjtransform.html">tjtransform</a></td><td class="indexvalue">Lossless transform </td></tr>
+</table>
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/bc_s.png b/doc/html/bc_s.png
new file mode 100644
index 0000000..e401862
--- /dev/null
+++ b/doc/html/bc_s.png
Binary files differ
diff --git a/doc/html/classes.html b/doc/html/classes.html
new file mode 100644
index 0000000..db2e269
--- /dev/null
+++ b/doc/html/classes.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: Data Structure Index</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li><a href="modules.html"><span>Modules</span></a></li>
+      <li class="current"><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+  <div id="navrow2" class="tabs2">
+    <ul class="tablist">
+      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li class="current"><a href="classes.html"><span>Data&#160;Structure&#160;Index</span></a></li>
+      <li><a href="functions.html"><span>Data&#160;Fields</span></a></li>
+    </ul>
+  </div>
+</div>
+<div class="header">
+  <div class="headertitle">
+<div class="title">Data Structure Index</div>  </div>
+</div>
+<div class="contents">
+<div class="qindex"><a class="qindex" href="#letter_T">T</a></div>
+<table align="center" width="95%" border="0" cellspacing="0" cellpadding="0">
+<tr><td><a name="letter_T"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;T&#160;&#160;</div></td></tr></table>
+</td><td><a class="el" href="structtjregion.html">tjregion</a>&#160;&#160;&#160;</td><td><a class="el" href="structtjscalingfactor.html">tjscalingfactor</a>&#160;&#160;&#160;</td><td><a class="el" href="structtjtransform.html">tjtransform</a>&#160;&#160;&#160;</td></tr></table><div class="qindex"><a class="qindex" href="#letter_T">T</a></div>
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/closed.png b/doc/html/closed.png
new file mode 100644
index 0000000..b7d4bd9
--- /dev/null
+++ b/doc/html/closed.png
Binary files differ
diff --git a/doc/html/doxygen.css b/doc/html/doxygen.css
new file mode 100644
index 0000000..74445fe
--- /dev/null
+++ b/doc/html/doxygen.css
@@ -0,0 +1,835 @@
+/* The standard CSS for doxygen */
+
+body, table, div, p, dl {
+	font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
+	font-size: 12px;
+}
+
+/* @group Heading Levels */
+
+h1 {
+	font-size: 150%;
+}
+
+.title {
+	font-size: 150%;
+	font-weight: bold;
+	margin: 10px 2px;
+}
+
+h2 {
+	font-size: 120%;
+}
+
+h3 {
+	font-size: 100%;
+}
+
+dt {
+	font-weight: bold;
+}
+
+div.multicol {
+	-moz-column-gap: 1em;
+	-webkit-column-gap: 1em;
+	-moz-column-count: 3;
+	-webkit-column-count: 3;
+}
+
+p.startli, p.startdd, p.starttd {
+	margin-top: 2px;
+}
+
+p.endli {
+	margin-bottom: 0px;
+}
+
+p.enddd {
+	margin-bottom: 4px;
+}
+
+p.endtd {
+	margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+	font-weight: bold;
+}
+
+span.legend {
+        font-size: 70%;
+        text-align: center;
+}
+
+h3.version {
+        font-size: 90%;
+        text-align: center;
+}
+
+div.qindex, div.navtab{
+	background-color: #EBEFF6;
+	border: 1px solid #A3B4D7;
+	text-align: center;
+	margin: 2px;
+	padding: 2px;
+}
+
+div.qindex, div.navpath {
+	width: 100%;
+	line-height: 140%;
+}
+
+div.navtab {
+	margin-right: 15px;
+}
+
+/* @group Link Styling */
+
+a {
+	color: #3D578C;
+	font-weight: normal;
+	text-decoration: none;
+}
+
+.contents a:visited {
+	color: #4665A2;
+}
+
+a:hover {
+	text-decoration: underline;
+}
+
+a.qindex {
+	font-weight: bold;
+}
+
+a.qindexHL {
+	font-weight: bold;
+	background-color: #9CAFD4;
+	color: #ffffff;
+	border: 1px double #869DCA;
+}
+
+.contents a.qindexHL:visited {
+        color: #ffffff;
+}
+
+a.el {
+	font-weight: bold;
+}
+
+a.elRef {
+}
+
+a.code {
+	color: #4665A2;
+}
+
+a.codeRef {
+	color: #4665A2;
+}
+
+/* @end */
+
+dl.el {
+	margin-left: -1cm;
+}
+
+.fragment {
+	font-family: monospace, fixed;
+	font-size: 105%;
+}
+
+pre.fragment {
+	border: 1px solid #C4CFE5;
+	background-color: #FBFCFD;
+	padding: 4px 6px;
+	margin: 4px 8px 4px 2px;
+	overflow: auto;
+	word-wrap: break-word;
+	font-size:  9pt;
+	line-height: 125%;
+}
+
+div.ah {
+	background-color: black;
+	font-weight: bold;
+	color: #ffffff;
+	margin-bottom: 3px;
+	margin-top: 3px;
+	padding: 0.2em;
+	border: solid thin #333;
+	border-radius: 0.5em;
+	-webkit-border-radius: .5em;
+	-moz-border-radius: .5em;
+	box-shadow: 2px 2px 3px #999;
+	-webkit-box-shadow: 2px 2px 3px #999;
+	-moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+	background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+	background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
+}
+
+div.groupHeader {
+	margin-left: 16px;
+	margin-top: 12px;
+	font-weight: bold;
+}
+
+div.groupText {
+	margin-left: 16px;
+	font-style: italic;
+}
+
+body {
+	background: white;
+	color: black;
+        margin: 0;
+}
+
+div.contents {
+	margin-top: 10px;
+	margin-left: 10px;
+	margin-right: 5px;
+}
+
+td.indexkey {
+	background-color: #EBEFF6;
+	font-weight: bold;
+	border: 1px solid #C4CFE5;
+	margin: 2px 0px 2px 0;
+	padding: 2px 10px;
+}
+
+td.indexvalue {
+	background-color: #EBEFF6;
+	border: 1px solid #C4CFE5;
+	padding: 2px 10px;
+	margin: 2px 0px;
+}
+
+tr.memlist {
+	background-color: #EEF1F7;
+}
+
+p.formulaDsp {
+	text-align: center;
+}
+
+img.formulaDsp {
+	
+}
+
+img.formulaInl {
+	vertical-align: middle;
+}
+
+div.center {
+	text-align: center;
+        margin-top: 0px;
+        margin-bottom: 0px;
+        padding: 0px;
+}
+
+div.center img {
+	border: 0px;
+}
+
+address.footer {
+	text-align: right;
+	padding-right: 12px;
+}
+
+img.footer {
+	border: 0px;
+	vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+	color: #008000
+}
+
+span.keywordtype {
+	color: #604020
+}
+
+span.keywordflow {
+	color: #e08000
+}
+
+span.comment {
+	color: #800000
+}
+
+span.preprocessor {
+	color: #806020
+}
+
+span.stringliteral {
+	color: #002080
+}
+
+span.charliteral {
+	color: #008080
+}
+
+span.vhdldigit { 
+	color: #ff00ff 
+}
+
+span.vhdlchar { 
+	color: #000000 
+}
+
+span.vhdlkeyword { 
+	color: #700070 
+}
+
+span.vhdllogic { 
+	color: #ff0000 
+}
+
+/* @end */
+
+/*
+.search {
+	color: #003399;
+	font-weight: bold;
+}
+
+form.search {
+	margin-bottom: 0px;
+	margin-top: 0px;
+}
+
+input.search {
+	font-size: 75%;
+	color: #000080;
+	font-weight: normal;
+	background-color: #e8eef2;
+}
+*/
+
+td.tiny {
+	font-size: 75%;
+}
+
+.dirtab {
+	padding: 4px;
+	border-collapse: collapse;
+	border: 1px solid #A3B4D7;
+}
+
+th.dirtab {
+	background: #EBEFF6;
+	font-weight: bold;
+}
+
+hr {
+	height: 0px;
+	border: none;
+	border-top: 1px solid #4A6AAA;
+}
+
+hr.footer {
+	height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+	border-spacing: 0px;
+	padding: 0px;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+	background-color: #F9FAFC;
+	border: none;
+	margin: 4px;
+	padding: 1px 0 0 8px;
+}
+
+.mdescLeft, .mdescRight {
+	padding: 0px 8px 4px 8px;
+	color: #555;
+}
+
+.memItemLeft, .memItemRight, .memTemplParams {
+	border-top: 1px solid #C4CFE5;
+}
+
+.memItemLeft, .memTemplItemLeft {
+        white-space: nowrap;
+}
+
+.memItemRight {
+	width: 100%;
+}
+
+.memTemplParams {
+	color: #4665A2;
+        white-space: nowrap;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtemplate {
+	font-size: 80%;
+	color: #4665A2;
+	font-weight: normal;
+	margin-left: 9px;
+}
+
+.memnav {
+	background-color: #EBEFF6;
+	border: 1px solid #A3B4D7;
+	text-align: center;
+	margin: 2px;
+	margin-right: 15px;
+	padding: 2px;
+}
+
+.mempage {
+	width: 100%;
+}
+
+.memitem {
+	padding: 0;
+	margin-bottom: 10px;
+	margin-right: 5px;
+}
+
+.memname {
+        white-space: nowrap;
+        font-weight: bold;
+        margin-left: 6px;
+}
+
+.memproto {
+        border-top: 1px solid #A8B8D9;
+        border-left: 1px solid #A8B8D9;
+        border-right: 1px solid #A8B8D9;
+        padding: 6px 0px 6px 0px;
+        color: #253555;
+        font-weight: bold;
+        text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+        /* opera specific markup */
+        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+        border-top-right-radius: 8px;
+        border-top-left-radius: 8px;
+        /* firefox specific markup */
+        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+        -moz-border-radius-topright: 8px;
+        -moz-border-radius-topleft: 8px;
+        /* webkit specific markup */
+        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+        -webkit-border-top-right-radius: 8px;
+        -webkit-border-top-left-radius: 8px;
+        background-image:url('nav_f.png');
+        background-repeat:repeat-x;
+        background-color: #E2E8F2;
+
+}
+
+.memdoc {
+        border-bottom: 1px solid #A8B8D9;      
+        border-left: 1px solid #A8B8D9;      
+        border-right: 1px solid #A8B8D9; 
+        padding: 2px 5px;
+        background-color: #FBFCFD;
+        border-top-width: 0;
+        /* opera specific markup */
+        border-bottom-left-radius: 8px;
+        border-bottom-right-radius: 8px;
+        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+        /* firefox specific markup */
+        -moz-border-radius-bottomleft: 8px;
+        -moz-border-radius-bottomright: 8px;
+        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+        background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7);
+        /* webkit specific markup */
+        -webkit-border-bottom-left-radius: 8px;
+        -webkit-border-bottom-right-radius: 8px;
+        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+        background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7));
+}
+
+.paramkey {
+	text-align: right;
+}
+
+.paramtype {
+	white-space: nowrap;
+}
+
+.paramname {
+	color: #602020;
+	white-space: nowrap;
+}
+.paramname em {
+	font-style: normal;
+}
+
+.params, .retval, .exception, .tparams {
+        border-spacing: 6px 2px;
+}       
+
+.params .paramname, .retval .paramname {
+        font-weight: bold;
+        vertical-align: top;
+}
+        
+.params .paramtype {
+        font-style: italic;
+        vertical-align: top;
+}       
+        
+.params .paramdir {
+        font-family: "courier new",courier,monospace;
+        vertical-align: top;
+}
+
+
+
+
+/* @end */
+
+/* @group Directory (tree) */
+
+/* for the tree view */
+
+.ftvtree {
+	font-family: sans-serif;
+	margin: 0px;
+}
+
+/* these are for tree view when used as main index */
+
+.directory {
+	font-size: 9pt;
+	font-weight: bold;
+	margin: 5px;
+}
+
+.directory h3 {
+	margin: 0px;
+	margin-top: 1em;
+	font-size: 11pt;
+}
+
+/*
+The following two styles can be used to replace the root node title
+with an image of your choice.  Simply uncomment the next two styles,
+specify the name of your image and be sure to set 'height' to the
+proper pixel height of your image.
+*/
+
+/*
+.directory h3.swap {
+	height: 61px;
+	background-repeat: no-repeat;
+	background-image: url("yourimage.gif");
+}
+.directory h3.swap span {
+	display: none;
+}
+*/
+
+.directory > h3 {
+	margin-top: 0;
+}
+
+.directory p {
+	margin: 0px;
+	white-space: nowrap;
+}
+
+.directory div {
+	display: none;
+	margin: 0px;
+}
+
+.directory img {
+	vertical-align: -30%;
+}
+
+/* these are for tree view when not used as main index */
+
+.directory-alt {
+	font-size: 100%;
+	font-weight: bold;
+}
+
+.directory-alt h3 {
+	margin: 0px;
+	margin-top: 1em;
+	font-size: 11pt;
+}
+
+.directory-alt > h3 {
+	margin-top: 0;
+}
+
+.directory-alt p {
+	margin: 0px;
+	white-space: nowrap;
+}
+
+.directory-alt div {
+	display: none;
+	margin: 0px;
+}
+
+.directory-alt img {
+	vertical-align: -30%;
+}
+
+/* @end */
+
+div.dynheader {
+        margin-top: 8px;
+}
+
+address {
+	font-style: normal;
+	color: #2A3D61;
+}
+
+table.doxtable {
+	border-collapse:collapse;
+}
+
+table.doxtable td, table.doxtable th {
+	border: 1px solid #2D4068;
+	padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+	background-color: #374F7F;
+	color: #FFFFFF;
+	font-size: 110%;
+	padding-bottom: 4px;
+	padding-top: 5px;
+	text-align:left;
+}
+
+.tabsearch {
+	top: 0px;
+	left: 10px;
+	height: 36px;
+	background-image: url('tab_b.png');
+	z-index: 101;
+	overflow: hidden;
+	font-size: 13px;
+}
+
+.navpath ul
+{
+	font-size: 11px;
+	background-image:url('tab_b.png');
+	background-repeat:repeat-x;
+	height:30px;
+	line-height:30px;
+	color:#8AA0CC;
+	border:solid 1px #C2CDE4;
+	overflow:hidden;
+	margin:0px;
+	padding:0px;
+}
+
+.navpath li
+{
+	list-style-type:none;
+	float:left;
+	padding-left:10px;
+	padding-right:15px;
+	background-image:url('bc_s.png');
+	background-repeat:no-repeat;
+	background-position:right;
+	color:#364D7C;
+}
+
+.navpath li.navelem a
+{
+	height:32px;
+	display:block;
+	text-decoration: none;
+	outline: none;
+}
+
+.navpath li.navelem a:hover
+{
+	color:#6884BD;
+}
+
+.navpath li.footer
+{
+        list-style-type:none;
+        float:right;
+        padding-left:10px;
+        padding-right:15px;
+        background-image:none;
+        background-repeat:no-repeat;
+        background-position:right;
+        color:#364D7C;
+        font-size: 8pt;
+}
+
+
+div.summary
+{
+	float: right;
+	font-size: 8pt;
+	padding-right: 5px;
+	width: 50%;
+	text-align: right;
+}       
+
+div.summary a
+{
+	white-space: nowrap;
+}
+
+div.ingroups
+{
+	font-size: 8pt;
+	padding-left: 5px;
+	width: 50%;
+	text-align: left;
+}
+
+div.ingroups a
+{
+	white-space: nowrap;
+}
+
+div.header
+{
+        background-image:url('nav_h.png');
+        background-repeat:repeat-x;
+	background-color: #F9FAFC;
+	margin:  0px;
+	border-bottom: 1px solid #C4CFE5;
+}
+
+div.headertitle
+{
+	padding: 5px 5px 5px 10px;
+}
+
+dl
+{
+        padding: 0 0 0 10px;
+}
+
+dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug
+{
+        border-left:4px solid;
+        padding: 0 0 0 6px;
+}
+
+dl.note
+{
+        border-color: #D0C000;
+}
+
+dl.warning, dl.attention
+{
+        border-color: #FF0000;
+}
+
+dl.pre, dl.post, dl.invariant
+{
+        border-color: #00D000;
+}
+
+dl.deprecated
+{
+        border-color: #505050;
+}
+
+dl.todo
+{
+        border-color: #00C0E0;
+}
+
+dl.test
+{
+        border-color: #3030E0;
+}
+
+dl.bug
+{
+        border-color: #C08050;
+}
+
+#projectlogo
+{
+	text-align: center;
+	vertical-align: bottom;
+	border-collapse: separate;
+}
+ 
+#projectlogo img
+{ 
+	border: 0px none;
+}
+ 
+#projectname
+{
+	font: 300% Tahoma, Arial,sans-serif;
+	margin: 0px;
+	padding: 2px 0px;
+}
+    
+#projectbrief
+{
+	font: 120% Tahoma, Arial,sans-serif;
+	margin: 0px;
+	padding: 0px;
+}
+
+#projectnumber
+{
+	font: 50% Tahoma, Arial,sans-serif;
+	margin: 0px;
+	padding: 0px;
+}
+
+#titlearea
+{
+	padding: 0px;
+	margin: 0px;
+	width: 100%;
+	border-bottom: 1px solid #5373B4;
+}
+
+.image
+{
+        text-align: center;
+}
+
+.dotgraph
+{
+        text-align: center;
+}
+
+.mscgraph
+{
+        text-align: center;
+}
+
+.caption
+{
+	font-weight: bold;
+}
+
diff --git a/doc/html/doxygen.png b/doc/html/doxygen.png
new file mode 100644
index 0000000..635ed52
--- /dev/null
+++ b/doc/html/doxygen.png
Binary files differ
diff --git a/doc/html/functions.html b/doc/html/functions.html
new file mode 100644
index 0000000..3e04f69
--- /dev/null
+++ b/doc/html/functions.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: Data Fields</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li><a href="modules.html"><span>Modules</span></a></li>
+      <li class="current"><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+  <div id="navrow2" class="tabs2">
+    <ul class="tablist">
+      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li><a href="classes.html"><span>Data&#160;Structure&#160;Index</span></a></li>
+      <li class="current"><a href="functions.html"><span>Data&#160;Fields</span></a></li>
+    </ul>
+  </div>
+  <div id="navrow3" class="tabs2">
+    <ul class="tablist">
+      <li class="current"><a href="functions.html"><span>All</span></a></li>
+      <li><a href="functions_vars.html"><span>Variables</span></a></li>
+    </ul>
+  </div>
+</div>
+<div class="contents">
+<div class="textblock">Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:</div><ul>
+<li>denom
+: <a class="el" href="structtjscalingfactor.html#aefbcdf3e9e62274b2d312c695f133ce3">tjscalingfactor</a>
+</li>
+<li>h
+: <a class="el" href="structtjregion.html#aecefc45a26f4d8b60dd4d825c1710115">tjregion</a>
+</li>
+<li>num
+: <a class="el" href="structtjscalingfactor.html#a9b011e57f981ee23083e2c1aa5e640ec">tjscalingfactor</a>
+</li>
+<li>op
+: <a class="el" href="structtjtransform.html#a2525aab4ba6978a1c273f74fef50e498">tjtransform</a>
+</li>
+<li>options
+: <a class="el" href="structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6">tjtransform</a>
+</li>
+<li>r
+: <a class="el" href="structtjtransform.html#ac324e5e442abec8a961e5bf219db12cf">tjtransform</a>
+</li>
+<li>w
+: <a class="el" href="structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42">tjregion</a>
+</li>
+<li>x
+: <a class="el" href="structtjregion.html#a4b6a37a93997091b26a75831fa291ad9">tjregion</a>
+</li>
+<li>y
+: <a class="el" href="structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2">tjregion</a>
+</li>
+</ul>
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/functions_vars.html b/doc/html/functions_vars.html
new file mode 100644
index 0000000..3d53433
--- /dev/null
+++ b/doc/html/functions_vars.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: Data Fields - Variables</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li><a href="modules.html"><span>Modules</span></a></li>
+      <li class="current"><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+  <div id="navrow2" class="tabs2">
+    <ul class="tablist">
+      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li><a href="classes.html"><span>Data&#160;Structure&#160;Index</span></a></li>
+      <li class="current"><a href="functions.html"><span>Data&#160;Fields</span></a></li>
+    </ul>
+  </div>
+  <div id="navrow3" class="tabs2">
+    <ul class="tablist">
+      <li><a href="functions.html"><span>All</span></a></li>
+      <li class="current"><a href="functions_vars.html"><span>Variables</span></a></li>
+    </ul>
+  </div>
+</div>
+<div class="contents">
+&#160;<ul>
+<li>denom
+: <a class="el" href="structtjscalingfactor.html#aefbcdf3e9e62274b2d312c695f133ce3">tjscalingfactor</a>
+</li>
+<li>h
+: <a class="el" href="structtjregion.html#aecefc45a26f4d8b60dd4d825c1710115">tjregion</a>
+</li>
+<li>num
+: <a class="el" href="structtjscalingfactor.html#a9b011e57f981ee23083e2c1aa5e640ec">tjscalingfactor</a>
+</li>
+<li>op
+: <a class="el" href="structtjtransform.html#a2525aab4ba6978a1c273f74fef50e498">tjtransform</a>
+</li>
+<li>options
+: <a class="el" href="structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6">tjtransform</a>
+</li>
+<li>r
+: <a class="el" href="structtjtransform.html#ac324e5e442abec8a961e5bf219db12cf">tjtransform</a>
+</li>
+<li>w
+: <a class="el" href="structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42">tjregion</a>
+</li>
+<li>x
+: <a class="el" href="structtjregion.html#a4b6a37a93997091b26a75831fa291ad9">tjregion</a>
+</li>
+<li>y
+: <a class="el" href="structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2">tjregion</a>
+</li>
+</ul>
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/group___turbo_j_p_e_g.html b/doc/html/group___turbo_j_p_e_g.html
new file mode 100644
index 0000000..43c14c3
--- /dev/null
+++ b/doc/html/group___turbo_j_p_e_g.html
@@ -0,0 +1,1348 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: TurboJPEG</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li><a href="modules.html"><span>Modules</span></a></li>
+      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+</div>
+<div class="header">
+  <div class="summary">
+<a href="#nested-classes">Data Structures</a> &#124;
+<a href="#define-members">Defines</a> &#124;
+<a href="#typedef-members">Typedefs</a> &#124;
+<a href="#enum-members">Enumerations</a> &#124;
+<a href="#func-members">Functions</a> &#124;
+<a href="#var-members">Variables</a>  </div>
+  <div class="headertitle">
+<div class="title">TurboJPEG</div>  </div>
+</div>
+<div class="contents">
+
+<p>TurboJPEG API.  
+<a href="#details">More...</a></p>
+<table class="memberdecls">
+<tr><td colspan="2"><h2><a name="nested-classes"></a>
+Data Structures</h2></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">struct &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjscalingfactor.html">tjscalingfactor</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Scaling factor.  <a href="structtjscalingfactor.html#details">More...</a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">struct &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjregion.html">tjregion</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Cropping region.  <a href="structtjregion.html#details">More...</a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">struct &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html">tjtransform</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Lossless transform.  <a href="structtjtransform.html#details">More...</a><br/></td></tr>
+<tr><td colspan="2"><h2><a name="define-members"></a>
+Defines</h2></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ga5ef3d169162ce77ce348e292a0b7477c"></a><!-- doxytag: member="TurboJPEG::TJ_NUMSAMP" ref="ga5ef3d169162ce77ce348e292a0b7477c" args="" -->
+#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga5ef3d169162ce77ce348e292a0b7477c">TJ_NUMSAMP</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The number of chrominance subsampling options. <br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ga7010a4402f54a45ba822ad8675a4655e"></a><!-- doxytag: member="TurboJPEG::TJ_NUMPF" ref="ga7010a4402f54a45ba822ad8675a4655e" args="" -->
+#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga7010a4402f54a45ba822ad8675a4655e">TJ_NUMPF</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The number of pixel formats. <br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga109343795e7845e921a490a834809d64">TJ_BOTTOMUP</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Bottom-up flag.  <a href="#ga109343795e7845e921a490a834809d64"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga5592507320e240386d9ae06bf34a522a">TJ_FORCEMMX</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Force MMX flag.  <a href="#ga5592507320e240386d9ae06bf34a522a"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga7a71fec0a95f179db6ba478aa3f4258b">TJ_FORCESSE</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Force SSE flag.  <a href="#ga7a71fec0a95f179db6ba478aa3f4258b"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa1f9581ec7c9bbaaa927b058843b859c">TJ_FORCESSE2</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Force SSE2 flag.  <a href="#gaa1f9581ec7c9bbaaa927b058843b859c"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gad26795eaa44f3829b84ac738c0e3254d">TJ_FORCESSE3</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Force SSE3 flag.  <a href="#gad26795eaa44f3829b84ac738c0e3254d"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaac2d4b966a497ad5db3cc8ba88e739b5">TJ_FASTUPSAMPLE</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Fast upsampling flag.  <a href="#gaac2d4b966a497ad5db3cc8ba88e739b5"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga928d11244f17d473b507be12655c0d81">TJ_NOREALLOC</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">No reallocation flag.  <a href="#ga928d11244f17d473b507be12655c0d81"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ga9c18c2d64582faf6d690e371be4dfac4"></a><!-- doxytag: member="TurboJPEG::NUMXFORMOPT" ref="ga9c18c2d64582faf6d690e371be4dfac4" args="" -->
+#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga9c18c2d64582faf6d690e371be4dfac4">NUMXFORMOPT</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Number of transform operations. <br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gacf0de2c44b5e8c1b82147279443b87f5">TJXFORM_PERFECT</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will cause <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform</a> to return an error if the transform is not perfect.  <a href="#gacf0de2c44b5e8c1b82147279443b87f5"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ga94541868bc454c1af315a586d9c8e86c"></a><!-- doxytag: member="TurboJPEG::TJXFORM_TRIM" ref="ga94541868bc454c1af315a586d9c8e86c" args="" -->
+#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga94541868bc454c1af315a586d9c8e86c">TJXFORM_TRIM</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will cause <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform</a> to discard any partial MCU blocks that cannot be transformed. <br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga3c57cabb332f276103ab2d142bf3138f">TJXFORM_CROP</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will enable lossless cropping.  <a href="#ga3c57cabb332f276103ab2d142bf3138f"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gabc33fd8dc6c0b1512d071555796e9d59">TJXFORM_GRAY</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will discard the color data in the input image and produce a grayscale output image.  <a href="#gabc33fd8dc6c0b1512d071555796e9d59"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ga0aba955473315e405295d978f0c16511"></a><!-- doxytag: member="TurboJPEG::TJPAD" ref="ga0aba955473315e405295d978f0c16511" args="(width)" -->
+#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511">TJPAD</a>(width)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Pad the given width to the nearest 32-bit boundary. <br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df">TJSCALED</a>(dimension, scalingFactor)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Compute the scaled value of dimension using the given scaling factor.  <a href="#ga84878bb65404204743aa18cac02781df"></a><br/></td></tr>
+<tr><td colspan="2"><h2><a name="typedef-members"></a>
+Typedefs</h2></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ga758d2634ecb4949de7815cba621f5763"></a><!-- doxytag: member="TurboJPEG::tjhandle" ref="ga758d2634ecb4949de7815cba621f5763" args="" -->
+typedef void *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">TurboJPEG instance handle. <br/></td></tr>
+<tr><td colspan="2"><h2><a name="enum-members"></a>
+Enumerations</h2></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom">{ <br/>
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#gga06fc87d81c62e9abb8790b6e5713c55ba599596595046eaf11990aa00951035cc">TJ_444</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga06fc87d81c62e9abb8790b6e5713c55bacaba016bd306c7b3d8ae97e5aef30807">TJ_422</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga06fc87d81c62e9abb8790b6e5713c55bae879a3c3c53178e19b14e2e5ef54e9b7">TJ_420</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga06fc87d81c62e9abb8790b6e5713c55ba0437a6ea7c98bfe8d2950bba0c7bee6e">TJ_GRAYSCALE</a>, 
+<br/>
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#gga06fc87d81c62e9abb8790b6e5713c55ba443c25f3448fa61584c9b8c32c3f0951">TJ_440</a>
+<br/>
+ }</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Chrominance subsampling options.  <a href="group___turbo_j_p_e_g.html#ga06fc87d81c62e9abb8790b6e5713c55b">More...</a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom">{ <br/>
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#ggadf764cbdea00d65edcd07bb9953ad2b7a74af394f6c7769ac9401a10d1d9be53c">TJ_RGB</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggadf764cbdea00d65edcd07bb9953ad2b7a74132a675a886956727f9a2a916b54b0">TJ_BGR</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggadf764cbdea00d65edcd07bb9953ad2b7aee389b6e87ef5b13cf03f86b88286f97">TJ_RGBX</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggadf764cbdea00d65edcd07bb9953ad2b7a67c69a5a0c0e99b17b1f409c8193dc61">TJ_BGRX</a>, 
+<br/>
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#ggadf764cbdea00d65edcd07bb9953ad2b7a4e6bcc27376f00171bb6803d1fbeaac2">TJ_XBGR</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggadf764cbdea00d65edcd07bb9953ad2b7ad92888632971887d4ed62e04a2d2256d">TJ_XRGB</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggadf764cbdea00d65edcd07bb9953ad2b7aeee1a57b7d6670a8c92482d673afe9df">TJ_GRAY</a>
+<br/>
+ }</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Pixel formats.  <a href="group___turbo_j_p_e_g.html#gadf764cbdea00d65edcd07bb9953ad2b7">More...</a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom">{ <br/>
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#gga99fb83031ce9923c84392b4e92f956b5a23735f831ff620902a6b2ebf57450e58">TJXFORM_NONE</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga99fb83031ce9923c84392b4e92f956b5ab70bca72789cb695d5c99ffc06152d45">TJXFORM_HFLIP</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga99fb83031ce9923c84392b4e92f956b5a54561bd932092708eddcac697092e766">TJXFORM_VFLIP</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga99fb83031ce9923c84392b4e92f956b5ac2ea856cee65b962b49824075119fa4c">TJXFORM_TRANSPOSE</a>, 
+<br/>
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#gga99fb83031ce9923c84392b4e92f956b5a26b8e50a16084c032a2249646b2badc8">TJXFORM_TRANSVERSE</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga99fb83031ce9923c84392b4e92f956b5a820a77baba633ed44e86aae1ba0af7ca">TJXFORM_ROT90</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga99fb83031ce9923c84392b4e92f956b5a72830c4f667d5453cb52ce2d323ce280">TJXFORM_ROT180</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga99fb83031ce9923c84392b4e92f956b5a41481b0bd887df6403e0f69c06115e18">TJXFORM_ROT270</a>
+<br/>
+ }</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Transform operations for <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform</a>.  <a href="group___turbo_j_p_e_g.html#ga99fb83031ce9923c84392b4e92f956b5">More...</a><br/></td></tr>
+<tr><td colspan="2"><h2><a name="func-members"></a>
+Functions</h2></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga3d10c47fbe4a2489a2b30c931551d01a">tjInitCompress</a> (void)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a TurboJPEG compressor instance.  <a href="#ga3d10c47fbe4a2489a2b30c931551d01a"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2">tjCompress2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress an RGB or grayscale image into a JPEG image.  <a href="#gaba62b7a98f960839b588579898495cf2"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned long DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga68f4761dc5213cb9653a2f6ce236716e">TJBUFSIZE</a> (int width, int height)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.  <a href="#ga68f4761dc5213cb9653a2f6ce236716e"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned long DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga8e624b291053bf850b7409af9b2d7ac8">TJBUFSIZEYUV</a> (int width, int height, int jpegSubsamp)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters.  <a href="#ga8e624b291053bf850b7409af9b2d7ac8"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0fa4e7b1943687c6a0c0304529c55d35">tjEncodeYUV2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf, int subsamp, int flags)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Encode an RGB or grayscale image into a YUV planar image.  <a href="#ga0fa4e7b1943687c6a0c0304529c55d35"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gae5408179d041e2a2f7199c8283cf649e">tjInitDecompress</a> (void)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a TurboJPEG decompressor instance.  <a href="#gae5408179d041e2a2f7199c8283cf649e"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gac5675fceb7997b385516cdffdb34e6aa">tjDecompressHeader2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, int *jpegSubsamp)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Retrieve information about a JPEG image without decompressing it.  <a href="#gac5675fceb7997b385516cdffdb34e6aa"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a> *DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga6449044b9af402999ccf52f401333be8">tjGetScalingFactors</a> (int *numscalingfactors)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns a list of fractional scaling factors that the JPEG decompressor in this implementation of TurboJPEG supports.  <a href="#ga6449044b9af402999ccf52f401333be8"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gada69cc6443d1bb493b40f1626259e5e9">tjDecompress2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat, int flags)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image to an RGB or grayscale image.  <a href="#gada69cc6443d1bb493b40f1626259e5e9"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gad7810af095624a4016e72957a50f77d8">tjDecompressToYUV</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, int flags)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image to a YUV planar image.  <a href="#gad7810af095624a4016e72957a50f77d8"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga3155b775bfbac9dbba869b95a0367902">tjInitTransform</a> (void)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a new TurboJPEG transformer instance.  <a href="#ga3155b775bfbac9dbba869b95a0367902"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616">tjTransform</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *jpegBuf, unsigned long jpegSize, int n, unsigned char **dstBufs, unsigned long *dstSizes, <a class="el" href="structtjtransform.html">tjtransform</a> *transforms, int flags)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Losslessly transform a JPEG image into another JPEG image.  <a href="#gae403193ceb4aafb7e0f56ab587b48616"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga674adee917b95ad4a896f1ba39e12540">tjDestroy</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Destroy a TurboJPEG compressor, decompressor, or transformer instance.  <a href="#ga674adee917b95ad4a896f1ba39e12540"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">DLLEXPORT char *DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf">tjGetErrorStr</a> (void)</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns a descriptive error message explaining why the last command failed.  <a href="#ga9af79c908ec131b1ae8d52fe40375abf"></a><br/></td></tr>
+<tr><td colspan="2"><h2><a name="var-members"></a>
+Variables</h2></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c">tjMCUWidth</a> [TJ_NUMSAMP]</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">MCU block width (in pixels) for a given level of chrominance subsampling.  <a href="#ga9e61e7cd47a15a173283ba94e781308c"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf">tjMCUHeight</a> [TJ_NUMSAMP]</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">MCU block height (in pixels) for a given level of chrominance subsampling.  <a href="#gabd247bb9fecb393eca57366feb8327bf"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gadd9b446742ac8a3923f7992c7988fea8">tjRedOffset</a> [TJ_NUMPF]</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Red offset (in bytes) for a given pixel format.  <a href="#gadd9b446742ac8a3923f7992c7988fea8"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga82d6e35da441112a411da41923c0ba2f">tjGreenOffset</a> [TJ_NUMPF]</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Green offset (in bytes) for a given pixel format.  <a href="#ga82d6e35da441112a411da41923c0ba2f"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea">tjBlueOffset</a> [TJ_NUMPF]</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Blue offset (in bytes) for a given pixel format.  <a href="#ga84e2e35d3f08025f976ec1ec53693dea"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="gad77cf8fe5b2bfd3cb3f53098146abb4c"></a><!-- doxytag: member="TurboJPEG::tjPixelSize" ref="gad77cf8fe5b2bfd3cb3f53098146abb4c" args="[TJ_NUMPF]" -->
+static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c">tjPixelSize</a> [TJ_NUMPF]</td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Pixel size (in bytes) for a given pixel format. <br/></td></tr>
+</table>
+<hr/><a name="details" id="details"></a><h2>Detailed Description</h2>
+<p>TurboJPEG API. </p>
+<p>This API provides an interface for generating, decoding, and transforming planar YUV and JPEG images in memory. </p>
+<hr/><h2>Define Documentation</h2>
+<a class="anchor" id="ga109343795e7845e921a490a834809d64"></a><!-- doxytag: member="turbojpeg.h::TJ_BOTTOMUP" ref="ga109343795e7845e921a490a834809d64" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJ_BOTTOMUP</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Bottom-up flag. </p>
+<p><a class="anchor" id="flags"></a> The uncompressed source/destination image is stored in bottom-up (Windows, OpenGL) order, not top-down (X11) order. </p>
+
+</div>
+</div>
+<a class="anchor" id="gaac2d4b966a497ad5db3cc8ba88e739b5"></a><!-- doxytag: member="turbojpeg.h::TJ_FASTUPSAMPLE" ref="gaac2d4b966a497ad5db3cc8ba88e739b5" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJ_FASTUPSAMPLE</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Fast upsampling flag. </p>
+<p>Use fast, inaccurate chrominance upsampling routines in the JPEG decompressor (libjpeg and libjpeg-turbo versions only) </p>
+
+</div>
+</div>
+<a class="anchor" id="ga5592507320e240386d9ae06bf34a522a"></a><!-- doxytag: member="turbojpeg.h::TJ_FORCEMMX" ref="ga5592507320e240386d9ae06bf34a522a" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJ_FORCEMMX</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Force MMX flag. </p>
+<p>Turn off CPU auto-detection and force TurboJPEG to use MMX code (IPP and 32-bit libjpeg-turbo versions only.) </p>
+
+</div>
+</div>
+<a class="anchor" id="ga7a71fec0a95f179db6ba478aa3f4258b"></a><!-- doxytag: member="turbojpeg.h::TJ_FORCESSE" ref="ga7a71fec0a95f179db6ba478aa3f4258b" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJ_FORCESSE</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Force SSE flag. </p>
+<p>Turn off CPU auto-detection and force TurboJPEG to use SSE code (32-bit IPP and 32-bit libjpeg-turbo versions only) </p>
+
+</div>
+</div>
+<a class="anchor" id="gaa1f9581ec7c9bbaaa927b058843b859c"></a><!-- doxytag: member="turbojpeg.h::TJ_FORCESSE2" ref="gaa1f9581ec7c9bbaaa927b058843b859c" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJ_FORCESSE2</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Force SSE2 flag. </p>
+<p>Turn off CPU auto-detection and force TurboJPEG to use SSE2 code (32-bit IPP and 32-bit libjpeg-turbo versions only) </p>
+
+</div>
+</div>
+<a class="anchor" id="gad26795eaa44f3829b84ac738c0e3254d"></a><!-- doxytag: member="turbojpeg.h::TJ_FORCESSE3" ref="gad26795eaa44f3829b84ac738c0e3254d" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJ_FORCESSE3</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Force SSE3 flag. </p>
+<p>Turn off CPU auto-detection and force TurboJPEG to use SSE3 code (64-bit IPP version only) </p>
+
+</div>
+</div>
+<a class="anchor" id="ga928d11244f17d473b507be12655c0d81"></a><!-- doxytag: member="turbojpeg.h::TJ_NOREALLOC" ref="ga928d11244f17d473b507be12655c0d81" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJ_NOREALLOC</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>No reallocation flag. </p>
+<p>If passed to <a class="el" href="group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2" title="Compress an RGB or grayscale image into a JPEG image.">tjCompress2()</a> or <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a>, this flag will cause those functions to generate an error if the JPEG image buffer is invalid or too small rather than attempting to allocate or reallocate that buffer. This reproduces the behavior of earlier versions of TurboJPEG. </p>
+
+</div>
+</div>
+<a class="anchor" id="ga84878bb65404204743aa18cac02781df"></a><!-- doxytag: member="turbojpeg.h::TJSCALED" ref="ga84878bb65404204743aa18cac02781df" args="(dimension, scalingFactor)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJSCALED</td>
+          <td>(</td>
+          <td class="paramtype">&#160;</td>
+          <td class="paramname">dimension, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">&#160;</td>
+          <td class="paramname">scalingFactor&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Compute the scaled value of dimension using the given scaling factor. </p>
+<p>This macro performs the integer equivalent of <code>ceil(dimension * scalingFactor)</code>. </p>
+
+</div>
+</div>
+<a class="anchor" id="ga3c57cabb332f276103ab2d142bf3138f"></a><!-- doxytag: member="turbojpeg.h::TJXFORM_CROP" ref="ga3c57cabb332f276103ab2d142bf3138f" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJXFORM_CROP</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>This option will enable lossless cropping. </p>
+<p>See <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform</a> for more information. </p>
+
+</div>
+</div>
+<a class="anchor" id="gabc33fd8dc6c0b1512d071555796e9d59"></a><!-- doxytag: member="turbojpeg.h::TJXFORM_GRAY" ref="gabc33fd8dc6c0b1512d071555796e9d59" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJXFORM_GRAY</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>This option will discard the color data in the input image and produce a grayscale output image. </p>
+<p><a class="anchor" id="xformopt"></a> </p>
+
+</div>
+</div>
+<a class="anchor" id="gacf0de2c44b5e8c1b82147279443b87f5"></a><!-- doxytag: member="turbojpeg.h::TJXFORM_PERFECT" ref="gacf0de2c44b5e8c1b82147279443b87f5" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJXFORM_PERFECT</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>This option will cause <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform</a> to return an error if the transform is not perfect. </p>
+<p>Lossless transforms operate on MCU blocks, whose size depends on the level of chrominance subsampling used (see <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a> and <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>.) If the image's width or height is not evenly divisible by the MCU block size, then there will be partial MCU blocks on the right and/or bottom edges. It is not possible to move these partial MCU blocks to the top or left of the image, so any transform that would require that is "imperfect." If this option is not specified, then any partial MCU blocks that cannot be transformed will be left in place, which will create odd-looking strips on the right or bottom edge of the image. </p>
+
+</div>
+</div>
+<hr/><h2>Enumeration Type Documentation</h2>
+<a class="anchor" id="ga06fc87d81c62e9abb8790b6e5713c55b"></a><!-- doxytag: member="turbojpeg.h::@0" ref="ga06fc87d81c62e9abb8790b6e5713c55b" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">anonymous enum</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Chrominance subsampling options. </p>
+<p><a class="anchor" id="subsamp"></a> When an image is converted from the RGB to the YCbCr colorspace as part of the JPEG compression process, some of the Cb and Cr (chrominance) components can be discarded or averaged together to produce a smaller image with little perceptible loss of image clarity (the human eye is more sensitive to small changes in brightness than small changes in color.) This is called "chrominance subsampling". </p>
+<dl><dt><b>Enumerator: </b></dt><dd><table border="0" cellspacing="2" cellpadding="0">
+<tr><td valign="top"><em><a class="anchor" id="gga06fc87d81c62e9abb8790b6e5713c55ba599596595046eaf11990aa00951035cc"></a><!-- doxytag: member="TJ_444" ref="gga06fc87d81c62e9abb8790b6e5713c55ba599596595046eaf11990aa00951035cc" args="" -->TJ_444</em>&nbsp;</td><td>
+<p>4:4:4 chrominance subsampling (no chrominance subsampling). </p>
+<p>The JPEG or YUV image will contain one chrominance component for every pixel in the source image. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga06fc87d81c62e9abb8790b6e5713c55bacaba016bd306c7b3d8ae97e5aef30807"></a><!-- doxytag: member="TJ_422" ref="gga06fc87d81c62e9abb8790b6e5713c55bacaba016bd306c7b3d8ae97e5aef30807" args="" -->TJ_422</em>&nbsp;</td><td>
+<p>4:2:2 chrominance subsampling. </p>
+<p>The JPEG or YUV image will contain one chrominance component for every 2x1 block of pixels in the source image. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga06fc87d81c62e9abb8790b6e5713c55bae879a3c3c53178e19b14e2e5ef54e9b7"></a><!-- doxytag: member="TJ_420" ref="gga06fc87d81c62e9abb8790b6e5713c55bae879a3c3c53178e19b14e2e5ef54e9b7" args="" -->TJ_420</em>&nbsp;</td><td>
+<p>4:2:0 chrominance subsampling. </p>
+<p>The JPEG or YUV image will contain one chrominance component for every 2x2 block of pixels in the source image. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga06fc87d81c62e9abb8790b6e5713c55ba0437a6ea7c98bfe8d2950bba0c7bee6e"></a><!-- doxytag: member="TJ_GRAYSCALE" ref="gga06fc87d81c62e9abb8790b6e5713c55ba0437a6ea7c98bfe8d2950bba0c7bee6e" args="" -->TJ_GRAYSCALE</em>&nbsp;</td><td>
+<p>Grayscale. </p>
+<p>The JPEG or YUV image will contain no chrominance components. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga06fc87d81c62e9abb8790b6e5713c55ba443c25f3448fa61584c9b8c32c3f0951"></a><!-- doxytag: member="TJ_440" ref="gga06fc87d81c62e9abb8790b6e5713c55ba443c25f3448fa61584c9b8c32c3f0951" args="" -->TJ_440</em>&nbsp;</td><td>
+<p>4:4:0 chrominance subsampling. </p>
+<p>The JPEG or YUV image will contain one chrominance component for every 1x2 block of pixels in the source image. </p>
+</td></tr>
+</table>
+</dd>
+</dl>
+
+</div>
+</div>
+<a class="anchor" id="gadf764cbdea00d65edcd07bb9953ad2b7"></a><!-- doxytag: member="turbojpeg.h::@1" ref="gadf764cbdea00d65edcd07bb9953ad2b7" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">anonymous enum</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Pixel formats. </p>
+<p><a class="anchor" id="pixelformats"></a> </p>
+<dl><dt><b>Enumerator: </b></dt><dd><table border="0" cellspacing="2" cellpadding="0">
+<tr><td valign="top"><em><a class="anchor" id="ggadf764cbdea00d65edcd07bb9953ad2b7a74af394f6c7769ac9401a10d1d9be53c"></a><!-- doxytag: member="TJ_RGB" ref="ggadf764cbdea00d65edcd07bb9953ad2b7a74af394f6c7769ac9401a10d1d9be53c" args="" -->TJ_RGB</em>&nbsp;</td><td>
+<p>RGB pixel format. </p>
+<p>The red, green, and blue components in the image are stored in 3-byte pixels in the order R, G, B from lowest to highest byte address within each pixel. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="ggadf764cbdea00d65edcd07bb9953ad2b7a74132a675a886956727f9a2a916b54b0"></a><!-- doxytag: member="TJ_BGR" ref="ggadf764cbdea00d65edcd07bb9953ad2b7a74132a675a886956727f9a2a916b54b0" args="" -->TJ_BGR</em>&nbsp;</td><td>
+<p>BGR pixel format. </p>
+<p>The red, green, and blue components in the image are stored in 3-byte pixels in the order B, G, R from lowest to highest byte address within each pixel. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="ggadf764cbdea00d65edcd07bb9953ad2b7aee389b6e87ef5b13cf03f86b88286f97"></a><!-- doxytag: member="TJ_RGBX" ref="ggadf764cbdea00d65edcd07bb9953ad2b7aee389b6e87ef5b13cf03f86b88286f97" args="" -->TJ_RGBX</em>&nbsp;</td><td>
+<p>RGBX pixel format. </p>
+<p>The red, green, and blue components in the image are stored in 4-byte pixels in the order R, G, B from lowest to highest byte address within each pixel. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="ggadf764cbdea00d65edcd07bb9953ad2b7a67c69a5a0c0e99b17b1f409c8193dc61"></a><!-- doxytag: member="TJ_BGRX" ref="ggadf764cbdea00d65edcd07bb9953ad2b7a67c69a5a0c0e99b17b1f409c8193dc61" args="" -->TJ_BGRX</em>&nbsp;</td><td>
+<p>BGRX pixel format. </p>
+<p>The red, green, and blue components in the image are stored in 4-byte pixels in the order B, G, R from lowest to highest byte address within each pixel. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="ggadf764cbdea00d65edcd07bb9953ad2b7a4e6bcc27376f00171bb6803d1fbeaac2"></a><!-- doxytag: member="TJ_XBGR" ref="ggadf764cbdea00d65edcd07bb9953ad2b7a4e6bcc27376f00171bb6803d1fbeaac2" args="" -->TJ_XBGR</em>&nbsp;</td><td>
+<p>XBGR pixel format. </p>
+<p>The red, green, and blue components in the image are stored in 4-byte pixels in the order R, G, B from highest to lowest byte address within each pixel. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="ggadf764cbdea00d65edcd07bb9953ad2b7ad92888632971887d4ed62e04a2d2256d"></a><!-- doxytag: member="TJ_XRGB" ref="ggadf764cbdea00d65edcd07bb9953ad2b7ad92888632971887d4ed62e04a2d2256d" args="" -->TJ_XRGB</em>&nbsp;</td><td>
+<p>XRGB pixel format. </p>
+<p>The red, green, and blue components in the image are stored in 4-byte pixels in the order B, G, R from highest to lowest byte address within each pixel. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="ggadf764cbdea00d65edcd07bb9953ad2b7aeee1a57b7d6670a8c92482d673afe9df"></a><!-- doxytag: member="TJ_GRAY" ref="ggadf764cbdea00d65edcd07bb9953ad2b7aeee1a57b7d6670a8c92482d673afe9df" args="" -->TJ_GRAY</em>&nbsp;</td><td>
+<p>Grayscale pixel format. </p>
+<p>Each 1-byte pixel represents a luminance (brightness) level from 0 to 255. </p>
+</td></tr>
+</table>
+</dd>
+</dl>
+
+</div>
+</div>
+<a class="anchor" id="ga99fb83031ce9923c84392b4e92f956b5"></a><!-- doxytag: member="turbojpeg.h::@2" ref="ga99fb83031ce9923c84392b4e92f956b5" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">anonymous enum</td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Transform operations for <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform</a>. </p>
+<p><a class="anchor" id="xformop"></a> </p>
+<dl><dt><b>Enumerator: </b></dt><dd><table border="0" cellspacing="2" cellpadding="0">
+<tr><td valign="top"><em><a class="anchor" id="gga99fb83031ce9923c84392b4e92f956b5a23735f831ff620902a6b2ebf57450e58"></a><!-- doxytag: member="TJXFORM_NONE" ref="gga99fb83031ce9923c84392b4e92f956b5a23735f831ff620902a6b2ebf57450e58" args="" -->TJXFORM_NONE</em>&nbsp;</td><td>
+<p>Do not transform the position of the image pixels. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga99fb83031ce9923c84392b4e92f956b5ab70bca72789cb695d5c99ffc06152d45"></a><!-- doxytag: member="TJXFORM_HFLIP" ref="gga99fb83031ce9923c84392b4e92f956b5ab70bca72789cb695d5c99ffc06152d45" args="" -->TJXFORM_HFLIP</em>&nbsp;</td><td>
+<p>Flip (mirror) image horizontally. </p>
+<p>This transform is imperfect if there are any partial MCU blocks on the right edge (see <a class="el" href="group___turbo_j_p_e_g.html#gacf0de2c44b5e8c1b82147279443b87f5" title="This option will cause tjTransform to return an error if the transform is not perfect.">TJXFORM_PERFECT</a>.) </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga99fb83031ce9923c84392b4e92f956b5a54561bd932092708eddcac697092e766"></a><!-- doxytag: member="TJXFORM_VFLIP" ref="gga99fb83031ce9923c84392b4e92f956b5a54561bd932092708eddcac697092e766" args="" -->TJXFORM_VFLIP</em>&nbsp;</td><td>
+<p>Flip (mirror) image vertically. </p>
+<p>This transform is imperfect if there are any partial MCU blocks on the bottom edge (see <a class="el" href="group___turbo_j_p_e_g.html#gacf0de2c44b5e8c1b82147279443b87f5" title="This option will cause tjTransform to return an error if the transform is not perfect.">TJXFORM_PERFECT</a>.) </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga99fb83031ce9923c84392b4e92f956b5ac2ea856cee65b962b49824075119fa4c"></a><!-- doxytag: member="TJXFORM_TRANSPOSE" ref="gga99fb83031ce9923c84392b4e92f956b5ac2ea856cee65b962b49824075119fa4c" args="" -->TJXFORM_TRANSPOSE</em>&nbsp;</td><td>
+<p>Transpose image (flip/mirror along upper left to lower right axis.) This transform is always perfect. </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga99fb83031ce9923c84392b4e92f956b5a26b8e50a16084c032a2249646b2badc8"></a><!-- doxytag: member="TJXFORM_TRANSVERSE" ref="gga99fb83031ce9923c84392b4e92f956b5a26b8e50a16084c032a2249646b2badc8" args="" -->TJXFORM_TRANSVERSE</em>&nbsp;</td><td>
+<p>Transverse transpose image (flip/mirror along upper right to lower left axis.) This transform is imperfect if there are any partial MCU blocks in the image (see <a class="el" href="group___turbo_j_p_e_g.html#gacf0de2c44b5e8c1b82147279443b87f5" title="This option will cause tjTransform to return an error if the transform is not perfect.">TJXFORM_PERFECT</a>.) </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga99fb83031ce9923c84392b4e92f956b5a820a77baba633ed44e86aae1ba0af7ca"></a><!-- doxytag: member="TJXFORM_ROT90" ref="gga99fb83031ce9923c84392b4e92f956b5a820a77baba633ed44e86aae1ba0af7ca" args="" -->TJXFORM_ROT90</em>&nbsp;</td><td>
+<p>Rotate image clockwise by 90 degrees. </p>
+<p>This transform is imperfect if there are any partial MCU blocks on the bottom edge (see <a class="el" href="group___turbo_j_p_e_g.html#gacf0de2c44b5e8c1b82147279443b87f5" title="This option will cause tjTransform to return an error if the transform is not perfect.">TJXFORM_PERFECT</a>.) </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga99fb83031ce9923c84392b4e92f956b5a72830c4f667d5453cb52ce2d323ce280"></a><!-- doxytag: member="TJXFORM_ROT180" ref="gga99fb83031ce9923c84392b4e92f956b5a72830c4f667d5453cb52ce2d323ce280" args="" -->TJXFORM_ROT180</em>&nbsp;</td><td>
+<p>Rotate image 180 degrees. </p>
+<p>This transform is imperfect if there are any partial MCU blocks in the image (see <a class="el" href="group___turbo_j_p_e_g.html#gacf0de2c44b5e8c1b82147279443b87f5" title="This option will cause tjTransform to return an error if the transform is not perfect.">TJXFORM_PERFECT</a>.) </p>
+</td></tr>
+<tr><td valign="top"><em><a class="anchor" id="gga99fb83031ce9923c84392b4e92f956b5a41481b0bd887df6403e0f69c06115e18"></a><!-- doxytag: member="TJXFORM_ROT270" ref="gga99fb83031ce9923c84392b4e92f956b5a41481b0bd887df6403e0f69c06115e18" args="" -->TJXFORM_ROT270</em>&nbsp;</td><td>
+<p>Rotate image counter-clockwise by 90 degrees. </p>
+<p>This transform is imperfect if there are any partial MCU blocks on the right edge (see <a class="el" href="group___turbo_j_p_e_g.html#gacf0de2c44b5e8c1b82147279443b87f5" title="This option will cause tjTransform to return an error if the transform is not perfect.">TJXFORM_PERFECT</a>.) </p>
+</td></tr>
+</table>
+</dd>
+</dl>
+
+</div>
+</div>
+<hr/><h2>Function Documentation</h2>
+<a class="anchor" id="ga68f4761dc5213cb9653a2f6ce236716e"></a><!-- doxytag: member="turbojpeg.h::TJBUFSIZE" ref="ga68f4761dc5213cb9653a2f6ce236716e" args="(int width, int height)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT unsigned long DLLCALL TJBUFSIZE </td>
+          <td>(</td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters. </p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">width</td><td>width of the image (in pixels) </td></tr>
+    <tr><td class="paramname">height</td><td>height of the image (in pixels)</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>the maximum size of the buffer (in bytes) required to hold the image, or -1 if the arguments are out of bounds. </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="ga8e624b291053bf850b7409af9b2d7ac8"></a><!-- doxytag: member="turbojpeg.h::TJBUFSIZEYUV" ref="ga8e624b291053bf850b7409af9b2d7ac8" args="(int width, int height, int jpegSubsamp)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV </td>
+          <td>(</td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>jpegSubsamp</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters. </p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">width</td><td>width of the image (in pixels) </td></tr>
+    <tr><td class="paramname">height</td><td>height of the image (in pixels) </td></tr>
+    <tr><td class="paramname">jpegSubsamp</td><td>level of chrominance subsampling in the image (see <a class="el" href="group___turbo_j_p_e_g.html#subsamp">Chrominance subsampling options</a>.)</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>the size of the buffer (in bytes) required to hold the image, or -1 if the arguments are out of bounds. </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="gaba62b7a98f960839b588579898495cf2"></a><!-- doxytag: member="turbojpeg.h::tjCompress2" ref="gaba62b7a98f960839b588579898495cf2" args="(tjhandle handle, unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int DLLCALL tjCompress2 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>srcBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pitch</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char **&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned long *&#160;</td>
+          <td class="paramname"><em>jpegSize</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>jpegSubsamp</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>jpegQual</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>flags</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Compress an RGB or grayscale image into a JPEG image. </p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor or transformer instance </td></tr>
+    <tr><td class="paramname">srcBuf</td><td>pointer to an image buffer containing RGB or grayscale pixels to be compressed </td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the source image </td></tr>
+    <tr><td class="paramname">pitch</td><td>bytes per line of the source image. Normally, this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code> if the image is unpadded, or <code><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511" title="Pad the given width to the nearest 32-bit boundary.">TJPAD</a>(width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat])</code> if each line of the image is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps. You can also be clever and use this parameter to skip lines, etc. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>. </td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the source image </td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the source image (see <a class="el" href="group___turbo_j_p_e_g.html#pixelformats">Pixel formats</a>.) </td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>address of a pointer to an image buffer that will receive the JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to accommodate the size of the JPEG image. Thus, you can choose to:<ol type="1">
+<li>pre-allocate the JPEG buffer with an arbitrary size and let TurboJPEG grow the buffer as needed,</li>
+<li>set <code>*jpegBuf</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
+<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga68f4761dc5213cb9653a2f6ce236716e" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters...">TJBUFSIZE()</a>. This should ensure that the buffer never has to be re-allocated (setting the <a class="el" href="group___turbo_j_p_e_g.html#ga928d11244f17d473b507be12655c0d81" title="No reallocation flag.">TJ_NOREALLOC</a> flag guarantees this.)</li>
+</ol>
+If you choose option 1 or 3, <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set the <a class="el" href="group___turbo_j_p_e_g.html#ga928d11244f17d473b507be12655c0d81" title="No reallocation flag.">TJ_NOREALLOC</a> flag, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed. </td></tr>
+    <tr><td class="paramname">jpegSize</td><td>pointer to an unsigned long variable which holds the size of the JPEG image buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) </td></tr>
+    <tr><td class="paramname">jpegSubsamp</td><td>the level of chrominance subsampling to be used when generating the JPEG image (see <a class="el" href="group___turbo_j_p_e_g.html#subsamp">Chrominance subsampling options</a>.) </td></tr>
+    <tr><td class="paramname">jpegQual</td><td>the image quality of the generated JPEG image (1 = worst, 100 = best) </td></tr>
+    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#flags">flags</a>.</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="gada69cc6443d1bb493b40f1626259e5e9"></a><!-- doxytag: member="turbojpeg.h::tjDecompress2" ref="gada69cc6443d1bb493b40f1626259e5e9" args="(tjhandle handle, unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat, int flags)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int DLLCALL tjDecompress2 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned long&#160;</td>
+          <td class="paramname"><em>jpegSize</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>dstBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pitch</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>flags</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Decompress a JPEG image to an RGB or grayscale image. </p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG decompressor or transformer instance </td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a buffer containing the JPEG image to decompress </td></tr>
+    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes) </td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to an image buffer which will receive the decompressed image. This buffer should normally be <code>pitch * scaledHeight</code> bytes in size, where <code>scaledHeight</code> can be determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a> with the JPEG image height and one of the scaling factors returned by <a class="el" href="group___turbo_j_p_e_g.html#ga6449044b9af402999ccf52f401333be8" title="Returns a list of fractional scaling factors that the JPEG decompressor in this implementation of Tur...">tjGetScalingFactors()</a>. The dstBuf pointer may also be used to decompress into a specific region of a larger buffer. </td></tr>
+    <tr><td class="paramname">width</td><td>desired width (in pixels) of the destination image. If this is smaller than the width of the JPEG image being decompressed, then TurboJPEG will use scaling in the JPEG decompressor to generate the largest possible image that will fit within the desired width. If width is set to 0, then only the height will be considered when determining the scaled image size. </td></tr>
+    <tr><td class="paramname">pitch</td><td>bytes per line of the destination image. Normally, this is <code>scaledWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code> if the decompressed image is unpadded, else <code><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511" title="Pad the given width to the nearest 32-bit boundary.">TJPAD</a>(scaledWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat])</code> if each line of the decompressed image is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps. (NOTE: <code>scaledWidth</code> can be determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a> with the JPEG image width and one of the scaling factors returned by <a class="el" href="group___turbo_j_p_e_g.html#ga6449044b9af402999ccf52f401333be8" title="Returns a list of fractional scaling factors that the JPEG decompressor in this implementation of Tur...">tjGetScalingFactors()</a>.) You can also be clever and use the pitch parameter to skip lines, etc. Setting this parameter to 0 is the equivalent of setting it to <code>scaledWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>. </td></tr>
+    <tr><td class="paramname">height</td><td>desired height (in pixels) of the destination image. If this is smaller than the height of the JPEG image being decompressed, then TurboJPEG will use scaling in the JPEG decompressor to generate the largest possible image that will fit within the desired height. If height is set to 0, then only the width will be considered when determining the scaled image size. </td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the destination image (see <a class="el" href="group___turbo_j_p_e_g.html#pixelformats">Pixel formats</a>.) </td></tr>
+    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#flags">flags</a>.</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="gac5675fceb7997b385516cdffdb34e6aa"></a><!-- doxytag: member="turbojpeg.h::tjDecompressHeader2" ref="gac5675fceb7997b385516cdffdb34e6aa" args="(tjhandle handle, unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, int *jpegSubsamp)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int DLLCALL tjDecompressHeader2 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned long&#160;</td>
+          <td class="paramname"><em>jpegSize</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>jpegSubsamp</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Retrieve information about a JPEG image without decompressing it. </p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG decompressor or transformer instance </td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a buffer containing a JPEG image </td></tr>
+    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes) </td></tr>
+    <tr><td class="paramname">width</td><td>pointer to an integer variable which will receive the width (in pixels) of the JPEG image </td></tr>
+    <tr><td class="paramname">height</td><td>pointer to an integer variable which will receive the height (in pixels) of the JPEG image </td></tr>
+    <tr><td class="paramname">jpegSubsamp</td><td>pointer to an integer variable which will receive the level of chrominance subsampling used when compressing the JPEG image (see <a class="el" href="group___turbo_j_p_e_g.html#subsamp">Chrominance subsampling options</a>.)</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="gad7810af095624a4016e72957a50f77d8"></a><!-- doxytag: member="turbojpeg.h::tjDecompressToYUV" ref="gad7810af095624a4016e72957a50f77d8" args="(tjhandle handle, unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, int flags)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int DLLCALL tjDecompressToYUV </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned long&#160;</td>
+          <td class="paramname"><em>jpegSize</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>dstBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>flags</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Decompress a JPEG image to a YUV planar image. </p>
+<p>This function performs JPEG decompression but leaves out the color conversion step, so a planar YUV image is generated instead of an RGB image. The padding of the planes in this image is the same as the images generated by <a class="el" href="group___turbo_j_p_e_g.html#ga0fa4e7b1943687c6a0c0304529c55d35" title="Encode an RGB or grayscale image into a YUV planar image.">tjEncodeYUV2()</a>. Note that, if the width or height of the image is not an even multiple of the MCU block size (see <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a> and <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>), then an intermediate buffer copy will be performed within TurboJPEG.</p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG decompressor or transformer instance </td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a buffer containing the JPEG image to decompress </td></tr>
+    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes) </td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to an image buffer which will receive the YUV image. Use <a class="el" href="group___turbo_j_p_e_g.html#ga8e624b291053bf850b7409af9b2d7ac8" title="The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters...">TJBUFSIZEYUV</a> to determine the appropriate size for this buffer based on the image width, height, and level of subsampling. </td></tr>
+    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#flags">flags</a>.</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="ga674adee917b95ad4a896f1ba39e12540"></a><!-- doxytag: member="turbojpeg.h::tjDestroy" ref="ga674adee917b95ad4a896f1ba39e12540" args="(tjhandle handle)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int DLLCALL tjDestroy </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em></td><td>)</td>
+          <td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Destroy a TurboJPEG compressor, decompressor, or transformer instance. </p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor, decompressor or transformer instance</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="ga0fa4e7b1943687c6a0c0304529c55d35"></a><!-- doxytag: member="turbojpeg.h::tjEncodeYUV2" ref="ga0fa4e7b1943687c6a0c0304529c55d35" args="(tjhandle handle, unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf, int subsamp, int flags)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int DLLCALL tjEncodeYUV2 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>srcBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pitch</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>dstBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>subsamp</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>flags</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Encode an RGB or grayscale image into a YUV planar image. </p>
+<p>This function uses the accelerated color conversion routines in TurboJPEG's underlying codec to produce a planar YUV image that is suitable for X Video. Specifically, if the chrominance components are subsampled along the horizontal dimension, then the width of the luminance plane is padded to 2 in the output image (same goes for the height of the luminance plane, if the chrominance components are subsampled along the vertical dimension.) Also, each line of each plane in the output image is padded to 4 bytes. Although this will work with any subsampling option, it is really only useful in combination with TJ_420, which produces an image compatible with the I420 (AKA "YUV420P") format.</p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor or transformer instance </td></tr>
+    <tr><td class="paramname">srcBuf</td><td>pointer to an image buffer containing RGB or grayscale pixels to be encoded </td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the source image </td></tr>
+    <tr><td class="paramname">pitch</td><td>bytes per line of the source image. Normally, this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code> if the image is unpadded, or <code><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511" title="Pad the given width to the nearest 32-bit boundary.">TJPAD</a>(width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat])</code> if each line of the image is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps. You can also be clever and use this parameter to skip lines, etc. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>. </td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the source image </td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the source image (see <a class="el" href="group___turbo_j_p_e_g.html#pixelformats">Pixel formats</a>.) </td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to an image buffer which will receive the YUV image. Use <a class="el" href="group___turbo_j_p_e_g.html#ga8e624b291053bf850b7409af9b2d7ac8" title="The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters...">TJBUFSIZEYUV()</a> to determine the appropriate size for this buffer based on the image width, height, and level of chrominance subsampling. </td></tr>
+    <tr><td class="paramname">subsamp</td><td>the level of chrominance subsampling to be used when generating the YUV image (see <a class="el" href="group___turbo_j_p_e_g.html#subsamp">Chrominance subsampling options</a>.) </td></tr>
+    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#flags">flags</a>.</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="ga9af79c908ec131b1ae8d52fe40375abf"></a><!-- doxytag: member="turbojpeg.h::tjGetErrorStr" ref="ga9af79c908ec131b1ae8d52fe40375abf" args="(void)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT char* DLLCALL tjGetErrorStr </td>
+          <td>(</td>
+          <td class="paramtype">void&#160;</td>
+          <td class="paramname"></td><td>)</td>
+          <td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Returns a descriptive error message explaining why the last command failed. </p>
+<dl class="return"><dt><b>Returns:</b></dt><dd>a descriptive error message explaining why the last command failed. </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="ga6449044b9af402999ccf52f401333be8"></a><!-- doxytag: member="turbojpeg.h::tjGetScalingFactors" ref="ga6449044b9af402999ccf52f401333be8" args="(int *numscalingfactors)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a>* DLLCALL tjGetScalingFactors </td>
+          <td>(</td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>numscalingfactors</em></td><td>)</td>
+          <td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Returns a list of fractional scaling factors that the JPEG decompressor in this implementation of TurboJPEG supports. </p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">numscalingfactors</td><td>pointer to an integer variable that will receive the number of elements in the list</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>a pointer to a list of fractional scaling factors, or NULL if an error is encountered (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="ga3d10c47fbe4a2489a2b30c931551d01a"></a><!-- doxytag: member="turbojpeg.h::tjInitCompress" ref="ga3d10c47fbe4a2489a2b30c931551d01a" args="(void)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> DLLCALL tjInitCompress </td>
+          <td>(</td>
+          <td class="paramtype">void&#160;</td>
+          <td class="paramname"></td><td>)</td>
+          <td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Create a TurboJPEG compressor instance. </p>
+<dl class="return"><dt><b>Returns:</b></dt><dd>a handle to the newly-created instance, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="gae5408179d041e2a2f7199c8283cf649e"></a><!-- doxytag: member="turbojpeg.h::tjInitDecompress" ref="gae5408179d041e2a2f7199c8283cf649e" args="(void)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> DLLCALL tjInitDecompress </td>
+          <td>(</td>
+          <td class="paramtype">void&#160;</td>
+          <td class="paramname"></td><td>)</td>
+          <td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Create a TurboJPEG decompressor instance. </p>
+<dl class="return"><dt><b>Returns:</b></dt><dd>a handle to the newly-created instance, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="ga3155b775bfbac9dbba869b95a0367902"></a><!-- doxytag: member="turbojpeg.h::tjInitTransform" ref="ga3155b775bfbac9dbba869b95a0367902" args="(void)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> DLLCALL tjInitTransform </td>
+          <td>(</td>
+          <td class="paramtype">void&#160;</td>
+          <td class="paramname"></td><td>)</td>
+          <td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Create a new TurboJPEG transformer instance. </p>
+<dl class="return"><dt><b>Returns:</b></dt><dd>a handle to the newly-created instance, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a class="anchor" id="gae403193ceb4aafb7e0f56ab587b48616"></a><!-- doxytag: member="turbojpeg.h::tjTransform" ref="gae403193ceb4aafb7e0f56ab587b48616" args="(tjhandle handle, unsigned char *jpegBuf, unsigned long jpegSize, int n, unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *transforms, int flags)" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int DLLCALL tjTransform </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned long&#160;</td>
+          <td class="paramname"><em>jpegSize</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>n</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char **&#160;</td>
+          <td class="paramname"><em>dstBufs</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned long *&#160;</td>
+          <td class="paramname"><em>dstSizes</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype"><a class="el" href="structtjtransform.html">tjtransform</a> *&#160;</td>
+          <td class="paramname"><em>transforms</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>flags</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Losslessly transform a JPEG image into another JPEG image. </p>
+<p>Lossless transforms work by moving the raw coefficients from one JPEG image structure to another without altering the values of the coefficients. While this is typically faster than decompressing the image, transforming it, and re-compressing it, lossless transforms are not free. Each lossless transform requires reading and Huffman decoding all of the coefficients in the source image, regardless of the size of the destination image. Thus, this function provides a means of generating multiple transformed images from the same source or of applying multiple transformations simultaneously, in order to eliminate the need to read the source coefficients multiple times.</p>
+<dl><dt><b>Parameters:</b></dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG transformer instance </td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a buffer containing the JPEG image to transform </td></tr>
+    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes) </td></tr>
+    <tr><td class="paramname">n</td><td>the number of transformed JPEG images to generate </td></tr>
+    <tr><td class="paramname">dstBufs</td><td>pointer to an array of n image buffers. <code>dstBufs[i]</code> will receive a JPEG image that has been transformed using the parameters in <code>transforms[i]</code>. TurboJPEG has the ability to reallocate the JPEG buffer to accommodate the size of the JPEG image. Thus, you can choose to:<ol type="1">
+<li>pre-allocate the JPEG buffer with an arbitrary size and let TurboJPEG grow the buffer as needed,</li>
+<li>set <code>dstBufs[i]</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
+<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga68f4761dc5213cb9653a2f6ce236716e" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters...">TJBUFSIZE()</a> with the cropped width and height. This should ensure that the buffer never has to be re-allocated (setting the <a class="el" href="group___turbo_j_p_e_g.html#ga928d11244f17d473b507be12655c0d81" title="No reallocation flag.">TJ_NOREALLOC</a> flag guarantees this.)</li>
+</ol>
+If you choose option 1 or 3, <code>dstSizes[i]</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set the <a class="el" href="group___turbo_j_p_e_g.html#ga928d11244f17d473b507be12655c0d81" title="No reallocation flag.">TJ_NOREALLOC</a> flag, you should always check <code>dstBufs[i]</code> upon return from this function, as it may have changed. </td></tr>
+    <tr><td class="paramname">dstSizes</td><td>pointer to an array of n unsigned long variables which will receive the actual sizes (in bytes) of each transformed JPEG image. If <code>dstBufs[i]</code> points to a pre-allocated buffer, then <code>dstSizes[i]</code> should be set to the size of the buffer. Upon return, <code>dstSizes[i]</code> will contain the size of the JPEG image (in bytes.) </td></tr>
+    <tr><td class="paramname">transforms</td><td>pointer to an array of n tjtransform structures, each of which specifies the transform parameters and/or cropping region for the corresponding transformed output image. </td></tr>
+    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#flags">flags</a>.</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="return"><dt><b>Returns:</b></dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<hr/><h2>Variable Documentation</h2>
+<a class="anchor" id="ga84e2e35d3f08025f976ec1ec53693dea"></a><!-- doxytag: member="turbojpeg.h::tjBlueOffset" ref="ga84e2e35d3f08025f976ec1ec53693dea" args="[TJ_NUMPF]" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">const int <a class="el" href="group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea">tjBlueOffset</a>[TJ_NUMPF]<code> [static]</code></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Blue offset (in bytes) for a given pixel format. </p>
+<p>This specifies the number of bytes that the Blue component is offset from the start of the pixel. For instance, if a pixel of format TJ_BGRX is stored in <code>char pixel[]</code>, then the blue component will be <code>pixel[tjBlueOffset[TJ_BGRX]]</code>. </p>
+
+</div>
+</div>
+<a class="anchor" id="ga82d6e35da441112a411da41923c0ba2f"></a><!-- doxytag: member="turbojpeg.h::tjGreenOffset" ref="ga82d6e35da441112a411da41923c0ba2f" args="[TJ_NUMPF]" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">const int <a class="el" href="group___turbo_j_p_e_g.html#ga82d6e35da441112a411da41923c0ba2f">tjGreenOffset</a>[TJ_NUMPF]<code> [static]</code></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Green offset (in bytes) for a given pixel format. </p>
+<p>This specifies the number of bytes that the green component is offset from the start of the pixel. For instance, if a pixel of format TJ_BGRX is stored in <code>char pixel[]</code>, then the green component will be <code>pixel[tjGreenOffset[TJ_BGRX]]</code>. </p>
+
+</div>
+</div>
+<a class="anchor" id="gabd247bb9fecb393eca57366feb8327bf"></a><!-- doxytag: member="turbojpeg.h::tjMCUHeight" ref="gabd247bb9fecb393eca57366feb8327bf" args="[TJ_NUMSAMP]" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">const int <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf">tjMCUHeight</a>[TJ_NUMSAMP]<code> [static]</code></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>MCU block height (in pixels) for a given level of chrominance subsampling. </p>
+<p>MCU block sizes:</p>
+<ul>
+<li>8x8 for no subsampling or grayscale</li>
+<li>16x8 for 4:2:2</li>
+<li>8x16 for 4:4:0</li>
+<li>16x16 for 4:2:0 </li>
+</ul>
+
+</div>
+</div>
+<a class="anchor" id="ga9e61e7cd47a15a173283ba94e781308c"></a><!-- doxytag: member="turbojpeg.h::tjMCUWidth" ref="ga9e61e7cd47a15a173283ba94e781308c" args="[TJ_NUMSAMP]" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">const int <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c">tjMCUWidth</a>[TJ_NUMSAMP]<code> [static]</code></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>MCU block width (in pixels) for a given level of chrominance subsampling. </p>
+<p>MCU block sizes:</p>
+<ul>
+<li>8x8 for no subsampling or grayscale</li>
+<li>16x8 for 4:2:2</li>
+<li>8x16 for 4:4:0</li>
+<li>16x16 for 4:2:0 </li>
+</ul>
+
+</div>
+</div>
+<a class="anchor" id="gadd9b446742ac8a3923f7992c7988fea8"></a><!-- doxytag: member="turbojpeg.h::tjRedOffset" ref="gadd9b446742ac8a3923f7992c7988fea8" args="[TJ_NUMPF]" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">const int <a class="el" href="group___turbo_j_p_e_g.html#gadd9b446742ac8a3923f7992c7988fea8">tjRedOffset</a>[TJ_NUMPF]<code> [static]</code></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>Red offset (in bytes) for a given pixel format. </p>
+<p>This specifies the number of bytes that the red component is offset from the start of the pixel. For instance, if a pixel of format TJ_BGRX is stored in <code>char pixel[]</code>, then the red component will be <code>pixel[tjRedOffset[TJ_BGRX]]</code>. </p>
+
+</div>
+</div>
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/index.html b/doc/html/index.html
new file mode 100644
index 0000000..99ae4df
--- /dev/null
+++ b/doc/html/index.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: Main Page</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li class="current"><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li><a href="modules.html"><span>Modules</span></a></li>
+      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+</div>
+<div class="header">
+  <div class="headertitle">
+<div class="title">TurboJPEG Documentation</div>  </div>
+</div>
+<div class="contents">
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/installdox b/doc/html/installdox
new file mode 100755
index 0000000..edf5bbf
--- /dev/null
+++ b/doc/html/installdox
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+
+%subst = ( );
+$quiet   = 0;
+
+while ( @ARGV ) {
+  $_ = shift @ARGV;
+  if ( s/^-// ) {
+    if ( /^l(.*)/ ) {
+      $v = ($1 eq "") ? shift @ARGV : $1;
+      ($v =~ /\/$/) || ($v .= "/");
+      $_ = $v;
+      if ( /(.+)\@(.+)/ ) {
+        if ( exists $subst{$1} ) {
+          $subst{$1} = $2;
+        } else {
+          print STDERR "Unknown tag file $1 given with option -l\n";
+          &usage();
+        }
+      } else {
+        print STDERR "Argument $_ is invalid for option -l\n";
+        &usage();
+      }
+    }
+    elsif ( /^q/ ) {
+      $quiet = 1;
+    }
+    elsif ( /^\?|^h/ ) {
+      &usage();
+    }
+    else {
+      print STDERR "Illegal option -$_\n";
+      &usage();
+    }
+  }
+  else {
+    push (@files, $_ );
+  }
+}
+
+foreach $sub (keys %subst)
+{
+  if ( $subst{$sub} eq "" ) 
+  {
+    print STDERR "No substitute given for tag file `$sub'\n";
+    &usage();
+  }
+  elsif ( ! $quiet && $sub ne "_doc" && $sub ne "_cgi" )
+  {
+    print "Substituting $subst{$sub} for each occurrence of tag file $sub\n"; 
+  }
+}
+
+if ( ! @files ) {
+  if (opendir(D,".")) {
+    foreach $file ( readdir(D) ) {
+      $match = ".html";
+      next if ( $file =~ /^\.\.?$/ );
+      ($file =~ /$match/) && (push @files, $file);
+      ($file =~ /\.svg/) && (push @files, $file);
+      ($file =~ "navtree.js") && (push @files, $file);
+    }
+    closedir(D);
+  }
+}
+
+if ( ! @files ) {
+  print STDERR "Warning: No input files given and none found!\n";
+}
+
+foreach $f (@files)
+{
+  if ( ! $quiet ) {
+    print "Editing: $f...\n";
+  }
+  $oldf = $f;
+  $f   .= ".bak";
+  unless (rename $oldf,$f) {
+    print STDERR "Error: cannot rename file $oldf\n";
+    exit 1;
+  }
+  if (open(F,"<$f")) {
+    unless (open(G,">$oldf")) {
+      print STDERR "Error: opening file $oldf for writing\n";
+      exit 1;
+    }
+    if ($oldf ne "tree.js") {
+      while (<F>) {
+        s/doxygen\=\"([^ \"\:\t\>\<]*)\:([^ \"\t\>\<]*)\" (xlink:href|href|src)=\"\2/doxygen\=\"$1:$subst{$1}\" \3=\"$subst{$1}/g;
+        print G "$_";
+      }
+    }
+    else {
+      while (<F>) {
+        s/\"([^ \"\:\t\>\<]*)\:([^ \"\t\>\<]*)\", \"\2/\"$1:$subst{$1}\" ,\"$subst{$1}/g;
+        print G "$_";
+      }
+    }
+  } 
+  else {
+    print STDERR "Warning file $f does not exist\n";
+  }
+  unlink $f;
+}
+
+sub usage {
+  print STDERR "Usage: installdox [options] [html-file [html-file ...]]\n";
+  print STDERR "Options:\n";
+  print STDERR "     -l tagfile\@linkName   tag file + URL or directory \n";
+  print STDERR "     -q                    Quiet mode\n\n";
+  exit 1;
+}
diff --git a/doc/html/jquery.js b/doc/html/jquery.js
new file mode 100644
index 0000000..c052173
--- /dev/null
+++ b/doc/html/jquery.js
@@ -0,0 +1,54 @@
+/*
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){
+var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0)
+{I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function()
+{G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
+/*
+ * jQuery UI 1.7.2
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI
+ */
+jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.2",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m<n.length;m++){if(j.options[n[m][0]]){n[m][1].apply(j.element,k)}}}},contains:function(k,j){return document.compareDocumentPosition?k.compareDocumentPosition(j)&16:k!==j&&k.contains(j)},hasScroll:function(m,k){if(c(m).css("overflow")=="hidden"){return false}var j=(k&&k=="left")?"scrollLeft":"scrollTop",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/* * jQuery UI Resizable 1.7.2
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ *	ui.core.js
+ */
+(function(c){c.widget("ui.resizable",c.extend({},c.ui.mouse,{_init:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f<k.length;f++){var h=c.trim(k[f]),d="ui-resizable-"+h;var g=c('<div class="ui-resizable-handle '+d+'"></div>');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidth<k.width),l=a(k.height)&&h.maxHeight&&(h.maxHeight<k.height),g=a(k.width)&&h.minWidth&&(h.minWidth>k.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e<this._proportionallyResizeElements.length;e++){var g=this._proportionallyResizeElements[e];if(!this.borderDif){var d=[g.css("borderTopWidth"),g.css("borderRightWidth"),g.css("borderBottomWidth"),g.css("borderLeftWidth")],h=[g.css("paddingTop"),g.css("paddingRight"),g.css("paddingBottom"),g.css("paddingLeft")];this.borderDif=c.map(d,function(k,m){var l=parseInt(k,10)||0,n=parseInt(h[m],10)||0;return l+n})}if(c.browser.msie&&!(!(c(f).is(":hidden")||c(f).parents(":hidden").length))){continue}g.css({height:(f.height()-this.borderDif[0]-this.borderDif[2])||0,width:(f.width()-this.borderDif[1]-this.borderDif[3])||0})}},_renderProxy:function(){var e=this.element,h=this.options;this.elementOffset=e.offset();if(this._helper){this.helper=this.helper||c('<div style="overflow:hidden;"></div>');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0))
+{s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;
+/**
+ * jQuery.ScrollTo - Easy element scrolling using jQuery.
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com
+ * Licensed under GPL license (http://www.opensource.org/licenses/gpl-license.php).
+ * Date: 2/8/2008
+ * @author Ariel Flesler
+ * @version 1.3.2
+ */
+;(function($){var o=$.scrollTo=function(a,b,c){o.window().scrollTo(a,b,c)};o.defaults={axis:'y',duration:1};o.window=function(){return $($.browser.safari?'body':'html')};$.fn.scrollTo=function(l,m,n){if(typeof m=='object'){n=m;m=0}n=$.extend({},o.defaults,n);m=m||n.speed||n.duration;n.queue=n.queue&&n.axis.length>1;if(n.queue)m/=2;n.offset=j(n.offset);n.over=j(n.over);return this.each(function(){var a=this,b=$(a),t=l,c,d={},w=b.is('html,body');switch(typeof t){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(t)){t=j(t);break}t=$(t,this);case'object':if(t.is||t.style)c=(t=$(t)).offset()}$.each(n.axis.split(''),function(i,f){var P=f=='x'?'Left':'Top',p=P.toLowerCase(),k='scroll'+P,e=a[k],D=f=='x'?'Width':'Height';if(c){d[k]=c[p]+(w?0:e-b.offset()[p]);if(n.margin){d[k]-=parseInt(t.css('margin'+P))||0;d[k]-=parseInt(t.css('border'+P+'Width'))||0}d[k]+=n.offset[p]||0;if(n.over[p])d[k]+=t[D.toLowerCase()]()*n.over[p]}else d[k]=t[p];if(/^\d+$/.test(d[k]))d[k]=d[k]<=0?0:Math.min(d[k],h(D));if(!i&&n.queue){if(e!=d[k])g(n.onAfterFirst);delete d[k]}});g(n.onAfter);function g(a){b.animate(d,m,n.easing,a&&function(){a.call(this,l)})};function h(D){var b=w?$.browser.opera?document.body:document.documentElement:a;return b['scroll'+D]-b['client'+D]}})};function j(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
+
diff --git a/doc/html/modules.html b/doc/html/modules.html
new file mode 100644
index 0000000..eaf4ba0
--- /dev/null
+++ b/doc/html/modules.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: Modules</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li class="current"><a href="modules.html"><span>Modules</span></a></li>
+      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+</div>
+<div class="header">
+  <div class="headertitle">
+<div class="title">Modules</div>  </div>
+</div>
+<div class="contents">
+<div class="textblock">Here is a list of all modules:</div><ul>
+<li><a class="el" href="group___turbo_j_p_e_g.html">TurboJPEG</a></li>
+</ul>
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/nav_f.png b/doc/html/nav_f.png
new file mode 100644
index 0000000..1b07a16
--- /dev/null
+++ b/doc/html/nav_f.png
Binary files differ
diff --git a/doc/html/nav_h.png b/doc/html/nav_h.png
new file mode 100644
index 0000000..01f5fa6
--- /dev/null
+++ b/doc/html/nav_h.png
Binary files differ
diff --git a/doc/html/open.png b/doc/html/open.png
new file mode 100644
index 0000000..7b35d2c
--- /dev/null
+++ b/doc/html/open.png
Binary files differ
diff --git a/doc/html/search/all_64.html b/doc/html/search/all_64.html
new file mode 100644
index 0000000..5db4361
--- /dev/null
+++ b/doc/html/search/all_64.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_denom">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjscalingfactor.html#aefbcdf3e9e62274b2d312c695f133ce3" target="_parent">denom</a>
+  <span class="SRScope">tjscalingfactor</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/all_68.html b/doc/html/search/all_68.html
new file mode 100644
index 0000000..ccb671d
--- /dev/null
+++ b/doc/html/search/all_68.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_h">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html#aecefc45a26f4d8b60dd4d825c1710115" target="_parent">h</a>
+  <span class="SRScope">tjregion</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/all_6e.html b/doc/html/search/all_6e.html
new file mode 100644
index 0000000..b9f5b05
--- /dev/null
+++ b/doc/html/search/all_6e.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_num">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjscalingfactor.html#a9b011e57f981ee23083e2c1aa5e640ec" target="_parent">num</a>
+  <span class="SRScope">tjscalingfactor</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/all_6f.html b/doc/html/search/all_6f.html
new file mode 100644
index 0000000..d95bbef
--- /dev/null
+++ b/doc/html/search/all_6f.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_op">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjtransform.html#a2525aab4ba6978a1c273f74fef50e498" target="_parent">op</a>
+  <span class="SRScope">tjtransform</span>
+ </div>
+</div>
+<div class="SRResult" id="SR_options">
+ <div class="SREntry">
+  <a id="Item1" onkeydown="return searchResults.Nav(event,1)" onkeypress="return searchResults.Nav(event,1)" onkeyup="return searchResults.Nav(event,1)" class="SRSymbol" href="../structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6" target="_parent">options</a>
+  <span class="SRScope">tjtransform</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/all_72.html b/doc/html/search/all_72.html
new file mode 100644
index 0000000..465fe88
--- /dev/null
+++ b/doc/html/search/all_72.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_r">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjtransform.html#ac324e5e442abec8a961e5bf219db12cf" target="_parent">r</a>
+  <span class="SRScope">tjtransform</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/all_74.html b/doc/html/search/all_74.html
new file mode 100644
index 0000000..fd77663
--- /dev/null
+++ b/doc/html/search/all_74.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_tjregion">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html" target="_parent">tjregion</a>
+ </div>
+</div>
+<div class="SRResult" id="SR_tjscalingfactor">
+ <div class="SREntry">
+  <a id="Item1" onkeydown="return searchResults.Nav(event,1)" onkeypress="return searchResults.Nav(event,1)" onkeyup="return searchResults.Nav(event,1)" class="SRSymbol" href="../structtjscalingfactor.html" target="_parent">tjscalingfactor</a>
+ </div>
+</div>
+<div class="SRResult" id="SR_tjtransform">
+ <div class="SREntry">
+  <a id="Item2" onkeydown="return searchResults.Nav(event,2)" onkeypress="return searchResults.Nav(event,2)" onkeyup="return searchResults.Nav(event,2)" class="SRSymbol" href="../structtjtransform.html" target="_parent">tjtransform</a>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/all_77.html b/doc/html/search/all_77.html
new file mode 100644
index 0000000..b4c8d88
--- /dev/null
+++ b/doc/html/search/all_77.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_w">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42" target="_parent">w</a>
+  <span class="SRScope">tjregion</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/all_78.html b/doc/html/search/all_78.html
new file mode 100644
index 0000000..a357691
--- /dev/null
+++ b/doc/html/search/all_78.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_x">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html#a4b6a37a93997091b26a75831fa291ad9" target="_parent">x</a>
+  <span class="SRScope">tjregion</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/all_79.html b/doc/html/search/all_79.html
new file mode 100644
index 0000000..a883bd1
--- /dev/null
+++ b/doc/html/search/all_79.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_y">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2" target="_parent">y</a>
+  <span class="SRScope">tjregion</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/classes_74.html b/doc/html/search/classes_74.html
new file mode 100644
index 0000000..fd77663
--- /dev/null
+++ b/doc/html/search/classes_74.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_tjregion">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html" target="_parent">tjregion</a>
+ </div>
+</div>
+<div class="SRResult" id="SR_tjscalingfactor">
+ <div class="SREntry">
+  <a id="Item1" onkeydown="return searchResults.Nav(event,1)" onkeypress="return searchResults.Nav(event,1)" onkeyup="return searchResults.Nav(event,1)" class="SRSymbol" href="../structtjscalingfactor.html" target="_parent">tjscalingfactor</a>
+ </div>
+</div>
+<div class="SRResult" id="SR_tjtransform">
+ <div class="SREntry">
+  <a id="Item2" onkeydown="return searchResults.Nav(event,2)" onkeypress="return searchResults.Nav(event,2)" onkeyup="return searchResults.Nav(event,2)" class="SRSymbol" href="../structtjtransform.html" target="_parent">tjtransform</a>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/close.png b/doc/html/search/close.png
new file mode 100644
index 0000000..9342d3d
--- /dev/null
+++ b/doc/html/search/close.png
Binary files differ
diff --git a/doc/html/search/mag_sel.png b/doc/html/search/mag_sel.png
new file mode 100644
index 0000000..81f6040
--- /dev/null
+++ b/doc/html/search/mag_sel.png
Binary files differ
diff --git a/doc/html/search/nomatches.html b/doc/html/search/nomatches.html
new file mode 100644
index 0000000..b1ded27
--- /dev/null
+++ b/doc/html/search/nomatches.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="NoMatches">No Matches</div>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/search.css b/doc/html/search/search.css
new file mode 100644
index 0000000..50249e5
--- /dev/null
+++ b/doc/html/search/search.css
@@ -0,0 +1,240 @@
+/*---------------- Search Box */
+
+#FSearchBox {
+    float: left;
+}
+
+#searchli {
+    float: right;
+    display: block;
+    width: 170px;
+    height: 36px;
+}
+
+#MSearchBox {
+    white-space : nowrap;
+    position: absolute;
+    float: none;
+    display: inline;
+    margin-top: 8px;
+    right: 0px;
+    width: 170px;
+    z-index: 102;
+}
+
+#MSearchBox .left
+{
+    display:block;
+    position:absolute;
+    left:10px;
+    width:20px;
+    height:19px;
+    background:url('search_l.png') no-repeat;
+    background-position:right;
+}
+
+#MSearchSelect {
+    display:block;
+    position:absolute;
+    width:20px;
+    height:19px;
+}
+
+.left #MSearchSelect {
+    left:4px;
+}
+
+.right #MSearchSelect {
+    right:5px;
+}
+
+#MSearchField {
+    display:block;
+    position:absolute;
+    height:19px;
+    background:url('search_m.png') repeat-x;
+    border:none;
+    width:116px;
+    margin-left:20px;
+    padding-left:4px;
+    color: #909090;
+    outline: none;
+    font: 9pt Arial, Verdana, sans-serif;
+}
+
+#FSearchBox #MSearchField {
+    margin-left:15px;
+}
+
+#MSearchBox .right {
+    display:block;
+    position:absolute;
+    right:10px;
+    top:0px;
+    width:20px;
+    height:19px;
+    background:url('search_r.png') no-repeat;
+    background-position:left;
+}
+
+#MSearchClose {
+    display: none;
+    position: absolute;
+    top: 4px;
+    background : none;
+    border: none;
+    margin: 0px 4px 0px 0px;
+    padding: 0px 0px;
+    outline: none;
+}
+
+.left #MSearchClose {
+    left: 6px;
+}
+
+.right #MSearchClose {
+    right: 2px;
+}
+
+.MSearchBoxActive #MSearchField {
+    color: #000000;
+}
+
+/*---------------- Search filter selection */
+
+#MSearchSelectWindow {
+    display: none;
+    position: absolute;
+    left: 0; top: 0;
+    border: 1px solid #90A5CE;
+    background-color: #F9FAFC;
+    z-index: 1;
+    padding-top: 4px;
+    padding-bottom: 4px;
+    -moz-border-radius: 4px;
+    -webkit-border-top-left-radius: 4px;
+    -webkit-border-top-right-radius: 4px;
+    -webkit-border-bottom-left-radius: 4px;
+    -webkit-border-bottom-right-radius: 4px;
+    -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+}
+
+.SelectItem {
+    font: 8pt Arial, Verdana, sans-serif;
+    padding-left:  2px;
+    padding-right: 12px;
+    border: 0px;
+}
+
+span.SelectionMark {
+    margin-right: 4px;
+    font-family: monospace;
+    outline-style: none;
+    text-decoration: none;
+}
+
+a.SelectItem {
+    display: block;
+    outline-style: none;
+    color: #000000; 
+    text-decoration: none;
+    padding-left:   6px;
+    padding-right: 12px;
+}
+
+a.SelectItem:focus,
+a.SelectItem:active {
+    color: #000000; 
+    outline-style: none;
+    text-decoration: none;
+}
+
+a.SelectItem:hover {
+    color: #FFFFFF;
+    background-color: #3D578C;
+    outline-style: none;
+    text-decoration: none;
+    cursor: pointer;
+    display: block;
+}
+
+/*---------------- Search results window */
+
+iframe#MSearchResults {
+    width: 60ex;
+    height: 15em;
+}
+
+#MSearchResultsWindow {
+    display: none;
+    position: absolute;
+    left: 0; top: 0;
+    border: 1px solid #000;
+    background-color: #EEF1F7;
+}
+
+/* ----------------------------------- */
+
+
+#SRIndex {
+    clear:both; 
+    padding-bottom: 15px;
+}
+
+.SREntry {
+    font-size: 10pt;
+    padding-left: 1ex;
+}
+
+.SRPage .SREntry {
+    font-size: 8pt;
+    padding: 1px 5px;
+}
+
+body.SRPage {
+    margin: 5px 2px;
+}
+
+.SRChildren {
+    padding-left: 3ex; padding-bottom: .5em 
+}
+
+.SRPage .SRChildren {
+    display: none;
+}
+
+.SRSymbol {
+    font-weight: bold; 
+    color: #425E97;
+    font-family: Arial, Verdana, sans-serif;
+    text-decoration: none;
+    outline: none;
+}
+
+a.SRScope {
+    display: block;
+    color: #425E97; 
+    font-family: Arial, Verdana, sans-serif;
+    text-decoration: none;
+    outline: none;
+}
+
+a.SRSymbol:focus, a.SRSymbol:active,
+a.SRScope:focus, a.SRScope:active {
+    text-decoration: underline;
+}
+
+.SRPage .SRStatus {
+    padding: 2px 5px;
+    font-size: 8pt;
+    font-style: italic;
+}
+
+.SRResult {
+    display: none;
+}
+
+DIV.searchresults {
+    margin-left: 10px;
+    margin-right: 10px;
+}
diff --git a/doc/html/search/search.js b/doc/html/search/search.js
new file mode 100644
index 0000000..9b77adc
--- /dev/null
+++ b/doc/html/search/search.js
@@ -0,0 +1,730 @@
+// Search script generated by doxygen
+// Copyright (C) 2009 by Dimitri van Heesch.
+
+// The code in this file is loosly based on main.js, part of Natural Docs,
+// which is Copyright (C) 2003-2008 Greg Valure
+// Natural Docs is licensed under the GPL.
+
+var indexSectionsWithContent =
+{
+  0: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000011001010011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+  1: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+  2: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000011001000011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+};
+
+var indexSectionNames =
+{
+  0: "all",
+  1: "classes",
+  2: "variables"
+};
+
+function convertToId(search)
+{
+  var result = '';
+  for (i=0;i<search.length;i++)
+  {
+    var c = search.charAt(i);
+    var cn = c.charCodeAt(0);
+    if (c.match(/[a-z0-9]/))
+    {
+      result+=c;
+    }
+    else if (cn<16) 
+    {
+      result+="_0"+cn.toString(16);
+    }
+    else 
+    {
+      result+="_"+cn.toString(16);
+    }
+  }
+  return result;
+}
+
+function getXPos(item)
+{
+  var x = 0;
+  if (item.offsetWidth)
+  {
+    while (item && item!=document.body)
+    {
+      x   += item.offsetLeft;
+      item = item.offsetParent;
+    }
+  }
+  return x;
+}
+
+function getYPos(item)
+{
+  var y = 0;
+  if (item.offsetWidth)
+  {
+     while (item && item!=document.body)
+     {
+       y   += item.offsetTop;
+       item = item.offsetParent;
+     }
+  }
+  return y;
+}
+
+/* A class handling everything associated with the search panel.
+
+   Parameters:
+   name - The name of the global variable that will be 
+          storing this instance.  Is needed to be able to set timeouts.
+   resultPath - path to use for external files
+*/
+function SearchBox(name, resultsPath, inFrame, label)
+{
+  if (!name || !resultsPath) {  alert("Missing parameters to SearchBox."); }
+   
+  // ---------- Instance variables
+  this.name                  = name;
+  this.resultsPath           = resultsPath;
+  this.keyTimeout            = 0;
+  this.keyTimeoutLength      = 500;
+  this.closeSelectionTimeout = 300;
+  this.lastSearchValue       = "";
+  this.lastResultsPage       = "";
+  this.hideTimeout           = 0;
+  this.searchIndex           = 0;
+  this.searchActive          = false;
+  this.insideFrame           = inFrame;
+  this.searchLabel           = label;
+
+  // ----------- DOM Elements
+
+  this.DOMSearchField = function()
+  {  return document.getElementById("MSearchField");  }
+
+  this.DOMSearchSelect = function()
+  {  return document.getElementById("MSearchSelect");  }
+
+  this.DOMSearchSelectWindow = function()
+  {  return document.getElementById("MSearchSelectWindow");  }
+
+  this.DOMPopupSearchResults = function()
+  {  return document.getElementById("MSearchResults");  }
+
+  this.DOMPopupSearchResultsWindow = function()
+  {  return document.getElementById("MSearchResultsWindow");  }
+
+  this.DOMSearchClose = function()
+  {  return document.getElementById("MSearchClose"); }
+
+  this.DOMSearchBox = function()
+  {  return document.getElementById("MSearchBox");  }
+
+  // ------------ Event Handlers
+
+  // Called when focus is added or removed from the search field.
+  this.OnSearchFieldFocus = function(isActive)
+  {
+    this.Activate(isActive);
+  }
+
+  this.OnSearchSelectShow = function()
+  {
+    var searchSelectWindow = this.DOMSearchSelectWindow();
+    var searchField        = this.DOMSearchSelect();
+
+    if (this.insideFrame)
+    {
+      var left = getXPos(searchField);
+      var top  = getYPos(searchField);
+      left += searchField.offsetWidth + 6;
+      top += searchField.offsetHeight;
+
+      // show search selection popup
+      searchSelectWindow.style.display='block';
+      left -= searchSelectWindow.offsetWidth;
+      searchSelectWindow.style.left =  left + 'px';
+      searchSelectWindow.style.top  =  top  + 'px';
+    }
+    else
+    {
+      var left = getXPos(searchField);
+      var top  = getYPos(searchField);
+      top += searchField.offsetHeight;
+
+      // show search selection popup
+      searchSelectWindow.style.display='block';
+      searchSelectWindow.style.left =  left + 'px';
+      searchSelectWindow.style.top  =  top  + 'px';
+    }
+
+    // stop selection hide timer
+    if (this.hideTimeout) 
+    {
+      clearTimeout(this.hideTimeout);
+      this.hideTimeout=0;
+    }
+    return false; // to avoid "image drag" default event
+  }
+
+  this.OnSearchSelectHide = function()
+  {
+    this.hideTimeout = setTimeout(this.name +".CloseSelectionWindow()",
+                                  this.closeSelectionTimeout);
+  }
+
+  // Called when the content of the search field is changed.
+  this.OnSearchFieldChange = function(evt)
+  {
+    if (this.keyTimeout) // kill running timer
+    {
+      clearTimeout(this.keyTimeout);
+      this.keyTimeout = 0;
+    }
+
+    var e  = (evt) ? evt : window.event; // for IE
+    if (e.keyCode==40 || e.keyCode==13)
+    {
+      if (e.shiftKey==1)
+      {
+        this.OnSearchSelectShow();
+        var win=this.DOMSearchSelectWindow(); 
+        for (i=0;i<win.childNodes.length;i++)
+        {
+          var child = win.childNodes[i]; // get span within a
+          if (child.className=='SelectItem')
+          {
+            child.focus();
+            return;
+          }
+        }
+        return;
+      }
+      else if (window.frames.MSearchResults.searchResults)
+      {
+        var elem = window.frames.MSearchResults.searchResults.NavNext(0);
+        if (elem) elem.focus();
+      }
+    }
+    else if (e.keyCode==27) // Escape out of the search field
+    {
+      this.DOMSearchField().blur();
+      this.DOMPopupSearchResultsWindow().style.display = 'none';
+      this.DOMSearchClose().style.display = 'none';
+      this.lastSearchValue = '';
+      this.Activate(false);
+      return;
+    }
+
+    // strip whitespaces
+    var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
+
+    if (searchValue != this.lastSearchValue) // search value has changed
+    {
+      if (searchValue != "") // non-empty search
+      {
+        // set timer for search update
+        this.keyTimeout = setTimeout(this.name + '.Search()',
+                                     this.keyTimeoutLength);
+      }
+      else // empty search field
+      {
+        this.DOMPopupSearchResultsWindow().style.display = 'none';
+        this.DOMSearchClose().style.display = 'none';
+        this.lastSearchValue = '';
+      }
+    }
+  }
+
+  this.SelectItemCount = function(id)
+  {
+    var count=0;
+    var win=this.DOMSearchSelectWindow(); 
+    for (i=0;i<win.childNodes.length;i++)
+    {
+      var child = win.childNodes[i]; // get span within a
+      if (child.className=='SelectItem')
+      {
+        count++;
+      }
+    }
+    return count;
+  }
+
+  this.SelectItemSet = function(id)
+  {
+    var i,j=0;
+    var win=this.DOMSearchSelectWindow(); 
+    for (i=0;i<win.childNodes.length;i++)
+    {
+      var child = win.childNodes[i]; // get span within a
+      if (child.className=='SelectItem')
+      {
+        var node = child.firstChild;
+        if (j==id)
+        {
+          node.innerHTML='&bull;';
+        }
+        else
+        {
+          node.innerHTML='&#160;';
+        }
+        j++;
+      }
+    }
+  }
+
+  // Called when an search filter selection is made.
+  // set item with index id as the active item
+  this.OnSelectItem = function(id)
+  {
+    this.searchIndex = id;
+    this.SelectItemSet(id);
+    var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
+    if (searchValue!="" && this.searchActive) // something was found -> do a search
+    {
+      this.Search();
+    }
+  }
+
+  this.OnSearchSelectKey = function(evt)
+  {
+    var e = (evt) ? evt : window.event; // for IE
+    if (e.keyCode==40 && this.searchIndex<this.SelectItemCount()) // Down
+    {
+      this.searchIndex++;
+      this.OnSelectItem(this.searchIndex);
+    }
+    else if (e.keyCode==38 && this.searchIndex>0) // Up
+    {
+      this.searchIndex--;
+      this.OnSelectItem(this.searchIndex);
+    }
+    else if (e.keyCode==13 || e.keyCode==27)
+    {
+      this.OnSelectItem(this.searchIndex);
+      this.CloseSelectionWindow();
+      this.DOMSearchField().focus();
+    }
+    return false;
+  }
+
+  // --------- Actions
+
+  // Closes the results window.
+  this.CloseResultsWindow = function()
+  {
+    this.DOMPopupSearchResultsWindow().style.display = 'none';
+    this.DOMSearchClose().style.display = 'none';
+    this.Activate(false);
+  }
+
+  this.CloseSelectionWindow = function()
+  {
+    this.DOMSearchSelectWindow().style.display = 'none';
+  }
+
+  // Performs a search.
+  this.Search = function()
+  {
+    this.keyTimeout = 0;
+
+    // strip leading whitespace
+    var searchValue = this.DOMSearchField().value.replace(/^ +/, "");
+
+    var code = searchValue.toLowerCase().charCodeAt(0);
+    var hexCode;
+    if (code<16) 
+    {
+      hexCode="0"+code.toString(16);
+    }
+    else 
+    {
+      hexCode=code.toString(16);
+    }
+
+    var resultsPage;
+    var resultsPageWithSearch;
+    var hasResultsPage;
+
+    if (indexSectionsWithContent[this.searchIndex].charAt(code) == '1')
+    {
+       resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';
+       resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
+       hasResultsPage = true;
+    }
+    else // nothing available for this search term
+    {
+       resultsPage = this.resultsPath + '/nomatches.html';
+       resultsPageWithSearch = resultsPage;
+       hasResultsPage = false;
+    }
+
+    window.frames.MSearchResults.location.href = resultsPageWithSearch;  
+    var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();
+
+    if (domPopupSearchResultsWindow.style.display!='block')
+    {
+       var domSearchBox = this.DOMSearchBox();
+       this.DOMSearchClose().style.display = 'inline';
+       if (this.insideFrame)
+       {
+         var domPopupSearchResults = this.DOMPopupSearchResults();
+         domPopupSearchResultsWindow.style.position = 'relative';
+         domPopupSearchResultsWindow.style.display  = 'block';
+         var width = document.body.clientWidth - 8; // the -8 is for IE :-(
+         domPopupSearchResultsWindow.style.width    = width + 'px';
+         domPopupSearchResults.style.width          = width + 'px';
+       }
+       else
+       {
+         var domPopupSearchResults = this.DOMPopupSearchResults();
+         var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth;
+         var top  = getYPos(domSearchBox) + 20;  // domSearchBox.offsetHeight + 1;
+         domPopupSearchResultsWindow.style.display = 'block';
+         left -= domPopupSearchResults.offsetWidth;
+         domPopupSearchResultsWindow.style.top     = top  + 'px';
+         domPopupSearchResultsWindow.style.left    = left + 'px';
+       }
+    }
+
+    this.lastSearchValue = searchValue;
+    this.lastResultsPage = resultsPage;
+  }
+
+  // -------- Activation Functions
+
+  // Activates or deactivates the search panel, resetting things to 
+  // their default values if necessary. 
+  this.Activate = function(isActive)
+  {
+    if (isActive || // open it
+        this.DOMPopupSearchResultsWindow().style.display == 'block' 
+       )
+    {
+      this.DOMSearchBox().className = 'MSearchBoxActive';
+
+      var searchField = this.DOMSearchField();
+
+      if (searchField.value == this.searchLabel) // clear "Search" term upon entry
+      {  
+        searchField.value = '';  
+        this.searchActive = true;
+      }
+    }
+    else if (!isActive) // directly remove the panel
+    {
+      this.DOMSearchBox().className = 'MSearchBoxInactive';
+      this.DOMSearchField().value   = this.searchLabel;
+      this.searchActive             = false;
+      this.lastSearchValue          = ''
+      this.lastResultsPage          = '';
+    }
+  }
+}
+
+// -----------------------------------------------------------------------
+
+// The class that handles everything on the search results page.
+function SearchResults(name)
+{
+    // The number of matches from the last run of <Search()>.
+    this.lastMatchCount = 0;
+    this.lastKey = 0;
+    this.repeatOn = false;
+
+    // Toggles the visibility of the passed element ID.
+    this.FindChildElement = function(id)
+    {
+      var parentElement = document.getElementById(id);
+      var element = parentElement.firstChild;
+
+      while (element && element!=parentElement)
+      {
+        if (element.nodeName == 'DIV' && element.className == 'SRChildren')
+        {
+          return element;
+        }
+
+        if (element.nodeName == 'DIV' && element.hasChildNodes())
+        {  
+           element = element.firstChild;  
+        }
+        else if (element.nextSibling)
+        {  
+           element = element.nextSibling;  
+        }
+        else
+        {
+          do
+          {
+            element = element.parentNode;
+          }
+          while (element && element!=parentElement && !element.nextSibling);
+
+          if (element && element!=parentElement)
+          {  
+            element = element.nextSibling;  
+          }
+        }
+      }
+    }
+
+    this.Toggle = function(id)
+    {
+      var element = this.FindChildElement(id);
+      if (element)
+      {
+        if (element.style.display == 'block')
+        {
+          element.style.display = 'none';
+        }
+        else
+        {
+          element.style.display = 'block';
+        }
+      }
+    }
+
+    // Searches for the passed string.  If there is no parameter,
+    // it takes it from the URL query.
+    //
+    // Always returns true, since other documents may try to call it
+    // and that may or may not be possible.
+    this.Search = function(search)
+    {
+      if (!search) // get search word from URL
+      {
+        search = window.location.search;
+        search = search.substring(1);  // Remove the leading '?'
+        search = unescape(search);
+      }
+
+      search = search.replace(/^ +/, ""); // strip leading spaces
+      search = search.replace(/ +$/, ""); // strip trailing spaces
+      search = search.toLowerCase();
+      search = convertToId(search);
+
+      var resultRows = document.getElementsByTagName("div");
+      var matches = 0;
+
+      var i = 0;
+      while (i < resultRows.length)
+      {
+        var row = resultRows.item(i);
+        if (row.className == "SRResult")
+        {
+          var rowMatchName = row.id.toLowerCase();
+          rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_'
+
+          if (search.length<=rowMatchName.length && 
+             rowMatchName.substr(0, search.length)==search)
+          {
+            row.style.display = 'block';
+            matches++;
+          }
+          else
+          {
+            row.style.display = 'none';
+          }
+        }
+        i++;
+      }
+      document.getElementById("Searching").style.display='none';
+      if (matches == 0) // no results
+      {
+        document.getElementById("NoMatches").style.display='block';
+      }
+      else // at least one result
+      {
+        document.getElementById("NoMatches").style.display='none';
+      }
+      this.lastMatchCount = matches;
+      return true;
+    }
+
+    // return the first item with index index or higher that is visible
+    this.NavNext = function(index)
+    {
+      var focusItem;
+      while (1)
+      {
+        var focusName = 'Item'+index;
+        focusItem = document.getElementById(focusName);
+        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
+        {
+          break;
+        }
+        else if (!focusItem) // last element
+        {
+          break;
+        }
+        focusItem=null;
+        index++;
+      }
+      return focusItem;
+    }
+
+    this.NavPrev = function(index)
+    {
+      var focusItem;
+      while (1)
+      {
+        var focusName = 'Item'+index;
+        focusItem = document.getElementById(focusName);
+        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
+        {
+          break;
+        }
+        else if (!focusItem) // last element
+        {
+          break;
+        }
+        focusItem=null;
+        index--;
+      }
+      return focusItem;
+    }
+
+    this.ProcessKeys = function(e)
+    {
+      if (e.type == "keydown") 
+      {
+        this.repeatOn = false;
+        this.lastKey = e.keyCode;
+      }
+      else if (e.type == "keypress")
+      {
+        if (!this.repeatOn)
+        {
+          if (this.lastKey) this.repeatOn = true;
+          return false; // ignore first keypress after keydown
+        }
+      }
+      else if (e.type == "keyup")
+      {
+        this.lastKey = 0;
+        this.repeatOn = false;
+      }
+      return this.lastKey!=0;
+    }
+
+    this.Nav = function(evt,itemIndex) 
+    {
+      var e  = (evt) ? evt : window.event; // for IE
+      if (e.keyCode==13) return true;
+      if (!this.ProcessKeys(e)) return false;
+
+      if (this.lastKey==38) // Up
+      {
+        var newIndex = itemIndex-1;
+        var focusItem = this.NavPrev(newIndex);
+        if (focusItem)
+        {
+          var child = this.FindChildElement(focusItem.parentNode.parentNode.id);
+          if (child && child.style.display == 'block') // children visible
+          { 
+            var n=0;
+            var tmpElem;
+            while (1) // search for last child
+            {
+              tmpElem = document.getElementById('Item'+newIndex+'_c'+n);
+              if (tmpElem)
+              {
+                focusItem = tmpElem;
+              }
+              else // found it!
+              {
+                break;
+              }
+              n++;
+            }
+          }
+        }
+        if (focusItem)
+        {
+          focusItem.focus();
+        }
+        else // return focus to search field
+        {
+           parent.document.getElementById("MSearchField").focus();
+        }
+      }
+      else if (this.lastKey==40) // Down
+      {
+        var newIndex = itemIndex+1;
+        var focusItem;
+        var item = document.getElementById('Item'+itemIndex);
+        var elem = this.FindChildElement(item.parentNode.parentNode.id);
+        if (elem && elem.style.display == 'block') // children visible
+        {
+          focusItem = document.getElementById('Item'+itemIndex+'_c0');
+        }
+        if (!focusItem) focusItem = this.NavNext(newIndex);
+        if (focusItem)  focusItem.focus();
+      }
+      else if (this.lastKey==39) // Right
+      {
+        var item = document.getElementById('Item'+itemIndex);
+        var elem = this.FindChildElement(item.parentNode.parentNode.id);
+        if (elem) elem.style.display = 'block';
+      }
+      else if (this.lastKey==37) // Left
+      {
+        var item = document.getElementById('Item'+itemIndex);
+        var elem = this.FindChildElement(item.parentNode.parentNode.id);
+        if (elem) elem.style.display = 'none';
+      }
+      else if (this.lastKey==27) // Escape
+      {
+        parent.searchBox.CloseResultsWindow();
+        parent.document.getElementById("MSearchField").focus();
+      }
+      else if (this.lastKey==13) // Enter
+      {
+        return true;
+      }
+      return false;
+    }
+
+    this.NavChild = function(evt,itemIndex,childIndex)
+    {
+      var e  = (evt) ? evt : window.event; // for IE
+      if (e.keyCode==13) return true;
+      if (!this.ProcessKeys(e)) return false;
+
+      if (this.lastKey==38) // Up
+      {
+        if (childIndex>0)
+        {
+          var newIndex = childIndex-1;
+          document.getElementById('Item'+itemIndex+'_c'+newIndex).focus();
+        }
+        else // already at first child, jump to parent
+        {
+          document.getElementById('Item'+itemIndex).focus();
+        }
+      }
+      else if (this.lastKey==40) // Down
+      {
+        var newIndex = childIndex+1;
+        var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex);
+        if (!elem) // last child, jump to parent next parent
+        {
+          elem = this.NavNext(itemIndex+1);
+        }
+        if (elem)
+        {
+          elem.focus();
+        } 
+      }
+      else if (this.lastKey==27) // Escape
+      {
+        parent.searchBox.CloseResultsWindow();
+        parent.document.getElementById("MSearchField").focus();
+      }
+      else if (this.lastKey==13) // Enter
+      {
+        return true;
+      }
+      return false;
+    }
+}
diff --git a/doc/html/search/search_l.png b/doc/html/search/search_l.png
new file mode 100644
index 0000000..c872f4d
--- /dev/null
+++ b/doc/html/search/search_l.png
Binary files differ
diff --git a/doc/html/search/search_m.png b/doc/html/search/search_m.png
new file mode 100644
index 0000000..b429a16
--- /dev/null
+++ b/doc/html/search/search_m.png
Binary files differ
diff --git a/doc/html/search/search_r.png b/doc/html/search/search_r.png
new file mode 100644
index 0000000..97ee8b4
--- /dev/null
+++ b/doc/html/search/search_r.png
Binary files differ
diff --git a/doc/html/search/variables_64.html b/doc/html/search/variables_64.html
new file mode 100644
index 0000000..5db4361
--- /dev/null
+++ b/doc/html/search/variables_64.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_denom">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjscalingfactor.html#aefbcdf3e9e62274b2d312c695f133ce3" target="_parent">denom</a>
+  <span class="SRScope">tjscalingfactor</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/variables_68.html b/doc/html/search/variables_68.html
new file mode 100644
index 0000000..ccb671d
--- /dev/null
+++ b/doc/html/search/variables_68.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_h">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html#aecefc45a26f4d8b60dd4d825c1710115" target="_parent">h</a>
+  <span class="SRScope">tjregion</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/variables_6e.html b/doc/html/search/variables_6e.html
new file mode 100644
index 0000000..b9f5b05
--- /dev/null
+++ b/doc/html/search/variables_6e.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_num">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjscalingfactor.html#a9b011e57f981ee23083e2c1aa5e640ec" target="_parent">num</a>
+  <span class="SRScope">tjscalingfactor</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/variables_6f.html b/doc/html/search/variables_6f.html
new file mode 100644
index 0000000..d95bbef
--- /dev/null
+++ b/doc/html/search/variables_6f.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_op">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjtransform.html#a2525aab4ba6978a1c273f74fef50e498" target="_parent">op</a>
+  <span class="SRScope">tjtransform</span>
+ </div>
+</div>
+<div class="SRResult" id="SR_options">
+ <div class="SREntry">
+  <a id="Item1" onkeydown="return searchResults.Nav(event,1)" onkeypress="return searchResults.Nav(event,1)" onkeyup="return searchResults.Nav(event,1)" class="SRSymbol" href="../structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6" target="_parent">options</a>
+  <span class="SRScope">tjtransform</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/variables_72.html b/doc/html/search/variables_72.html
new file mode 100644
index 0000000..465fe88
--- /dev/null
+++ b/doc/html/search/variables_72.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_r">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjtransform.html#ac324e5e442abec8a961e5bf219db12cf" target="_parent">r</a>
+  <span class="SRScope">tjtransform</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/variables_77.html b/doc/html/search/variables_77.html
new file mode 100644
index 0000000..b4c8d88
--- /dev/null
+++ b/doc/html/search/variables_77.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_w">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42" target="_parent">w</a>
+  <span class="SRScope">tjregion</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/variables_78.html b/doc/html/search/variables_78.html
new file mode 100644
index 0000000..a357691
--- /dev/null
+++ b/doc/html/search/variables_78.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_x">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html#a4b6a37a93997091b26a75831fa291ad9" target="_parent">x</a>
+  <span class="SRScope">tjregion</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/search/variables_79.html b/doc/html/search/variables_79.html
new file mode 100644
index 0000000..a883bd1
--- /dev/null
+++ b/doc/html/search/variables_79.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head><title></title>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<link rel="stylesheet" type="text/css" href="search.css"/>
+<script type="text/javascript" src="search.js"></script>
+</head>
+<body class="SRPage">
+<div id="SRIndex">
+<div class="SRStatus" id="Loading">Loading...</div>
+<div class="SRResult" id="SR_y">
+ <div class="SREntry">
+  <a id="Item0" onkeydown="return searchResults.Nav(event,0)" onkeypress="return searchResults.Nav(event,0)" onkeyup="return searchResults.Nav(event,0)" class="SRSymbol" href="../structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2" target="_parent">y</a>
+  <span class="SRScope">tjregion</span>
+ </div>
+</div>
+<div class="SRStatus" id="Searching">Searching...</div>
+<div class="SRStatus" id="NoMatches">No Matches</div>
+<script type="text/javascript"><!--
+document.getElementById("Loading").style.display="none";
+document.getElementById("NoMatches").style.display="none";
+var searchResults = new SearchResults("searchResults");
+searchResults.Search();
+--></script>
+</div>
+</body>
+</html>
diff --git a/doc/html/structtjregion.html b/doc/html/structtjregion.html
new file mode 100644
index 0000000..d94603d
--- /dev/null
+++ b/doc/html/structtjregion.html
@@ -0,0 +1,172 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: tjregion Struct Reference</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li><a href="modules.html"><span>Modules</span></a></li>
+      <li class="current"><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+  <div id="navrow2" class="tabs2">
+    <ul class="tablist">
+      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li><a href="classes.html"><span>Data&#160;Structure&#160;Index</span></a></li>
+      <li><a href="functions.html"><span>Data&#160;Fields</span></a></li>
+    </ul>
+  </div>
+</div>
+<div class="header">
+  <div class="summary">
+<a href="#pub-attribs">Data Fields</a>  </div>
+  <div class="headertitle">
+<div class="title">tjregion Struct Reference<div class="ingroups"><a class="el" href="group___turbo_j_p_e_g.html">TurboJPEG</a></div></div>  </div>
+</div>
+<div class="contents">
+<!-- doxytag: class="tjregion" -->
+<p>Cropping region.  
+ <a href="structtjregion.html#details">More...</a></p>
+
+<p><code>#include &lt;turbojpeg.h&gt;</code></p>
+<table class="memberdecls">
+<tr><td colspan="2"><h2><a name="pub-attribs"></a>
+Data Fields</h2></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjregion.html#a4b6a37a93997091b26a75831fa291ad9">x</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The left boundary of the cropping region.  <a href="#a4b6a37a93997091b26a75831fa291ad9"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2">y</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The upper boundary of the cropping region.  <a href="#a7b3e0c24cfe87acc80e334cafdcf22c2"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42">w</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The width of the cropping region.  <a href="#ab6eb73ceef584fc23c8c8097926dce42"></a><br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjregion.html#aecefc45a26f4d8b60dd4d825c1710115">h</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The height of the cropping region.  <a href="#aecefc45a26f4d8b60dd4d825c1710115"></a><br/></td></tr>
+</table>
+<hr/><a name="details" id="details"></a><h2>Detailed Description</h2>
+<div class="textblock"><p>Cropping region. </p>
+</div><hr/><h2>Field Documentation</h2>
+<a class="anchor" id="aecefc45a26f4d8b60dd4d825c1710115"></a><!-- doxytag: member="tjregion::h" ref="aecefc45a26f4d8b60dd4d825c1710115" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">int <a class="el" href="structtjregion.html#aecefc45a26f4d8b60dd4d825c1710115">tjregion::h</a></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>The height of the cropping region. </p>
+<p>Setting this to 0 is the equivalent of setting it to the height of the source JPEG image - y. </p>
+
+</div>
+</div>
+<a class="anchor" id="ab6eb73ceef584fc23c8c8097926dce42"></a><!-- doxytag: member="tjregion::w" ref="ab6eb73ceef584fc23c8c8097926dce42" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">int <a class="el" href="structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42">tjregion::w</a></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>The width of the cropping region. </p>
+<p>Setting this to 0 is the equivalent of setting it to the width of the source JPEG image - x. </p>
+
+</div>
+</div>
+<a class="anchor" id="a4b6a37a93997091b26a75831fa291ad9"></a><!-- doxytag: member="tjregion::x" ref="a4b6a37a93997091b26a75831fa291ad9" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">int <a class="el" href="structtjregion.html#a4b6a37a93997091b26a75831fa291ad9">tjregion::x</a></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>The left boundary of the cropping region. </p>
+<p>This must be evenly divisible by the MCU block width (see <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a>.) </p>
+
+</div>
+</div>
+<a class="anchor" id="a7b3e0c24cfe87acc80e334cafdcf22c2"></a><!-- doxytag: member="tjregion::y" ref="a7b3e0c24cfe87acc80e334cafdcf22c2" args="" -->
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">int <a class="el" href="structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2">tjregion::y</a></td>
+        </tr>
+      </table>
+</div>
+<div class="memdoc">
+
+<p>The upper boundary of the cropping region. </p>
+<p>This must be evenly divisible by the MCU block height (see <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>.) </p>
+
+</div>
+</div>
+<hr/>The documentation for this struct was generated from the following file:<ul>
+<li>turbojpeg.h</li>
+</ul>
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/structtjscalingfactor.html b/doc/html/structtjscalingfactor.html
new file mode 100644
index 0000000..d99350f
--- /dev/null
+++ b/doc/html/structtjscalingfactor.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: tjscalingfactor Struct Reference</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li><a href="modules.html"><span>Modules</span></a></li>
+      <li class="current"><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+  <div id="navrow2" class="tabs2">
+    <ul class="tablist">
+      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li><a href="classes.html"><span>Data&#160;Structure&#160;Index</span></a></li>
+      <li><a href="functions.html"><span>Data&#160;Fields</span></a></li>
+    </ul>
+  </div>
+</div>
+<div class="header">
+  <div class="summary">
+<a href="#pub-attribs">Data Fields</a>  </div>
+  <div class="headertitle">
+<div class="title">tjscalingfactor Struct Reference<div class="ingroups"><a class="el" href="group___turbo_j_p_e_g.html">TurboJPEG</a></div></div>  </div>
+</div>
+<div class="contents">
+<!-- doxytag: class="tjscalingfactor" -->
+<p>Scaling factor.  
+ <a href="structtjscalingfactor.html#details">More...</a></p>
+
+<p><code>#include &lt;turbojpeg.h&gt;</code></p>
+<table class="memberdecls">
+<tr><td colspan="2"><h2><a name="pub-attribs"></a>
+Data Fields</h2></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="a9b011e57f981ee23083e2c1aa5e640ec"></a><!-- doxytag: member="tjscalingfactor::num" ref="a9b011e57f981ee23083e2c1aa5e640ec" args="" -->
+int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjscalingfactor.html#a9b011e57f981ee23083e2c1aa5e640ec">num</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Numerator. <br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="aefbcdf3e9e62274b2d312c695f133ce3"></a><!-- doxytag: member="tjscalingfactor::denom" ref="aefbcdf3e9e62274b2d312c695f133ce3" args="" -->
+int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjscalingfactor.html#aefbcdf3e9e62274b2d312c695f133ce3">denom</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Denominator. <br/></td></tr>
+</table>
+<hr/><a name="details" id="details"></a><h2>Detailed Description</h2>
+<div class="textblock"><p>Scaling factor. </p>
+</div><hr/>The documentation for this struct was generated from the following file:<ul>
+<li>turbojpeg.h</li>
+</ul>
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/structtjtransform.html b/doc/html/structtjtransform.html
new file mode 100644
index 0000000..b70bc4a
--- /dev/null
+++ b/doc/html/structtjtransform.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<title>TurboJPEG: tjtransform Struct Reference</title>
+<link href="tabs.css" rel="stylesheet" type="text/css"/>
+<link href="search/search.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="search/search.js"></script>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head>
+<body onload='searchBox.OnSelectItem(0);'>
+<!-- Generated by Doxygen 1.7.4 -->
+<script type="text/javascript"><!--
+var searchBox = new SearchBox("searchBox", "search",false,'Search');
+--></script>
+<div id="top">
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <td style="padding-left: 0.5em;">
+   <div id="projectname">TurboJPEG&#160;<span id="projectnumber">1.2</span></div>
+  </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+  <div id="navrow1" class="tabs">
+    <ul class="tablist">
+      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+      <li><a href="modules.html"><span>Modules</span></a></li>
+      <li class="current"><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li id="searchli">
+        <div id="MSearchBox" class="MSearchBoxInactive">
+        <span class="left">
+          <img id="MSearchSelect" src="search/mag_sel.png"
+               onmouseover="return searchBox.OnSearchSelectShow()"
+               onmouseout="return searchBox.OnSearchSelectHide()"
+               alt=""/>
+          <input type="text" id="MSearchField" value="Search" accesskey="S"
+               onfocus="searchBox.OnSearchFieldFocus(true)" 
+               onblur="searchBox.OnSearchFieldFocus(false)" 
+               onkeyup="searchBox.OnSearchFieldChange(event)"/>
+          </span><span class="right">
+            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
+          </span>
+        </div>
+      </li>
+    </ul>
+  </div>
+  <div id="navrow2" class="tabs2">
+    <ul class="tablist">
+      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+      <li><a href="classes.html"><span>Data&#160;Structure&#160;Index</span></a></li>
+      <li><a href="functions.html"><span>Data&#160;Fields</span></a></li>
+    </ul>
+  </div>
+</div>
+<div class="header">
+  <div class="summary">
+<a href="#pub-attribs">Data Fields</a>  </div>
+  <div class="headertitle">
+<div class="title">tjtransform Struct Reference<div class="ingroups"><a class="el" href="group___turbo_j_p_e_g.html">TurboJPEG</a></div></div>  </div>
+</div>
+<div class="contents">
+<!-- doxytag: class="tjtransform" -->
+<p>Lossless transform.  
+ <a href="structtjtransform.html#details">More...</a></p>
+
+<p><code>#include &lt;turbojpeg.h&gt;</code></p>
+<table class="memberdecls">
+<tr><td colspan="2"><h2><a name="pub-attribs"></a>
+Data Fields</h2></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ac324e5e442abec8a961e5bf219db12cf"></a><!-- doxytag: member="tjtransform::r" ref="ac324e5e442abec8a961e5bf219db12cf" args="" -->
+<a class="el" href="structtjregion.html">tjregion</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#ac324e5e442abec8a961e5bf219db12cf">r</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Cropping region. <br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="a2525aab4ba6978a1c273f74fef50e498"></a><!-- doxytag: member="tjtransform::op" ref="a2525aab4ba6978a1c273f74fef50e498" args="" -->
+int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#a2525aab4ba6978a1c273f74fef50e498">op</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">One of the transform operations (see <a class="el" href="group___turbo_j_p_e_g.html#xformop">Transform operations</a>.) <br/></td></tr>
+<tr><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ac0e74655baa4402209a21e1ae481c8f6"></a><!-- doxytag: member="tjtransform::options" ref="ac0e74655baa4402209a21e1ae481c8f6" args="" -->
+int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6">options</a></td></tr>
+<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The bitwise OR of one of more of the transform options (see <a class="el" href="group___turbo_j_p_e_g.html#xformopt">Transform options</a>.) <br/></td></tr>
+</table>
+<hr/><a name="details" id="details"></a><h2>Detailed Description</h2>
+<div class="textblock"><p>Lossless transform. </p>
+</div><hr/>The documentation for this struct was generated from the following file:<ul>
+<li>turbojpeg.h</li>
+</ul>
+</div>
+<!-- window showing the filter options -->
+<div id="MSearchSelectWindow"
+     onmouseover="return searchBox.OnSearchSelectShow()"
+     onmouseout="return searchBox.OnSearchSelectHide()"
+     onkeydown="return searchBox.OnSearchSelectKey(event)">
+<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Variables</a></div>
+
+<!-- iframe showing the search results (closed by default) -->
+<div id="MSearchResultsWindow">
+<iframe src="javascript:void(0)" frameborder="0" 
+        name="MSearchResults" id="MSearchResults">
+</iframe>
+</div>
+
+<hr class="footer"/><address class="footer"><small>Generated on Sat May 21 2011 09:17:13 for TurboJPEG by&#160;
+<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
+</body>
+</html>
diff --git a/doc/html/tab_a.png b/doc/html/tab_a.png
new file mode 100644
index 0000000..2d99ef2
--- /dev/null
+++ b/doc/html/tab_a.png
Binary files differ
diff --git a/doc/html/tab_b.png b/doc/html/tab_b.png
new file mode 100644
index 0000000..b2c3d2b
--- /dev/null
+++ b/doc/html/tab_b.png
Binary files differ
diff --git a/doc/html/tab_h.png b/doc/html/tab_h.png
new file mode 100644
index 0000000..c11f48f
--- /dev/null
+++ b/doc/html/tab_h.png
Binary files differ
diff --git a/doc/html/tab_s.png b/doc/html/tab_s.png
new file mode 100644
index 0000000..978943a
--- /dev/null
+++ b/doc/html/tab_s.png
Binary files differ
diff --git a/doc/html/tabs.css b/doc/html/tabs.css
new file mode 100644
index 0000000..2192056
--- /dev/null
+++ b/doc/html/tabs.css
@@ -0,0 +1,59 @@
+.tabs, .tabs2, .tabs3 {
+    background-image: url('tab_b.png');
+    width: 100%;
+    z-index: 101;
+    font-size: 13px;
+}
+
+.tabs2 {
+    font-size: 10px;
+}
+.tabs3 {
+    font-size: 9px;
+}
+
+.tablist {
+    margin: 0;
+    padding: 0;
+    display: table;
+}
+
+.tablist li {
+    float: left;
+    display: table-cell;
+    background-image: url('tab_b.png');
+    line-height: 36px;
+    list-style: none;
+}
+
+.tablist a {
+    display: block;
+    padding: 0 20px;
+    font-weight: bold;
+    background-image:url('tab_s.png');
+    background-repeat:no-repeat;
+    background-position:right;
+    color: #283A5D;
+    text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+    text-decoration: none;
+    outline: none;
+}
+
+.tabs3 .tablist a {
+    padding: 0 10px;
+}
+
+.tablist a:hover {
+    background-image: url('tab_h.png');
+    background-repeat:repeat-x;
+    color: #fff;
+    text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+    text-decoration: none;
+}
+
+.tablist li.current a {
+    background-image: url('tab_a.png');
+    background-repeat:repeat-x;
+    color: #fff;
+    text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+}
diff --git a/doxygen.config b/doxygen.config
new file mode 100644
index 0000000..6c6e8ee
--- /dev/null
+++ b/doxygen.config
@@ -0,0 +1,13 @@
+PROJECT_NAME = TurboJPEG
+PROJECT_NUMBER = 1.2
+OUTPUT_DIRECTORY = doc/
+USE_WINDOWS_ENCODING = NO
+OPTIMIZE_OUTPUT_FOR_C = YES
+WARN_NO_PARAMDOC = YES
+GENERATE_LATEX = NO
+FILE_PATTERNS = turbojpeg.h
+HIDE_UNDOC_MEMBERS = YES
+VERBATIM_HEADERS = NO
+EXTRACT_STATIC = YES
+JAVADOC_AUTOBRIEF = YES
+MAX_INITIALIZER_LINES = 0
diff --git a/jdatadst-tj.c b/jdatadst-tj.c
new file mode 100644
index 0000000..3816f95
--- /dev/null
+++ b/jdatadst-tj.c
@@ -0,0 +1,187 @@
+/*
+ * jdatadst.c
+ *
+ * Copyright (C) 1994-1996, 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.
+ *
+ * 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.
+ * 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.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#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
+
+
+#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;
+  boolean alloc;
+} 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.
+ */
+
+METHODDEF(void)
+init_mem_destination (j_compress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * In typical applications, this should write the entire output buffer
+ * (ignoring the current state of next_output_byte & free_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been dumped.
+ *
+ * In applications that need to be able to suspend compression due to output
+ * overrun, a FALSE return indicates that the buffer cannot be emptied now.
+ * In this situation, the compressor will return to its caller (possibly with
+ * an indication that it has not accepted all the supplied scanlines).  The
+ * application should resume compression after it has made more room in the
+ * output buffer.  Note that there are substantial restrictions on the use of
+ * suspension --- see the documentation.
+ *
+ * When suspending, the compressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_output_byte & free_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point will be regenerated after resumption, so do not
+ * write it out when emptying the buffer externally.
+ */
+
+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;
+
+  if (!dest->alloc) ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+  /* Try to allocate new buffer with double size */
+  nextsize = dest->bufsize * 2;
+  nextbuffer = 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
+ * after all data has been written.  Usually needs to flush buffer.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_mem_destination (j_compress_ptr cinfo)
+{
+  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
+
+  if(dest->alloc) *dest->outbuffer = dest->buffer;
+  *dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer);
+}
+
+
+/*
+ * 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.
+ */
+
+GLOBAL(void)
+jpeg_mem_dest_tj (j_compress_ptr cinfo,
+	       unsigned char ** outbuffer, unsigned long * outsize,
+	       boolean alloc)
+{
+  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;
+  dest->alloc = alloc;
+
+  if (*outbuffer == NULL || *outsize == 0) {
+    if (alloc) {
+      /* Allocate initial buffer */
+      dest->newbuffer = *outbuffer = malloc(OUTPUT_BUF_SIZE);
+      if (dest->newbuffer == NULL)
+        ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+      *outsize = OUTPUT_BUF_SIZE;
+    }
+    else ERREXIT(cinfo, JERR_BUFFER_SIZE);
+  }
+
+  dest->pub.next_output_byte = dest->buffer = *outbuffer;
+  dest->pub.free_in_buffer = dest->bufsize = *outsize;
+}
diff --git a/jdatasrc-tj.c b/jdatasrc-tj.c
new file mode 100644
index 0000000..d860a02
--- /dev/null
+++ b/jdatasrc-tj.c
@@ -0,0 +1,182 @@
+/*
+ * jdatasrc.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-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.
+ *
+ * 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.
+ * 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.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+METHODDEF(void)
+init_mem_source (j_decompress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * In typical applications, this should read fresh data into the buffer
+ * (ignoring the current state of next_input_byte & bytes_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been reloaded.  It is not necessary to
+ * fill the buffer entirely, only to obtain at least one more byte.
+ *
+ * There is no such thing as an EOF return.  If the end of the file has been
+ * reached, the routine has a choice of ERREXIT() or inserting fake data into
+ * the buffer.  In most cases, generating a warning message and inserting a
+ * fake EOI marker is the best course of action --- this will allow the
+ * decompressor to output however much of the image is there.  However,
+ * the resulting error message is misleading if the real problem is an empty
+ * input file, so we handle that case specially.
+ *
+ * In applications that need to be able to suspend compression due to input
+ * not being available yet, a FALSE return indicates that no more data can be
+ * obtained right now, but more may be forthcoming later.  In this situation,
+ * the decompressor will return to its caller (with an indication of the
+ * number of scanlines it has read, if any).  The application should resume
+ * decompression after it has loaded more data into the input buffer.  Note
+ * that there are substantial restrictions on the use of suspension --- see
+ * the documentation.
+ *
+ * When suspending, the decompressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point must be rescanned after resumption, so move it to
+ * the front of the buffer rather than discarding it.
+ */
+
+METHODDEF(boolean)
+fill_mem_input_buffer (j_decompress_ptr cinfo)
+{
+  static JOCTET mybuffer[4];
+
+  /* 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 */
+  mybuffer[0] = (JOCTET) 0xFF;
+  mybuffer[1] = (JOCTET) JPEG_EOI;
+
+  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
+ * uninteresting data (such as an APPn marker).
+ *
+ * Writers of suspendable-input applications must note that skip_input_data
+ * is not granted the right to give a suspension return.  If the skip extends
+ * beyond the data currently in the buffer, the buffer can be marked empty so
+ * that the next read will cause a fill_input_buffer call that can suspend.
+ * Arranging for additional bytes to be discarded before reloading the input
+ * buffer is the application writer's problem.
+ */
+
+METHODDEF(void)
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+  struct jpeg_source_mgr * src = 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);
+      /* 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;
+  }
+}
+
+
+/*
+ * An additional method that can be provided by data source modules is the
+ * resync_to_restart method for error recovery in the presence of RST markers.
+ * For the moment, this source module just uses the default resync method
+ * provided by the JPEG library.  That method assumes that no backtracking
+ * is possible.
+ */
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read.  Often a no-op.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_source (j_decompress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a supplied memory buffer.
+ * The buffer must contain the whole JPEG data.
+ */
+
+GLOBAL(void)
+jpeg_mem_src_tj (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;
+}
diff --git a/jpegut.c b/jpegut.c
index a96dbbf..961c51f 100644
--- a/jpegut.c
+++ b/jpegut.c
@@ -214,7 +214,7 @@
 int checkbufyuv(unsigned char *buf, int w, int h, int subsamp)
 {
 	int i, j;
-	int hsf=tjmcuw[subsamp]/8, vsf=tjmcuh[subsamp]/8;
+	int hsf=tjMCUWidth[subsamp]/8, vsf=tjMCUHeight[subsamp]/8;
 	int pw=PAD(w, hsf), ph=PAD(h, vsf);
 	int cw=pw/hsf, ch=ph/vsf;
 	int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
diff --git a/jpgtest.c b/jpgtest.c
index ab4d9f8..f069b6e 100644
--- a/jpgtest.c
+++ b/jpgtest.c
@@ -491,13 +491,13 @@
 
 			if(xformopt&TJXFORM_GRAY) _jpegsub=TJ_GRAYSCALE;
 			if(xformop==TJXFORM_HFLIP || xformop==TJXFORM_ROT180)
-				_w=_w-(_w%tjmcuw[_jpegsub]);
+				_w=_w-(_w%tjMCUWidth[_jpegsub]);
 			if(xformop==TJXFORM_VFLIP || xformop==TJXFORM_ROT180)
-				_h=_h-(_h%tjmcuh[_jpegsub]);
+				_h=_h-(_h%tjMCUHeight[_jpegsub]);
 			if(xformop==TJXFORM_TRANSVERSE || xformop==TJXFORM_ROT90)
-				_w=_w-(_w%tjmcuh[_jpegsub]);
+				_w=_w-(_w%tjMCUHeight[_jpegsub]);
 			if(xformop==TJXFORM_TRANSVERSE || xformop==TJXFORM_ROT270)
-				_h=_h-(_h%tjmcuw[_jpegsub]);
+				_h=_h-(_h%tjMCUWidth[_jpegsub]);
 			_numtilesx=(_w+_tilesizex-1)/_tilesizex;
 			_numtilesy=(_h+_tilesizey-1)/_tilesizey;
 
diff --git a/turbojpeg-jni.c b/turbojpeg-jni.c
index 099d6bf..e851dcf 100644
--- a/turbojpeg-jni.c
+++ b/turbojpeg-jni.c
@@ -34,12 +34,6 @@
 #include "java/org_libjpegturbo_turbojpeg_TJDecompressor.h"
 #include "java/org_libjpegturbo_turbojpeg_TJ.h"
 
-static const int _pixelsize[org_libjpegturbo_turbojpeg_TJ_NUMPF]=
-	{3, 3, 4, 4, 4, 4, 1};
-
-static const int _flags[org_libjpegturbo_turbojpeg_TJ_NUMPF]=
-	{0, TJ_BGR, 0, TJ_BGR, TJ_BGR|TJ_ALPHAFIRST, TJ_ALPHAFIRST, 0};
-
 #define _throw(msg) {  \
 	jclass _exccls=(*env)->FindClass(env, "java/lang/Exception");  \
 	if(!_exccls) goto bailout;  \
@@ -96,125 +90,128 @@
 
 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII
 	(JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch,
-		jint height, jint pf, jbyteArray dst, jint jpegsubsamp, jint jpegqual,
+		jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual,
 		jint flags)
 {
-	tjhandle handle=0;  int pixelsize;
-	unsigned long size=0;  jsize arraysize=0;
-	unsigned char *srcbuf=NULL, *dstbuf=NULL;
+	tjhandle handle=0;
+	unsigned long jpegSize=0;  jsize arraySize=0;
+	unsigned char *srcBuf=NULL, *jpegBuf=NULL;
 
 	gethandle();
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1
 		|| pitch<0)
 		_throw("Invalid argument in compress()");
-	flags|=_flags[pf];
-	pixelsize=_pixelsize[pf];
+	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
+		_throw("Mismatch between Java and C API");
 
-	arraysize=(pitch==0)? width*pixelsize*height:pitch*height;
-	if((*env)->GetArrayLength(env, src)<arraysize)
+	arraySize=(pitch==0)? width*tjPixelSize[pf]*height:pitch*height;
+	if((*env)->GetArrayLength(env, src)<arraySize)
 		_throw("Source buffer is not large enough");
-	if((*env)->GetArrayLength(env, dst)<(jsize)TJBUFSIZE(width, height))
+	jpegSize=TJBUFSIZE(width, height);
+	if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize)
 		_throw("Destination buffer is not large enough");
 
-	bailif0(srcbuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
-	bailif0(dstbuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
+	bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
+	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
-	if(tjCompress(handle, srcbuf, width, pitch, height, pixelsize, dstbuf,
-		&size, jpegsubsamp, jpegqual, flags)==-1)
+	if(tjCompress2(handle, srcBuf, width, pitch, height, pf, &jpegBuf,
+		&jpegSize, jpegSubsamp, jpegQual, flags|TJ_NOREALLOC)==-1)
 	{
-		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-		(*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
-		dstbuf=srcbuf=NULL;
+		(*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
+		(*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
+		jpegBuf=srcBuf=NULL;
 		_throw(tjGetErrorStr());
 	}
 
 	bailout:
-	if(dstbuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-	if(srcbuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
-	return (jint)size;
+	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
+	if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
+	return (jint)jpegSize;
 }
 
 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII
 	(JNIEnv *env, jobject obj, jintArray src, jint width, jint pitch,
-		jint height, jint pf, jbyteArray dst, jint jpegsubsamp, jint jpegqual,
+		jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual,
 		jint flags)
 {
 	tjhandle handle=0;
-	unsigned long size=0;  jsize arraysize=0;
-	unsigned char *srcbuf=NULL, *dstbuf=NULL;
+	unsigned long jpegSize=0;  jsize arraySize=0;
+	unsigned char *srcBuf=NULL, *jpegBuf=NULL;
 
 	gethandle();
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1
 		|| pitch<0)
 		_throw("Invalid argument in compress()");
-	if(_pixelsize[pf]!=sizeof(jint))
+	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
+		_throw("Mismatch between Java and C API");
+	if(tjPixelSize[pf]!=sizeof(jint))
 		_throw("Pixel format must be 32-bit when compressing from an integer buffer.");
-	flags|=_flags[pf];
 
-	arraysize=(pitch==0)? width*height:pitch*height;
-	if((*env)->GetArrayLength(env, src)<arraysize)
+	arraySize=(pitch==0)? width*height:pitch*height;
+	if((*env)->GetArrayLength(env, src)<arraySize)
 		_throw("Source buffer is not large enough");
-	if((*env)->GetArrayLength(env, dst)<(jsize)TJBUFSIZE(width, height))
+	jpegSize=TJBUFSIZE(width, height);
+	if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize)
 		_throw("Destination buffer is not large enough");
 
-	bailif0(srcbuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
-	bailif0(dstbuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
+	bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
+	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
-	if(tjCompress(handle, srcbuf, width, pitch*sizeof(jint), height,
-		sizeof(jint),	dstbuf, &size, jpegsubsamp, jpegqual, flags)==-1)
+	if(tjCompress2(handle, srcBuf, width, pitch*sizeof(jint), height, pf,
+		&jpegBuf, &jpegSize, jpegSubsamp, jpegQual, flags|TJ_NOREALLOC)==-1)
 	{
-		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-		(*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
-		dstbuf=srcbuf=NULL;
+		(*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
+		(*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
+		jpegBuf=srcBuf=NULL;
 		_throw(tjGetErrorStr());
 	}
 
 	bailout:
-	if(dstbuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-	if(srcbuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
-	return (jint)size;
+	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
+	if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
+	return (jint)jpegSize;
 }
 
 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII
 	(JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch,
 		jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
 {
-	tjhandle handle=0;  int pixelsize;
-	jsize arraysize=0;
-	unsigned char *srcbuf=NULL, *dstbuf=NULL;
+	tjhandle handle=0;
+	jsize arraySize=0;
+	unsigned char *srcBuf=NULL, *dstBuf=NULL;
 
 	gethandle();
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1
 		|| pitch<0)
 		_throw("Invalid argument in encodeYUV()");
-	flags|=_flags[pf];
-	pixelsize=_pixelsize[pf];
+	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
+		_throw("Mismatch between Java and C API");
 
-	arraysize=(pitch==0)? width*pixelsize*height:pitch*height;
-	if((*env)->GetArrayLength(env, src)<arraysize)
+	arraySize=(pitch==0)? width*tjPixelSize[pf]*height:pitch*height;
+	if((*env)->GetArrayLength(env, src)<arraySize)
 		_throw("Source buffer is not large enough");
 	if((*env)->GetArrayLength(env, dst)
 		<(jsize)TJBUFSIZEYUV(width, height, subsamp))
 		_throw("Destination buffer is not large enough");
 
-	bailif0(srcbuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
-	bailif0(dstbuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
+	bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
+	bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
-	if(tjEncodeYUV(handle, srcbuf, width, pitch, height, pixelsize, dstbuf,
-		subsamp, flags)==-1)
+	if(tjEncodeYUV2(handle, srcBuf, width, pitch, height, pf, dstBuf, subsamp,
+		flags)==-1)
 	{
-		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-		(*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
-		dstbuf=srcbuf=NULL;
+		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+		(*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
+		dstBuf=srcBuf=NULL;
 		_throw(tjGetErrorStr());
 	}
 
 	bailout:
-	if(dstbuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-	if(srcbuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
+	if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+	if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
 	return;
 }
 
@@ -223,40 +220,41 @@
 		jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
 {
 	tjhandle handle=0;
-	jsize arraysize=0;
-	unsigned char *srcbuf=NULL, *dstbuf=NULL;
+	jsize arraySize=0;
+	unsigned char *srcBuf=NULL, *dstBuf=NULL;
 
 	gethandle();
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1
 		|| pitch<0)
 		_throw("Invalid argument in compress()");
-	if(_pixelsize[pf]!=sizeof(jint))
+	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
+		_throw("Mismatch between Java and C API");
+	if(tjPixelSize[pf]!=sizeof(jint))
 		_throw("Pixel format must be 32-bit when encoding from an integer buffer.");
-	flags|=_flags[pf];
 
-	arraysize=(pitch==0)? width*height:pitch*height;
-	if((*env)->GetArrayLength(env, src)<arraysize)
+	arraySize=(pitch==0)? width*height:pitch*height;
+	if((*env)->GetArrayLength(env, src)<arraySize)
 		_throw("Source buffer is not large enough");
 	if((*env)->GetArrayLength(env, dst)
 		<(jsize)TJBUFSIZEYUV(width, height, subsamp))
 		_throw("Destination buffer is not large enough");
 
-	bailif0(srcbuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
-	bailif0(dstbuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
+	bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
+	bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
-	if(tjEncodeYUV(handle, srcbuf, width, pitch*sizeof(jint), height,
-		sizeof(jint),	dstbuf, subsamp, flags)==-1)
+	if(tjEncodeYUV2(handle, srcBuf, width, pitch*sizeof(jint), height, pf,
+		dstBuf, subsamp, flags)==-1)
 	{
-		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-		(*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
-		dstbuf=srcbuf=NULL;
+		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+		(*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
+		dstBuf=srcBuf=NULL;
 		_throw(tjGetErrorStr());
 	}
 
 	bailout:
-	if(dstbuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-	if(srcbuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
+	if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+	if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
 	return;
 }
 
@@ -320,29 +318,29 @@
 }
 
 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader
-	(JNIEnv *env, jobject obj, jbyteArray src, jint size)
+	(JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize)
 {
 	tjhandle handle=0;
-	unsigned char *srcbuf=NULL;
-	int width=0, height=0, jpegsubsamp=-1;
+	unsigned char *jpegBuf=NULL;
+	int width=0, height=0, jpegSubsamp=-1;
 
 	gethandle();
 
-	if((*env)->GetArrayLength(env, src)<size)
+	if((*env)->GetArrayLength(env, src)<jpegSize)
 		_throw("Source buffer is not large enough");
 
-	bailif0(srcbuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
+	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
 
-	if(tjDecompressHeader2(handle, srcbuf, (unsigned long)size, 
-		&width, &height, &jpegsubsamp)==-1)
+	if(tjDecompressHeader2(handle, jpegBuf, (unsigned long)jpegSize, 
+		&width, &height, &jpegSubsamp)==-1)
 	{
-		(*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
+		(*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);
 		_throw(tjGetErrorStr());
 	}
-	(*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);  srcbuf=NULL;
+	(*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);  jpegBuf=NULL;
 
 	bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
-	(*env)->SetIntField(env, obj, _fid, jpegsubsamp);
+	(*env)->SetIntField(env, obj, _fid, jpegSubsamp);
 	bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
 	(*env)->SetIntField(env, obj, _fid, width);
 	bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
@@ -353,95 +351,96 @@
 }
 
 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIII
-	(JNIEnv *env, jobject obj, jbyteArray src, jint size, jbyteArray dst,
+	(JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
 		jint width, jint pitch, jint height, jint pf, jint flags)
 {
-	tjhandle handle=0;  int pixelsize;
-	jsize arraysize=0;
-	unsigned char *srcbuf=NULL, *dstbuf=NULL;
+	tjhandle handle=0;
+	jsize arraySize=0;
+	unsigned char *jpegBuf=NULL, *dstBuf=NULL;
 
 	gethandle();
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
 		_throw("Invalid argument in decompress()");
-	flags|=_flags[pf];
-	pixelsize=_pixelsize[pf];
+	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
+		_throw("Mismatch between Java and C API");
 
-	if((*env)->GetArrayLength(env, src)<size)
+	if((*env)->GetArrayLength(env, src)<jpegSize)
 		_throw("Source buffer is not large enough");
-	arraysize=(pitch==0)? width*pixelsize*height:pitch*height;
-	if((*env)->GetArrayLength(env, dst)<arraysize)
+	arraySize=(pitch==0)? width*tjPixelSize[pf]*height:pitch*height;
+	if((*env)->GetArrayLength(env, dst)<arraySize)
 		_throw("Destination buffer is not large enough");
 
-	bailif0(srcbuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
-	bailif0(dstbuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
+	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
+	bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
-	if(tjDecompress(handle, srcbuf, (unsigned long)size, dstbuf, width, pitch,
-		height, pixelsize, flags)==-1)
+	if(tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize, dstBuf, width,
+		pitch, height, pf, flags)==-1)
 	{
-		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-		(*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
-		dstbuf=srcbuf=NULL;
+		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+		(*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);
+		dstBuf=jpegBuf=NULL;
 		_throw(tjGetErrorStr());
 	}
 
 	bailout:
-	if(dstbuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-	if(srcbuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
+	if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);
 	return;
 }
 
 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII
-	(JNIEnv *env, jobject obj, jbyteArray src, jint size, jintArray dst,
+	(JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
 		jint width, jint pitch, jint height, jint pf, jint flags)
 {
 	tjhandle handle=0;
-	jsize arraysize=0;
-	unsigned char *srcbuf=NULL, *dstbuf=NULL;
+	jsize arraySize=0;
+	unsigned char *jpegBuf=NULL, *dstBuf=NULL;
 
 	gethandle();
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
 		_throw("Invalid argument in decompress()");
-	if(_pixelsize[pf]!=sizeof(jint))
+	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
+		_throw("Mismatch between Java and C API");
+	if(tjPixelSize[pf]!=sizeof(jint))
 		_throw("Pixel format must be 32-bit when decompressing to an integer buffer.");
-	flags|=_flags[pf];
 
-	if((*env)->GetArrayLength(env, src)<size)
+	if((*env)->GetArrayLength(env, src)<jpegSize)
 		_throw("Source buffer is not large enough");
-	arraysize=(pitch==0)? width*height:pitch*height;
-	if((*env)->GetArrayLength(env, dst)<arraysize)
+	arraySize=(pitch==0)? width*height:pitch*height;
+	if((*env)->GetArrayLength(env, dst)<arraySize)
 		_throw("Destination buffer is not large enough");
 
-	bailif0(srcbuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
-	bailif0(dstbuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
+	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
+	bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
-	if(tjDecompress(handle, srcbuf, (unsigned long)size, dstbuf, width,
-		pitch*sizeof(jint), height, sizeof(jint), flags)==-1)
+	if(tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize, dstBuf, width,
+		pitch*sizeof(jint), height, pf, flags)==-1)
 	{
-		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-		(*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
-		dstbuf=srcbuf=NULL;
+		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+		(*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);
+		dstBuf=jpegBuf=NULL;
 		_throw(tjGetErrorStr());
 	}
 
 	bailout:
-	if(dstbuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-	if(srcbuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
+	if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);
 	return;
 }
 
 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV
-	(JNIEnv *env, jobject obj, jbyteArray src, jint size, jbyteArray dst,
+	(JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
 		jint flags)
 {
 	tjhandle handle=0;
-	unsigned char *srcbuf=NULL, *dstbuf=NULL;
+	unsigned char *jpegBuf=NULL, *dstBuf=NULL;
 	int jpegSubsamp=-1, jpegWidth=0, jpegHeight=0;
 
 	gethandle();
 
-	if((*env)->GetArrayLength(env, src)<size)
+	if((*env)->GetArrayLength(env, src)<jpegSize)
 		_throw("Source buffer is not large enough");
 	bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
 	jpegSubsamp=(int)(*env)->GetIntField(env, obj, _fid);
@@ -453,20 +452,21 @@
 		<(jsize)TJBUFSIZEYUV(jpegWidth, jpegHeight, jpegSubsamp))
 		_throw("Destination buffer is not large enough");
 
-	bailif0(srcbuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
-	bailif0(dstbuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
+	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
+	bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
-	if(tjDecompressToYUV(handle, srcbuf, (unsigned long)size, dstbuf, flags)==-1)
+	if(tjDecompressToYUV(handle, jpegBuf, (unsigned long)jpegSize, dstBuf,
+		flags)==-1)
 	{
-		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-		(*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
-		dstbuf=srcbuf=NULL;
+		(*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+		(*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);
+		dstBuf=jpegBuf=NULL;
 		_throw(tjGetErrorStr());
 	}
 
 	bailout:
-	if(dstbuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstbuf, 0);
-	if(srcbuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcbuf, 0);
+	if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
+	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);
 	return;
 }
 
@@ -488,19 +488,19 @@
 }
 
 JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transform
-	(JNIEnv *env, jobject obj, jbyteArray jsrcbuf, jint srcsize,
+	(JNIEnv *env, jobject obj, jbyteArray jsrcBuf, jint jpegSize,
 		jobjectArray dstobjs, jobjectArray tobjs, jint flags)
 {
 	tjhandle handle=0;  int i;
-	unsigned char *srcbuf=NULL, **dstbufs=NULL;  jsize n=0;
-	unsigned long *dstsizes=NULL;  tjtransform *t=NULL;
-	jbyteArray *jdstbufs=NULL;
+	unsigned char *jpegBuf=NULL, **dstBufs=NULL;  jsize n=0;
+	unsigned long *dstSizes=NULL;  tjtransform *t=NULL;
+	jbyteArray *jdstBufs=NULL;
 	int jpegWidth=0, jpegHeight=0;
-	jintArray jdstsizes=0;  jint *dstsizesi=NULL;
+	jintArray jdstSizes=0;  jint *dstSizesi=NULL;
 
 	gethandle();
 
-	if((*env)->GetArrayLength(env, jsrcbuf)<srcsize)
+	if((*env)->GetArrayLength(env, jsrcBuf)<jpegSize)
 		_throw("Source buffer is not large enough");
 	bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
 	jpegWidth=(int)(*env)->GetIntField(env, obj, _fid);
@@ -511,17 +511,17 @@
 	if(n!=(*env)->GetArrayLength(env, tobjs))
 		_throw("Mismatch between size of transforms array and destination buffers array");
 
-	if((dstbufs=(unsigned char **)malloc(sizeof(unsigned char *)*n))==NULL)
+	if((dstBufs=(unsigned char **)malloc(sizeof(unsigned char *)*n))==NULL)
 		_throw("Memory allocation failure");
-	if((jdstbufs=(jbyteArray *)malloc(sizeof(jbyteArray)*n))==NULL)
+	if((jdstBufs=(jbyteArray *)malloc(sizeof(jbyteArray)*n))==NULL)
 		_throw("Memory allocation failure");
-	if((dstsizes=(unsigned long *)malloc(sizeof(unsigned long)*n))==NULL)
+	if((dstSizes=(unsigned long *)malloc(sizeof(unsigned long)*n))==NULL)
 		_throw("Memory allocation failure");
 	if((t=(tjtransform *)malloc(sizeof(tjtransform)*n))==NULL)
 		_throw("Memory allocation failure");
 	for(i=0; i<n; i++)
 	{
-		dstbufs[i]=NULL;  jdstbufs[i]=NULL;  dstsizes[i]=0;
+		dstBufs[i]=NULL;  jdstBufs[i]=NULL;  dstSizes[i]=0;
 		memset(&t[i], 0, sizeof(tjtransform));
 	}
 
@@ -545,50 +545,51 @@
 		t[i].r.h=(*env)->GetIntField(env, tobj, _fid);
 	}
 
-	bailif0(srcbuf=(*env)->GetPrimitiveArrayCritical(env, jsrcbuf, 0));
+	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0));
 	for(i=0; i<n; i++)
 	{
 		int w=jpegWidth, h=jpegHeight;
 		if(t[i].r.w!=0) w=t[i].r.w;
 		if(t[i].r.h!=0) h=t[i].r.h;
-		bailif0(jdstbufs[i]=(*env)->GetObjectArrayElement(env, dstobjs, i));
-		if((*env)->GetArrayLength(env, jdstbufs[i])<TJBUFSIZE(w, h))
+		bailif0(jdstBufs[i]=(*env)->GetObjectArrayElement(env, dstobjs, i));
+		if((*env)->GetArrayLength(env, jdstBufs[i])<TJBUFSIZE(w, h))
 			_throw("Destination buffer is not large enough");
-		bailif0(dstbufs[i]=(*env)->GetPrimitiveArrayCritical(env, jdstbufs[i], 0));
+		bailif0(dstBufs[i]=(*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0));
 	}
 
-	if(tjTransform(handle, srcbuf, srcsize, n, dstbufs, dstsizes, t, flags)==-1)
+	if(tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t,
+		flags)==-1)
 	{
-		(*env)->ReleasePrimitiveArrayCritical(env, jsrcbuf, srcbuf, 0);
-		srcbuf=NULL;
+		(*env)->ReleasePrimitiveArrayCritical(env, jsrcBuf, jpegBuf, 0);
+		jpegBuf=NULL;
 		for(i=0; i<n; i++)
 		{
-			(*env)->ReleasePrimitiveArrayCritical(env, jdstbufs[i], dstbufs[i], 0);
-			dstbufs[i]=NULL;
+			(*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0);
+			dstBufs[i]=NULL;
 		}
 		_throw(tjGetErrorStr());
 	}
 
-	jdstsizes=(*env)->NewIntArray(env, n);
-	bailif0(dstsizesi=(*env)->GetIntArrayElements(env, jdstsizes, 0));
-	for(i=0; i<n; i++) dstsizesi[i]=(int)dstsizes[i];
+	jdstSizes=(*env)->NewIntArray(env, n);
+	bailif0(dstSizesi=(*env)->GetIntArrayElements(env, jdstSizes, 0));
+	for(i=0; i<n; i++) dstSizesi[i]=(int)dstSizes[i];
 
 	bailout:
-	if(srcbuf) (*env)->ReleasePrimitiveArrayCritical(env, jsrcbuf, srcbuf, 0);
-	if(dstbufs)
+	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, jsrcBuf, jpegBuf, 0);
+	if(dstBufs)
 	{
 		for(i=0; i<n; i++)
 		{
-			if(dstbufs[i] && jdstbufs && jdstbufs[i])
-				(*env)->ReleasePrimitiveArrayCritical(env, jdstbufs[i], dstbufs[i], 0);
+			if(dstBufs[i] && jdstBufs && jdstBufs[i])
+				(*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0);
 		}
-		free(dstbufs);
+		free(dstBufs);
 	}
-	if(jdstbufs) free(jdstbufs);
-	if(dstsizes) free(dstsizes);
-	if(dstsizesi) (*env)->ReleaseIntArrayElements(env, jdstsizes, dstsizesi, 0);
+	if(jdstBufs) free(jdstBufs);
+	if(dstSizes) free(dstSizes);
+	if(dstSizesi) (*env)->ReleaseIntArrayElements(env, jdstSizes, dstSizesi, 0);
 	if(t) free(t);
-	return jdstsizes;
+	return jdstSizes;
 }
 
 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy
diff --git a/turbojpeg-mapfile b/turbojpeg-mapfile
index 293bd42..5f896b7 100755
--- a/turbojpeg-mapfile
+++ b/turbojpeg-mapfile
@@ -25,6 +25,9 @@
 TURBOJPEG_1.2
 {
 	global:
+		tjCompress2
+		tjDecompress2
+		tjEncodeYUV2
 		tjGetScalingFactors;
 		tjInitTransform;
 		tjTransform;
diff --git a/turbojpeg.h b/turbojpeg.h
index e075277..c7463bf 100644
--- a/turbojpeg.h
+++ b/turbojpeg.h
@@ -1,519 +1,767 @@
-/* Copyright (C)2004 Landmark Graphics Corporation
- * Copyright (C)2005, 2006 Sun Microsystems, Inc.
- * Copyright (C)2009-2011 D. R. Commander
+/*
+ * Copyright (C)2009-2011 D. R. Commander.  All Rights Reserved.
  *
- * This library is free software and may be redistributed and/or modified under
- * the terms of the wxWindows Library License, Version 3.1 or (at your option)
- * any later version.  The full license is in the LICENSE.txt file included
- * with this distribution.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
  *
- * 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
- * wxWindows Library License for more details.
+ * - 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.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ *   contributors may 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 HOLDERS 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.
  */
 
-#if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) && defined(_WIN32) && defined(DLLDEFINE)
+#if defined(_WIN32) && defined(DLLDEFINE)
 #define DLLEXPORT __declspec(dllexport)
 #else
 #define DLLEXPORT
 #endif
-
 #define DLLCALL
 
-/* Subsampling */
-#define NUMSUBOPT 5
 
-enum {TJ_444=0, TJ_422, TJ_420, TJ_GRAYSCALE, TJ_440};
-#define TJ_411 TJ_420  /* for backward compatibility with VirtualGL <= 2.1.x,
-                          TurboVNC <= 0.6, and TurboJPEG/IPP */
+/**
+ * @addtogroup TurboJPEG
+ * TurboJPEG API.  This API provides an interface for generating, decoding, and
+ * transforming planar YUV and JPEG images in memory.
+ *
+ * @{
+ */
 
-/* MCU block sizes:
-   8x8 for no subsampling or grayscale
-   16x8 for 4:2:2
-   8x16 for 4:4:0
-   16x16 for 4:2:0 */
-static const int tjmcuw[NUMSUBOPT]={8, 16, 16, 8, 8};
-static const int tjmcuh[NUMSUBOPT]={8, 8, 16, 8, 16};
 
-/* Flags */
-#define TJ_BGR             1
-  /* The components of each pixel in the uncompressed source/destination image
-     are stored in B,G,R order, not R,G,B */
-#define TJ_BOTTOMUP        2
-  /* The uncompressed source/destination image is stored in bottom-up (Windows,
-     OpenGL) order, not top-down (X11) order */
-#define TJ_FORCEMMX        8
-  /* Turn off CPU auto-detection and force TurboJPEG to use MMX code
-     (IPP and 32-bit libjpeg-turbo versions only) */
-#define TJ_FORCESSE       16
-  /* Turn off CPU auto-detection and force TurboJPEG to use SSE code
-     (32-bit IPP and 32-bit libjpeg-turbo versions only) */
-#define TJ_FORCESSE2      32
-  /* Turn off CPU auto-detection and force TurboJPEG to use SSE2 code
-     (32-bit IPP and 32-bit libjpeg-turbo versions only) */
-#define TJ_ALPHAFIRST     64
-  /* If the uncompressed source/destination image has 32 bits per pixel,
-     assume that each pixel is ARGB/XRGB (or ABGR/XBGR if TJ_BGR is also
-     specified) */
-#define TJ_FORCESSE3     128
-  /* Turn off CPU auto-detection and force TurboJPEG to use SSE3 code
-     (64-bit IPP version only) */
-#define TJ_FASTUPSAMPLE  256
-  /* Use fast, inaccurate chrominance upsampling routines in the JPEG
-     decompressor (libjpeg and libjpeg-turbo versions only) */
-#define TJ_YUV           512
-  /* Nothing to see here.  Pay no attention to the man behind the curtain. */
+/**
+ * The number of chrominance subsampling options
+ */
+#define TJ_NUMSAMP 5
 
-/* Scaling factor structure */
-typedef struct
+/**
+ * Chrominance subsampling options.
+ * @anchor subsamp
+ * When an image is converted from the RGB to the YCbCr colorspace as part of
+ * the JPEG compression process, some of the Cb and Cr (chrominance) components
+ * can be discarded or averaged together to produce a smaller image with little
+ * perceptible loss of image clarity (the human eye is more sensitive to small
+ * changes in brightness than small changes in color.)  This is called
+ * "chrominance subsampling".
+ */
+enum
 {
-	int num, denom;
-} tjscalingfactor;
-
-/* Transform operations for tjTransform() */
-#define NUMXFORMOPT 8
-
-enum {
-TJXFORM_NONE=0,     /* Do not transform the position of the image pixels */
-TJXFORM_HFLIP,      /* Flip (mirror) image horizontally.  This transform is
-                       imperfect if there are any partial MCU blocks on the
-                       right edge (see below for explanation.) */
-TJXFORM_VFLIP,      /* Flip (mirror) image vertically.  This transform is
-                       imperfect if there are any partial MCU blocks on the
-                       bottom edge. */
-TJXFORM_TRANSPOSE,  /* Transpose image (flip/mirror along upper left to lower
-                       right axis.)  This transform is always perfect. */
-TJXFORM_TRANSVERSE, /* Transverse transpose image (flip/mirror along upper
-                       right to lower left axis.)  This transform is imperfect
-                       if there are any partial MCU blocks in the image. */
-TJXFORM_ROT90,      /* Rotate image clockwise by 90 degrees.  This transform
-                       is imperfect if there are any partial MCU blocks on the
-                       bottom edge. */
-TJXFORM_ROT180,     /* Rotate image 180 degrees.  This transform is imperfect
-                       if there are any partial MCU blocks in the image. */
-TJXFORM_ROT270      /* Rotate image counter-clockwise by 90 degrees.  This
-                       transform is imperfect if there are any partial MCU
-                       blocks on the right edge. */
+  /**
+   * 4:4:4 chrominance subsampling (no chrominance subsampling).  The JPEG or
+   * YUV image will contain one chrominance component for every pixel in the
+   * source image.
+   */
+  TJ_444=0,
+  /**
+   * 4:2:2 chrominance subsampling.  The JPEG or YUV image will contain one
+   * chrominance component for every 2x1 block of pixels in the source image.
+   */
+  TJ_422,
+  /**
+   * 4:2:0 chrominance subsampling.  The JPEG or YUV image will contain one
+   * chrominance component for every 2x2 block of pixels in the source image.
+   */
+  TJ_420,
+  /**
+   * Grayscale.  The JPEG or YUV image will contain no chrominance components.
+   */
+  TJ_GRAYSCALE,
+  /**
+   * 4:4:0 chrominance subsampling.  The JPEG or YUV image will contain one
+   * chrominance component for every 1x2 block of pixels in the source image.
+   */
+  TJ_440
 };
 
-/* Transform options (these can be OR'ed together) */
-#define TJXFORM_PERFECT  1
-  /* This will cause the tjTransform() function to return an error if the
-     transform is not perfect.  Lossless transforms operate on MCU blocks,
-     whose size depends on the level of chrominance subsampling used (see
-     "MCU block sizes" above).  If the image's width or height is not evenly
-     divisible by the MCU block size, then there will be partial MCU blocks on
-     the right and/or bottom edges.  It is not possible to move these partial
-     MCU blocks to the top or left of the image, so any transform that would
-     require that is "imperfect."  If this option is not specified, then any
-     partial MCU blocks that cannot be transformed will be left in place, which
-     will create odd-looking strips on the right or bottom edge of the image.
-     */
-#define TJXFORM_TRIM     2
-  /* This option will cause tjTransform() to discard any partial MCU blocks
-     that cannot be transformed. */
-#define TJXFORM_CROP     4
-  /* This option will enable lossless cropping.  See the description of
-     tjTransform() below for more information. */
-#define TJXFORM_GRAY     8
-  /* This option will discard the color data in the input image and produce
-     a grayscale output image. */
+/**
+ * MCU block width (in pixels) for a given level of chrominance subsampling.
+ * MCU block sizes:
+ * - 8x8 for no subsampling or grayscale
+ * - 16x8 for 4:2:2
+ * - 8x16 for 4:4:0
+ * - 16x16 for 4:2:0 
+ */
+static const int tjMCUWidth[TJ_NUMSAMP]  = {8, 16, 16, 8, 8};
 
+/**
+ * MCU block height (in pixels) for a given level of chrominance subsampling.
+ * MCU block sizes:
+ * - 8x8 for no subsampling or grayscale
+ * - 16x8 for 4:2:2
+ * - 8x16 for 4:4:0
+ * - 16x16 for 4:2:0 
+ */
+static const int tjMCUHeight[TJ_NUMSAMP] = {8, 8, 16, 8, 16};
+
+
+/**
+ * The number of pixel formats
+ */
+#define TJ_NUMPF 7
+
+/**
+ * Pixel formats
+ * @anchor pixelformats
+ */
+enum
+{
+  /**
+   * RGB pixel format.  The red, green, and blue components in the image are
+   * stored in 3-byte pixels in the order R, G, B from lowest to highest byte
+   * address within each pixel.
+   */
+  TJ_RGB=0,
+  /**
+   * BGR pixel format.  The red, green, and blue components in the image are
+   * stored in 3-byte pixels in the order B, G, R from lowest to highest byte
+   * address within each pixel.
+   */
+  TJ_BGR,
+  /**
+   * RGBX pixel format.  The red, green, and blue components in the image are
+   * stored in 4-byte pixels in the order R, G, B from lowest to highest byte
+   * address within each pixel.
+   */
+  TJ_RGBX,
+  /**
+   * BGRX pixel format.  The red, green, and blue components in the image are
+   * stored in 4-byte pixels in the order B, G, R from lowest to highest byte
+   * address within each pixel.
+   */
+  TJ_BGRX,
+  /**
+   * XBGR pixel format.  The red, green, and blue components in the image are
+   * stored in 4-byte pixels in the order R, G, B from highest to lowest byte
+   * address within each pixel.
+   */
+  TJ_XBGR,
+  /**
+   * XRGB pixel format.  The red, green, and blue components in the image are
+   * stored in 4-byte pixels in the order B, G, R from highest to lowest byte
+   * address within each pixel.
+   */
+  TJ_XRGB,
+  /**
+   * Grayscale pixel format.  Each 1-byte pixel represents a luminance
+   * (brightness) level from 0 to 255.
+   */
+  TJ_GRAY
+};
+
+/**
+ * Red offset (in bytes) for a given pixel format.  This specifies the number
+ * of bytes that the red component is offset from the start of the pixel.  For
+ * instance, if a pixel of format TJ_BGRX is stored in <tt>char pixel[]</tt>,
+ * then the red component will be <tt>pixel[tjRedOffset[TJ_BGRX]]</tt>.
+ */
+static const int tjRedOffset[TJ_NUMPF] = {0, 2, 0, 2, 3, 1, 0};
+/**
+ * Green offset (in bytes) for a given pixel format.  This specifies the number
+ * of bytes that the green component is offset from the start of the pixel.
+ * For instance, if a pixel of format TJ_BGRX is stored in
+ * <tt>char pixel[]</tt>, then the green component will be
+ * <tt>pixel[tjGreenOffset[TJ_BGRX]]</tt>.
+ */
+static const int tjGreenOffset[TJ_NUMPF] = {1, 1, 1, 1, 2, 2, 0};
+/**
+ * Blue offset (in bytes) for a given pixel format.  This specifies the number
+ * of bytes that the Blue component is offset from the start of the pixel.  For
+ * instance, if a pixel of format TJ_BGRX is stored in <tt>char pixel[]</tt>,
+ * then the blue component will be <tt>pixel[tjBlueOffset[TJ_BGRX]]</tt>.
+ */
+static const int tjBlueOffset[TJ_NUMPF] = {2, 0, 2, 0, 1, 3, 0};
+
+/**
+ * Pixel size (in bytes) for a given pixel format.
+ */
+static const int tjPixelSize[TJ_NUMPF] = {3, 3, 4, 4, 4, 4, 1};
+
+
+/**
+ * Bottom-up flag.
+ * @anchor flags
+ * The uncompressed source/destination image is stored in bottom-up (Windows,
+ * OpenGL) order, not top-down (X11) order.
+ */
+#define TJ_BOTTOMUP        2
+/**
+ * Force MMX flag.  Turn off CPU auto-detection and force TurboJPEG to use MMX
+ * code (IPP and 32-bit libjpeg-turbo versions only.)
+ */
+#define TJ_FORCEMMX        8
+/**
+ * Force SSE flag.  Turn off CPU auto-detection and force TurboJPEG to use SSE
+ * code (32-bit IPP and 32-bit libjpeg-turbo versions only)
+ */
+#define TJ_FORCESSE       16
+/**
+ * Force SSE2 flag.  Turn off CPU auto-detection and force TurboJPEG to use
+ * SSE2 code (32-bit IPP and 32-bit libjpeg-turbo versions only)
+ */
+#define TJ_FORCESSE2      32
+/**
+ * Force SSE3 flag.  Turn off CPU auto-detection and force TurboJPEG to use
+ * SSE3 code (64-bit IPP version only)
+ */
+#define TJ_FORCESSE3     128
+/**
+ * Fast upsampling flag.  Use fast, inaccurate chrominance upsampling routines
+ * in the JPEG decompressor (libjpeg and libjpeg-turbo versions only)
+ */
+#define TJ_FASTUPSAMPLE  256
+/**
+ * No reallocation flag.  If passed to #tjCompress2() or #tjTransform(), this
+ * flag will cause those functions to generate an error if the JPEG image
+ * buffer is invalid or too small rather than attempting to allocate or
+ * reallocate that buffer.  This reproduces the behavior of earlier versions of
+ * TurboJPEG.
+ */
+#define TJ_NOREALLOC     1024
+
+
+/**
+ * Number of transform operations
+ */
+#define NUMXFORMOPT 8
+
+/**
+ * Transform operations for #tjTransform
+ * @anchor xformop
+ */
+enum
+{
+  /**
+   * Do not transform the position of the image pixels
+   */
+  TJXFORM_NONE=0,
+  /**
+   * Flip (mirror) image horizontally.  This transform is imperfect if there
+   * are any partial MCU blocks on the right edge (see #TJXFORM_PERFECT.)
+   */
+  TJXFORM_HFLIP,
+  /**
+   * Flip (mirror) image vertically.  This transform is imperfect if there are
+   * any partial MCU blocks on the bottom edge (see #TJXFORM_PERFECT.)
+   */
+  TJXFORM_VFLIP,
+  /**
+   * Transpose image (flip/mirror along upper left to lower right axis.)  This
+   * transform is always perfect.
+   */
+  TJXFORM_TRANSPOSE,
+  /**
+   * Transverse transpose image (flip/mirror along upper right to lower left
+   * axis.)  This transform is imperfect if there are any partial MCU blocks in
+   * the image (see #TJXFORM_PERFECT.)
+   */
+  TJXFORM_TRANSVERSE,
+  /**
+   * Rotate image clockwise by 90 degrees.  This transform is imperfect if
+   * there are any partial MCU blocks on the bottom edge (see
+   * #TJXFORM_PERFECT.)
+   */
+  TJXFORM_ROT90,
+  /**
+   * Rotate image 180 degrees.  This transform is imperfect if there are any
+   * partial MCU blocks in the image (see #TJXFORM_PERFECT.)
+   */
+  TJXFORM_ROT180,
+  /**
+   * Rotate image counter-clockwise by 90 degrees.  This transform is imperfect
+   * if there are any partial MCU blocks on the right edge (see
+   * #TJXFORM_PERFECT.)
+   */
+  TJXFORM_ROT270
+};
+
+
+/**
+ * This option will cause #tjTransform to return an error if the transform is
+ * not perfect.  Lossless transforms operate on MCU blocks, whose size depends
+ * on the level of chrominance subsampling used (see #tjMCUWidth
+ * and #tjMCUHeight.)  If the image's width or height is not evenly divisible
+ * by the MCU block size, then there will be partial MCU blocks on the right
+ * and/or bottom edges.  It is not possible to move these partial MCU blocks to
+ * the top or left of the image, so any transform that would require that is
+ * "imperfect."  If this option is not specified, then any partial MCU blocks
+ * that cannot be transformed will be left in place, which will create
+ * odd-looking strips on the right or bottom edge of the image.
+ */
+#define TJXFORM_PERFECT  1
+/**
+ * This option will cause #tjTransform to discard any partial MCU blocks that
+ * cannot be transformed.
+ */
+#define TJXFORM_TRIM     2
+/**
+ * This option will enable lossless cropping.  See #tjTransform for more
+ * information.
+ */
+#define TJXFORM_CROP     4
+/**
+ * This option will discard the color data in the input image and produce
+ * a grayscale output image.
+ * @anchor xformopt
+ */
+#define TJXFORM_GRAY     8
+
+
+/**
+ * Scaling factor
+ */
 typedef struct
 {
-	int x, y, w, h;
+  /**
+   * Numerator
+   */
+  int num;
+  /**
+   * Denominator
+   */
+  int denom;
+} tjscalingfactor;
+
+/**
+ * Cropping region
+ */
+typedef struct
+{
+  /**
+   * The left boundary of the cropping region.  This must be evenly divisible
+   * by the MCU block width (see #tjMCUWidth.)
+   */
+  int x;
+  /**
+   * The upper boundary of the cropping region.  This must be evenly divisible
+   * by the MCU block height (see #tjMCUHeight.)
+   */
+  int y;
+  /**
+   * The width of the cropping region. Setting this to 0 is the equivalent of
+   * setting it to the width of the source JPEG image - x.
+   */
+  int w;
+  /**
+   * The height of the cropping region. Setting this to 0 is the equivalent of
+   * setting it to the height of the source JPEG image - y.
+   */
+  int h;
 } tjregion;
 
+/**
+ * Lossless transform
+ */
 typedef struct
 {
-	tjregion r;
-	int op, options;
+  /**
+   * Cropping region
+   */
+  tjregion r;
+  /**
+   * One of the transform operations (see @ref xformop "Transform operations".)
+   */
+  int op;
+  /**
+   * The bitwise OR of one of more of the transform options (see @ref xformopt
+   * "Transform options".)
+   */
+  int options;
 } tjtransform;
 
+/**
+ * TurboJPEG instance handle
+ */
 typedef void* tjhandle;
 
-#define TJPAD(p) (((p)+3)&(~3))
+
+/**
+ * Pad the given width to the nearest 32-bit boundary
+ */
+#define TJPAD(width) (((width)+3)&(~3))
+
+/**
+ * Compute the scaled value of dimension using the given scaling factor.  This
+ * macro performs the integer equivalent of <tt>ceil(dimension *
+ * scalingFactor)</tt>. 
+ */
+#define TJSCALED(dimension, scalingFactor) ((dimension * scalingFactor.num \
+  + scalingFactor.denom - 1) / scalingFactor.denom)
+
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* API follows */
 
-
-/*
-  tjhandle tjInitCompress(void)
-
-  Creates a new JPEG compressor instance, allocates memory for the structures,
-  and returns a handle to the instance.  Most applications will only
-  need to call this once at the beginning of the program or once for each
-  concurrent thread.  Don't try to create a new instance every time you
-  compress an image, because this may cause performance to suffer in some
-  TurboJPEG implementations.
-
-  RETURNS: NULL on error
-*/
+/**
+ * Create a TurboJPEG compressor instance.
+ *
+ * @return a handle to the newly-created instance, or NULL if an error
+ * occurred (see #tjGetErrorStr().)
+ */
 DLLEXPORT tjhandle DLLCALL tjInitCompress(void);
 
 
-/*
-  int tjCompress(tjhandle hnd,
-     unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
-     unsigned char *dstbuf, unsigned long *size,
-     int jpegsubsamp, int jpegqual, int flags)
-
-  [INPUT] hnd = instance handle previously returned from a call to
-     tjInitCompress() or tjInitTransform()
-  [INPUT] srcbuf = pointer to user-allocated image buffer containing RGB or
-     grayscale pixels to be compressed
-  [INPUT] width = width (in pixels) of the source image
-  [INPUT] pitch = bytes per line of the source image (width*pixelsize if the
-     image is unpadded, else TJPAD(width*pixelsize) if each line of the image
-     is padded to the nearest 32-bit boundary, such as is the case for Windows
-     bitmaps.  You can also be clever and use this parameter to skip lines,
-     etc.  Setting this parameter to 0 is the equivalent of setting it to
-     width*pixelsize.
-  [INPUT] height = height (in pixels) of the source image
-  [INPUT] pixelsize = size (in bytes) of each pixel in the source image
-     RGBX/BGRX/XRGB/XBGR: 4, RGB/BGR: 3, Grayscale: 1
-  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
-     the JPEG image.  Use the TJBUFSIZE(width, height) function to determine
-     the maximum size for this buffer based on the image width and height.
-  [OUTPUT] size = pointer to unsigned long which receives the actual size (in
-     bytes) of the JPEG image
-  [INPUT] jpegsubsamp = Specifies the level of chrominance subsampling.  When
-     the image is converted from the RGB to YCbCr colorspace as part of the
-     JPEG compression process, some of the Cb and Cr (chrominance) components
-     can be discarded or averaged together to produce a smaller image with
-     little perceptible loss of image clarity (the human eye is more sensitive
-     to small changes in brightness than small changes in color.)
-
-     TJ_420: 4:2:0 subsampling.  The JPEG image will contain one chrominance
-        component for every 2x2 block of pixels in the source image.
-     TJ_422: 4:2:2 subsampling.  The JPEG image will contain one chrominance
-        component for every 2x1 block of pixels in the source image.
-     TJ_440: 4:4:0 subsampling.  The JPEG image will contain one chrominance
-        component for every 1x2 block of pixels in the source image.
-     TJ_444: no subsampling.  The JPEG image will contain one chrominance
-        component for every pixel in the source image.
-     TJ_GRAYSCALE: Generate grayscale JPEG image.  The JPEG image will contain
-        no chrominance components.
-
-  [INPUT] jpegqual = JPEG quality (an integer between 0 and 100 inclusive)
-  [INPUT] flags = the bitwise OR of one or more of the flags described in the
-     "Flags" section above
-
-  RETURNS: 0 on success, -1 on error
+/**
+ * Compress an RGB or grayscale image into a JPEG image.
+ *
+ * @param handle a handle to a TurboJPEG compressor or transformer instance
+ * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels
+ *        to be compressed
+ * @param width width (in pixels) of the source image
+ * @param pitch bytes per line of the source image.  Normally, this should be
+ *        <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded,
+ *        or <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of
+ *        the image is padded to the nearest 32-bit boundary, as is the case
+ *        for Windows bitmaps.  You can also be clever and use this parameter
+ *        to skip lines, etc.  Setting this parameter to 0 is the equivalent of
+ *        setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ * @param height height (in pixels) of the source image
+ * @param pixelFormat pixel format of the source image (see @ref pixelformats
+ *        "Pixel formats".)
+ * @param jpegBuf address of a pointer to an image buffer that will receive the
+ *        JPEG image.  TurboJPEG has the ability to reallocate the JPEG buffer
+ *        to accommodate the size of the JPEG image.  Thus, you can choose to:
+ *        -# pre-allocate the JPEG buffer with an arbitrary size and let
+ *        TurboJPEG grow the buffer as needed,
+ *        -# set <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the
+ *        buffer for you, or
+ *        -# pre-allocate the buffer to a "worst case" size determined by
+ *        calling #TJBUFSIZE().  This should ensure that the buffer never has
+ *        to be re-allocated (setting the #TJ_NOREALLOC flag guarantees this.)
+ *        .
+ *        If you choose option 1 or 3, <tt>*jpegSize</tt> should be set to the
+ *        size of your pre-allocated buffer.  In any case, unless you have
+ *        set the #TJ_NOREALLOC flag, you should always check
+ *        <tt>*jpegBuf</tt> upon return from this function, as it may have
+ *        changed.
+ * @param jpegSize pointer to an unsigned long variable which holds the size of
+ *        the JPEG image buffer.  If <tt>*jpegBuf</tt> points to a
+ *        pre-allocated buffer, then <tt>*jpegSize</tt> should be set to the
+ *        size of the buffer.  Upon return, <tt>*jpegSize</tt> will contain the
+ *        size of the JPEG image (in bytes.)
+ * @param jpegSubsamp the level of chrominance subsampling to be used when
+ *        generating the JPEG image (see @ref subsamp
+ *        "Chrominance subsampling options".)
+ * @param jpegQual the image quality of the generated JPEG image (1 = worst,
+          100 = best)
+ * @param flags the bitwise OR of one or more of the @ref flags.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
 */
-DLLEXPORT int DLLCALL tjCompress(tjhandle hnd,
-	unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
-	unsigned char *dstbuf, unsigned long *size,
-	int jpegsubsamp, int jpegqual, int flags);
+DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
+  int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
+  unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags);
 
 
-/*
-  unsigned long TJBUFSIZE(int width, int height)
-
-  Convenience function which returns the maximum size of the buffer required to
-  hold a JPEG image with the given width and height
-
-  RETURNS: -1 if arguments are out of bounds
-*/
+/**
+ * The maximum size of the buffer (in bytes) required to hold a JPEG image with
+ * the given parameters.
+ *
+ * @param width width of the image (in pixels)
+ * @param height height of the image (in pixels)
+ *
+ * @return the maximum size of the buffer (in bytes) required to hold the
+ * image, or -1 if the arguments are out of bounds.
+ */
 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height);
 
 
-/*
-  unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
-
-  Convenience function which returns the size of the buffer required to
-  hold a YUV planar image with the given width, height, and level of
-  chrominance subsampling
-
-  RETURNS: -1 if arguments are out of bounds
-*/
+/**
+ * The size of the buffer (in bytes) required to hold a YUV planar image with
+ * the given parameters.
+ *
+ * @param width width of the image (in pixels)
+ * @param height height of the image (in pixels)
+ * @param jpegSubsamp level of chrominance subsampling in the image (see
+ *        @ref subsamp "Chrominance subsampling options".)
+ *
+ * @return the size of the buffer (in bytes) required to hold the image, or
+ * -1 if the arguments are out of bounds.
+ */
 DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
-  int subsamp);
+  int jpegSubsamp);
 
 
-/*
-  int tjEncodeYUV(tjhandle hnd,
-     unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
-     unsigned char *dstbuf, int subsamp, int flags)
-
-  This function uses the accelerated color conversion routines in TurboJPEG's
-  underlying codec to produce a planar YUV image that is suitable for X Video.
-  Specifically, if the chrominance components are subsampled along the
-  horizontal dimension, then the width of the luminance plane is padded to 2 in
-  the output image (same goes for the height of the luminance plane, if the
-  chrominance components are subsampled along the vertical dimension.)  Also,
-  each line of each plane in the output image is padded to 4 bytes.  Although
-  this will work with any subsampling option, it is really only useful in
-  combination with TJ_420, which produces an image compatible with the I420
-  (AKA "YUV420P") format.
-
-  [INPUT] hnd = instance handle previously returned from a call to
-     tjInitCompress() or tjInitTransform()
-  [INPUT] srcbuf = pointer to user-allocated image buffer containing RGB or
-     grayscale pixels to be encoded
-  [INPUT] width = width (in pixels) of the source image
-  [INPUT] pitch = bytes per line of the source image (width*pixelsize if the
-     image is unpadded, else TJPAD(width*pixelsize) if each line of the image
-     is padded to the nearest 32-bit boundary, such as is the case for Windows
-     bitmaps.  You can also be clever and use this parameter to skip lines,
-     etc.  Setting this parameter to 0 is the equivalent of setting it to
-     width*pixelsize.
-  [INPUT] height = height (in pixels) of the source image
-  [INPUT] pixelsize = size (in bytes) of each pixel in the source image
-     RGBX/BGRX/XRGB/XBGR: 4, RGB/BGR: 3, Grayscale: 1
-  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
-     the YUV image.  Use the TJBUFSIZEYUV(width, height, subsamp) function to
-     determine the appropriate size for this buffer based on the image width,
-     height, and level of subsampling.
-  [INPUT] subsamp = specifies the level of chrominance subsampling for the
-     YUV image.  See description under tjCompress())
-  [INPUT] flags = the bitwise OR of one or more of the flags described in the
-     "Flags" section above
-
-  RETURNS: 0 on success, -1 on error
+/**
+ * Encode an RGB or grayscale image into a YUV planar image.  This function
+ * uses the accelerated color conversion routines in TurboJPEG's underlying
+ * codec to produce a planar YUV image that is suitable for X Video.
+ * Specifically, if the chrominance components are subsampled along the
+ * horizontal dimension, then the width of the luminance plane is padded to 2
+ * in the output image (same goes for the height of the luminance plane, if the
+ * chrominance components are subsampled along the vertical dimension.)  Also,
+ * each line of each plane in the output image is padded to 4 bytes.  Although
+ * this will work with any subsampling option, it is really only useful in
+ * combination with TJ_420, which produces an image compatible with the I420
+ * (AKA "YUV420P") format.
+ *
+ * @param handle a handle to a TurboJPEG compressor or transformer instance
+ * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels
+ *        to be encoded
+ * @param width width (in pixels) of the source image
+ * @param pitch bytes per line of the source image.  Normally, this should be
+ *        <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded,
+ *        or <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of
+ *        the image is padded to the nearest 32-bit boundary, as is the case
+ *        for Windows bitmaps.  You can also be clever and use this parameter
+ *        to skip lines, etc.  Setting this parameter to 0 is the equivalent of
+ *        setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ * @param height height (in pixels) of the source image
+ * @param pixelFormat pixel format of the source image (see @ref pixelformats
+ *        "Pixel formats".)
+ * @param dstBuf pointer to an image buffer which will receive the YUV image.
+ *        Use #TJBUFSIZEYUV() to determine the appropriate size for this buffer
+ *        based on the image width, height, and level of chrominance
+ *        subsampling.
+ * @param subsamp the level of chrominance subsampling to be used when
+ *        generating the YUV image (see @ref subsamp
+ *        "Chrominance subsampling options".)
+ * @param flags the bitwise OR of one or more of the @ref flags.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
 */
-DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle hnd,
-	unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
-	unsigned char *dstbuf, int subsamp, int flags);
+DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle,
+  unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat,
+  unsigned char *dstBuf, int subsamp, int flags);
 
 
-/*
-  tjhandle tjInitDecompress(void)
-
-  Creates a new JPEG decompressor instance, allocates memory for the
-  structures, and returns a handle to the instance.  Most applications will
-  only need to call this once at the beginning of the program or once for each
-  concurrent thread.  Don't try to create a new instance every time you
-  decompress an image, because this may cause performance to suffer in some
-  TurboJPEG implementations.
-
-  RETURNS: NULL on error
+/**
+ * Create a TurboJPEG decompressor instance.
+ *
+ * @return a handle to the newly-created instance, or NULL if an error
+ * occurred (see #tjGetErrorStr().)
 */
 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void);
 
 
-/*
-  int tjDecompressHeader2(tjhandle hnd,
-     unsigned char *srcbuf, unsigned long size,
-     int *width, int *height, int *jpegsubsamp)
-
-  [INPUT] hnd = instance handle previously returned from a call to
-     tjInitDecompress() or tjInitTransform()
-  [INPUT] srcbuf = pointer to a user-allocated buffer containing a JPEG image
-  [INPUT] size = size of the JPEG image buffer (in bytes)
-  [OUTPUT] width = width (in pixels) of the JPEG image
-  [OUTPUT] height = height (in pixels) of the JPEG image
-  [OUTPUT] jpegsubsamp = type of chrominance subsampling used when compressing
-     the JPEG image
-
-  RETURNS: 0 on success, -1 on error
+/**
+ * Retrieve information about a JPEG image without decompressing it.
+ *
+ * @param handle a handle to a TurboJPEG decompressor or transformer instance
+ * @param jpegBuf pointer to a buffer containing a JPEG image
+ * @param jpegSize size of the JPEG image (in bytes)
+ * @param width pointer to an integer variable which will receive the width (in
+ *        pixels) of the JPEG image
+ * @param height pointer to an integer variable which will receive the height
+ *        (in pixels) of the JPEG image
+ * @param jpegSubsamp pointer to an integer variable which will receive the
+ *        level of chrominance subsampling used when compressing the JPEG image
+ *        (see @ref subsamp "Chrominance subsampling options".)
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
 */
-DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long size,
-	int *width, int *height, int *jpegsubsamp);
-
-/*
-  Legacy version of the above function
-*/
-DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long size,
-	int *width, int *height);
+DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
+  unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
+  int *jpegSubsamp);
 
 
-/*
-  tjscalingfactor *tjGetScalingFactors(int *numscalingfactors)
-
-  Returns a list of fractional scaling factors that the JPEG decompressor in
-  this implementation of TurboJPEG supports.
-
-  [OUTPUT] numscalingfactors = the size of the list
-
-  RETURNS: NULL on error
+/**
+ * Returns a list of fractional scaling factors that the JPEG decompressor in
+ * this implementation of TurboJPEG supports.
+ *
+ * @param numscalingfactors pointer to an integer variable that will receive
+ *        the number of elements in the list
+ *
+ * @return a pointer to a list of fractional scaling factors, or NULL if an
+ * error is encountered (see #tjGetErrorStr().)
 */
 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors);
 
 
-/*
-  int tjDecompress(tjhandle hnd,
-     unsigned char *srcbuf, unsigned long size,
-     unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,
-     int flags)
-
-  [INPUT] hnd = instance handle previously returned from a call to
-     tjInitDecompress() or tjInitTransform()
-  [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
-     to decompress
-  [INPUT] size = size of the JPEG image buffer (in bytes)
-  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
-     the decompressed image.  This buffer should normally be
-     pitch*scaled_height bytes in size, where scaled_height is
-     ceil(jpeg_height*scaling_factor), and the supported scaling factors can be
-     determined by calling tjGetScalingFactors().  The dstbuf pointer may also
-     be used to decompress into a specific region of a larger buffer.
-  [INPUT] width = desired width (in pixels) of the destination image.  If this
-     is smaller than the width of the JPEG image being decompressed, then
-     TurboJPEG will use scaling in the JPEG decompressor to generate the
-     largest possible image that will fit within the desired width.  If width
-     is set to 0, then only the height will be considered when determining the
-     scaled image size.
-  [INPUT] pitch = bytes per line of the destination image.  Normally, this is
-     scaled_width*pixelsize if the decompressed image is unpadded, else
-     TJPAD(scaled_width*pixelsize) if each line of the decompressed image is
-     padded to the nearest 32-bit boundary, such as is the case for Windows
-     bitmaps.  (NOTE: scaled_width = ceil(jpeg_width*scaling_factor).)  You can
-     also be clever and use this parameter to skip lines, etc.  Setting this
-     parameter to 0 is the equivalent of setting it to scaled_width*pixelsize.
-  [INPUT] height = desired height (in pixels) of the destination image.  If
-     this is smaller than the height of the JPEG image being decompressed, then
-     TurboJPEG will use scaling in the JPEG decompressor to generate the
-     largest possible image that will fit within the desired height.  If
-     height is set to 0, then only the width will be considered when
-     determining the scaled image size.
-  [INPUT] pixelsize = size (in bytes) of each pixel in the destination image
-     RGBX/BGRX/XRGB/XBGR: 4, RGB/BGR: 3, Grayscale: 1
-  [INPUT] flags = the bitwise OR of one or more of the flags described in the
-     "Flags" section above.
-
-  RETURNS: 0 on success, -1 on error
-*/
-DLLEXPORT int DLLCALL tjDecompress(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long size,
-	unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,
-	int flags);
+/**
+ * Decompress a JPEG image to an RGB or grayscale image.
+ *
+ * @param handle a handle to a TurboJPEG decompressor or transformer instance
+ * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
+ * @param jpegSize size of the JPEG image (in bytes)
+ * @param dstBuf pointer to an image buffer which will receive the decompressed
+ *        image.  This buffer should normally be <tt>pitch * scaledHeight</tt>
+ *        bytes in size, where <tt>scaledHeight</tt> can be determined by
+ *        calling #TJSCALED() with the JPEG image height and one of the scaling
+ *        factors returned by #tjGetScalingFactors().  The dstBuf pointer may
+ *        also be used to decompress into a specific region of a larger buffer.
+ * @param width desired width (in pixels) of the destination image.  If this is
+ *        smaller than the width of the JPEG image being decompressed, then
+ *        TurboJPEG will use scaling in the JPEG decompressor to generate the
+ *        largest possible image that will fit within the desired width.  If
+ *        width is set to 0, then only the height will be considered when
+ *        determining the scaled image size.
+ * @param pitch bytes per line of the destination image.  Normally, this is
+ *        <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt> if the decompressed
+ *        image is unpadded, else <tt>#TJPAD(scaledWidth *
+ *        #tjPixelSize[pixelFormat])</tt> if each line of the decompressed
+ *        image is padded to the nearest 32-bit boundary, as is the case for
+ *        Windows bitmaps.  (NOTE: <tt>scaledWidth</tt> can be determined by
+ *        calling #TJSCALED() with the JPEG image width and one of the scaling
+ *        factors returned by #tjGetScalingFactors().)  You can also be clever
+ *        and use the pitch parameter to skip lines, etc.  Setting this
+ *        parameter to 0 is the equivalent of setting it to <tt>scaledWidth
+ *        * #tjPixelSize[pixelFormat]</tt>.
+ * @param height desired height (in pixels) of the destination image.  If this
+ *        is smaller than the height of the JPEG image being decompressed, then
+ *        TurboJPEG will use scaling in the JPEG decompressor to generate the
+ *        largest possible image that will fit within the desired height.  If
+ *        height is set to 0, then only the width will be considered when
+ *        determining the scaled image size.
+ * @param pixelFormat pixel format of the destination image (see @ref
+ *        pixelformats "Pixel formats".)
+ * @param flags the bitwise OR of one or more of the @ref flags.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
+ */
+DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
+  unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
+  int width, int pitch, int height, int pixelFormat, int flags);
 
 
-/*
-  int tjDecompressToYUV(tjhandle hnd,
-     unsigned char *srcbuf, unsigned long size,
-     unsigned char *dstbuf, int flags)
-
-  This function performs JPEG decompression but leaves out the color conversion
-  step, so a planar YUV image is generated instead of an RGB image.  The
-  padding of the planes in this image is the same as the images generated
-  by tjEncodeYUV().  Note that, if the width or height of the image is not an
-  even multiple of the MCU block size (see "MCU block sizes" above), then an
-  intermediate buffer copy will be performed within TurboJPEG.
-
-  [INPUT] hnd = instance handle previously returned from a call to
-     tjInitDecompress() or tjInitTransform()
-  [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
-     to decompress
-  [INPUT] size = size of the JPEG image buffer (in bytes)
-  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
-     the YUV image.  Use the TJBUFSIZEYUV(width, height, subsamp) function to
-     determine the appropriate size for this buffer based on the image width,
-     height, and level of subsampling.
-  [INPUT] flags = the bitwise OR of one or more of the flags described in the
-     "Flags" section above.
-
-  RETURNS: 0 on success, -1 on error
-*/
-DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long size,
-	unsigned char *dstbuf, int flags);
+/**
+ * Decompress a JPEG image to a YUV planar image.  This function performs JPEG
+ * decompression but leaves out the color conversion step, so a planar YUV
+ * image is generated instead of an RGB image.  The padding of the planes in
+ * this image is the same as the images generated by #tjEncodeYUV2().  Note
+ * that, if the width or height of the image is not an even multiple of the MCU
+ * block size (see #tjMCUWidth and #tjMCUHeight), then an intermediate buffer
+ * copy will be performed within TurboJPEG.
+ *
+ * @param handle a handle to a TurboJPEG decompressor or transformer instance
+ * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
+ * @param jpegSize size of the JPEG image (in bytes)
+ * @param dstBuf pointer to an image buffer which will receive the YUV image.
+ *        Use #TJBUFSIZEYUV to determine the appropriate size for this buffer
+ *        based on the image width, height, and level of subsampling.
+ * @param flags the bitwise OR of one or more of the @ref flags.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
+ */
+DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
+  unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
+  int flags);
 
 
-/*
-  tjhandle tjInitTransform(void)
-
-  Creates a new JPEG transformer instance, allocates memory for the structures,
-  and returns a handle to the instance.  Most applications will only need to
-  call this once at the beginning of the program or once for each concurrent
-  thread.  Don't try to create a new instance every time you transform an
-  image, because this may cause performance to suffer in some TurboJPEG
-  implementations.
-
-  RETURNS: NULL on error
-*/
+/**
+ * Create a new TurboJPEG transformer instance.
+ *
+ * @return a handle to the newly-created instance, or NULL if an error
+ * occurred (see #tjGetErrorStr().)
+ */
 DLLEXPORT tjhandle DLLCALL tjInitTransform(void);
 
 
-/*
-  int tjTransform(tjhandle hnd,
-     unsigned char *srcbuf, unsigned long srcsize,
-     int n, unsigned char **dstbufs, unsigned long *dstsizes,
-     tjtransform *transforms, int flags);
-
-  This function can losslessly transform a JPEG image into another JPEG image.
-  Lossless transforms work by moving the raw coefficients from one JPEG image
-  structure to another without altering the values of the coefficients.  While
-  this is typically faster than decompressing the image, transforming it, and
-  re-compressing it, lossless transforms are not free.  Each lossless transform
-  requires reading and Huffman decoding all of the coefficients in the source
-  image, regardless of the size of the destination image.  Thus, this function
-  provides a means of generating multiple transformed images from the same
-  source or of applying multiple transformations simultaneously, in order to
-  eliminate the need to read the source coefficients multiple times.
-
-  [INPUT] hnd = instance handle previously returned from a call to
-     tjInitTransform()
-  [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
-     to transform
-  [INPUT] srcsize = size of the source JPEG image buffer (in bytes)
-  [INPUT] n = the number of transformed JPEG images to generate
-  [INPUT] dstbufs = pointer to an array of n user-allocated image buffers.
-     dstbufs[i] will receive a JPEG image that has been transformed using the
-     parameters in transforms[i].  Use the TJBUFSIZE(width, height) function to
-     determine the maximum size for each buffer based on the cropped width and
-     height.
-  [OUTPUT] dstsizes = pointer to an array of n unsigned longs which will
-     receive the actual sizes (in bytes) of each transformed JPEG image
-  [INPUT] transforms = pointer to an array of n tjtransform structures, each of
-     which specifies the transform parameters and/or cropping region for the
-     corresponding transformed output image.  The structure members are as
-     follows:
-
-     r.x = the left boundary of the cropping region.  This must be evenly
-        divisible by tjmcuw[subsamp] (the MCU block width corresponding to the
-        level of chrominance subsampling used in the source image)
-     r.y = the upper boundary of the cropping region.  This must be evenly
-        divisible by tjmcuh[subsamp] (the MCU block height corresponding to the
-        level of chrominance subsampling used in the source image)
-     r.w = the width of the cropping region.  Setting this to 0 is the
-        equivalent of setting it to the width of the source JPEG image - r.x.
-     r.h = the height of the cropping region.  Setting this to 0 is the
-        equivalent of setting it to the height of the source JPEG image - r.y.
-     op = one of the transform operations described in the
-        "Transform operations" section above
-     options = the bitwise OR of one or more of the transform options described
-        in the "Transform options" section above.
-
-  [INPUT] flags = the bitwise OR of one or more of the flags described in the
-     "Flags" section above.
-
-  RETURNS: 0 on success, -1 on error
-*/
-DLLEXPORT int DLLCALL tjTransform(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long srcsize,
-	int n, unsigned char **dstbufs, unsigned long *dstsizes,
-	tjtransform *transforms, int flags);
+/**
+ * Losslessly transform a JPEG image into another JPEG image.  Lossless
+ * transforms work by moving the raw coefficients from one JPEG image structure
+ * to another without altering the values of the coefficients.  While this is
+ * typically faster than decompressing the image, transforming it, and
+ * re-compressing it, lossless transforms are not free.  Each lossless
+ * transform requires reading and Huffman decoding all of the coefficients in
+ * the source image, regardless of the size of the destination image.  Thus,
+ * this function provides a means of generating multiple transformed images
+ * from the same source or of applying multiple transformations simultaneously,
+ * in order to eliminate the need to read the source coefficients multiple
+ * times.
+ *
+ * @param handle a handle to a TurboJPEG transformer instance
+ * @param jpegBuf pointer to a buffer containing the JPEG image to transform
+ * @param jpegSize size of the JPEG image (in bytes)
+ * @param n the number of transformed JPEG images to generate
+ * @param dstBufs pointer to an array of n image buffers.  <tt>dstBufs[i]</tt>
+ *        will receive a JPEG image that has been transformed using the
+ *        parameters in <tt>transforms[i]</tt>.  TurboJPEG has the ability to
+ *        reallocate the JPEG buffer to accommodate the size of the JPEG image.
+ *        Thus, you can choose to:
+ *        -# pre-allocate the JPEG buffer with an arbitrary size and let
+ *        TurboJPEG grow the buffer as needed,
+ *        -# set <tt>dstBufs[i]</tt> to NULL to tell TurboJPEG to allocate the
+ *        buffer for you, or
+ *        -# pre-allocate the buffer to a "worst case" size determined by
+ *        calling #TJBUFSIZE() with the cropped width and height.  This should
+ *        ensure that the buffer never has to be re-allocated (setting the
+ *        #TJ_NOREALLOC flag guarantees this.)
+ *        .
+ *        If you choose option 1 or 3, <tt>dstSizes[i]</tt> should be set to
+ *        the size of your pre-allocated buffer.  In any case, unless you have
+ *        set the #TJ_NOREALLOC flag, you should always check
+ *        <tt>dstBufs[i]</tt> upon return from this function, as it may have
+ *        changed.
+ * @param dstSizes pointer to an array of n unsigned long variables which will
+ *        receive the actual sizes (in bytes) of each transformed JPEG image.
+ *        If <tt>dstBufs[i]</tt> points to a pre-allocated buffer, then
+ *        <tt>dstSizes[i]</tt> should be set to the size of the buffer.  Upon
+ *        return, <tt>dstSizes[i]</tt> will contain the size of the JPEG image
+ *        (in bytes.)
+ * @param transforms pointer to an array of n tjtransform structures, each of
+ *        which specifies the transform parameters and/or cropping region for
+ *        the corresponding transformed output image.
+ * @param flags the bitwise OR of one or more of the @ref flags.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
+ */
+DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
+  unsigned long jpegSize, int n, unsigned char **dstBufs,
+  unsigned long *dstSizes, tjtransform *transforms, int flags);
 
 
-/*
-  int tjDestroy(tjhandle h)
-
-  Frees structures associated with a compression or decompression instance
-  
-  [INPUT] h = instance handle (returned from a previous call to
-     tjInitCompress(), tjInitDecompress(), or tjInitTransform()
-
-  RETURNS: 0 on success, -1 on error
-*/
-DLLEXPORT int DLLCALL tjDestroy(tjhandle h);
+/**
+ * Destroy a TurboJPEG compressor, decompressor, or transformer instance.
+ *
+ * @param handle a handle to a TurboJPEG compressor, decompressor or
+ *        transformer instance
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
+ */
+DLLEXPORT int DLLCALL tjDestroy(tjhandle handle);
 
 
-/*
-  char *tjGetErrorStr(void)
-  
-  Returns a descriptive error message explaining why the last command failed
-*/
+/**
+ * Returns a descriptive error message explaining why the last command failed.
+ *
+ * @return a descriptive error message explaining why the last command failed.
+ */
 DLLEXPORT char* DLLCALL tjGetErrorStr(void);
 
+
+/* Backward compatibility functions and macros (nothing to see here) */
+#define NUMSUBOPT TJ_NUMSAMP
+#define TJ_411 TJ_420
+
+#define TJ_ALPHAFIRST 64
+#define TJ_YUV 512
+
+DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
+  int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
+  unsigned long *compressedSize, int jpegSubsamp, int jpegQual, int flags);
+
+DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle,
+  unsigned char *srcBuf, int width, int pitch, int height, int pixelSize,
+  unsigned char *dstBuf, int subsamp, int flags);
+
+DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
+  unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height);
+
+DLLEXPORT int DLLCALL tjDecompress(tjhandle handle,
+  unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
+  int width, int pitch, int height, int pixelSize, int flags);
+
+
+/**
+ * @}
+ */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/turbojpegl.c b/turbojpegl.c
index 266e335..4db335d 100644
--- a/turbojpegl.c
+++ b/turbojpegl.c
@@ -1,19 +1,32 @@
-/* Copyright (C)2004 Landmark Graphics Corporation
- * Copyright (C)2005 Sun Microsystems, Inc.
- * Copyright (C)2009-2011 D. R. Commander
+/*
+ * Copyright (C)2009-2011 D. R. Commander.  All Rights Reserved.
  *
- * This library is free software and may be redistributed and/or modified under
- * the terms of the wxWindows Library License, Version 3.1 or (at your option)
- * any later version.  The full license is in the LICENSE.txt file included
- * with this distribution.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
  *
- * 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
- * wxWindows Library License for more details.
+ * - 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.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ *   contributors may 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 HOLDERS 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.
  */
 
-// This implements a JPEG compressor/decompressor using the libjpeg API
+/* TurboJPEG/OSS:  this implements the TurboJPEG API using libjpeg-turbo */
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -26,6 +39,10 @@
 #include "./rrutil.h"
 #include "transupp.h"
 
+extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
+	unsigned long *, boolean);
+extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
+
 #ifndef min
  #define min(a,b) ((a)<(b)?(a):(b))
 #endif
@@ -33,46 +50,51 @@
 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
 
 
-// Error handling
+/* Error handling (based on example in example.c) */
 
-static char lasterror[JMSG_LENGTH_MAX]="No error";
+static char errStr[JMSG_LENGTH_MAX]="No error";
 
-typedef struct _error_mgr
+struct my_error_mgr
 {
 	struct jpeg_error_mgr pub;
-	jmp_buf jb;
-} error_mgr;
+	jmp_buf setjmp_buffer;
+};
+typedef struct my_error_mgr *my_error_ptr;
 
 static void my_error_exit(j_common_ptr cinfo)
 {
-	error_mgr *myerr = (error_mgr *)cinfo->err;
+	my_error_ptr myerr=(my_error_ptr)cinfo->err;
 	(*cinfo->err->output_message)(cinfo);
-	longjmp(myerr->jb, 1);
+	longjmp(myerr->setjmp_buffer, 1);
 }
 
+/* Based on output_message() in jerror.c */
+
 static void my_output_message(j_common_ptr cinfo)
 {
-	(*cinfo->err->format_message)(cinfo, lasterror);
+	(*cinfo->err->format_message)(cinfo, errStr);
 }
 
 
-// Global structures, macros, etc.
+/* Global structures, macros, etc. */
 
-typedef struct _jpgstruct
+enum {COMPRESS=1, DECOMPRESS=2};
+
+typedef struct _tjinstance
 {
 	struct jpeg_compress_struct cinfo;
 	struct jpeg_decompress_struct dinfo;
-	struct jpeg_destination_mgr jdms;
-	struct jpeg_source_mgr jsms;
-	error_mgr jerr;
-	int initc, initd;
-} jpgstruct;
+	struct my_error_mgr jerr;
+	int init;
+} tjinstance;
 
 static const int pixelsize[NUMSUBOPT]={3, 3, 3, 1, 3};
+
 static const JXFORM_CODE xformtypes[NUMXFORMOPT]={
 	JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
 	JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
 };
+
 #define NUMSF 4
 static const tjscalingfactor sf[NUMSF]={
 	{1, 1},
@@ -81,55 +103,177 @@
 	{1, 8}
 };
 
-#define _throw(c) {snprintf(lasterror, JMSG_LENGTH_MAX, "%s", c);  \
+#define _throw(c) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", c);  \
 	retval=-1;  goto bailout;}
-#define checkhandle(hnd) jpgstruct *j=(jpgstruct *)hnd; \
-	if(!j) {snprintf(lasterror, JMSG_LENGTH_MAX, "Invalid handle");  return -1;}
+#define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
+	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
+	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
+		return -1;}  \
+	cinfo=&this->cinfo;  dinfo=&this->dinfo;
 
-
-// CO
-
-static boolean empty_output_buffer(struct jpeg_compress_struct *cinfo)
+static int getPixelFormat(int pixelSize, int flags)
 {
-	ERREXIT(cinfo, JERR_BUFFER_SIZE);
-	return TRUE;
+	if(pixelSize==1) return TJ_GRAY;
+	if(pixelSize==3)
+	{
+		if(flags&TJ_BGR) return TJ_BGR;
+		else return TJ_RGB;
+	}
+	if(pixelSize==4)
+	{
+		if(flags&TJ_ALPHAFIRST)
+		{
+			if(flags&TJ_BGR) return TJ_XBGR;
+			else return TJ_XRGB;
+		}
+		else
+		{
+			if(flags&TJ_BGR) return TJ_BGRX;
+			else return TJ_RGBX;
+		}
+	}
+	return -1;
 }
 
-static void destination_noop(struct jpeg_compress_struct *cinfo)
+static void setCompDefaults(struct jpeg_compress_struct *cinfo,
+	int pixelFormat, int subsamp, int jpegQual)
 {
-}
-
-static tjhandle _tjInitCompress(jpgstruct *j)
-{
-	j->cinfo.err=jpeg_std_error(&j->jerr.pub);
-	j->jerr.pub.error_exit=my_error_exit;
-	j->jerr.pub.output_message=my_output_message;
-
-	if(setjmp(j->jerr.jb))
-	{ // this will execute if LIBJPEG has an error
-		if(j) free(j);  return NULL;
+	switch(pixelFormat)
+	{
+		case TJ_GRAY:
+			cinfo->in_color_space=JCS_GRAYSCALE;  break;
+		#if JCS_EXTENSIONS==1
+		case TJ_RGB:
+			cinfo->in_color_space=JCS_EXT_RGB;  break;
+		case TJ_BGR:
+			cinfo->in_color_space=JCS_EXT_BGR;  break;
+		case TJ_RGBX:
+			cinfo->in_color_space=JCS_EXT_RGBX;  break;
+		case TJ_BGRX:
+			cinfo->in_color_space=JCS_EXT_BGRX;  break;
+		case TJ_XRGB:
+			cinfo->in_color_space=JCS_EXT_XRGB;  break;
+		case TJ_XBGR:
+			cinfo->in_color_space=JCS_EXT_XBGR;  break;
+		#else
+		case TJ_RGB:
+			if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3)
+			{
+				cinfo->in_color_space=JCS_RGB;  break;
+			}
+		default:
+			_throw("Unsupported pixel format");
+		#endif
 	}
 
-	jpeg_create_compress(&j->cinfo);
-	j->cinfo.dest=&j->jdms;
-	j->jdms.init_destination=destination_noop;
-	j->jdms.empty_output_buffer=empty_output_buffer;
-	j->jdms.term_destination=destination_noop;
+	cinfo->input_components=tjPixelSize[pixelFormat];
+	jpeg_set_defaults(cinfo);
+	if(jpegQual>=0)
+	{
+		jpeg_set_quality(cinfo, jpegQual, TRUE);
+		if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW;
+		else cinfo->dct_method=JDCT_FASTEST;
+	}
+	if(subsamp==TJ_GRAYSCALE)
+		jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
+	else
+		jpeg_set_colorspace(cinfo, JCS_YCbCr);
 
-	j->initc=1;
-	return (tjhandle)j;
+	cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
+	cinfo->comp_info[1].h_samp_factor=1;
+	cinfo->comp_info[2].h_samp_factor=1;
+	cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
+	cinfo->comp_info[1].v_samp_factor=1;
+	cinfo->comp_info[2].v_samp_factor=1;
+}
+
+static void setDecompDefaults(struct jpeg_decompress_struct *dinfo,
+	int pixelFormat)
+{
+	switch(pixelFormat)
+	{
+		case TJ_GRAY:
+			dinfo->out_color_space=JCS_GRAYSCALE;  break;
+		#if JCS_EXTENSIONS==1
+		case TJ_RGB:
+			dinfo->out_color_space=JCS_EXT_RGB;  break;
+		case TJ_BGR:
+			dinfo->out_color_space=JCS_EXT_BGR;  break;
+		case TJ_RGBX:
+			dinfo->out_color_space=JCS_EXT_RGBX;  break;
+		case TJ_BGRX:
+			dinfo->out_color_space=JCS_EXT_BGRX;  break;
+		case TJ_XRGB:
+			dinfo->out_color_space=JCS_EXT_XRGB;  break;
+		case TJ_XBGR:
+			dinfo->out_color_space=JCS_EXT_XBGR;  break;
+		#else
+		case TJ_RGB:
+			if(RGB_RED==0 && RGB_GREEN==1 && RGB_BLUE==2 && RGB_PIXELSIZE==3)
+			{
+				dinfo->out_color_space=JCS_RGB;  break;
+			}
+		default:
+			_throw("Unsupported pixel format");
+		#endif
+	}
+}
+
+
+/* General API functions */
+
+DLLEXPORT char* DLLCALL tjGetErrorStr(void)
+{
+	return errStr;
+}
+
+
+DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
+{
+	getinstance(handle);
+	if(setjmp(this->jerr.setjmp_buffer)) return -1;
+	if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
+	if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
+	free(this);
+	return 0;
+}
+
+
+/* Compressor  */
+
+static tjhandle _tjInitCompress(tjinstance *this)
+{
+	unsigned char buffer[1], *buf=buffer;  unsigned long size=1;
+
+	/* This is also straight out of example.c */
+	this->cinfo.err=jpeg_std_error(&this->jerr.pub);
+	this->jerr.pub.error_exit=my_error_exit;
+	this->jerr.pub.output_message=my_output_message;
+
+	if(setjmp(this->jerr.setjmp_buffer))
+	{
+		/* If we get here, the JPEG code has signaled an error. */
+		if(this) free(this);  return NULL;
+	}
+
+	jpeg_create_compress(&this->cinfo);
+	/* Make an initial call so it will create the destination manager */
+	jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
+
+	this->init=COMPRESS;
+	return (tjhandle)this;
 }
 
 DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
 {
-	jpgstruct *j=NULL;
-	if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
+	tjinstance *this=NULL;
+	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
 	{
-		snprintf(lasterror, JMSG_LENGTH_MAX, "Memory allocation failure");
+		snprintf(errStr, JMSG_LENGTH_MAX, "Memory allocation failure");
 		return NULL;
 	}
-	memset(j, 0, sizeof(jpgstruct));
-	return _tjInitCompress(j);
+	memset(this, 0, sizeof(tjinstance));
+	return _tjInitCompress(this);
 }
 
 
@@ -156,9 +300,9 @@
 	int pw, ph, cw, ch;
 	if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
 		_throw("Invalid argument in TJBUFSIZEYUV()");
-	pw=PAD(width, tjmcuw[subsamp]/8);
-	ph=PAD(height, tjmcuh[subsamp]/8);
-	cw=pw*8/tjmcuw[subsamp];  ch=ph*8/tjmcuh[subsamp];
+	pw=PAD(width, tjMCUWidth[subsamp]/8);
+	ph=PAD(height, tjMCUHeight[subsamp]/8);
+	cw=pw*8/tjMCUWidth[subsamp];  ch=ph*8/tjMCUHeight[subsamp];
 	retval=PAD(pw, 4)*ph + (subsamp==TJ_GRAYSCALE? 0:PAD(cw, 4)*ch*2);
 
 	bailout:
@@ -166,17 +310,100 @@
 }
 
 
-DLLEXPORT int DLLCALL tjCompress(tjhandle hnd,
-	unsigned char *srcbuf, int width, int pitch, int height, int ps,
-	unsigned char *dstbuf, unsigned long *size,
-	int jpegsub, int qual, int flags)
+DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
+	int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
+	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
+{
+	int i, retval=0;  JSAMPROW *row_pointer=NULL;
+
+	getinstance(handle)
+	if((this->init&COMPRESS)==0)
+		_throw("Instance has not been initialized for compression");
+
+	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
+		|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
+		|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
+		_throw("tjCompress(): Invalid argument");
+
+	if(setjmp(this->jerr.setjmp_buffer))
+	{
+		/* If we get here, the JPEG code has signaled an error. */
+		retval=-1;
+		goto bailout;
+	}
+
+	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
+
+	cinfo->image_width=width;
+	cinfo->image_height=height;
+
+	if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
+	else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
+	else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+
+	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, (flags&TJ_NOREALLOC)==0);
+	setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual);
+
+	jpeg_start_compress(cinfo, TRUE);
+	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
+		_throw("Memory allocation failed in tjCompress()");
+	for(i=0; i<height; i++)
+	{
+		if(flags&TJ_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
+		else row_pointer[i]=&srcBuf[i*pitch];
+	}
+	while(cinfo->next_scanline<cinfo->image_height)
+	{
+		jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
+			cinfo->image_height-cinfo->next_scanline);
+	}
+	jpeg_finish_compress(cinfo);
+
+	bailout:
+	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
+	if(row_pointer) free(row_pointer);
+	return retval;
+}
+
+DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
+	int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
+	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
+{
+	int retval=0;  unsigned long size;
+	if(flags&TJ_YUV)
+	{
+		size=TJBUFSIZEYUV(width, height, jpegSubsamp);
+		retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
+			getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
+	}
+	else
+	{
+		size=TJBUFSIZE(width, height);
+		retval=tjCompress2(handle, srcBuf, width, pitch, height,
+			getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
+			flags|TJ_NOREALLOC);
+	}
+	*jpegSize=size;
+	return retval;
+}
+
+
+DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
+	int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
+	int subsamp, int flags)
 {
 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
 	JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
 	JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
 	JSAMPROW *outbuf[MAX_COMPONENTS];
+	int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
+	JSAMPLE *ptr=dstBuf;
+  unsigned long yuvsize=0;
+	jpeg_component_info *compptr;
 
-	checkhandle(hnd);
+	getinstance(handle);
+	if((this->init&COMPRESS)==0)
+		_throw("Instance has not been initialized for compression");
 
 	for(i=0; i<MAX_COMPONENTS; i++)
 	{
@@ -184,165 +411,102 @@
 		tmpbuf2[i]=NULL;  _tmpbuf2[i]=NULL;  outbuf[i]=NULL;
 	}
 
-	if(srcbuf==NULL || width<=0 || pitch<0 || height<=0
-		|| dstbuf==NULL || size==NULL
-		|| jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100)
-		_throw("Invalid argument in tjCompress()");
-	if(ps!=3 && ps!=4 && ps!=1)
-		_throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input");
-	if(!j->initc) _throw("Instance has not been initialized for compression");
+	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
+		|| pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
+		|| subsamp>=NUMSUBOPT)
+		_throw("tjEncodeYUV2(): Invalid argument");
 
-	if(pitch==0) pitch=width*ps;
+	if(setjmp(this->jerr.setjmp_buffer))
+	{
+		/* If we get here, the JPEG code has signaled an error. */
+		retval=-1;
+		goto bailout;
+	}
 
-	j->cinfo.image_width = width;
-	j->cinfo.image_height = height;
-	j->cinfo.input_components = ps;
+	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
 
-	if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE;
-	#if JCS_EXTENSIONS==1
-	else j->cinfo.in_color_space = JCS_EXT_RGB;
-	if(ps==3 && (flags&TJ_BGR))
-		j->cinfo.in_color_space = JCS_EXT_BGR;
-	else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
-		j->cinfo.in_color_space = JCS_EXT_RGBX;
-	else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
-		j->cinfo.in_color_space = JCS_EXT_BGRX;
-	else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
-		j->cinfo.in_color_space = JCS_EXT_XBGR;
-	else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
-		j->cinfo.in_color_space = JCS_EXT_XRGB;
-	#else
-	#error "TurboJPEG requires JPEG colorspace extensions"
-	#endif
+	cinfo->image_width=width;
+	cinfo->image_height=height;
 
 	if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
 	else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
 	else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
 
-	if(setjmp(j->jerr.jb))
-	{  // this will execute if LIBJPEG has an error
-		retval=-1;
-		goto bailout;
-	}
+	yuvsize=TJBUFSIZEYUV(width, height, subsamp);
+	jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
+	setCompDefaults(cinfo, pixelFormat, subsamp, -1);
 
-	jpeg_set_defaults(&j->cinfo);
+	jpeg_start_compress(cinfo, TRUE);
+	pw=PAD(width, cinfo->max_h_samp_factor);
+	ph=PAD(height, cinfo->max_v_samp_factor);
 
-	jpeg_set_quality(&j->cinfo, qual, TRUE);
-	if(jpegsub==TJ_GRAYSCALE)
-		jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE);
-	else
-		jpeg_set_colorspace(&j->cinfo, JCS_YCbCr);
-	if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW;
-	else j->cinfo.dct_method=JDCT_FASTEST;
-
-	j->cinfo.comp_info[0].h_samp_factor=tjmcuw[jpegsub]/8;
-	j->cinfo.comp_info[1].h_samp_factor=1;
-	j->cinfo.comp_info[2].h_samp_factor=1;
-	j->cinfo.comp_info[0].v_samp_factor=tjmcuh[jpegsub]/8;
-	j->cinfo.comp_info[1].v_samp_factor=1;
-	j->cinfo.comp_info[2].v_samp_factor=1;
-
-	j->jdms.next_output_byte = dstbuf;
-	j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height);
-
-	jpeg_start_compress(&j->cinfo, TRUE);
-	if(flags&TJ_YUV)
+	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
+		_throw("Memory allocation failed in tjCompress()");
+	for(i=0; i<height; i++)
 	{
-		j_compress_ptr cinfo=&j->cinfo;
-		int row;
-		int pw=PAD(width, cinfo->max_h_samp_factor);
-		int ph=PAD(height, cinfo->max_v_samp_factor);
-		int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
-		jpeg_component_info *compptr;
-		JSAMPLE *ptr=dstbuf;  unsigned long yuvsize=0;
+		if(flags&TJ_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
+		else row_pointer[i]=&srcBuf[i*pitch];
+	}
+	if(height<ph)
+		for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
 
-		if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
-			_throw("Memory allocation failed in tjCompress()");
-		for(i=0; i<height; i++)
+	for(i=0; i<cinfo->num_components; i++)
+	{
+		compptr=&cinfo->comp_info[i];
+		_tmpbuf[i]=(JSAMPLE *)malloc(
+			PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
+				/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
+		if(!_tmpbuf[i]) _throw("Memory allocation failure");
+		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
+		if(!tmpbuf[i]) _throw("Memory allocation failure");
+		for(row=0; row<cinfo->max_v_samp_factor; row++)
 		{
-			if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
-			else row_pointer[i]= &srcbuf[i*pitch];
-		}
-		if(height<ph)
-			for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
-
-		for(i=0; i<cinfo->num_components; i++)
-		{
-			compptr=&cinfo->comp_info[i];
-			_tmpbuf[i]=(JSAMPLE *)malloc(
+			unsigned char *_tmpbuf_aligned=
+				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
+			tmpbuf[i][row]=&_tmpbuf_aligned[
 				PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
-					/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
-			if(!_tmpbuf[i]) _throw("Memory allocation failure");
-			tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
-			if(!tmpbuf[i]) _throw("Memory allocation failure");
-			for(row=0; row<cinfo->max_v_samp_factor; row++)
-			{
-				unsigned char *_tmpbuf_aligned=
-					(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
-				tmpbuf[i][row]=&_tmpbuf_aligned[
-					PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
-						/compptr->h_samp_factor, 16) * row];
-			}
-			_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
-				* compptr->v_samp_factor + 16);
-			if(!_tmpbuf2[i]) _throw("Memory allocation failure");
-			tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
-			if(!tmpbuf2[i]) _throw("Memory allocation failure");
-			for(row=0; row<compptr->v_samp_factor; row++)
-			{
-				unsigned char *_tmpbuf2_aligned=
-					(unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
-				tmpbuf2[i][row]=&_tmpbuf2_aligned[
-					PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
-			}
-			cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
-			ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
-			outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
-			if(!outbuf[i]) _throw("Memory allocation failure");
-			for(row=0; row<ch[i]; row++)
-			{
-				outbuf[i][row]=ptr;
-				ptr+=PAD(cw[i], 4);
-			}
+					/compptr->h_samp_factor, 16) * row];
 		}
-		yuvsize=(unsigned long)(ptr-dstbuf);
+		_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
+			* compptr->v_samp_factor + 16);
+		if(!_tmpbuf2[i]) _throw("Memory allocation failure");
+		tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
+		if(!tmpbuf2[i]) _throw("Memory allocation failure");
+		for(row=0; row<compptr->v_samp_factor; row++)
+		{
+			unsigned char *_tmpbuf2_aligned=
+				(unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
+			tmpbuf2[i][row]=&_tmpbuf2_aligned[
+				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
+		}
+		cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
+		ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
+		outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
+		if(!outbuf[i]) _throw("Memory allocation failure");
+		for(row=0; row<ch[i]; row++)
+		{
+			outbuf[i][row]=ptr;
+			ptr+=PAD(cw[i], 4);
+		}
+	}
+	if(yuvsize!=(unsigned long)(ptr-dstBuf))
+		_throw("tjEncodeYUV2(): Generated image is not the correct size");
 
-		for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
-		{
-			(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf,
-				0, cinfo->max_v_samp_factor);
-			(cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
-			for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components;
-				i++, compptr++)
-				jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
-					row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
-					compptr->v_samp_factor, cw[i]);
-		}
-		*size=yuvsize;
-		cinfo->next_scanline+=height;
-		jpeg_abort_compress(&j->cinfo);
-	}
-	else
+	for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
 	{
-		if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
-			_throw("Memory allocation failed in tjCompress()");
-		for(i=0; i<height; i++)
-		{
-			if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
-			else row_pointer[i]= &srcbuf[i*pitch];
-		}
-		while(j->cinfo.next_scanline<j->cinfo.image_height)
-		{
-			jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
-				j->cinfo.image_height-j->cinfo.next_scanline);
-		}
-		jpeg_finish_compress(&j->cinfo);
-		*size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)
-			-(unsigned long)(j->jdms.free_in_buffer);
+		(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
+			cinfo->max_v_samp_factor);
+		(cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
+		for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
+			jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
+				row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
+				compptr->v_samp_factor, cw[i]);
 	}
+	cinfo->next_scanline+=height;
+	jpeg_abort_compress(cinfo);
 
 	bailout:
-	if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
+	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
 	if(row_pointer) free(row_pointer);
 	for(i=0; i<MAX_COMPONENTS; i++)
 	{
@@ -355,133 +519,117 @@
 	return retval;
 }
 
-
-DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle hnd,
-	unsigned char *srcbuf, int width, int pitch, int height, int ps,
-	unsigned char *dstbuf, int subsamp, int flags)
+DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
+	int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
+	int subsamp, int flags)
 {
-	unsigned long size;
-	return tjCompress(hnd, srcbuf, width, pitch, height, ps, dstbuf, &size,
-		subsamp, 0, flags|TJ_YUV);
+	return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
+		getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
 }
 
 
-// DEC
+/* Decompressor */
 
-static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo)
+static tjhandle _tjInitDecompress(tjinstance *this)
 {
-	ERREXIT(dinfo, JERR_BUFFER_SIZE);
-	return TRUE;
-}
+	unsigned char buffer[1];
 
-static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes)
-{
-	dinfo->src->next_input_byte += (size_t) num_bytes;
-	dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
-}
+	/* This is also straight out of example.c */
+	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
+	this->jerr.pub.error_exit=my_error_exit;
+	this->jerr.pub.output_message=my_output_message;
 
-static void source_noop (struct jpeg_decompress_struct *dinfo)
-{
-}
-
-static tjhandle _tjInitDecompress(jpgstruct *j)
-{
-	j->dinfo.err=jpeg_std_error(&j->jerr.pub);
-	j->jerr.pub.error_exit=my_error_exit;
-	j->jerr.pub.output_message=my_output_message;
-
-	if(setjmp(j->jerr.jb))
-	{ // this will execute if LIBJPEG has an error
-		free(j);  return NULL;
+	if(setjmp(this->jerr.setjmp_buffer))
+	{
+		/* If we get here, the JPEG code has signaled an error. */
+		if(this) free(this);  return NULL;
 	}
 
-	jpeg_create_decompress(&j->dinfo);
-	j->dinfo.src=&j->jsms;
-	j->jsms.init_source=source_noop;
-	j->jsms.fill_input_buffer = fill_input_buffer;
-	j->jsms.skip_input_data = skip_input_data;
-	j->jsms.resync_to_restart = jpeg_resync_to_restart;
-	j->jsms.term_source = source_noop;
+	jpeg_create_decompress(&this->dinfo);
+	/* Make an initial call so it will create the source manager */
+	jpeg_mem_src_tj(&this->dinfo, buffer, 1);
 
-	j->initd=1;
-	return (tjhandle)j;
+	this->init=DECOMPRESS;
+	return (tjhandle)this;
 }
 
 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
 {
-	jpgstruct *j;
-	if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
+	tjinstance *this;
+	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
 	{
-		snprintf(lasterror, JMSG_LENGTH_MAX, "Memory allocation failure");
+		snprintf(errStr, JMSG_LENGTH_MAX, "Memory allocation failure");
 		return NULL;
 	}
-	memset(j, 0, sizeof(jpgstruct));
-	return _tjInitDecompress(j);
+	memset(this, 0, sizeof(tjinstance));
+	return _tjInitDecompress(this);
 }
 
 
-DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long size,
-	int *width, int *height, int *jpegsub)
+DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
+	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
+	int *jpegSubsamp)
 {
 	int i, k, retval=0;
 
-	checkhandle(hnd);
+	getinstance(handle);
+	if((this->init&DECOMPRESS)==0)
+		_throw("Instance has not been initialized for decompression");
 
-	if(srcbuf==NULL || size<=0 || width==NULL || height==NULL || jpegsub==NULL)
-		_throw("Invalid argument in tjDecompressHeader2()");
-	if(!j->initd) _throw("Instance has not been initialized for decompression");
+	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
+		|| jpegSubsamp==NULL)
+		_throw("tjDecompressHeader2(): Invalid argument");
 
-	if(setjmp(j->jerr.jb))
-	{  // this will execute if LIBJPEG has an error
+	if(setjmp(this->jerr.setjmp_buffer))
+	{
+		/* If we get here, the JPEG code has signaled an error. */
 		return -1;
 	}
 
-	j->jsms.bytes_in_buffer = size;
-	j->jsms.next_input_byte = srcbuf;
+	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+	jpeg_read_header(dinfo, TRUE);
 
-	jpeg_read_header(&j->dinfo, TRUE);
-
-	*width=j->dinfo.image_width;  *height=j->dinfo.image_height;
-	*jpegsub=-1;
+	*width=dinfo->image_width;
+	*height=dinfo->image_height;
+	*jpegSubsamp=-1;
 	for(i=0; i<NUMSUBOPT; i++)
 	{
-		if(j->dinfo.num_components==pixelsize[i])
+		if(dinfo->num_components==pixelsize[i])
 		{
-			if(j->dinfo.comp_info[0].h_samp_factor==tjmcuw[i]/8
-				&& j->dinfo.comp_info[0].v_samp_factor==tjmcuh[i]/8)
+			if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
+				&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
 			{
 				int match=0;
-				for(k=1; k<j->dinfo.num_components; k++)
+				for(k=1; k<dinfo->num_components; k++)
 				{
-					if(j->dinfo.comp_info[k].h_samp_factor==1
-						&& j->dinfo.comp_info[k].v_samp_factor==1)
+					if(dinfo->comp_info[k].h_samp_factor==1
+						&& dinfo->comp_info[k].v_samp_factor==1)
 						match++;
 				}
-				if(match==j->dinfo.num_components-1)
+				if(match==dinfo->num_components-1)
 				{
-					*jpegsub=i;  break;
+					*jpegSubsamp=i;  break;
 				}
 			}
 		}
 	}
 
-	jpeg_abort_decompress(&j->dinfo);
+	jpeg_abort_decompress(dinfo);
 
-	if(*jpegsub<0) _throw("Could not determine subsampling type for JPEG image");
+	if(*jpegSubsamp<0)
+		_throw("Could not determine subsampling type for JPEG image");
 	if(*width<1 || *height<1) _throw("Invalid data returned in header");
 
 	bailout:
 	return retval;
 }
 
-
-DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long size,
-	int *width, int *height)
+DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
+	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
 {
-	int jpegsub;
-	return tjDecompressHeader2(hnd, srcbuf, size, width, height, &jpegsub);
+	int jpegSubsamp;
+	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
+		&jpegSubsamp);
 }
 
 
@@ -489,7 +637,7 @@
 {
 	if(numscalingfactors==NULL)
 	{
-		snprintf(lasterror, JMSG_LENGTH_MAX,
+		snprintf(errStr, JMSG_LENGTH_MAX,
 			"Invalid argument in tjGetScalingFactors()");
 		return NULL;
 	}
@@ -499,246 +647,253 @@
 }
 
 
-DLLEXPORT int DLLCALL tjDecompress(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long size,
-	unsigned char *dstbuf, int width, int pitch, int height, int ps,
-	int flags)
+DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
+	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
+	int height, int pixelFormat, int flags)
 {
-	int i, row, retval=0;  JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
-	int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
-		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
-	JSAMPLE *_tmpbuf=NULL;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
+	int i, retval=0;  JSAMPROW *row_pointer=NULL;
 	int jpegwidth, jpegheight, scaledw, scaledh;
 
-	checkhandle(hnd);
+	getinstance(handle);
+	if((this->init&DECOMPRESS)==0)
+		_throw("Instance has not been initialized for decompression");
+
+	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
+		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
+		_throw("tjDecompress2(): Invalid argument");
+
+	if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
+	else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
+	else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+
+	if(setjmp(this->jerr.setjmp_buffer))
+	{
+		/* If we get here, the JPEG code has signaled an error. */
+		retval=-1;
+		goto bailout;
+	}
+
+	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+	jpeg_read_header(dinfo, TRUE);
+	setDecompDefaults(dinfo, pixelFormat);
+
+	if(flags&TJ_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
+	if(flags&TJ_YUV) dinfo->raw_data_out=TRUE;
+
+	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
+	if(width==0) width=jpegwidth;
+	if(height==0) height=jpegheight;
+	for(i=0; i<NUMSF; i++)
+	{
+		scaledw=TJSCALED(jpegwidth, sf[i]);
+		scaledh=TJSCALED(jpegheight, sf[i]);
+		if(scaledw<=width && scaledh<=height)
+				break;
+	}
+	if(scaledw>width || scaledh>height)
+		_throw("Could not scale down to desired image dimensions");
+	width=scaledw;  height=scaledh;
+	dinfo->scale_num=sf[i].num;
+	dinfo->scale_denom=sf[i].denom;
+
+	jpeg_start_decompress(dinfo);
+	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
+	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
+		*dinfo->output_height))==NULL)
+		_throw("Memory allocation failed in tjInitDecompress()");
+	for(i=0; i<(int)dinfo->output_height; i++)
+	{
+		if(flags&TJ_BOTTOMUP)
+			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
+		else row_pointer[i]=&dstBuf[i*pitch];
+	}
+	while(dinfo->output_scanline<dinfo->output_height)
+	{
+		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
+			dinfo->output_height-dinfo->output_scanline);
+	}
+	jpeg_finish_decompress(dinfo);
+
+	bailout:
+	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
+	if(row_pointer) free(row_pointer);
+	return retval;
+}
+
+DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
+	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
+	int height, int pixelSize, int flags)
+{
+	if(flags&TJ_YUV)
+		return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
+	else
+		return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
+			height, getPixelFormat(pixelSize, flags), flags);
+}
+
+
+DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
+	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
+	int flags)
+{
+	int i, row, retval=0;  JSAMPROW *outbuf[MAX_COMPONENTS];
+	int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
+		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
+	JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
+
+	getinstance(handle);
+	if((this->init&DECOMPRESS)==0)
+		_throw("Instance has not been initialized for decompression");
 
 	for(i=0; i<MAX_COMPONENTS; i++)
 	{
 		tmpbuf[i]=NULL;  outbuf[i]=NULL;
 	}
 
-	if(srcbuf==NULL || size<=0
-		|| dstbuf==NULL || width<0 || pitch<0 || height<0)
-		_throw("Invalid argument in tjDecompress()");
-	if(ps!=3 && ps!=4 && ps!=1)
-		_throw("This decompressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale output");
-	if(!j->initd) _throw("Instance has not been initialized for decompression");
+	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
+		_throw("tjDecompressToYUV(): Invalid argument");
 
 	if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
 	else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
 	else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
 
-	if(setjmp(j->jerr.jb))
-	{  // this will execute if LIBJPEG has an error
+	if(setjmp(this->jerr.setjmp_buffer))
+	{
+		/* If we get here, the JPEG code has signaled an error. */
 		retval=-1;
 		goto bailout;
 	}
 
-	j->jsms.bytes_in_buffer = size;
-	j->jsms.next_input_byte = srcbuf;
+	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+	jpeg_read_header(dinfo, TRUE);
 
-	jpeg_read_header(&j->dinfo, TRUE);
-
-	if(flags&TJ_YUV)
+	for(i=0; i<dinfo->num_components; i++)
 	{
-		j_decompress_ptr dinfo=&j->dinfo;
-		JSAMPLE *ptr=dstbuf;
+		jpeg_component_info *compptr=&dinfo->comp_info[i];
+		int ih;
+		iw[i]=compptr->width_in_blocks*DCTSIZE;
+		ih=compptr->height_in_blocks*DCTSIZE;
+		cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
+			*compptr->h_samp_factor/dinfo->max_h_samp_factor;
+		ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
+			*compptr->v_samp_factor/dinfo->max_v_samp_factor;
+		if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
+		th[i]=compptr->v_samp_factor*DCTSIZE;
+		tmpbufsize+=iw[i]*th[i];
+		if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
+			_throw("Memory allocation failed in tjDecompress()");
+		for(row=0; row<ch[i]; row++)
+		{
+			outbuf[i][row]=ptr;
+			ptr+=PAD(cw[i], 4);
+		}
+	}
+	if(usetmpbuf)
+	{
+		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
+			_throw("Memory allocation failed in tjDecompress()");
+		ptr=_tmpbuf;
+		for(i=0; i<dinfo->num_components; i++)
+		{
+			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
+				_throw("Memory allocation failed in tjDecompress()");
+			for(row=0; row<th[i]; row++)
+			{
+				tmpbuf[i][row]=ptr;
+				ptr+=iw[i];
+			}
+		}
+	}
 
+	if(flags&TJ_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
+	dinfo->raw_data_out=TRUE;
+
+	jpeg_start_decompress(dinfo);
+	for(row=0; row<(int)dinfo->output_height;
+		row+=dinfo->max_v_samp_factor*DCTSIZE)
+	{
+		JSAMPARRAY yuvptr[MAX_COMPONENTS];
+		int crow[MAX_COMPONENTS];
 		for(i=0; i<dinfo->num_components; i++)
 		{
 			jpeg_component_info *compptr=&dinfo->comp_info[i];
-			int ih;
-			iw[i]=compptr->width_in_blocks*DCTSIZE;
-			ih=compptr->height_in_blocks*DCTSIZE;
-			cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
-				*compptr->h_samp_factor/dinfo->max_h_samp_factor;
-			ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
-				*compptr->v_samp_factor/dinfo->max_v_samp_factor;
-			if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
-			th[i]=compptr->v_samp_factor*DCTSIZE;
-			tmpbufsize+=iw[i]*th[i];
-			if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
-				_throw("Memory allocation failed in tjDecompress()");
-			for(row=0; row<ch[i]; row++)
-			{
-				outbuf[i][row]=ptr;
-				ptr+=PAD(cw[i], 4);
-			}
+			crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
+			if(usetmpbuf) yuvptr[i]=tmpbuf[i];
+			else yuvptr[i]=&outbuf[i][crow[i]];
 		}
+		jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
 		if(usetmpbuf)
 		{
-			if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
-				_throw("Memory allocation failed in tjDecompress()");
-			ptr=_tmpbuf;
+			int j;
 			for(i=0; i<dinfo->num_components; i++)
 			{
-				if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
-					_throw("Memory allocation failed in tjDecompress()");
-				for(row=0; row<th[i]; row++)
+				for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
 				{
-					tmpbuf[i][row]=ptr;
-					ptr+=iw[i];
+					memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
 				}
 			}
 		}
 	}
-
-	if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE;
-	#if JCS_EXTENSIONS==1
-	else j->dinfo.out_color_space = JCS_EXT_RGB;
-	if(ps==3 && (flags&TJ_BGR))
-		j->dinfo.out_color_space = JCS_EXT_BGR;
-	else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
-		j->dinfo.out_color_space = JCS_EXT_RGBX;
-	else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
-		j->dinfo.out_color_space = JCS_EXT_BGRX;
-	else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
-		j->dinfo.out_color_space = JCS_EXT_XBGR;
-	else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
-		j->dinfo.out_color_space = JCS_EXT_XRGB;
-	#else
-	#error "TurboJPEG requires JPEG colorspace extensions"
-	#endif
-
-	if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
-	if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE;
-	else
-	{
-		jpegwidth=j->dinfo.image_width;  jpegheight=j->dinfo.image_height;
-		if(width==0) width=jpegwidth;
-		if(height==0) height=jpegheight;
-		for(i=0; i<NUMSF; i++)
-		{
-			scaledw=(jpegwidth*sf[i].num+sf[i].denom-1)/sf[i].denom;
-			scaledh=(jpegheight*sf[i].num+sf[i].denom-1)/sf[i].denom;
-			if(scaledw<=width && scaledh<=height)
-					break;
-		}
-		if(scaledw>width || scaledh>height)
-			_throw("Could not scale down to desired image dimensions");
-		width=scaledw;  height=scaledh;
-		j->dinfo.scale_num=sf[i].num;
-		j->dinfo.scale_denom=sf[i].denom;
-	}
-
-	jpeg_start_decompress(&j->dinfo);
-	if(flags&TJ_YUV)
-	{
-		j_decompress_ptr dinfo=&j->dinfo;
-		for(row=0; row<(int)dinfo->output_height;
-			row+=dinfo->max_v_samp_factor*DCTSIZE)
-		{
-			JSAMPARRAY yuvptr[MAX_COMPONENTS];
-			int crow[MAX_COMPONENTS];
-			for(i=0; i<dinfo->num_components; i++)
-			{
-				jpeg_component_info *compptr=&dinfo->comp_info[i];
-				crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
-				if(usetmpbuf) yuvptr[i]=tmpbuf[i];
-				else yuvptr[i]=&outbuf[i][crow[i]];
-			}
-			jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
-			if(usetmpbuf)
-			{
-				int j;
-				for(i=0; i<dinfo->num_components; i++)
-				{
-					for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
-					{
-						memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
-					}
-				}
-			}
-		}
-	}
-	else
-	{
-		if(pitch==0) pitch=j->dinfo.output_width*ps;
-		if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
-			*j->dinfo.output_height))==NULL)
-			_throw("Memory allocation failed in tjInitDecompress()");
-		for(i=0; i<(int)j->dinfo.output_height; i++)
-		{
-			if(flags&TJ_BOTTOMUP)
-				row_pointer[i]= &dstbuf[(j->dinfo.output_height-i-1)*pitch];
-			else row_pointer[i]= &dstbuf[i*pitch];
-		}
-		while(j->dinfo.output_scanline<j->dinfo.output_height)
-		{
-			jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
-				j->dinfo.output_height-j->dinfo.output_scanline);
-		}
-	}
-	jpeg_finish_decompress(&j->dinfo);
+	jpeg_finish_decompress(dinfo);
 
 	bailout:
-	if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
+	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
 	for(i=0; i<MAX_COMPONENTS; i++)
 	{
 		if(tmpbuf[i]) free(tmpbuf[i]);
 		if(outbuf[i]) free(outbuf[i]);
 	}
 	if(_tmpbuf) free(_tmpbuf);
-	if(row_pointer) free(row_pointer);
 	return retval;
 }
 
 
-DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long size,
-	unsigned char *dstbuf, int flags)
-{
-	return tjDecompress(hnd, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV);
-}
-
-
-// Transformation
+/* Transformer */
 
 DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
 {
-	jpgstruct *j=NULL;  tjhandle tj=NULL;
-	if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
+	tjinstance *this=NULL;  tjhandle handle=NULL;
+	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
 	{
-		snprintf(lasterror, JMSG_LENGTH_MAX, "Memory allocation failure");
+		snprintf(errStr, JMSG_LENGTH_MAX, "Memory allocation failure");
 		return NULL;
 	}
-	memset(j, 0, sizeof(jpgstruct));
-	tj=_tjInitCompress(j);
-	if(!tj) return NULL;
-	tj=_tjInitDecompress(j);
-	return tj;
+	memset(this, 0, sizeof(tjinstance));
+	handle=_tjInitCompress(this);
+	if(!handle) return NULL;
+	handle=_tjInitDecompress(this);
+	return handle;
 }
 
 
-DLLEXPORT int DLLCALL tjTransform(tjhandle hnd,
-	unsigned char *srcbuf, unsigned long srcsize,
-	int n, unsigned char **dstbufs, unsigned long *dstsizes,
-	tjtransform *t, int flags)
+DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
+	unsigned long jpegSize, int n, unsigned char **dstBufs,
+	unsigned long *dstSizes, tjtransform *t, int flags)
 {
 	jpeg_transform_info *xinfo=NULL;
 	jvirt_barray_ptr *srccoefs, *dstcoefs;
 	int retval=0, i;
 
-	checkhandle(hnd);
-
-	if(srcbuf==NULL || srcsize<=0 || n<1 || dstbufs==NULL || dstsizes==NULL
-		|| t==NULL || flags<0)
-		_throw("Invalid argument in tjTransform()");
-	if(!j->initc || !j->initd)
+	getinstance(handle);
+	if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
 		_throw("Instance has not been initialized for transformation");
 
+	if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
+		|| t==NULL || flags<0)
+		_throw("tjTransform(): Invalid argument");
+
 	if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
 	else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
 	else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
 
-	if(setjmp(j->jerr.jb))
-	{  // this will execute if LIBJPEG has an error
+	if(setjmp(this->jerr.setjmp_buffer))
+	{
+		/* If we get here, the JPEG code has signaled an error. */
 		retval=-1;
 		goto bailout;
 	}
 
-	j->jsms.bytes_in_buffer=srcsize;
-	j->jsms.next_input_byte=srcbuf;
+	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
 
 	if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
 		==NULL)
@@ -772,12 +927,12 @@
 		}
 	}
 
-	jcopy_markers_setup(&j->dinfo, JCOPYOPT_ALL);
-	jpeg_read_header(&j->dinfo, TRUE);
+	jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
+	jpeg_read_header(dinfo, TRUE);
 
 	for(i=0; i<n; i++)
 	{
-		if(!jtransform_request_workspace(&j->dinfo, &xinfo[i]))
+		if(!jtransform_request_workspace(dinfo, &xinfo[i]))
 			_throw("Transform is not perfect");
 
 		if(xinfo[i].crop)
@@ -785,7 +940,7 @@
 			if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
 				|| (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
 			{
-				snprintf(lasterror, JMSG_LENGTH_MAX,
+				snprintf(errStr, JMSG_LENGTH_MAX,
 					"To crop this JPEG image, x must be a multiple of %d\n"
 					"and y must be a multiple of %d.\n",
 					xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
@@ -794,56 +949,36 @@
 		}
 	}
 
-	srccoefs=jpeg_read_coefficients(&j->dinfo);
+	srccoefs=jpeg_read_coefficients(dinfo);
 
 	for(i=0; i<n; i++)
 	{
 		int w, h;
-		j->jdms.next_output_byte=dstbufs[i];
+		jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i],
+			(flags&TJ_NOREALLOC)==0);
 		if(!xinfo[i].crop)
 		{
-			w=j->dinfo.image_width;  h=j->dinfo.image_height;
+			w=dinfo->image_width;  h=dinfo->image_height;
 		}
 		else
 		{
 			w=xinfo[i].crop_width;  h=xinfo[i].crop_height;
 		}
-		j->jdms.free_in_buffer=TJBUFSIZE(w, h);
-		jpeg_copy_critical_parameters(&j->dinfo, &j->cinfo);
-		dstcoefs=jtransform_adjust_parameters(&j->dinfo, &j->cinfo, srccoefs,
+		jpeg_copy_critical_parameters(dinfo, cinfo);
+		dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
 			&xinfo[i]);
-		jpeg_write_coefficients(&j->cinfo, dstcoefs);
-		jcopy_markers_execute(&j->dinfo, &j->cinfo, JCOPYOPT_ALL);
-		jtransform_execute_transformation(&j->dinfo, &j->cinfo, srccoefs,
+		jpeg_write_coefficients(cinfo, dstcoefs);
+		jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
+		jtransform_execute_transformation(dinfo, cinfo, srccoefs,
 			&xinfo[i]);
-		jpeg_finish_compress(&j->cinfo);
-
-		dstsizes[i]=TJBUFSIZE(w, h)-(unsigned long)(j->jdms.free_in_buffer);
+		jpeg_finish_compress(cinfo);
 	}
 
-	jpeg_finish_decompress(&j->dinfo);
+	jpeg_finish_decompress(dinfo);
 
 	bailout:
-	if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
-	if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
+	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
+	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
 	if(xinfo) free(xinfo);
 	return retval;
 }
-
-
-// General
-
-DLLEXPORT char* DLLCALL tjGetErrorStr(void)
-{
-	return lasterror;
-}
-
-DLLEXPORT int DLLCALL tjDestroy(tjhandle hnd)
-{
-	checkhandle(hnd);
-	if(setjmp(j->jerr.jb)) return -1;
-	if(j->initc) jpeg_destroy_compress(&j->cinfo);
-	if(j->initd) jpeg_destroy_decompress(&j->dinfo);
-	free(j);
-	return 0;
-}