Opened 15 years ago

Closed 14 years ago

#3201 closed defect (fixed)

GetBytes(), Write() on ImageObj results in error when parsing mapfile with AGG renderer in C# mapscript.

Reported by: getiem Owned by: tamas
Priority: normal Milestone: 5.6.1 release
Component: MapScript Version: svn-trunk (development)
Severity: normal Keywords:
Cc: dmorissette

Description (last modified by dmorissette)

GetBytes(), Write() on ImageObj results in error when parsing mapfile with AGG renderer specified.

Tested on mapserver-mapscript C# on windows through MS4W:

Options:

  1. MS4W 2.29 --> Mapserver 5.2
  2. MS4W 3.0 beta 7 --> Mapserver 5.4.2
  3. MS4W 5.6 beta 5 --> Mapserver 5.6 beta 5

Short description:

When using AGG renderer in the mapObj (mapfile) the code will return the following when using the function getBytes(), or Write() on the ImageObj.

With versions there are differences:

1) and 2) return an image. The image looks good, but when using OptiPNG or other programs, the internals of the PNG are crippled. This becomes visible within mapserver when using AGG + Quantization options on. The image is not usefull.(transparency is lost, blacks will become transparent all the time, labels lost).

3) returns an error, no matter the quantization or not: base {"getBytes: General error message. Failed to get image buffer;msSaveImageBufferGD(): Image handling error. Unknown output image type driver: gd/."} System.Exception {System.ApplicationException}

Above 3) shows where the error resides.

Further testing:

ImageObj.Save(image.png) returns the image as should in all cases. Normal image, good transparency. Also with the quantization options on.

Change History (7)

comment:1 by dmorissette, 15 years ago

Cc: dmorissette added
Description: modified (diff)

Tamas, Any idea? Is this a 5.6 blocker?

Gerben, could you provide a test case to reproduce this? (i.e. simple mapfile, data and script)

comment:2 by tamas, 15 years ago

I would require at least a code example to see how the imageObj has actually been created. I suspect it hasn't been initialized properly. In most of the cases the image is obtained as a return value of an operation like mapObj.draw() or mapObj.drawQuery() classObj.createLegendIcon() which should initialize the image in a reasonable way.

comment:3 by getiem, 15 years ago

I have no mapfile, no symbols.txt, no fonts.txt. All is done in code. The code is not in one class, so not very handy to give, data is in database, so not really handy. I will give you some snippets of my code, where you can add a layer of yourself in:

//Starting with:
private mapObj pngBasis = new mapObj(null);
pngBasis.extent = extent; 
//(where extent is a valid rectObj)
pngBasis.name = pngNaam;
 //(where pngNaam is a valid string)
foreach (symbolObj symbol in Symbol.ListOfSymbols) {
                pngBasis.symbolset.appendSymbol(symbol);
} 
//where Symbol.ListOfSymbols is a list with code factored symbols, see below
pngBasis.fontset.fonts.set("arial", fontFileArial); 
//(where fontFileArial is the string to path of the .ttf file.  
//This fontset is not written to mapfile with mapObj.save(). I will file  this as a separate bug.

///
Here adding all the layers with classes and styles.
///

//then adding the outputformat
outputFormatObj mapscriptOutputFormat = new outputFormatObj("AGG/PNG", outputformatname);
mapscriptOutputFormat.extension = "PNG";
mapscriptOutputFormat.transparent = 1;
mapscriptOutputFormat.imagemode = (int)MS_IMAGEMODE.MS_IMAGEMODE_RGBA;
mapscriptOutputFormat.setOption("QUANTIZE_FORCE", "on");
mapscriptOutputFormat.setOption("QUANTIZE_COLORS", "256");
mapscriptOutputFormat.validate();
pngBasis.appendOutputFormat(mapscriptOutputFormat);
pngBasis.selectOutputFormat(outputformatname);

//setting image size on mapobj:
pngBasis.width = kdbericht.KdPixelsBreed;
pngBasis.height = kdbericht.KdPixelsHoog;

//finally putting it in an imageobj
imageObj mapScriptImage = pngBasis.draw();



//Then the line where the error occurs:
byte[] imagebytes =  mapScriptImage.getBytes();

// Or when using a different one:
// mapScriptImage.write(memorystream)  gives the same error.






Symbols:

