From 6b2b036387784a74cf88f35715219071ee8718d2 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 1 May 2011 09:08:18 -0700 Subject: Added OpenSim.Capabilities.Handlers. For the moment it has only the GetTexture handler. The region module in Linden space uses it. WARNING: nothing of this works yet, it just compiles. --- .../Capabilities/Handlers/CapsServerConnector.cs | 73 +++++ OpenSim/Capabilities/Handlers/GetTextureHandler.cs | 356 +++++++++++++++++++++ .../ClientStack/Linden/Caps/GetTextureModule.cs | 315 +----------------- 3 files changed, 433 insertions(+), 311 deletions(-) create mode 100644 OpenSim/Capabilities/Handlers/CapsServerConnector.cs create mode 100644 OpenSim/Capabilities/Handlers/GetTextureHandler.cs (limited to 'OpenSim') diff --git a/OpenSim/Capabilities/Handlers/CapsServerConnector.cs b/OpenSim/Capabilities/Handlers/CapsServerConnector.cs new file mode 100644 index 0000000..561d767 --- /dev/null +++ b/OpenSim/Capabilities/Handlers/CapsServerConnector.cs @@ -0,0 +1,73 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; +using OpenMetaverse; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Capabilities.Handlers +{ + public class CapsServerConnector : ServiceConnector + { + private IAssetService m_AssetService; + private string m_ConfigName = "CapsService"; + + public CapsServerConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); + + string assetService = serverConfig.GetString("LocalServiceModule", + String.Empty); + + if (assetService == String.Empty) + throw new Exception("No LocalServiceModule in config file"); + + Object[] args = new Object[] { config }; + m_AssetService = + ServerUtils.LoadPlugin(assetService, args); + + if (m_AssetService == null) + throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); + + bool allowDelete = serverConfig.GetBoolean("AllowRemoteDelete", false); + + server.AddStreamHandler(new GetTextureHandler("/CAPS/" + UUID.Random() + "/", m_AssetService)); + } + + } +} diff --git a/OpenSim/Capabilities/Handlers/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTextureHandler.cs new file mode 100644 index 0000000..00186ee --- /dev/null +++ b/OpenSim/Capabilities/Handlers/GetTextureHandler.cs @@ -0,0 +1,356 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Drawing; +using System.Drawing.Imaging; +using System.Reflection; +using System.IO; +using System.Web; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Imaging; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Capabilities.Handlers +{ + + public class GetTextureHandler : BaseStreamHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IAssetService m_assetService; + + public const string DefaultFormat = "x-j2c"; + + // TODO: Change this to a config option + const string REDIRECT_URL = null; + + public GetTextureHandler(string path, IAssetService assService) : + base("GET", path) + { + m_assetService = assService; + } + + public override byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + //m_log.DebugFormat("[GETTEXTURE]: called in {0}", m_scene.RegionInfo.RegionName); + + // Try to parse the texture ID from the request URL + NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); + string textureStr = query.GetOne("texture_id"); + string format = query.GetOne("format"); + + if (m_assetService == null) + { + m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return null; + } + + UUID textureID; + if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) + { + string[] formats; + if (format != null && format != string.Empty) + { + formats = new string[1] { format.ToLower() }; + } + else + { + formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); + if (formats.Length == 0) + formats = new string[1] { DefaultFormat }; // default + + } + // OK, we have an array with preferred formats, possibly with only one entry + + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + foreach (string f in formats) + { + if (FetchTexture(httpRequest, httpResponse, textureID, f)) + break; + } + + } + else + { + m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); + } + + httpResponse.Send(); + return null; + } + + /// + /// + /// + /// + /// + /// + /// + /// False for "caller try another codec"; true otherwise + private bool FetchTexture(OSHttpRequest httpRequest, OSHttpResponse httpResponse, UUID textureID, string format) + { +// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); + AssetBase texture; + + string fullID = textureID.ToString(); + if (format != DefaultFormat) + fullID = fullID + "-" + format; + + if (!String.IsNullOrEmpty(REDIRECT_URL)) + { + // Only try to fetch locally cached textures. Misses are redirected + texture = m_assetService.GetCached(fullID); + + if (texture != null) + { + if (texture.Type != (sbyte)AssetType.Texture) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return true; + } + WriteTextureData(httpRequest, httpResponse, texture, format); + } + else + { + string textureUrl = REDIRECT_URL + textureID.ToString(); + m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl); + httpResponse.RedirectLocation = textureUrl; + return true; + } + } + else // no redirect + { + // try the cache + texture = m_assetService.GetCached(fullID); + + if (texture == null) + { + //m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache"); + + // Fetch locally or remotely. Misses return a 404 + texture = m_assetService.Get(textureID.ToString()); + + if (texture != null) + { + if (texture.Type != (sbyte)AssetType.Texture) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return true; + } + if (format == DefaultFormat) + { + WriteTextureData(httpRequest, httpResponse, texture, format); + return true; + } + else + { + AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID); + newTexture.Data = ConvertTextureData(texture, format); + if (newTexture.Data.Length == 0) + return false; // !!! Caller try another codec, please! + + newTexture.Flags = AssetFlags.Collectable; + newTexture.Temporary = true; + m_assetService.Store(newTexture); + WriteTextureData(httpRequest, httpResponse, newTexture, format); + return true; + } + } + } + else // it was on the cache + { + //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); + WriteTextureData(httpRequest, httpResponse, texture, format); + return true; + } + } + + // not found +// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return true; + } + + private void WriteTextureData(OSHttpRequest request, OSHttpResponse response, AssetBase texture, string format) + { + string range = request.Headers.GetOne("Range"); + //m_log.DebugFormat("[GETTEXTURE]: Range {0}", range); + if (!String.IsNullOrEmpty(range)) // JP2's only + { + // Range request + int start, end; + if (TryParseRange(range, out start, out end)) + { + // Before clamping start make sure we can satisfy it in order to avoid + // sending back the last byte instead of an error status + if (start >= texture.Data.Length) + { + response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; + return; + } + + end = Utils.Clamp(end, 0, texture.Data.Length - 1); + start = Utils.Clamp(start, 0, end); + int len = end - start + 1; + + //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); + + if (len < texture.Data.Length) + response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; + + response.ContentLength = len; + response.ContentType = texture.Metadata.ContentType; + response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); + + response.Body.Write(texture.Data, start, len); + } + else + { + m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); + response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; + } + } + else // JP2's or other formats + { + // Full content request + response.StatusCode = (int)System.Net.HttpStatusCode.OK; + response.ContentLength = texture.Data.Length; + if (format == DefaultFormat) + response.ContentType = texture.Metadata.ContentType; + else + response.ContentType = "image/" + format; + response.Body.Write(texture.Data, 0, texture.Data.Length); + } + } + + private bool TryParseRange(string header, out int start, out int end) + { + if (header.StartsWith("bytes=")) + { + string[] rangeValues = header.Substring(6).Split('-'); + if (rangeValues.Length == 2) + { + if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end)) + return true; + } + } + + start = end = 0; + return false; + } + + + private byte[] ConvertTextureData(AssetBase texture, string format) + { + m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format); + byte[] data = new byte[0]; + + MemoryStream imgstream = new MemoryStream(); + Bitmap mTexture = new Bitmap(1, 1); + ManagedImage managedImage; + Image image = (Image)mTexture; + + try + { + // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data + + imgstream = new MemoryStream(); + + // Decode image to System.Drawing.Image + if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image)) + { + // Save to bitmap + mTexture = new Bitmap(image); + + EncoderParameters myEncoderParameters = new EncoderParameters(); + myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); + + // Save bitmap to stream + ImageCodecInfo codec = GetEncoderInfo("image/" + format); + if (codec != null) + { + mTexture.Save(imgstream, codec, myEncoderParameters); + // Write the stream to a byte array for output + data = imgstream.ToArray(); + } + else + m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format); + + } + } + catch (Exception e) + { + m_log.WarnFormat("[GETTEXTURE]: Unable to convert texture {0} to {1}: {2}", texture.ID, format, e.Message); + } + finally + { + // Reclaim memory, these are unmanaged resources + // If we encountered an exception, one or more of these will be null + if (mTexture != null) + mTexture.Dispose(); + + if (image != null) + image.Dispose(); + + if (imgstream != null) + { + imgstream.Close(); + imgstream.Dispose(); + } + } + + return data; + } + + // From msdn + private static ImageCodecInfo GetEncoderInfo(String mimeType) + { + ImageCodecInfo[] encoders; + encoders = ImageCodecInfo.GetImageEncoders(); + for (int j = 0; j < encoders.Length; ++j) + { + if (encoders[j].MimeType == mimeType) + return encoders[j]; + } + return null; + } + + + } +} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index 58dbc14..341240d 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs @@ -46,30 +46,10 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; +using OpenSim.Capabilities.Handlers; namespace OpenSim.Region.ClientStack.Linden { - #region Stream Handler - - public delegate byte[] StreamHandlerCallback(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse); - - public class StreamHandler : BaseStreamHandler - { - StreamHandlerCallback m_callback; - - public StreamHandler(string httpMethod, string path, StreamHandlerCallback callback) - : base(httpMethod, path) - { - m_callback = callback; - } - - public override byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) - { - return m_callback(path, request, httpRequest, httpResponse); - } - } - - #endregion Stream Handler [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] public class GetTextureModule : IRegionModule @@ -107,298 +87,11 @@ namespace OpenSim.Region.ClientStack.Linden { UUID capID = UUID.Random(); -// m_log.InfoFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); - caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); + // m_log.InfoFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); + //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); + caps.RegisterHandler("GetTexture", new GetTextureHandler("/CAPS/" + capID + "/", m_assetService)); } #endregion - - private byte[] ProcessGetTexture(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) - { - //m_log.DebugFormat("[GETTEXTURE]: called in {0}", m_scene.RegionInfo.RegionName); - - // Try to parse the texture ID from the request URL - NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); - string textureStr = query.GetOne("texture_id"); - string format = query.GetOne("format"); - - if (m_assetService == null) - { - m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return null; - } - - UUID textureID; - if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) - { - string[] formats; - if (format != null && format != string.Empty) - { - formats = new string[1] { format.ToLower() }; - } - else - { - formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); - if (formats.Length == 0) - formats = new string[1] { DefaultFormat }; // default - - } - // OK, we have an array with preferred formats, possibly with only one entry - - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - foreach (string f in formats) - { - if (FetchTexture(httpRequest, httpResponse, textureID, f)) - break; - } - - } - else - { - m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); - } - - httpResponse.Send(); - return null; - } - - /// - /// - /// - /// - /// - /// - /// - /// False for "caller try another codec"; true otherwise - private bool FetchTexture(OSHttpRequest httpRequest, OSHttpResponse httpResponse, UUID textureID, string format) - { -// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); - AssetBase texture; - - string fullID = textureID.ToString(); - if (format != DefaultFormat) - fullID = fullID + "-" + format; - - if (!String.IsNullOrEmpty(REDIRECT_URL)) - { - // Only try to fetch locally cached textures. Misses are redirected - texture = m_assetService.GetCached(fullID); - - if (texture != null) - { - if (texture.Type != (sbyte)AssetType.Texture) - { - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return true; - } - WriteTextureData(httpRequest, httpResponse, texture, format); - } - else - { - string textureUrl = REDIRECT_URL + textureID.ToString(); - m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl); - httpResponse.RedirectLocation = textureUrl; - return true; - } - } - else // no redirect - { - // try the cache - texture = m_assetService.GetCached(fullID); - - if (texture == null) - { - //m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache"); - - // Fetch locally or remotely. Misses return a 404 - texture = m_assetService.Get(textureID.ToString()); - - if (texture != null) - { - if (texture.Type != (sbyte)AssetType.Texture) - { - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return true; - } - if (format == DefaultFormat) - { - WriteTextureData(httpRequest, httpResponse, texture, format); - return true; - } - else - { - AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID); - newTexture.Data = ConvertTextureData(texture, format); - if (newTexture.Data.Length == 0) - return false; // !!! Caller try another codec, please! - - newTexture.Flags = AssetFlags.Collectable; - newTexture.Temporary = true; - m_assetService.Store(newTexture); - WriteTextureData(httpRequest, httpResponse, newTexture, format); - return true; - } - } - } - else // it was on the cache - { - //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); - WriteTextureData(httpRequest, httpResponse, texture, format); - return true; - } - } - - // not found -// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return true; - } - - private void WriteTextureData(OSHttpRequest request, OSHttpResponse response, AssetBase texture, string format) - { - string range = request.Headers.GetOne("Range"); - //m_log.DebugFormat("[GETTEXTURE]: Range {0}", range); - if (!String.IsNullOrEmpty(range)) // JP2's only - { - // Range request - int start, end; - if (TryParseRange(range, out start, out end)) - { - // Before clamping start make sure we can satisfy it in order to avoid - // sending back the last byte instead of an error status - if (start >= texture.Data.Length) - { - response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; - return; - } - - end = Utils.Clamp(end, 0, texture.Data.Length - 1); - start = Utils.Clamp(start, 0, end); - int len = end - start + 1; - - //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); - - if (len < texture.Data.Length) - response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; - - response.ContentLength = len; - response.ContentType = texture.Metadata.ContentType; - response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); - - response.Body.Write(texture.Data, start, len); - } - else - { - m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); - response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; - } - } - else // JP2's or other formats - { - // Full content request - response.StatusCode = (int)System.Net.HttpStatusCode.OK; - response.ContentLength = texture.Data.Length; - if (format == DefaultFormat) - response.ContentType = texture.Metadata.ContentType; - else - response.ContentType = "image/" + format; - response.Body.Write(texture.Data, 0, texture.Data.Length); - } - } - - private bool TryParseRange(string header, out int start, out int end) - { - if (header.StartsWith("bytes=")) - { - string[] rangeValues = header.Substring(6).Split('-'); - if (rangeValues.Length == 2) - { - if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end)) - return true; - } - } - - start = end = 0; - return false; - } - - - private byte[] ConvertTextureData(AssetBase texture, string format) - { - m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format); - byte[] data = new byte[0]; - - MemoryStream imgstream = new MemoryStream(); - Bitmap mTexture = new Bitmap(1, 1); - ManagedImage managedImage; - Image image = (Image)mTexture; - - try - { - // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data - - imgstream = new MemoryStream(); - - // Decode image to System.Drawing.Image - if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image)) - { - // Save to bitmap - mTexture = new Bitmap(image); - - EncoderParameters myEncoderParameters = new EncoderParameters(); - myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); - - // Save bitmap to stream - ImageCodecInfo codec = GetEncoderInfo("image/" + format); - if (codec != null) - { - mTexture.Save(imgstream, codec, myEncoderParameters); - // Write the stream to a byte array for output - data = imgstream.ToArray(); - } - else - m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format); - - } - } - catch (Exception e) - { - m_log.WarnFormat("[GETTEXTURE]: Unable to convert texture {0} to {1}: {2}", texture.ID, format, e.Message); - } - finally - { - // Reclaim memory, these are unmanaged resources - // If we encountered an exception, one or more of these will be null - if (mTexture != null) - mTexture.Dispose(); - - if (image != null) - image.Dispose(); - - if (imgstream != null) - { - imgstream.Close(); - imgstream.Dispose(); - } - } - - return data; - } - - // From msdn - private static ImageCodecInfo GetEncoderInfo(String mimeType) - { - ImageCodecInfo[] encoders; - encoders = ImageCodecInfo.GetImageEncoders(); - for (int j = 0; j < encoders.Length; ++j) - { - if (encoders[j].MimeType == mimeType) - return encoders[j]; - } - return null; - } - - } } -- cgit v1.1