Exemplo n.º 1
0
	File  ( const TCHAR *name, const TCHAR *mode) 
	{ 
		// for a360 support - allows binary diff syncing
		if (mode != nullptr && (mode[0] == _T('w') || mode[0] == _T('a') || (mode[0] == _T('r') && mode[1] == _T('+') )))
		{
			MaxSDK::Util::Path storageNamePath(name);
			storageNamePath.SaveBaseFile();
		}
		stream = _tfopen(name,mode); 
	}
Exemplo n.º 2
0
void PrettyPrint(const TCHAR* name, CComPtr<IXMLDOMDocument> pXMLDoc)
{
	// perform formatting XSLT transform to get indented XML output
	CComPtr<IXMLDOMDocument> pXSLDoc;
	BSTR outputXML = NULL;
	HRESULT hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,  IID_IXMLDOMDocument, (void**)&pXSLDoc);
	if (SUCCEEDED(hr)) {
		// load indenting XSL doc 
		VARIANT_BOOL result;
		CComBSTR indentXSL(
			"<xsl:stylesheet version=\"1.0\""
			"      xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"
			"   <xsl:output method=\"xml\"/>"
			"   <xsl:param name=\"indent-increment\" select=\"'\t'\" />"
			"   <xsl:template match=\"node()\">"
			"      <xsl:param name=\"indent\" select=\"'&#xA;'\"/>"
			"      <xsl:value-of select=\"$indent\"/>"
			"      <xsl:copy>"
			"        <xsl:copy-of select=\"@*\" />"
			"        <xsl:apply-templates>"
			"          <xsl:with-param name=\"indent\""
			"               select=\"concat($indent, $indent-increment)\"/>"
			"        </xsl:apply-templates>"
			"        <xsl:if test=\"node()\">"
			"          <xsl:value-of select=\"$indent\"/>"
			"        </xsl:if>"
			"      </xsl:copy>"
			"   </xsl:template>"
//			"   <xsl:template match=\"comment()|processing-instruction()\">"
//			"      <xsl:copy />"
//			"   </xsl:template>"
//			"   <!-- WARNING: this is dangerous. Handle with care -->"
//			"   <xsl:template match=\"text()[normalize-space(.)='']\"/>"
			"</xsl:stylesheet>"
			);
		hr = pXSLDoc->loadXML(indentXSL, &result);
		if (SUCCEEDED(hr)) {
			// perform transform
			hr = pXMLDoc->transformNode(pXSLDoc, &outputXML);
		}
	}

	// output transformed XML if previous sequence succeeded, else normal XMLDoc save
	if (SUCCEEDED(hr)) {
		MaxSDK::Util::TextFile::Writer out;
		//Need UTF8
		if (out.Open(name, false, CP_UTF8))
		{
			// hack the UTF-16 back to UTF-8 (there probably is a way to mod the stylesheet to do this)
			wchar_t* enc = wcsstr(outputXML, L"\"UTF-16\"");
			if (enc != NULL) memcpy(enc, L"\"utf-8\" ", 8 * sizeof(wchar_t));
			// convert BSTR to MBCS for output
			// write the XML

			out.Write(outputXML);
			out.Close();
		}
		SysFreeString(outputXML);
	}
	else
	{
		// for a360 support - allows binary diff syncing
		MaxSDK::Util::Path storageNamePath(name);
		storageNamePath.SaveBaseFile();

		// save the XML graph out to the export file
		pXMLDoc->save(CComVariant(name));
	}

	
}
Exemplo n.º 3
0
int Blockporter::DoExport(const TCHAR* name, ExpInterface* ei, Interface* i, BOOL supressPrompts, DWORD options)
{
	INode* root;
	//caption and message for MessagesBoxes
	TCHAR msg[MB_BUFFER_LENGTH];
	TCHAR cap[MB_BUFFER_LENGTH];

	//Get the root node
	root = i->GetRootNode();

	//the node of our object should be a groupnode, which contains every object
	//we want to export
	i->PushPrompt(_T("Searching for Group..."));
	bool found = false;
	for(int idx = 0; idx < root->NumberOfChildren(); idx++)
	{
		if(root->GetChildNode(idx)->IsGroupHead())
		{
			//we found our group
			//next step is to make the group node our new root, because every object
			//we want is part of this group

			found = true;
			root = root->GetChildNode(idx);
			break;
		}
	}

	if(!found)
	{
		MessageBox(nullptr, GetString(IDS_ERROR_NO_GROUP, msg), GetString(IDS_GENERAL_ERROR, cap), MB_OK | MB_ICONERROR);
		return 0;
	}

	//Now that we have the groupnode let's compare the fileversions
	if(!IsNewModelVersion(name, root->GetName()))
	{
		if(MessageBox(nullptr, GetString(IDS_VER_TO_LOW_MSG, msg), GetString(IDS_VER_TO_LOW_CAP, cap), MB_YESNO | MB_ICONEXCLAMATION) == IDNO)
			return 1;
	}

	i->PushPrompt(_T("Opening File"));
	Interface14* iface = GetCOREInterface14();
	UINT code = iface->DefaultTextSaveCodePage(true);
	MaxSDK::Util::Path storageNamePath(name);
	storageNamePath.SaveBaseFile();
	switch (code & MaxSDK::Util::MaxStringDataEncoding::MSDE_CP_MASK)
	{
	case CP_UTF8:
		mStream = _tfopen(name, _T("wt, ccs=UFT-8"));
		break;
	case MaxSDK::Util::MaxStringDataEncoding::MSDE_CP_UTF16:
		mStream = _tfopen(name, _T("wt, ccs=UTF-16BE"));
		break;
	default:
		mStream = _tfopen(name, _T("wt"));
	}
	if(!mStream)
		return 0;

	//now we have our file stream, so let's write the header
	i->PushPrompt(_T("Writing Header"));
	WriteHeader(root->GetName(), root->NumberOfChildren());

	//now that we have the header written, let's iterate through the objects in the
	//group and export the meshes and lights

	INode* child;
    Point3 pMin(0,0,0), pMax(0,0,0);

	for(int idx = 0; idx < root->NumberOfChildren(); idx++)
	{
		child = root->GetChildNode(idx);
		i->PushPrompt(_T("Processing Object %s", child->GetName()));
		if(child->IsGroupHead())
		{
			MessageBox(nullptr, GetString(IDS_ERROR_TO_MANY_GROUPS, msg), GetString(IDS_GENERAL_ERROR, cap), MB_OK | MB_ICONERROR);
			continue;
		}

		ObjectState os = child->EvalWorldState(0);

		//let's take a look at the SuperClassID of the object
		//so we find out if it's a mesh or a light
		if(!os.obj)
			continue; //somehow this node doesn't have an object

        Box3 boundBox;

		switch(os.obj->SuperClassID())
		{
		case GEOMOBJECT_CLASS_ID:
			_ftprintf(mStream, _T("<ObjectID=%i>\n"), idx);
			i->PushPrompt(_T("Writing MeshData for Object %s", child->GetName()));
			boundBox = WriteMeshData(child, idx);
            pMin.x = (boundBox.Min().x < pMin.x) ? boundBox.Min().x : pMin.x;
            pMin.y = (boundBox.Min().y < pMin.y) ? boundBox.Min().y : pMin.y;
            pMax.x = (boundBox.Max().x > pMax.x) ? boundBox.Max().x : pMax.x;
            pMax.y = (boundBox.Max().y > pMax.y) ? boundBox.Max().y : pMax.y;
			i->PushPrompt(_T("Writing MaterialData for Object %s", child->GetName()));
			WriteMaterialData(child);
			_ftprintf(mStream, _T("</Object>\n"));
			break;
		//case LIGHT_CLASS_ID:
		//	WriteLightData(child, idx);
		//	break;
		}
	}

    //Write the Bounding Box
    _ftprintf(mStream, _T("<BoundingBox>\n"));
    _ftprintf(mStream, _T("\t<Min=%f,%f>\n"), pMin.x, pMin.y);
    _ftprintf(mStream, _T("\t<Max=%f,%f>\n"), pMax.x, pMax.y);
    _ftprintf(mStream, _T("</BoundingBox>\n"));
	//we are done exporting, so close the stream
	i->PushPrompt(_T("Closing file..."));
	fclose(mStream);

	MessageBox(nullptr, GetString(IDS_FINISH_MSG, msg), GetString(IDS_FINISH_CAP, cap), MB_OK | MB_ICONINFORMATION);

	return 1;
}
Exemplo n.º 4
0
/* This function handles writing out EPS files.  It is written to be
* as "PostScript friendly as possible", i.e. it:
*   1) Uses a fairly full set of DSC comments
*   2) Uses its own dictionary instead of assuming there is room in
*      the current one
*   3) If colorimage is not supported on the PostScript interpreter
*      and an RGB image was selected the image will be rendered as grayscale
*      instead using the NTSC conversion.
*/
BMMRES
	BitmapIO_EPS::Save(const TCHAR *name, Bitmap *bitmap) 
{
	int xOffset = 0;     // Offset for the lower left corner
	int yOffset = 0;     // of the image */
	int status;

	if (! bitmap) 
		return (ProcessImageIOError(&bi,BMMRES_INTERNALERROR));

	/* Compute the position on the page to output the image */
	Position (bitmap, &xOffset, &yOffset);

	// for a360 support - allows binary diff syncing
	MaxSDK::Util::Path storageNamePath(name);
	storageNamePath.SaveBaseFile();

	if ((mOutStream = _tfopen(name, _T("wb"))) == NULL)
		return (ProcessImageIOError(&bi));

	/* If a preview is desired then write the TIFF section */
	if (userSettings.preview)
	{
		status = WritePreview (userSettings.colorType, 
			userSettings.orientation,
			userSettings.xResolution,
			userSettings.yResolution,
			bitmap);
		if (status != BMMRES_SUCCESS)
		{
			fclose (mOutStream);
			return status;
		}
	}

	/* First the PostScript header */
	status = WriteHeader (bitmap, xOffset, yOffset);
	if (status != BMMRES_SUCCESS)
	{
		fclose (mOutStream);
		return status;
	}

	/* Now the image data itself */
	status = WriteImagePosition (bitmap, xOffset, yOffset);
	if (status != BMMRES_SUCCESS)
	{
		fclose (mOutStream);
		return status;
	}
	if (userSettings.binary && userSettings.colorType == RGBIMAGE)
		status = WriteBinaryRGBImage (bitmap);
	else if (userSettings.binary && userSettings.colorType == GRAYIMAGE)
		status = WriteBinaryGrayImage (bitmap);
	else if (userSettings.colorType == RGBIMAGE)
		status = WriteAsciiRGBImage (bitmap);
	else 
		status = WriteAsciiGrayImage (bitmap);
	if (status != BMMRES_SUCCESS)
	{
		fclose (mOutStream);
		return status;
	}

	/* Now the trailer */
	status = WriteTrailer ();

	/* If a preview was requested we need to now figure out the length of the
	* PostScript portion and write it to the header
	*/
	if (userSettings.preview)
		status = WritePSLength (userSettings.colorType, map);

	fclose (mOutStream);

	return (status);
}
Exemplo n.º 5
0
BMMRES
	BitmapIO_PNG::Save(const TCHAR *filename, Bitmap *map) 
{
	if(!map)
		return(ProcessImageIOError(&bi,BMMRES_INTERNALERROR));

	openMode = BMM_OPEN_W;

	// for a360 support - allows binary diff syncing
	MaxSDK::Util::Path storageNamePath(filename);
	storageNamePath.SaveBaseFile();

	if((mOutStream = _tfopen(filename,_T("wb"))) == NULL)
		return (ProcessImageIOError(&bi));

	BitmapStorage *palettedStorage = NULL;

	png = png_create_write_struct (PNG_VERSION, (void *) this, error_func, warning_func);
	if (setjmp(png->jmpbuf)) {
		if (info)
			for (png_uint_32 i = 0; i < info->height; i++)
				if (row_pointers[i]) free(row_pointers[i]);
		if (row_pointers) {
			free(row_pointers);
			row_pointers = NULL;
		}

		if (palettedStorage) delete palettedStorage;
		fclose(mOutStream);
		_tremove(filename);
		png_destroy_write_struct (&png, &info);
		return BMMRES_IOERROR;
	}
	info = png_create_info_struct(png);

	png_init_io(png, mOutStream);

	switch(cfg.color_type) {
	case PngPalette:
		info->color_type = PNG_COLOR_TYPE_PALETTE;
		info->pixel_depth = 8;
		info->valid |= PNG_INFO_PLTE;
		info->num_palette = 256;
		break;
	case PngRGB:
		info->color_type = PNG_COLOR_TYPE_RGB;
		break;
	case PngRGBA:
		info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
		break;
	case PngGray:
		info->color_type = PNG_COLOR_TYPE_GRAY;
		break;
	case PngGrayA:
		info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
		break;
	}
	info->width = map->Width();
	info->height = map->Height();
	
	// If gamma is on - store this in the file
	if (gammaMgr.enable) {
		info->valid |= PNG_INFO_gAMA;
		info->gamma = 1.0 / OutputGamma();
	} else info->gamma = 1.0f;

	if (map->Aspect() != 1.0f) {
		info->valid |= PNG_INFO_pHYs;
		info->x_pixels_per_unit = (png_uint_32)(1024.0f * map->Aspect());
		info->y_pixels_per_unit = 1024;
		info->phys_unit_type = 0;
	}

	if (cfg.interlaced)
		info->interlace_type = 1;
	else
		info->interlace_type = 0;

	switch( info->color_type) {
	case PNG_COLOR_TYPE_PALETTE:
	case PNG_COLOR_TYPE_GRAY:
		info->channels = 1;
		break;
	case PNG_COLOR_TYPE_GRAY_ALPHA:
		info->channels = 2;
		break;
	case PNG_COLOR_TYPE_RGB:
		info->channels = 3;
		break;
	case PNG_COLOR_TYPE_RGB_ALPHA:
		info->channels = 4;
		break;
	}

	info->bit_depth = cfg.bitdepth;
	info->rowbytes = info->width * info->channels * info->bit_depth / 8;

	row_pointers = (png_bytep *)malloc(info->height * sizeof(png_bytep));
	for (png_uint_32 i = 0; i < info->height; i++)
		row_pointers[i] = (png_bytep)malloc(info->rowbytes);

	switch (info->bit_depth) {
	case 16:  // this is only RGB/RGBA/Gray/GrayA
		switch(info->color_type) {
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			{
				// [dl | 22feb2005] Use a BMM_Color_fl buffer because the BMM_Color_64 version of GetOutputPixels()
				// uses a 13bit lookup table to do gamma correction, thus clamping the values.
				BMM_Color_fl *line_fl = (BMM_Color_fl *) calloc(info->width,sizeof(BMM_Color_fl));
				for (png_uint_32 iy = 0; iy < info->height; ++iy) {
					if (GetOutputPixels(0, iy, info->width, line_fl) != 1) {
						for (png_uint_32 i = 0; i < info->height; i++)
							if (row_pointers[i]) free(row_pointers[i]);
						if (row_pointers) {
							free(row_pointers);
							row_pointers = NULL;
						}

						fclose(mOutStream);
						_tremove(filename);
						free(line_fl);
						png_destroy_write_struct (&png, &info);
						return BMMRES_IOERROR;
					}
					BMM_Color_fl *l_fl=line_fl;
					unsigned short *oshort = (unsigned short *)row_pointers[iy];
					for (png_uint_32 ix = 0; ix < info->width; ++l_fl, ix++) {
						*oshort = BMM_Color_fl::clipColor(l_fl->r); 
						oshort++;
						*oshort = BMM_Color_fl::clipColor(l_fl->g); 
						oshort++;
						*oshort = BMM_Color_fl::clipColor(l_fl->b); 
						oshort++;
						if (info->channels == 4) {
							*oshort = BMM_Color_fl::clipColor(l_fl->a);
							oshort++;
						}
					}
				}
				free(line_fl);
			}
			break;
		case PNG_COLOR_TYPE_GRAY:
			{
				// [dl | 22feb2005] Use a float buffer because the BMM_Color_64 version of GetOutputPixels()
				// uses a 13bit lookup table to do gamma correction, thus clamping the values.
				float *line_fl_gray = (float*) calloc(info->width, sizeof(float));
				for (png_uint_32 iy = 0; iy < info->height; ++iy) {
					if (map->Get16Gray(0, iy, info->width, line_fl_gray) != 1) {
						for (png_uint_32 i = 0; i < info->height; i++)
							if (row_pointers[i]) free(row_pointers[i]);
						if (row_pointers) {
							free(row_pointers);
							row_pointers = NULL;
						}
						free(line_fl_gray);
						fclose(mOutStream);
						_tremove(filename);
						png_destroy_write_struct (&png, &info);
						return BMMRES_IOERROR;
					}
					float *l_fl_gray=line_fl_gray;
					unsigned short *oshort = (unsigned short *)row_pointers[iy];
					for (png_uint_32 ix = 0; ix < info->width; ix++, l_fl_gray++) {
						*oshort++ = BMM_Color_fl::clipColor(*l_fl_gray);
					}
				}
				free(line_fl_gray);
			}
			break;
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			{
				// [dl | 22feb2005] Use a BMM_Color_fl buffer because the BMM_Color_64 version of GetOutputPixels()
				// uses a 13bit lookup table to do gamma correction, thus clamping the values.
				BMM_Color_fl *line_fl = (BMM_Color_fl *) calloc(info->width, sizeof(BMM_Color_fl));
				float *line_fl_gray = (float*) calloc(info->width, sizeof(float));
				for (png_uint_32 iy = 0; iy < info->height; ++iy) {
					if (GetOutputPixels(0, iy, info->width, line_fl) != 1 ||
						map->Get16Gray(0, iy, info->width, line_fl_gray) != 1) {
							for (png_uint_32 i = 0; i < info->height; i++)
								if (row_pointers[i]) free(row_pointers[i]);
							if (row_pointers) {
								free(row_pointers);
								row_pointers = NULL;
							}
							free(line_fl);
							free(line_fl_gray);
							fclose(mOutStream);
							_tremove(filename);
							png_destroy_write_struct (&png, &info);
							return BMMRES_IOERROR;
					}
					BMM_Color_fl *l_fl = line_fl;
					float *l_fl_gray=line_fl_gray;
					unsigned short *oshort = (unsigned short *)row_pointers[iy];
					for (png_uint_32 ix = 0; ix < info->width; ix++, l_fl++, l_fl_gray++) {
						*oshort++ = BMM_Color_fl::clipColor(*l_fl_gray);
						*oshort++ = BMM_Color_fl::clipColor(l_fl->a);
					}
				}
				free(line_fl);
				free(line_fl_gray);
			}
			break;
		}
		break;

	case 8: // this can be any type
		switch(info->color_type) {
		case PNG_COLOR_TYPE_PALETTE: {
			// Set up a palette buffer
			PixelBuf48 palettebuf(info->num_palette);
			BMM_Color_48 *pal = palettebuf.Ptr();
			// Must compute a color palette, and reduce the image to 256 colors!
			// this calculates a palette based on the gamma corrected values, which
			// corresponds to what GetOutputPixels returns.
			if(CalcOutputPalette(256, pal) == 0) {
				for (png_uint_32 i = 0; i < info->height; i++)
					if (row_pointers[i]) free(row_pointers[i]);
				if (row_pointers) {
					free(row_pointers);
					row_pointers = NULL;
				}
				fclose(mOutStream);
				_tremove(filename);
				png_destroy_write_struct (&png, &info);
				return BMMRES_IOERROR;
			}
			info->palette = (png_color *)malloc(info->num_palette * sizeof(png_color));
			for (int i = 0; i < info->num_palette; i++) {
				info->palette[i].red = (unsigned char)(pal[i].r >> 8);
				info->palette[i].green = (unsigned char)(pal[i].g >> 8);
				info->palette[i].blue = (unsigned char)(pal[i].b >> 8);
			}
			PixelBuf64 line(info->width);
			ColorPacker* cpack = BMMNewColorPacker(info->width, pal, info->num_palette);
			for (png_uint_32 iy=0; iy < info->height; ++iy) {
				if(!GetOutputPixels(0, iy, info->width, line.Ptr())) {
					for (png_uint_32 i = 0; i < info->height; i++)
						if (row_pointers[i]) free(row_pointers[i]);
					if (row_pointers) {
						free(row_pointers);
						row_pointers = NULL;
					}
					fclose(mOutStream);
					_tremove(filename);
					png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				cpack->PackLine(line.Ptr(), row_pointers[iy], info->width);
			}
			cpack->DeleteThis();
									 }
									 break;
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			{
				BMM_Color_32 *line32 = (BMM_Color_32 *) calloc(info->width,sizeof(BMM_Color_32));
				for (png_uint_32 iy = 0; iy < info->height; ++iy) {
					if (GetDitheredOutputPixels(0, iy, info->width, line32) != 1) {
						for (png_uint_32 i = 0; i < info->height; i++)
							if (row_pointers[i]) free(row_pointers[i]);
						if (row_pointers) {
							free(row_pointers);
							row_pointers = NULL;
						}

						fclose(mOutStream);
						_tremove(filename);
						free(line32);
						png_destroy_write_struct (&png, &info);
						return BMMRES_IOERROR;
					}
					BMM_Color_32 *l32=line32;
					unsigned char *obyte = (unsigned char *)row_pointers[iy];
					for (png_uint_32 ix = 0; ix < info->width; ++l32, ix++) {
						*obyte = (unsigned char)l32->r; obyte++;
						*obyte = (unsigned char)l32->g; obyte++;
						*obyte = (unsigned char)l32->b; obyte++;
						if (info->channels == 4) {
							*obyte = (unsigned char)l32->a; obyte++;
						}
					}
				}
				free(line32);
			}
			break;
		case PNG_COLOR_TYPE_GRAY:
			{
				unsigned short *line = (unsigned short *) calloc(info->width * info->channels, sizeof(unsigned short));
				for (png_uint_32 iy = 0; iy < info->height; ++iy) {
					if (map->Get16Gray(0, iy, info->width, line) != 1) {
						for (png_uint_32 i = 0; i < info->height; i++)
							if (row_pointers[i]) free(row_pointers[i]);
						if (row_pointers) {
							free(row_pointers);
							row_pointers = NULL;
						}

						fclose(mOutStream);
						_tremove(filename);
						free(line);
						png_destroy_write_struct (&png, &info);
						return BMMRES_IOERROR;
					}
					unsigned short *l=line;
					unsigned char *obyte = (unsigned char *)row_pointers[iy];
					for (png_uint_32 ix = 0; ix < info->width; ix++) {
						*obyte++ = (unsigned char)(*l >> 8); l++;
					}
				}
				free(line);
			}
			break;
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			{
				BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width,sizeof(BMM_Color_64));
				unsigned short *line = (unsigned short *) calloc(info->width, sizeof(unsigned short));
				for (png_uint_32 iy = 0; iy < info->height; ++iy) {
					if (GetOutputPixels(0, iy, info->width, line64) != 1 ||
						map->Get16Gray(0, iy, info->width, line) != 1) {
							for (png_uint_32 i = 0; i < info->height; i++)
								if (row_pointers[i]) free(row_pointers[i]);
							if (row_pointers) {
								free(row_pointers);
								row_pointers = NULL;
							}

							fclose(mOutStream);
							_tremove(filename);
							free(line);
							free(line64);
							png_destroy_write_struct (&png, &info);
							return BMMRES_IOERROR;
					}
					unsigned short *l=line;
					BMM_Color_64 *l64 = line64;
					unsigned char *obyte = (unsigned char *)row_pointers[iy];
					for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) {
						*obyte++ = (unsigned char)(*l >> 8); l++;
						*obyte++ = (unsigned char)(l64->a >> 8);
					}
				}
				free(line);
				free(line64);
			}
			break;
		}
		break;
#ifdef OUTPUT_1_2_4
	case 4: { // Paletted only
			}
			break;
	case 2: { // Paletted only
			}
			break;
	case 1: { // Paletted only
			}
#endif
			break;
	}

	png_write_info(png, info);

	png_set_swap(png);

	png_write_image(png, row_pointers);

	png_write_end(png, info);
	fclose(mOutStream);

	for (png_uint_32 i = 0; i < info->height; i++)
		free(row_pointers[i]);

	free(row_pointers);

	png_destroy_write_struct (&png, &info);

	return BMMRES_SUCCESS;
}