public static class Symbol
    {
        private static Collection<symbolObj> symbols;


        public static Collection<symbolObj> ListOfSymbols
        {
            get
            {
                if (symbols == null) {
                    symbols = new Collection<symbolObj>();
                    symbols.Add(circle);
                    symbols.Add(puntPunt);
                    symbols.Add(streepStip);
                    symbols.Add(streepStreep);
                    symbols.Add(stipStip);
                    symbols.Add(puntPunt);

                }
                return symbols;
            }
        }
        private static symbolObj circle
        {
            get
            {                
                var symbol = new symbolObj(Repository.GmSymbolName.enmCode.circle.ToString(), null);
                symbol.type = (int)MS_SYMBOL_TYPE.MS_SYMBOL_ELLIPSE;
                symbol.filled = 1;
                var line = new lineObj();
                line.add(new pointObj(1, 1, 0, 0));
                symbol.setPoints(line);
                return symbol;
            }
        }
        private static symbolObj puntPunt
        {
            get
            {
                var symbol = new symbolObj(Repository.GmSymbolName.enmCode.puntpunt.ToString(), null);
                symbol.type = (int)MS_SYMBOL_TYPE.MS_SYMBOL_ELLIPSE;
                symbol.filled = 1;
                var line = new lineObj();
                line.add(new pointObj(1, 1, 0, 0));
                symbol.setPoints(line);
                symbol.patternlength = 4;
                symbol.setPattern(0, 1);
                symbol.setPattern(1, 20);
                symbol.setPattern(2, 1);
                symbol.setPattern(3, 20);
                return symbol;
            }
        }
        private static symbolObj stipStip
        {
            get
            {
                var symbol = new symbolObj(Repository.GmSymbolName.enmCode.stipstip.ToString(), null);
                symbol.type = (int)MS_SYMBOL_TYPE.MS_SYMBOL_ELLIPSE;
                symbol.filled = 1;
                var line = new lineObj();
                line.add(new pointObj(1, 1, 0, 0));
                symbol.setPoints(line);
                symbol.patternlength = 4;
                symbol.setPattern(0, 1);
                symbol.setPattern(1, 10);
                symbol.setPattern(2, 1);
                symbol.setPattern(3, 10);
                return symbol;
            }
        }
        private static symbolObj streepStip
        {
            get
            {
                var symbol = new symbolObj(Repository.GmSymbolName.enmCode.streepstip.ToString(), null);
                symbol.type = (int)MS_SYMBOL_TYPE.MS_SYMBOL_ELLIPSE;
                symbol.filled = 1;
                var line = new lineObj();
                line.add(new pointObj(1, 1, 0, 0));
                symbol.setPoints(line);
                symbol.patternlength = 4;
                symbol.setPattern(0, 10);
                symbol.setPattern(1, 5);
                symbol.setPattern(2, 1);
                symbol.setPattern(3, 5);
                return symbol;
            }
        }
        private static symbolObj streepStreep
        {
            get
            {
                var symbol = new symbolObj(Repository.GmSymbolName.enmCode.streepstreep.ToString(), null);
                symbol.type = (int)MS_SYMBOL_TYPE.MS_SYMBOL_ELLIPSE;
                symbol.filled = 1;
                var line = new lineObj();
                line.add(new pointObj(1, 1, 0, 0));
                symbol.setPoints(line);
                symbol.patternlength = 4;
                symbol.setPattern(0, 20);
                symbol.setPattern(1, 10);
                symbol.setPattern(2, 20);
                symbol.setPattern(3, 10);
                return symbol;
            }
        }
    }

comment:4 by tamas, 14 years ago

This sample seems to be working for me. I've uploaded the complete VS2008 example here http://vbkto.dyndns.org/tests/Sample.zip

comment:5 by getiem, 14 years ago

Thanks Tamas,

I worked the example. Added a layer + feature and saved the image in 3 ways. Save(), getBytes() --> write to file, write() --> stream --> write to file.

The error that occurs is described as the options 1 and 2. The image is not transparent, blacks are weird, transparency is on other features than supposed to be. Indeed, no error is given. Maybe that was in an other version of MS.

I didn't test it with other versions of mapscript/server as you already put in the newest version.

Added the rar file with the example here : http://jump.fm/CFNNP password: mapserver

comment:6 by tamas, 14 years ago

It looks like this option haven't been supported when rendering the image to a buffer. I consider the difference of the image saving methods are completely unwanted and the following fix is about to be applied in mapgd.c:

unsigned char *msSaveImageBufferGD(imageObj *img, int *size_ptr, outputFormatObj *format) {

unsigned char *imgbytes;

gdIOCtx *ctx = gdNewDynamicCtx (2048, NULL); if (msSaveImageGDCtx( img, ctx, format ) == MS_SUCCESS)

imgbytes = gdDPExtractData (ctx, size_ptr);

else

imgbytes = NULL;

ctx->gd_free(ctx);

return imgbytes;

}

comment:7 by tamas, 14 years ago

Component: MapScript-C#MapScript
Milestone: 5.6 release5.6.1 release
Resolution: fixed
Status: newclosed

Fixed in r9666 and r9667

Note: See TracTickets for help on using tickets.