Permalink
Browse files

Output format: add a AGG/MIXED pseudo driver.

This driver redirects to a concrete driver when the image
has non-opaque pixels, and to another one when the image
is fully opaque.

Requires to define TRANSPARENT_FORMAT and OPAQUE_FORMAT
FORMAT_OPTION on OUTPUTFORMATs that instanciate that
driver. Those underlying formats can be AGG/PNG, AGG/JPEG
or a GDAL/ one (anyone that uses AGG/ for rendering)

Two predefined formats image/jpeg-png and image/jpeg-png8
are added.

Example of custom mixed formats:

    OUTPUTFORMAT
      NAME jpeg_low
      MIMETYPE "image/jpeg; quality=50"
      DRIVER AGG/JPEG
      IMAGEMODE RGB
      FORMATOPTION "QUALITY=50"
    END

    OUTPUTFORMAT
      NAME jpeg_low_png
      MIMETYPE "image/jpeg_low-png"
      DRIVER AGG/MIXED
      FORMATOPTION "TRANSPARENT_FORMAT=png"
      FORMATOPTION "OPAQUE_FORMAT=jpeg_low"
    END

    OUTPUTFORMAT
      NAME jpeg_high
      MIMETYPE "image/jpeg; quality=99"
      DRIVER AGG/JPEG
      IMAGEMODE RGB
      FORMATOPTION "QUALITY=99"
    END

    OUTPUTFORMAT
      NAME jpeg_high_png8
      MIMETYPE "image/jpeg_high-png8"
      DRIVER AGG/MIXED
      FORMATOPTION "TRANSPARENT_FORMAT=png8"
      FORMATOPTION "OPAQUE_FORMAT=jpeg_high"
    END
  • Loading branch information...
rouault committed Jun 26, 2016
1 parent 003f17a commit 0badcfe0f193e46b4c4875194f7d53ce3723906f
Showing with 149 additions and 0 deletions.
  1. +144 −0 mapoutput.c
  2. +1 −0 mapserver.h
  3. +1 −0 mapwcs.c
  4. +1 −0 mapwcs11.c
  5. +1 −0 mapwcs20.c
  6. +1 −0 mapwms.c
