I have an .NET Core console application which does some update stuff to my CouchDB.
Now I have to add multiple attachments (in this case images) to my doc.
Here (https://docs.couchdb.org/en/stable/api/document/common.html#attachments) in point 1.4.1.1.4 they describe the way, but I get a Bad Request, I think my json is not perfect.
So I have a list of images that I convert and then send to DB, here is my code:
List<ImageFromApi> imagesFromApi = new List<ImageFromApi>();
string base64String;
foreach (var image in Images)
{
using (image)
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
base64String = Convert.ToBase64String(imageBytes);
}
}
ImageFromApi Imagebuffer = new ImageFromApi() {
content_type = "image/*",
data = base64String
};
imagesFromApi.Add(Imagebuffer);
DocAttachments bufferData = new DocAttachments() {imagesFromApi = imagesFromApi };
newImages._attachments = bufferData;
}
string imagesJson = JsonConvert.SerializeObject(newImages);
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(imagesJson);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
My Json from this code looks like this:
I see the difference between mine and the one from the documentation, but I dont know how to change my json correctly.
Any solutions?
So that nobody had a solution, i tried something around and find a way to achieve what i need. I made a new Attachment and added each image manually.
Here is an example of the first image:
Attachments attBuffer = new Attachments();
using (imagesFromApi[0])
{
using (MemoryStream m = new MemoryStream())
{
partImgs[0].Save(m, partImgs[0].RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
base64String = Convert.ToBase64String(imageBytes);
}
}
attBuffer.Hood = new Hood()
{
content_type = "image/jpeg",
data = base64String,
};
As you can see, i created any of my images as a class and then mapped the list to it. I think this is not the best way, but it works for me, so better than nothing.
Hope it helps you as well.
Related
the current code is working but the converted base64string output is attached to the api , but am having 404 error because the request url is too long. so i just need modification , to shorten the converted base64string. or any different approach.
var file = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions { PhotoSize = PhotoSize.Small });
byte[] imageArray = null;
if (file != null)
{
using (HttpClient client = new HttpClient())
using (MemoryStream ms = new MemoryStream())
{
var stream = file.GetStream();
stream.CopyTo(ms);
imageArray = ms.ToArray();
var base64String = Convert.ToBase64String(imageArray);
This is a very strange question.
I using C# to create a pass.json and save it to memoryStream, it work normally. After that I create the manifest.json SHA1 data which including that pass.json, the string of manifest.json like this and it is totally correct.
{"icon.png": "9423bd00e2b01c59a3265c38b5062fac7da0752d",
"icon#2x.png": "4d1db55bdaca70b685c013529a1c0dcbd7046524",
"logo.png": "ee5b053e63dbfe3b78378c15d163331d68a0ede8",
"logo#2x.png": "2f9e3a55bded1163620719a4d6c1ad496ed40c17",
"pass.json": "fd68bf77757d3057263a9aca0e5110ddd933934a"}
After generate pkpass as my phone, it can't open. I change the pass.json SHA1 code as "fd68bf77757d3057263a9aca0e5110ddd933934a" without using a value to save it, it work.
The coding like following:
// This version run success
var strPass = JavascriptSerialize(details);
var sw = new StreamWriter(assetsFolder + #"pass.json");
sw.Write(strPass);
sw.Close();
manifest.passjson = GetSha1Hash(assetsFolder + manifest.GetAssetBoardingPass(libPkPass_object_boardingPass.JsonObjects.AssetTypes.passjson));
//manifest.passjson = "2f9e3a55bded1163620719a4d6c1ad496ed40c17"
// end
// This version run fail
var strPass = JavascriptSerialize(details);
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(strPass);
writer.Write(s);
writer.Flush();
stream.Position = 0;
var a = GetSha1HashMemory(passStream);
private static string GetSha1HashMemory(Stream passStream)
{
//var bs = new BufferedStream(passStream);
using (SHA1Managed sha = new SHA1Managed())
{
byte[] checksum = sha.ComputeHash(passStream);
string sendCheckSum = BitConverter.ToString(checksum)
.Replace("-", string.Empty);
return sendCheckSum.ToString().ToLower();
}
}
manifest.passjson = a;
//manifest.passjson = "2f9e3a55bded1163620719a4d6c1ad496ed40c17" (same data )
//end
What is going on?????? I can find out any question that string is wrong.
The pkpass provide in here (sendspace).
Can any body told me where is wrong?
Big Thank!
Two mistakes :
ComputeHash(Stream) and using Stream
ComputeHash(Stream) : ComputeHash stream only using System.IO.Stream, but not MemoryStream, change to ComputeHash(bytes[]) can handle it
using Stream: I try to pass the stream to other function, it is not a good example, the stream need to create a new one and it may replace some bytes at your computer stream. In this case, I just need to call this function will out open new one, it will fix
StringBuilder formatted;
using (var sha1 = new SHA1Managed())
{
//var bytePass = ReadFully(passStream);
var bytePass = passStream.ToArray();
var hash = sha1.ComputeHash(bytePass);
formatted = new StringBuilder(2 * hash.Length);
foreach (var b in hash)
{
formatted.AppendFormat("{0:X2}", b);
}
}
manifest.passjson = formatted.ToString().ToLower();
Ive got a question I am having a case of rest response that is always string, it suppose to download content of the file, but there can be many different files, for example PNG, now if I'm getting a string in response is it possible to convert it back to PNG at the end, I tried something like:
byte[] array = Encoding.ASCII.GetBytes(result.data); //response content
MemoryStream ms = new MemoryStream(array);
Image i = Image.FromStream(ms);
I dont think im getting base64 string from rest looks like (part of it, and if i remmebr base64 ends with 3 === and don't have any non printable chars):
�PNG\r\n\n\0\0\0\rIHDR\0\0�\0\0\0�\b\0\0\0���\0\0\0sRGB\0���\0\0\0gAMA\0\0��\v�a\0\0\0\tpHYs\0\0t\0\0t�fx\0\0\f\aIDATx^��!x�L���Jde%�yY�D�H$�d%2��S��Hd%y�<�ӹ�B�ٝ�O�mﺔ��d����\r\0���\a�(H|\0���\a�(H|\0���\a�(H|\0���\a�(H|\0���\a�(H|\0���\a�(H|\0���\a�(H|\0���\a�(H|\0���\a�(H|\0���\a�(H|\0�\"D�WU��v������r��o#\f!��y�����K�\0�'D�O�SM�\f�����\0��Dǯ�z4�R��C�7\0��+�\0�\0Q��\0�\0Q��UU���ļO ?�������!�#J�>���|D��$>\f�|D��$>\f��7X,�?�_\v]�V�^/�=��#4$�����$:��P9
Assuming you are returning base 64 string from the API response, you can do something like this
byte[] bytes = Convert.FromBase64String(result.data);
Image image;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
return image;
Or you can save it directly to the file
string filePath = "Image.png";
File.WriteAllBytes(filePath, Convert.FromBase64String(result.data));
EDIT 1:
How are you returning data from your web API? You could do something like this to return byte array and then use this array directly to write to stream.
var result = new HttpResponseMessage(HttpStatusCode.OK);
String filePath = HostingEnvironment.MapPath("~/imagename.png");
FileStream fileStream = new FileStream(filePath, FileMode.Open);
Image image = Image.FromStream(fileStream);
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Jpeg);
result.Content = new ByteArrayContent(memoryStream.ToArray());
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return result;
and on the client side you can do something like
var data = response.Content.ReadAsByteArrayAsync().Result;
Image image;
using (MemoryStream ms = new MemoryStream(data))
{
image = Image.FromStream(ms);
}
return image;
I've searched here for help with this, but nothing quite matches what I need. I have an image that gets uploaded, and I'd like to change the size before it gets saved to azure.
So currently my code is:
public ActionResult UserDetails(HttpPostedFileBase photo)
{ var inputFile = new Photo()
{
FileName = photo.FileName,
Data = () => photo.InputStream
};
//then I save to Azure
How would I change the photo.InputStream to 100x 100 px for example?
Here is how I do it:
byte[] imageBytes;
//Of course image bytes is set to the bytearray of your image
using (MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length))
{
using (Image img = Image.FromStream(ms))
{
int h = 100;
int w = 100;
using (Bitmap b = new Bitmap(img, new Size(w,h)))
{
using (MemoryStream ms2 = new MemoryStream())
{
b.Save(ms2, System.Drawing.Imaging.ImageFormat.Jpeg);
imageBytes = ms2.ToArray();
}
}
}
}
From there, I use a MemoryStream to upload. I use blob storage and use the UploadFromStreamAsync to load to blob.
This is a basic view of it.
I'm using GZipStream to compress a string, and I've modified two different examples to see what works. The first code snippet, which is a heavily modified version of the example in the documentation, simply returns an empty string.
public static String CompressStringGzip(String uncompressed)
{
String compressedString;
// Convert the uncompressed source string to a stream stored in memory
// and create the MemoryStream that will hold the compressed string
using (MemoryStream inStream = new MemoryStream(Encoding.Unicode.GetBytes(uncompressed)),
outStream = new MemoryStream())
{
using (GZipStream compress = new GZipStream(outStream, CompressionMode.Compress))
{
inStream.CopyTo(compress);
StreamReader reader = new StreamReader(outStream);
compressedString = reader.ReadToEnd();
}
}
return compressedString;
and when I debug it, all I can tell is nothing is read from reader, which is compressedString is empty. However, the second method I wrote, modified from a CodeProject snippet is successful.
public static String CompressStringGzip3(String uncompressed)
{
//Transform string to byte array
String compressedString;
byte[] uncompressedByteArray = Encoding.Unicode.GetBytes(uncompressed);
using (MemoryStream outStream = new MemoryStream())
{
using (GZipStream compress = new GZipStream(outStream, CompressionMode.Compress))
{
compress.Write(uncompressedByteArray, 0, uncompressedByteArray.Length);
compress.Close();
}
byte[] compressedByteArray = outStream.ToArray();
StringBuilder compressedStringBuilder = new StringBuilder(compressedByteArray.Length);
foreach (byte b in compressedByteArray)
compressedStringBuilder.Append((char)b);
compressedString = compressedStringBuilder.ToString();
}
return compressedString;
}
Why is the first code snippet not successful while the other one is? Even though they're slightly different, I don't know why the minor changes in the second snippet allow it to work. The sample string I'm using is SELECT * FROM foods f WHERE f.name = 'chicken';
I ended up using the following code for compression and decompression:
public static String Compress(String decompressed)
{
byte[] data = Encoding.UTF8.GetBytes(decompressed);
using (var input = new MemoryStream(data))
using (var output = new MemoryStream())
{
using (var gzip = new GZipStream(output, CompressionMode.Compress, true))
{
input.CopyTo(gzip);
}
return Convert.ToBase64String(output.ToArray());
}
}
public static String Decompress(String compressed)
{
byte[] data = Convert.FromBase64String(compressed);
using (MemoryStream input = new MemoryStream(data))
using (GZipStream gzip = new GZipStream(input, CompressionMode.Decompress))
using (MemoryStream output = new MemoryStream())
{
gzip.CopyTo(output);
StringBuilder sb = new StringBuilder();
return Encoding.UTF8.GetString(output.ToArray());
}
}
The explanation for a part of the problem comes from this question. Although I fixed the problem by changing the code to what I included in this answer, these lines (in my original code):
foreach (byte b in compressedByteArray)
compressedStringBuilder.Append((char)b);
are problematic, because as dlev aptly phrased it:
You are interpreting each byte as its own character, when in fact that is not the case. Instead, you need the line:
string decoded = Encoding.Unicode.GetString(compressedByteArray);
The basic problem is that you are converting to a byte array based on an encoding, but then ignoring that encoding when you retrieve the bytes.
Therefore, the problem is solved, and the new code I'm using is much more succinct than my original code.
You need to move the code below outside the second using statement:
using (GZipStream compress = new GZipStream(outStream, CompressionMode.Compress))
{
inStream.CopyTo(compress);
outStream.Position = 0;
StreamReader reader = new StreamReader(outStream);
compressedString = reader.ReadToEnd();
}
CopyTo() is not flushing the results to the underlying MemoryStream.
Update
Seems that GZipStream closes and disposes it's underlying stream when it is disposed (not the way I would have designed the class). I've updated the sample above and tested it.