I am playing with the youtube api and I would like to download the thumbnails and process them. I've managed to download them in binary doing a simple http request and I can save them as a .jepec file. What I would like to do is not having to save the image as a file and parse the binary directly into an image all in memory to avoid leaving files behind.
Any idea on hat do I need to do to accompish this?
Here is my code:
#[tokio::main(flavor = "current_thread")]
async fn main() {
let res = reqwest::get("https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg")
.await
.unwrap();
let bytes: Bytes = res.bytes().await.unwrap();
let _ = fs::write("img.jpeg", bin.clone()); // this saves the image correctly
let img = ????::from(bytes); // help here
}
You can use the jpeg_decoder crate:
use jpeg_decoder::Decoder;
let mut decoder = Decoder::new(&*bytes);
let pixels = decoder.decode().expect("jpeg decoding failed");
let info = decoder.info().unwrap(); // image metadata
If you call decode() from an async function, you should do so in a blocking task using tokio::spawn_blocking, as decode() is not itself async.
Related
I would like to get my username in an std::String using the windows-rs crate.
use bindings::Windows::Win32::{
System::WindowsProgramming::GetUserNameW,
Foundation::PWSTR,
};
fn main() {
let mut pcbbuffer: u32 = 255;
let mut helper: u16 = 0;
let lpbuffer = PWSTR(&mut helper);
println!("lpbuffer: {:?}\npcbbuffer: {:?}", lpbuffer, pcbbuffer);
unsafe {
let success = GetUserNameW(lpbuffer, &mut pcbbuffer);
println!("GetUserNameW succeeded: {:?}\nlpbuffer: {:?}\npcbbuffer: {:?}", success.as_bool(), lpbuffer, pcbbuffer);
}
}
produces the output:
lpbuffer: PWSTR(0xca20f5f76e)
pcbbuffer: 255
GetUserNameW succeeded: true
lpbuffer: PWSTR(0x7200650073)
pcbbuffer: 5
The username is "user" that's 4 + 1 terminating character = 5 which is good. I also see the GetUserNameW function succeeded and the pointer to the string changed.
What are the next steps?
The code as posted works by coincidence alone. It sports a spectacular buffer overflow, hardly what you'd want to see in Rust code. Specifically, you're taking the address of a single u16 value, and pass it into an API, telling it that the pointed-to memory were 255 elements in size.
That needs to be solved: You will have to allocate a buffer large enough to hold the API's output first.
Converting a UTF-16 encoded string to a Rust String with its native encoding can be done using several different ways, such as String::from_utf16_lossy().
The following code roughly sketches out the approach:
fn main() {
let mut cb_buffer = 257_u32;
// Create a buffer of the required size
let mut buffer = Vec::<u16>::with_capacity(cb_buffer as usize);
// Construct a `PWSTR` by taking the address to the first element in the buffer
let lp_buffer = PWSTR(buffer.as_mut_ptr());
let result = unsafe { GetUserNameW(lp_buffer, &mut cb_buffer) };
// If the API returned success, and more than 0 characters were written
if result.as_bool() && cb_buffer > 0 {
// Construct a slice over the valid data
let buffer = unsafe { slice::from_raw_parts(lp_buffer.0, cb_buffer as usize - 1) };
// And convert from UTF-16 to Rust's native encoding
let user_name = String::from_utf16_lossy(buffer);
println!("User name: {}", user_name);
}
}
trying to rewrite using WINAPI library https://learn.microsoft.com/en-us/windows/win32/wnet/enumerating-network-resources on Rust
let dw_result: DWORD;
let mut h_enum: LPHANDLE = null_mut();
let mut lpnr_local: LPNETRESOURCEW = null_mut();
dw_result = WNetOpenEnumW(RESOURCE_GLOBALNET, // all network resources
RESOURCETYPE_ANY, // all resources
0, // enumerate all resources
lpnr_local, // NULL first time the function is called
h_enum);
if dw_result != WN_NO_ERROR {
println!("WnetOpenEnum failed with error {:?}\n", dw_result);
}
But this code assign 487 into dw_result which means ERROR_INVALID_ADDRESS
And I can't get what is wrong
I guess your doubt is the difference between LPHANDLE and HANDLE.
LP stands for Long Pointer. It's a pointer to a handle.
If you want to use LPHANDLE, please give it a legal address。
Like this:(C++)
HANDLE ph;
LPHANDLE hEnum = &ph;
Or simply use HANDLE.
let mut h_enum: HANDLE;
...
dw_result = WNetOpenEnumW(RESOURCE_GLOBALNET, // all network resources
RESOURCETYPE_ANY, // all resources
0, // enumerate all resources
lpnr_local, // NULL first time the function is called
&h_enum);
Related: LPHANDLE vs. HANDLE
I'm creating a simple HTTP server. I need to read the requested image and send it to browser. I'm using this code:
fn read_file(mut file_name: String) -> String {
file_name = file_name.replace("/", "");
if file_name.is_empty() {
file_name = String::from("index.html");
}
let path = Path::new(&file_name);
if !path.exists() {
return String::from("Not Found!");
}
let mut file_content = String::new();
let mut file = File::open(&file_name).expect("Unable to open file");
let res = match file.read_to_string(&mut file_content) {
Ok(content) => content,
Err(why) => panic!("{}",why),
};
return file_content;
}
This works if the requested file is text based, but when I want to read an image I get the following message:
stream did not contain valid UTF-8
What does it mean and how to fix it?
The documentation for String describes it as:
A UTF-8 encoded, growable string.
The Wikipedia definition of UTF-8 will give you a great deal of background on what that is. The short version is that computers use a unit called a byte to represent data. Unfortunately, these blobs of data represented with bytes have no intrinsic meaning; that has to be provided from outside. UTF-8 is one way of interpreting a sequence of bytes, as are file formats like JPEG.
UTF-8, like most text encodings, has specific requirements and sequences of bytes that are valid and invalid. Whatever image you have tried to load contains a sequence of bytes that cannot be interpreted as a UTF-8 string; this is what the error message is telling you.
To fix it, you should not use a String to hold arbitrary collections of bytes. In Rust, that's better represented by a Vec:
fn read_file(mut file_name: String) -> Vec<u8> {
file_name = file_name.replace("/", "");
if file_name.is_empty() {
file_name = String::from("index.html");
}
let path = Path::new(&file_name);
if !path.exists() {
return String::from("Not Found!").into();
}
let mut file_content = Vec::new();
let mut file = File::open(&file_name).expect("Unable to open file");
file.read_to_end(&mut file_content).expect("Unable to read");
file_content
}
To evangelize a bit, this is a great aspect of why Rust is a nice language. Because there is a type that represents "a set of bytes that is guaranteed to be a valid UTF-8 string", we can write safer programs since we know that this invariant will always be true. We don't have to keep checking throughout our program to "make sure" it's still a string.
I need to Convert a xamarin forms image into a base64 format, Can anyone help me with this?
This is how i've being trying to do it, but it doesent work.
var inputStream = signatureImage.Source.GetValue(UriImageSource.UriProperty);
//Getting Stream as a Memorystream
var signatureMemoryStream = inputStream as MemoryStream;
if (signatureMemoryStream == null)
{
signatureMemoryStream = new MemoryStream();
inputStream.CopyTo(signatureMemoryStream);
}
//Adding memorystream into a byte array
var byteArray = signatureMemoryStream.ToArray();
//Converting byte array into Base64 string
base64String = Convert.ToBase64String(byteArray);
"signatureImage" is the image name.
Once you get your file path , you can use the following code that worked for me.
var stream = file.GetStream();
var bytes = new byte [stream.Length];
await stream.ReadAsync(bytes, 0, (int)stream.Length);
string base64 = System.Convert.ToBase64String(bytes);
I found it here
Image is just a control in Xamarin forms to display the image.
It is not something from which you can get your image byte array out.
You will be better of using the Media Plugin and save it to disk. Then load it via memory stream and convert.
You can also use FFImageLoading. It has 2 methods which can be of use for you :
GetImageAsJpgAsync(int quality = 90, int desiredWidth = 0, int desiredHeight = 0)
GetImageAsPngAsync(int desiredWidth = 0, int desiredHeight = 0)
The SO question - Convert Image into byte array in Xamarin.Forms shows how to do it in Platform specific code here.
The forum thread (Convert Image to byte[]) has a good discussion on why you can't get it from the control.
You can do this as below as well
var base64String = Convert.ToBase64String(File.ReadAllBytes(file.Path))
I tried to get the image from clipboard when I press ctrl+v on a page, with the code from a gist, which will console.log the image content it gets.
I found the image content is a long base64 string with a special prefix:
data:image/png;base64,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
How to decode it to binary? I tried to remove the prefix data:image/png;base64, and use a base64 library to decode the rest into binary, and save it to a image.png file. But the file can't be displayed, with invalid format error.
But if I paste the whole string to http://base64online.org/decode/, it can play the image as well.
The base64 library I used is https://github.com/wstrange/base64, and my code is:
import 'package:base64_codec/base64_codec.dart';
var body = /* the long str above */;
var prefix = "data:image/png;base64,";
var bStr = body.substring(prefix.length);
var bs = Base64Codec.codec.decodeList(bStr.codeUnits);
var file = new File("image.png");
file.writeAsBytesSync(bs);
I don't know where is wrong :(
Try using the crypto package from the Dart SDK. This creates an image.png that opens fine (I believe it's this image... )
library foo;
import 'package:crypto/crypto.dart';
import 'dart:io';
void main() {
var body = "data:image/png;base64,iVBORw0KGgoAAAANSUh... snip";
var prefix = "data:image/png;base64,";
var bStr = body.substring(prefix.length);
var bytes = CryptoUtils.base64StringToBytes(bStr); // using CryptoUtils from Dart SDK
var file = new File("image.png");
file.writeAsBytesSync(bytes);
}
You'll need to add crypto to your pubspec.yaml :
dependencies:
crypto: any
The library linked at https://github.com/wstrange/base64, also notes in the README:
Deprecated
Note: The Dart SDK now includes a Base64 codec with url safe options. Unless you need streaming support, you should use the SDK methods as they are slightly faster.
See CryptoUtils
See also How to native convert string -> base64 and base64 -> string
Decoding as a string and then writing the bytes works:
var prefix = "data:image/png;base64,";
var bStr = body.substring(prefix.length);
var bs = Base64Codec.codec.decodeString(bStr);
var file = new File("image.png");
file.writeAsBytesSync(bs.codeUnits);
The easiest approach is:
import 'dart:convert';
final result = base64Decode(stringValue);