@@ -102,6 +102,8 @@ struct defaultOutputFormatEntry defaultoutputformats[] = {
{"jpeg","AGG/JPEG","image/jpeg"},
{"png8","AGG/PNG8","image/png; mode=8bit"},
{"png24","AGG/PNG","image/png; mode=24bit"},
{"jpegpng", "AGG/MIXED", "image/jpeg-png"},
{"jpegpng8", "AGG/MIXED", "image/jpeg-png8"},
#ifdef USE_CAIRO
{"pdf","CAIRO/PDF","application/x-pdf"},
{"svg","CAIRO/SVG","image/svg+xml"},
@@ -203,6 +205,37 @@ outputFormatObj *msCreateDefaultOutputFormat( mapObj *map,
format->renderer = MS_RENDER_WITH_AGG;
}
else if( strcasecmp(driver,"AGG/MIXED") == 0 &&
name != NULL && strcasecmp(name,"jpegpng") == 0 ) {
format = msAllocOutputFormat( map, name, driver );
format->mimetype = msStrdup("image/jpeg-png");
format->imagemode = MS_IMAGEMODE_RGBA;
format->extension = msStrdup("XXX");
format->renderer = MS_RENDER_WITH_AGG;
msSetOutputFormatOption( format, "OPAQUE_FORMAT", "jpeg");
msSetOutputFormatOption( format, "TRANSPARENT_FORMAT", "png24");
}
else if( strcasecmp(driver,"AGG/MIXED") == 0 &&
name != NULL && strcasecmp(name,"jpegpng8") == 0 ) {
format = msAllocOutputFormat( map, name, driver );
format->mimetype = msStrdup("image/jpeg-png8");
format->imagemode = MS_IMAGEMODE_RGBA;
format->extension = msStrdup("XXX");
format->renderer = MS_RENDER_WITH_AGG;
msSetOutputFormatOption( format, "OPAQUE_FORMAT", "jpeg");
msSetOutputFormatOption( format, "TRANSPARENT_FORMAT", "png8");
}
else if( strcasecmp(driver,"AGG/MIXED") == 0 ) {
if(!name) name="mixed";
format = msAllocOutputFormat( map, name, driver );
format->mimetype = msStrdup("image/mixed");
format->imagemode = MS_IMAGEMODE_RGBA;
format->extension = msStrdup("XXX");
format->renderer = MS_RENDER_WITH_AGG;
}
#if defined(USE_CAIRO)
else if( strcasecmp(driver,"CAIRO/PNG") == 0 ) {
if(!name) name="cairopng";
@@ -607,6 +640,7 @@ void msApplyOutputFormat( outputFormatObj **target,
if( format == NULL ) {
if( formatToFree )
msFreeOutputFormat( formatToFree );
*target = NULL;
return;
}
@@ -998,6 +1032,32 @@ int msOutputFormatValidate( outputFormatObj *format, int issue_error )
format->renderer = MS_RENDER_WITH_RAWDATA;
}
if( !strcasecmp(format->driver,"AGG/MIXED") )
{
if( !msGetOutputFormatOption(format, "TRANSPARENT_FORMAT", NULL) )
{
result = MS_FALSE;
if( issue_error )
msSetError( MS_MISCERR,
"OUTPUTFORMAT %s lacks a 'TRANSPARENT_FORMAT' FORMATOPTION.",
"msOutputFormatValidate()", format->name );
else
msDebug( "OUTPUTFORMAT %s lacks a 'TRANSPARENT_FORMAT' FORMATOPTION.",
format->name );
}
if( !msGetOutputFormatOption(format, "OPAQUE_FORMAT", NULL) )
{
result = MS_FALSE;
if( issue_error )
msSetError( MS_MISCERR,
"OUTPUTFORMAT %s lacks a 'OPAQUE_FORMAT' FORMATOPTION.",
"msOutputFormatValidate()", format->name );
else
msDebug( "OUTPUTFORMAT %s lacks a 'OPAQUE_FORMAT' FORMATOPTION.",
format->name );
}
}
return result;
}
@@ -1049,3 +1109,87 @@ int msInitializeRendererVTable(outputFormatObj *format)
return MS_FAILURE;
}
/************************************************************************/
/* msOutputFormatResolveFromImage() */
/************************************************************************/
void msOutputFormatResolveFromImage( mapObj *map, imageObj* img )
{
outputFormatObj* format = map->outputformat;
assert( img->format == format );
assert( img->format->refcount >= 2 );
if( format->renderer == MS_RENDER_WITH_AGG &&
strcmp(format->driver, "AGG/MIXED") == 0 &&
(format->imagemode == MS_IMAGEMODE_RGB ||
format->imagemode == MS_IMAGEMODE_RGBA) )
{
outputFormatObj * new_format;
int has_non_opaque_pixels = MS_FALSE;
const char* underlying_driver_type = NULL;
const char* underlying_driver_name = NULL;
// Check if the image has non opaque pixels
if( format->imagemode == MS_IMAGEMODE_RGBA )
{
rasterBufferObj rb;
int ret;
ret = format->vtable->getRasterBufferHandle(img,&rb);
assert( ret == MS_SUCCESS );
if( rb.data.rgba.a )
{
int row;
for(row=0; row<rb.height && !has_non_opaque_pixels; row++) {
int col;
unsigned char *a;
a=rb.data.rgba.a+row*rb.data.rgba.row_step;
for(col=0; col<rb.width && !has_non_opaque_pixels; col++) {
if(*a < 255) {
has_non_opaque_pixels = MS_TRUE;
}
a+=rb.data.rgba.pixel_step;
}
}
}
}
underlying_driver_type = ( has_non_opaque_pixels ) ?
"TRANSPARENT_FORMAT" : "OPAQUE_FORMAT";
underlying_driver_name = msGetOutputFormatOption(format, underlying_driver_type,
NULL);
if( underlying_driver_name == NULL ) {
msSetError(MS_MISCERR,
"Missing %s format option on %s.",
"msOutputFormatResolveFromImage()",
underlying_driver_type, format->name );
return;
}
new_format = msSelectOutputFormat( map, underlying_driver_name );
if( new_format == NULL ) {
msSetError(MS_MISCERR,
"Cannot find %s output format.",
"msOutputFormatResolveFromImage()",
underlying_driver_name );
return;
}
if( new_format->renderer != MS_RENDER_WITH_AGG )
{
msSetError(MS_MISCERR,
"%s cannot be used as the %s format of %s since it is not AGG based.",
"msOutputFormatResolveFromImage()",
underlying_driver_name, underlying_driver_type, format->name );
return;
}
msApplyOutputFormat( &(map->outputformat),
new_format,
has_non_opaque_pixels,
MS_NOOVERRIDE,
MS_NOOVERRIDE );
msFreeOutputFormat( format );
img->format = map->outputformat;
img->format->refcount ++;
}
}
@@ -2739,6 +2739,7 @@ void msPopulateTextSymbolForLabelAndString(textSymbolObj *ts, labelObj *l, char
MS_DLL_EXPORT outputFormatObj *msCloneOutputFormat( outputFormatObj *format );
MS_DLL_EXPORT int msOutputFormatValidate( outputFormatObj *format,
int issue_error );
void msOutputFormatResolveFromImage( mapObj *map, imageObj* img );
/* ==================================================================== */
/* End of prototypes for functions in mapoutput.c */
@@ -2060,6 +2060,7 @@ this request. Check wcs/ows_enable_request settings.", "msWCSGetCoverage()", par
fo_filename );
/* Emit back to client. */
msOutputFormatResolveFromImage( map, image );
msIO_setHeader("Content-Type","%s",MS_IMAGE_MIME_TYPE(map->outputformat));
msIO_sendHeaders();
status = msSaveImage(map, image, NULL);
@@ -1227,6 +1227,7 @@ int msWCSReturnCoverage11( wcsParamsObj *params, mapObj *map,
/* output a single "stock" filename. */
/* -------------------------------------------------------------------- */
if( filename == NULL ) {
msOutputFormatResolveFromImage( map, image );
msIO_fprintf(
stdout,
" <ows:Reference xlink:href=\"cid:coverage/wcs.%s\"/>\n"
@@ -2275,6 +2275,7 @@ static int msWCSWriteFile20(mapObj* map, imageObj* image, wcs20ParamsObjPtr para
/* output a single "stock" filename. */
/* -------------------------------------------------------------------- */
if( filename == NULL ) {
msOutputFormatResolveFromImage( map, image );
if(multipart) {
msIO_fprintf( stdout, "\r\n--wcs\r\n" );
msIO_fprintf(
@@ -3694,6 +3694,7 @@ int msWMSGetMap(mapObj *map, int nVersion, char **names, char **values, int nume
if(!strcmp(MS_IMAGE_MIME_TYPE(map->outputformat), "application/json")) {
msIO_setHeader("Content-Type","application/json; charset=utf-8");
} else {
msOutputFormatResolveFromImage( map, img );
msIO_setHeader("Content-Type", "%s", MS_IMAGE_MIME_TYPE(map->outputformat));
}
msIO_sendHeaders();

0 comments on commit 0badcfe

Please sign in to comment.