I have a custom user control that i use in a page in Umbraco CMS... since upgrading to version 4, it seems this user control wont work any longer.
The user control contains an ajax uploader control (support request post here: http://cutesoft.net/forums/53732/ShowThread.aspx#53732), which allows users to upload images, then displays the uploaded images to the user. The control and image displays are contained within an UpdatePanel, which is where this problem is - seems the data getting sent back to the updatePanel is not valid, so the client is spitting the dummy and throwing this error:
Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.
Details: Error parsing near '
<!DOCTYPE html PUBL'.
I think its somethihng to do with how Master Pages is implemented in Umbraco v4 that is causing this. Any ideas as to why this may have happened, and what i can look at to try to solve it?
FYI, here's a blog post that describes the error and its possible causes:
http://weblogs.asp.net/leftslipper/archive/2007/02/26/sys-webforms-pagerequestmanagerparsererrorexception-what-it-is-and-how-to-avoid-it.aspx
i'm doing any Response.write or Response.Redirect in the updatePanel
I'm not using any response filters
I've disabled server trace
I'm not using response.transfer
But, regardless of the above, this works fine using the same usercontrol on an Umbraco v3 site, which leads me to believe its somethign to do with v4 that's caused this.
Any suggestions greatly appreciated
I know that this whole answer is not directly a fix for your problem, but more like a workaround. this is because I am not familiar with the custom control you use.
i will however take a look tonight at your problem and see if i can find a solution for the code and plugin you use currently.
in the mean time i might give you some idea of the ajax upload i am using myself.
i know its a big chunk of code, but if you are interested you can go for it :)
my example case
I have an upload control in my own website and it works perfectly with umbraco.
the form and upload are powered with jQuery (upload is handled by jQuery.AjaxUpload plugin)
and i created a generic handler inside my umbraco folder which handles the file on the server.
creating a media item in the media library for it (and in my case beeing an avatar uploader on your profile page, it also adds the newly created mediaitem to the member's avatar property)
jQuery code: (stored in script block in the head of your page, or in a separate script)
initializeChangeAvatarForm = function() {
var button = $('#submitChangeAvatar'), interval;
new AjaxUpload(button,{
action: '/umbraco/AjaxFileUpload.ashx',
name: 'myfile',
onSubmit : function(file, ext){
// change button text to uploading + add class (with animating background loading image)
button.text('Uploading').addClass('loading');
// If you want to allow uploading only 1 file at time,
// you can disable upload button
this.disable();
},
onComplete: function(file, response){
button.text('Upload nieuw').removeClass('loading');
// Although plugins emulates hover effect automatically,
// it doens't work when button is disabled
button.removeClass('hover');
window.clearInterval(interval);
// enable upload button
this.enable();
}
});
};
$(document).ready(function(){
initializeChangeMailForm();
});
html code in your body:
<div id="container"><h2>Upload Avatar</h2><button class="button" id="submitChangeAvatar" type="button">Upload new</button></div>
jQuery ajaxupload plugin: (/scripts/jQuery.ajaxupload.js)
'since this code is too long i added a link directly to the .js file i use
'and another link to the page where i got the plugin
handler .ashx: (stored inside /umbraco/AjaxFileUpload.ashx)
using System;
using System.Collections;
using System.Data;
using System.Web;
using System.Web.SessionState;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.IO;
using System.Xml;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.member;
namespace SH.umbServices
{
/// <summary>
/// Summary description for $codebehindclassname$
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class AjaxFileUpload : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
string strResponse = "error";
try
{
//string strFileName = Path.GetFileName(context.Request.Files[0].FileName);
//string strExtension = Path.GetExtension(context.Request.Files[0].FileName).ToLower();
//string strSaveLocation = context.Server.MapPath("../images/temp") + "\\" + strFileName;
//context.Request.Files[0].SaveAs(strSaveLocation);
UmbracoSave(context);
strResponse = "success";
}
catch
{
}
context.Response.ContentType = "text/plain";
context.Response.Write(strResponse);
}
public bool IsReusable
{
get
{
return false;
}
}
#region "umbMediaItem"
protected string UmbracoSave(HttpContext context)
{
string mediaPath = "";
if (context.Request.Files[0] != null)
{
if (context.Request.Files[0].FileName != "")
{
// Find filename
string _text = context.Request.Files[0].FileName;
string _ext = Path.GetExtension(context.Request.Files[0].FileName);
string filename;
string _fullFilePath;
//filename = _text.Substring(_text.LastIndexOf("\\") + 1, _text.Length - _text.LastIndexOf("\\") - 1).ToLower();
filename = Path.GetFileName(_text);
string _filenameWithoutExtention = filename.Replace(_ext, "");
int _p = 1212; // parent node.. -1 for media root)
// create the Media Node
umbraco.cms.businesslogic.media.Media m = umbraco.cms.businesslogic.media.Media.MakeNew(
_filenameWithoutExtention, umbraco.cms.businesslogic.media.MediaType.GetByAlias("image"), User.GetUser(0), _p);
// Create a new folder in the /media folder with the name /media/propertyid
System.IO.Directory.CreateDirectory(System.Web.HttpContext.Current.Server.MapPath(umbraco.GlobalSettings.Path + "/../media/" + m.Id.ToString()));
_fullFilePath = System.Web.HttpContext.Current.Server.MapPath(umbraco.GlobalSettings.Path + "/../media/" + m.Id.ToString() + "/" + filename);
context.Request.Files[0].SaveAs(_fullFilePath);
// Save extension
//string orgExt = ((string)_text.Substring(_text.LastIndexOf(".") + 1, _text.Length - _text.LastIndexOf(".") - 1));
string orgExt = Path.GetExtension(context.Request.Files[0].FileName).ToLower();
orgExt = orgExt.Trim(char.Parse("."));
try
{
m.getProperty("umbracoExtension").Value = orgExt;
}
catch { }
// Save file size
try
{
System.IO.FileInfo fi = new FileInfo(_fullFilePath);
m.getProperty("umbracoBytes").Value = fi.Length.ToString();
}
catch { }
// Check if image and then get sizes, make thumb and update database
if (",jpeg,jpg,gif,bmp,png,tiff,tif,".IndexOf("," + orgExt + ",") > 0)
{
int fileWidth;
int fileHeight;
FileStream fs = new FileStream(_fullFilePath,
FileMode.Open, FileAccess.Read, FileShare.Read);
System.Drawing.Image image = System.Drawing.Image.FromStream(fs);
fileWidth = image.Width;
fileHeight = image.Height;
fs.Close();
try
{
m.getProperty("umbracoWidth").Value = fileWidth.ToString();
m.getProperty("umbracoHeight").Value = fileHeight.ToString();
}
catch { }
// Generate thumbnails
string fileNameThumb = _fullFilePath.Replace("." + orgExt, "_thumb");
generateThumbnail(image, 100, fileWidth, fileHeight, _fullFilePath, orgExt, fileNameThumb + ".jpg");
image.Dispose();
}
mediaPath = "/media/" + m.Id.ToString() + "/" + filename;
m.getProperty("umbracoFile").Value = mediaPath;
m.XmlGenerate(new XmlDocument());
Member mbr = Member.GetCurrentMember();
umbraco.cms.businesslogic.property.Property avt = mbr.getProperty("memberAvatar");
avt.Value = m.Id;
mbr.XmlGenerate(new XmlDocument());
mbr.Save();
//string commerceFileName = mediaPath;
//CommerceSave(commerceFileName);
}
}
return mediaPath;
}
protected void generateThumbnail(System.Drawing.Image image, int maxWidthHeight, int fileWidth, int fileHeight, string fullFilePath, string ext, string thumbnailFileName)
{
// Generate thumbnail
float fx = (float)fileWidth / (float)maxWidthHeight;
float fy = (float)fileHeight / (float)maxWidthHeight;
// must fit in thumbnail size
float f = Math.Max(fx, fy); //if (f < 1) f = 1;
int widthTh = (int)Math.Round((float)fileWidth / f); int heightTh = (int)Math.Round((float)fileHeight / f);
// fixes for empty width or height
if (widthTh == 0)
widthTh = 1;
if (heightTh == 0)
heightTh = 1;
// Create new image with best quality settings
Bitmap bp = new Bitmap(widthTh, heightTh);
Graphics g = Graphics.FromImage(bp);
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
// Copy the old image to the new and resized
Rectangle rect = new Rectangle(0, 0, widthTh, heightTh);
g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
// Copy metadata
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo codec = null;
for (int i = 0; i < codecs.Length; i++)
{
if (codecs[i].MimeType.Equals("image/jpeg"))
codec = codecs[i];
}
// Set compresion ratio to 90%
EncoderParameters ep = new EncoderParameters();
ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L);
// Save the new image
bp.Save(thumbnailFileName, codec, ep);
bp.Dispose();
g.Dispose();
}
#endregion
}
}
I hope this shed some light on what i use.
Pfew,..That's a lot of code.
I was only interessted in saving media in Umbraco but it's nice to see a jQuery upload too.
What upload jQuery lib your using? I've found serveral.
You could make the code a bit simpler by using Path.Combine, FileInfo.Extension merging if's and a few extra variables here an there. But hey I've got Resharper to make my live easier.
Related
I am struggling big time with generating QR barcodes as a byte[] or Stream (something that I can use on a XAML image source)
ZXING.NET
I've tried with Zxing.Net but I find the documentation is not great.
In fact, when installing in the xamarin forms class library I am able to compile, but as soon as I add some code to write barcodes I get a compilation error saying that
Can not resolve reference: `zxing`, referenced by `MyXamarinFormsClassLibrary`. Please add a NuGet package or assembly reference for `zxing`, or remove the reference to `Sasw.AforoPass`. 0
Something funky is going on with that library.
And I'm doing a simple example such as:
var options = new QrCodeEncodingOptions
{
DisableECI = true,
CharacterSet = "UTF-8",
Width = 250,
Height = 250
};
var writer = new BarcodeWriter<Image>();
writer.Format = BarcodeFormat.QR_CODE;
writer.Options = options;
var result = writer.Write("foo");
MyImage.Source = result.Source;
QRCoder
It's another nuget library. I've successfully used for dotnet core applications, but it does not seem to be compatible with Xamarin Forms (or Mono, or whatever). It says that the platform is not supported. Probably because it uses System.Drawing.Common?
ZXing.Net.Mobile.Forms
I've used this other library which underneath it uses ZXing.Net. What I don't like is that I don't know if there's any way to generate qr codes without relying on Xaml or the ZXingBarcodeImageView.
I managed to generate QR Codes that way as a workaround, but I hit another wall. See https://github.com/Redth/ZXing.Net.Mobile/issues/908 in which I describe the problems I have to embed the ZXingBarcodeImageView in a carousel inside a popup.
So basically I wanted to go back to the roots, and simply have a working example with the latest version of ZXing.Net (or an alternative, if it exists) that I am able to use in Xamarin Forms.
Most of the examples I find talk about BarcodeWriter but there is no such a class anymore. There is a generic one BarcodeWriter<TUnknownType>and a BarcodeWriterGeneric but as I said, I could not compile anything using Zxing.Net library and with through ZXing.Net.Mobile the images I generate are always empty.
Any help or "modern" code sample (ideally with an alternative) would be much appreciated
UPDATE 1
In other words, I'm looking to have in Xamarin Forms something similar to this code that I had using QrCoder library.
public class QrCodeService
: IQrCodeService
{
public Stream GetQrCode(Guid id, string mimeType = "image/jpeg")
{
if (mimeType is null)
{
throw new ArgumentNullException(nameof(mimeType));
}
var qrGenerator = new QRCodeGenerator();
var qrCodeData = qrGenerator.CreateQrCode(id.ToString(), QRCodeGenerator.ECCLevel.Q);
var qrCode = new QRCode(qrCodeData);
var qrCodeImage = qrCode.GetGraphic(20);
var myImageCodecInfo = GetEncoderInfo(mimeType);
var myEncoder = Encoder.Quality;
var myEncoderParameters = new EncoderParameters(1);
var myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;
var stream = new MemoryStream();
qrCodeImage.Save(stream, myImageCodecInfo, myEncoderParameters);
stream.Position = 0;
return stream;
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
var encoders = ImageCodecInfo.GetImageEncoders();
foreach (var encoder in encoders)
{
if (encoder.MimeType == mimeType)
{
return encoder;
}
}
throw new KeyNotFoundException($"Encoder for {mimeType} not found");
}
}
The solution uses QrCoder library and it works fine for Xamarin Forms as follows.
private byte[] GetQrImageAsBytes()
{
var randomText = Guid.NewGuid().ToString();
var qrGenerator = new QRCodeGenerator();
var qrCodeData = qrGenerator.CreateQrCode(randomText, QRCodeGenerator.ECCLevel.L);
var qRCode = new PngByteQRCode(qrCodeData);
var qrCodeBytes = qRCode.GetGraphic(20);
return qrCodeBytes;
}
Here a working sample with this implementation
QrCoder library can do this, but instead of using as in the main page of the project:
QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode("The text which should be encoded.", QRCodeGenerator.ECCLevel.Q);
QRCode qrCode = new QRCode(qrCodeData); // This point onwards is problematic
Bitmap qrCodeImage = qrCode.GetGraphic(20); // This will throw not supported exception
Switch the last 2 lines to:
var qrCode = new PngByteQRCode(qrCodeData);
byte[] imageByteArray = qrCode.GetGraphic(20);
You'll get byte array instead, but you can convert it into Stream or whatever you like afterwards.
Current project:
ASP.NET 4.5.2
MVC 5
I am trying to leverage the TinyPNG API, and if I just pipe the image over to it, it works great. However, since the majority of users will be on a mobile device, and these produce images at a far higher resolution than what is needed, I am hoping to reduce the resolution of these files prior to them being piped over to TinyPNG. It is my hope that these resized images will be considerably smaller than the originals, allowing me to conduct a faster round trip.
My code:
public static async Task<byte[]> TinyPng(Stream input, int aspect) {
using(Stream output = new MemoryStream())
using(var png = new TinyPngClient("kxR5d49mYik37CISWkJlC6YQjFMcUZI0")) {
ResizeImage(input, output, aspect, aspect); // Problem area
var result = await png.Compress(output);
using(var reader = new BinaryReader(await (await png.Download(result)).GetImageStreamData())) {
return reader.ReadBytes(result.Output.Size);
}
}
}
public static void ResizeImage(Stream input, Stream output, int newWidth, int maxHeight) {
using(var srcImage = Image.FromStream(input)) {
var newHeight = srcImage.Height * newWidth / srcImage.Width;
if(newHeight > maxHeight) {
newWidth = srcImage.Width * maxHeight / srcImage.Height;
newHeight = maxHeight;
}
using(var newImage = new Bitmap(newWidth, newHeight))
using(var gr = Graphics.FromImage(newImage)) {
gr.SmoothingMode = SmoothingMode.AntiAlias;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(srcImage, new Rectangle(0, 0, newWidth, newHeight));
newImage.Save(output, ImageFormat.Jpeg);
}
}
}
So the ResizeArea is supposed to accept a stream and output a stream, meaning that the TinyPNG .Compress() should work just as well with the output as it would with the original input. Unfortunately, only the .Compress(input) works -- with .Compress(output) TinyPNG throws back an error:
400 - Bad Request. InputMissing, File is empty
I know TinyPNG has its own resizing routines, but I want to do this before the image is sent out over the wire to TinyPNG so that file size (and therefore transmission time) is reduced as much as possible prior to the actual TinyPNG compression.
…Aaaaand I just solved my problem by using another tool entirely.
I found ImageProcessor. Documentation is a royal b**ch to get at because it only comes in a Windows *.chm help file (it’s not online… cue one epic Whisky. Tango. Foxtrot.), but after looking at a few examples it did solve my issue quite nicely:
public static async Task<byte[]> TinyPng(Stream input, int aspect) {
using(var output = new MemoryStream())
using(var png = new TinyPngClient("kxR5d49mYik37CISWkJlC6YQjFMcUZI0")) {
using(var imageFactory = new ImageFactory()) {
imageFactory.Load(input).Resize(new Size(aspect, 0)).Save(output);
}
var result = await png.Compress(output);
using(var reader = new BinaryReader(await (await png.Download(result)).GetImageStreamData())) {
return reader.ReadBytes(result.Output.Size);
}
}
}
and everything is working fine now. Uploads are much faster now as I am not piping a full-sized image straight through to TinyPNG, and since I am storing both final-“full”-sized images as well as thumbnails straight into the database, I am now not piping the whole bloody image twice.
Posted so that other wheel-reinventing chuckleheads like me will actually have something to go on.
I'm currently working on a data-check for images. I need to request the Size (width & height) and the resolution of the image. Files over 70MB throw an "out of memory" exception on GDI Problem. Is there an alternative way to get the file-information? The same error on parse it through FromStream...
Using myfile = Image.FromFile(filePath)
...
End Using
You can use the following code to get image properties (it loads metadata only):
using (var fs = new FileStream(#"C:\Users\Dmitry\Pictures\blue-earth-wallpaper.jpg", FileMode.Open, FileAccess.Read)) {
var decoder = BitmapDecoder.Create(fs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
var size = decoder.Frames[0].PixelWidth;
var height = decoder.Frames[0].PixelHeight;
var dpiX = decoder.Frames[0].DpiX;
var dpiY = decoder.Frames[0].DpiY;
}
I found this link http://www.fastgraph.com/help/image_file_header_formats.html that tells where in the file you can find the type and its dimensions. I guess, if you use something like this below to seek and get the first few bytes and close once you are done, shouldnt be using much resources
Untested code below...
// This really needs to be a member-level variable;
private static readonly object fsLock = new object();
// Instantiate this in a static constructor or initialize() method
private static FileStream fs = new FileStream("myFile.txt", FileMode.Open);
public string ReadFile(int fileOffset) {
byte[] buffer = new byte[bufferSize];
int arrayOffset = 0;
lock (fsLock) {
fs.Seek(fileOffset, SeekOrigin.Begin);
int numBytesRead = fs.Read(bytes, arrayOffset , bufferSize);
// Typically used if you're in a loop, reading blocks at a time
arrayOffset += numBytesRead;
}
// Do what you want to the byte array and close
}
i want to create SQL CLR integrated function from Visual C#, now my requirement is user will pass a folder path as a paramter, and the function should get all the image file from the the folder, and get its basic property like FileSize, dimension etc.. but it seems SQL project does not supports System.Drawing Namespace... as i created the same function in normal project it worked fine, as i was able to use System.Drawing Namespace, but here i cannot use, System.Drawing Namespace.. so is there any other way to get the image dimension...
below is the code i have used in my normal project.
public DataTable InsertFile(string FolderPath)
{
DataTable dt = new DataTable();
DataColumn[] col = new DataColumn[] { new DataColumn("FileName", typeof(System.String)), new DataColumn("FileSize", typeof(System.Int32)), new DataColumn("FilePath", typeof(System.String)), new DataColumn("Width", typeof(System.Int32)), new DataColumn("Height", typeof(System.Int32)) };
dt.Columns.AddRange(col);
FileInfo info= null;
Bitmap bmp = null;
foreach (String s in Directory.GetFiles(FolderPath, "*.jpg"))
{
info = new FileInfo(s);
bmp = new Bitmap(s);
DataRow dr = dt.NewRow();
dr["FileName"] = Path.GetFileName(s);
dr["FileSize"] = info.Length / 1024;
dr["FilePath"] = s;
dr["Width"] = bmp.Width;
dr["Height"] = bmp.Height;
dt.Rows.Add(dr);
}
return dt;
}
does anyone have any idea how to get image dimension without using System.Drawing Namespace.
wow never seen anyone try this before, but if using Drawing in a SQL project isn't allowed try reading the header info like this http://www.codeproject.com/KB/cs/ReadingImageHeaders.aspx
Edit included the code, with the change to remove the dependency on Size.
while (binaryReader.ReadByte() == 0xff)
{
byte marker = binaryReader.ReadByte();
ushort chunkLength = binaryReader.ReadLittleEndianInt16();
if (marker == 0xc0)
{
binaryReader.ReadByte();
int height = binaryReader.ReadLittleEndianInt16();
int width = binaryReader.ReadLittleEndianInt16();
return new int[] { width, height };
}
binaryReader.ReadBytes(chunkLength - 2);
}
Is the Image object any better for you?
System.Drawing.Image forSize = System.Drawing.Image.FromFile(s);
dr["Width"] = forSize.Width;
and so forth.
That any better or same problem?
i use this code to create thumbnails
System.Drawing.Image.GetThumbnailImageAbort abort = new System.Drawing.Image.GetThumbnailImageAbort(this.ThumbnailCallback);
System.Drawing.Image image2 = image.GetThumbnailImage((int)Math.Round((double)wid / difference), (int)Math.Round((double)hei / difference), abort, IntPtr.Zero);
image2.Save(str2, System.Drawing.Imaging.ImageFormat.Jpeg);
image2.Dispose();
but i get this very low quality image
but it is suposed to be like this one
what i am making wrong
or how can achieve this
Your problem is not really with the GetThumbnailImage() method, but instead in how you are saving the file. You need to specify the quality level of the JPEG you are saving, or it seems it always defaults to a very low value.
Consider this code as a guide (it's from an old .NET 2.0 project; the code still works fine compiled against 4.0, but there may be a more direct method in 4.0; I've never had reason to check)
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo jpegEncoder = null;
for (int x = 0; x < encoders.Length; x++) {
if (string.Compare(encoders[x].MimeType, "image/jpeg", true) == 0) {
jpegEncoder = encoders[x];
break;
}
}
if (jpegEncoder == null) throw new ApplicationException("Could not find JPEG encoder!");
EncoderParameters prms = new EncoderParameters(1);
prms.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80L);
bitmap.Save(fileName, jpegEncoder, prms);
Here is another solution that should always work without fetching out the encoder. It resizes keeping relation between width & heigh ... modify for your needs.
/// <summary>
/// Resize an image with high quality
/// </summary>
public static Image ResizeImage(Image srcImage, int width)
{
var b = new Bitmap(width, srcImage.Height * width / srcImage.Width);
using (var g = Graphics.FromImage((Image)b))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(srcImage, 0, 0, b.Width, b.Height);
}
return b;
}