NCBI C++ ToolKit
glcgi_image.cpp
Go to the documentation of this file.
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
Modified on Wed May 23 13:29:47 2012 by modify_doxy.py rev. 337098