|
NCBI C++ ToolKit
|
00001 /* $Id: glcgi_image.cpp 22039 2010-09-08 14:14:26Z kuznets $ 00002 * =========================================================================== 00003 * 00004 * PUBLIC DOMAIN NOTICE 00005 * National Center for Biotechnology Information 00006 * 00007 * This software/database is a "United States Government Work" under the 00008 * terms of the United States Copyright Act. It was written as part of 00009 * the author's official duties as a United States Government employee and 00010 * thus cannot be copyrighted. This software/database is freely available 00011 * to the public for use. The National Library of Medicine and the U.S. 00012 * Government have not placed any restriction on its use or reproduction. 00013 * 00014 * Although all reasonable efforts have been taken to ensure the accuracy 00015 * and reliability of the software and data, the NLM and the U.S. 00016 * Government do not and cannot warrant the performance or results that 00017 * may be obtained by using this software or data. The NLM and the U.S. 00018 * Government disclaim all warranties, express or implied, including 00019 * warranties of performance, merchantability or fitness for any particular 00020 * purpose. 00021 * 00022 * Please cite the author in any work or product based on this material. 00023 * 00024 * =========================================================================== 00025 * 00026 * Author: Denis Vakatov 00027 * 00028 * File Description: 00029 * CGlCgiImage -- base class for producing images via a CGI using OpenGL 00030 */ 00031 00032 #include <ncbi_pch.hpp> 00033 #include <gui/opengl/mesa/glcgi_image.hpp> 00034 #include <gui/opengl/mesa/gloscontext.hpp> 00035 #include <html/page.hpp> 00036 00037 #include <util/image/image.hpp> 00038 #include <util/image/image_util.hpp> 00039 #include <util/image/image_io.hpp> 00040 00041 00042 BEGIN_NCBI_SCOPE 00043 00044 // 00045 // content-type headers for images 00046 // 00047 struct SContentType 00048 { 00049 CImageIO::EType m_Type; 00050 const char* m_Encoding; 00051 }; 00052 00053 static const SContentType kContentTypes[] = { 00054 { CImageIO::eBmp, "image/bmp" }, 00055 { CImageIO::eGif, "image/gif" }, 00056 { CImageIO::eJpeg, "image/jpeg" }, 00057 { CImageIO::ePng, "image/png" }, 00058 { CImageIO::eSgi, "image/sgi" }, 00059 { CImageIO::eTiff, "image/tiff" }, 00060 { CImageIO::eXpm, "image/xmp" }, 00061 00062 // must be last 00063 { CImageIO::eUnknown, NULL } 00064 }; 00065 00066 00067 // 00068 // default error template 00069 // this can be replaced as needed 00070 // 00071 00072 00073 // 00074 // default ctor 00075 // 00076 CGlCgiImageApplication::CGlCgiImageApplication() 00077 : m_Width (800), 00078 m_Height(600), 00079 m_Format(CImageIO::ePng) 00080 { 00081 } 00082 00083 00084 CGlCgiImageApplication::~CGlCgiImageApplication() 00085 { 00086 } 00087 00088 00089 // 00090 // get our aspect ratio 00091 // 00092 float CGlCgiImageApplication::GetAspectRatio(void) const 00093 { 00094 if (m_Context) { 00095 size_t width = m_Context->GetBuffer().GetWidth(); 00096 size_t height = m_Context->GetBuffer().GetHeight(); 00097 return (float)width / (float)height; 00098 } 00099 return 1.0f; 00100 } 00101 00102 00103 // 00104 // Init() 00105 // Initialize our renderer to a default size (800x600 pixels) 00106 void CGlCgiImageApplication::Init() 00107 { 00108 m_ErrorTemplate = GetConfig().Get("filesystem", "ErrorTemplate"); 00109 } 00110 00111 00112 CGlOsContext& CGlCgiImageApplication::x_GetContext(void) 00113 { 00114 if ( !m_Context ) { 00115 // create an off-screen renderer that handles a virtual frame buffer 00116 m_Context.Reset(new CGlOsContext(m_Width, m_Height)); 00117 } 00118 return *m_Context; 00119 } 00120 00121 00122 00123 // 00124 // ProcessRequest() 00125 // Here, we do a minimal amount of set-up and pass off to our rendering hook. 00126 // When this hook completes, we write out the resulting image to the response. 00127 // 00128 int CGlCgiImageApplication::ProcessRequest(CCgiContext& ctx) 00129 { 00130 CStopWatch sw; 00131 sw.Start(); 00132 00133 double render_time = 0; 00134 double image_flip_time = 0; 00135 try { 00136 // user hook: pre-rpocess 00137 x_PreProcess(ctx); 00138 00139 // create an off-screen renderer that handles a virtual frame buffer 00140 if ( !x_GetContext().MakeCurrent() ) { 00141 LOG_POST(Error << "CGlCgiImageApplication::ProcessRequest(): " 00142 "Failed to make off-screen renderer current"); 00143 return 1; 00144 } 00145 00146 00147 // call the rendering hook 00148 Render(ctx); 00149 00150 // call glFinish() - VERY IMPORTANT FOR OFF_SCREEN RENDERING 00151 // this forces any buffered OpenGL requests to complete now. 00152 glFinish(); 00153 00154 render_time = sw.Elapsed(); 00155 00156 // final image preparation 00157 // the image is upside-down because frame buffers are, in general, 00158 // upside-down. Also, we have an alpha channel we need to flatten. 00159 m_Context->SetBuffer().SetDepth(3); 00160 CImageUtil::FlipY(m_Context->SetBuffer()); 00161 00162 image_flip_time = sw.Elapsed(); 00163 00164 // user hook: post-process 00165 x_PostProcess(ctx); 00166 00167 } 00168 catch (CException& e) { 00169 x_HandleError(ctx, e.GetMsg()); 00170 return 1; 00171 } 00172 catch (std::exception& e) { 00173 x_HandleError(ctx, e.what()); 00174 return 1; 00175 } 00176 00177 // 00178 // and stream back the image 00179 // this requires that we first write the image to a temporary file and then 00180 // echo the contents of this image back 00181 // 00182 // don't forget to set our content-type 00183 string encoding("image/unknown"); 00184 for (const SContentType* type = kContentTypes; type->m_Encoding; ++type) { 00185 if (type->m_Type == m_Format) { 00186 encoding = type->m_Encoding; 00187 break; 00188 } 00189 } 00190 CCgiResponse& response = ctx.GetResponse(); 00191 response.SetContentType(encoding); 00192 00193 // 00194 // write the standard CGI headers 00195 // if this line is commented out, the image will be dumped to stdout anc 00196 // can be redirected to a file for local access 00197 // 00198 response.WriteHeader(); 00199 00200 // 00201 // write the image 00202 // we wrap the management of the temporary file in a class in case one of 00203 // our operations throws; this way, the stack unwinding for the exception 00204 // will insure that our temporary file gets cleaned up 00205 // 00206 00207 CImageIO::WriteImage(m_Context->GetBuffer(), response.out(), m_Format); 00208 00209 double image_encode_time = sw.Elapsed(); 00210 LOG_POST(Info << "CGlCgiImage::ProcessRequest():\n" 00211 << " render time = " << render_time << "\n" 00212 << " process time = " << image_flip_time - render_time << "\n" 00213 << " encode time = " << image_encode_time - image_flip_time << "\n"); 00214 00215 return 0; 00216 } 00217 00218 00219 void CGlCgiImageApplication::x_HandleError(CCgiContext& ctx, 00220 const string& msg) 00221 { 00222 CCgiResponse& response = ctx.GetResponse(); 00223 response.SetContentType("text/html"); 00224 response.WriteHeader(); 00225 00226 if (m_ErrorTemplate.empty()) { 00227 CHTMLPage page("CGI Error", m_ErrorTemplate); 00228 page.AppendChild(new CHTMLPlainText(msg)); 00229 page.Print(response.out()); 00230 } else { 00231 CHTMLPage page("", m_ErrorTemplate); 00232 page.AddTagMap("message", new CHTMLPlainText(msg)); 00233 page.Print(response.out()); 00234 } 00235 } 00236 00237 00238 void CGlCgiImageApplication::x_PreProcess(CCgiContext& ctx) 00239 { 00240 // set the width and height from the 'width=' and 'height=' keys 00241 {{ 00242 TCgiEntries::const_iterator width_iter = 00243 ctx.GetRequest().GetEntries().find("width"); 00244 if (width_iter != ctx.GetRequest().GetEntries().end()) { 00245 m_Width = NStr::StringToInt(width_iter->second); 00246 } 00247 00248 TCgiEntries::const_iterator height_iter = 00249 ctx.GetRequest().GetEntries().find("height"); 00250 if (height_iter != ctx.GetRequest().GetEntries().end()) { 00251 m_Height = NStr::StringToInt(height_iter->second); 00252 } 00253 }} 00254 00255 // set the image format using the 'fmt=' key 00256 TCgiEntries::const_iterator fmt_iter = 00257 ctx.GetRequest().GetEntries().find("fmt"); 00258 if (fmt_iter != ctx.GetRequest().GetEntries().end()) { 00259 string fmt(fmt_iter->second); 00260 fmt = "." + fmt; 00261 m_Format = CImageIO::GetTypeFromFileName(fmt); 00262 } 00263 } 00264 00265 00266 void CGlCgiImageApplication::x_PostProcess(CCgiContext& ctx) 00267 { 00268 } 00269 00270 00271 END_NCBI_SCOPE
1.7.5.1
Modified on Wed May 23 13:29:47 2012 by modify_doxy.py rev. 337098