How to set chunk size for HttpRequest/HttpEntity created from a ByteString - akka-http

If I want to upload a file in akka-http I can use a method like this where I can control the chunk size:
private def createUploadRequest(streamName: String, uri: Uri, path: Path): Future[(HttpRequest, Path)] = {
val bodyPart = FormData.BodyPart.fromPath("data", ContentTypes.`application/octet-stream`, path, chunkSize)
val body = FormData(bodyPart)
Marshal(body).to[RequestEntity].map { entity =>
HttpRequest(method = HttpMethods.POST, uri = uri, entity = entity) -> path
}
}
However if I only have a ByteString with the contents and want to upload it, I can't control the chunk size:
private def makeHttpRequest(streamName: String, serverInfo: ServerInfo, bs: ByteString): HttpRequest = {
HttpRequest(
HttpMethods.POST,
s"http://${serverInfo.host}:${serverInfo.port}$distRoute/$streamName",
entity = HttpEntity(ContentTypes.`application/octet-stream`, bs)
)
}
Is there any way to also control the chunk size when creating the HttpEntity from a ByteString?

Create a Chunked entity instead of using the HttpEntity.apply method:
import akka.http.scaladsl.model.HttpEntity.Chunked
import akka.http.scaladsl.model.HttpEntity.ChunkStreamPart
type ChunkSize = Int
val chunkedEntityFromByteString : ChunkSize => ByteString => Entity =
chunkSize => byteString =>
Chunked(
ContentTypes.`application/octet-stream`,
Source
.fromIterator(() => byteString sliding chunkSize)
.map(ChunkStreamPart.apply)
)

Just a minor correction to the posted solution to make it compile:
type ChunkSize = Int
val chunkedFromByteString : ChunkSize => ByteString => HttpEntity =
chunkSize => byteString =>
Chunked(
ContentTypes.`application/octet-stream`,
Source
.fromIterator(() => byteString sliding chunkSize)
.map(ChunkStreamPart.apply)
)

Related

SixLabors.ImageSharp Compressing image is making the image bigger as a byte

I have compress method which is uses SixLabors.ImageSharp. When i compress a image on that method, its getting more size before then i upload it. The image i upload is 2,03 mb
and when its come out from the compression method, its getting like that 4,54 mb
and here it's my compression method :
public async Task<FileRepo> FileUploadToDatabase(List<IFormFile> files)
{
foreach (var file in files)
{
var fileName = Path.GetFileNameWithoutExtension(file.FileName);
var fileExtension = Path.GetExtension(file.FileName);
using var image = Image.Load(file.OpenReadStream());
IImageEncoder imageEncoderForJpeg = new JpegEncoder()
{
Quality = 80,
};
IImageEncoder imageEncoderForPng = new PngEncoder()
{
CompressionLevel = PngCompressionLevel.Level9,
};
_fileRepo = new FileRepo
{
FileName = fileName,
FileExtension = fileExtension,
FileType = file.ContentType,
CreatedDate = DateTime.Now
};
using (var ms = new MemoryStream())
{
if (fileExtension == ".png")
{
image.Save(ms, imageEncoderForPng);
}
if (fileExtension == ".JPEG" || fileExtension == ".jpg")
{
image.Save(ms, imageEncoderForJpeg);
}
await file.CopyToAsync(ms);
_fileRepo.FileData = ms.ToArray();
}
}
return _fileRepo;
}
i dont know whats wrong with that method , it should be less size then first one right ?
let me know if that question is duplicate.

How to get the index of a gson object?

I need to get the index of the array containing the member fileName = "Andres"
data class File(var fileName: String, var _id : String? = null)
data class Files(val files: Array<File>)
val miObjetG = Gson().fromJson(response_files, Files::class.java)
var indice = miObjetG.files.filterIndexed { index, file -> file.fileName == "Andres"}
I think indexOfFirst is what you are looking for:
val index = miObjetG.files.indexOfFirst{ it.fileName == "Andres" }

Saving Arrays in Swift

I have a question about saving Arrays in Apple's new programming language Swift. In Objective-C I saved data with NSFileManager... but this doesn't work anymore in Swift. So I wanted to ask how I should save an array WITHOUT using NSUserDefaults which isn't really suited for storing a big amount of data. I would really much appreciate any help :]
First (if your array is not of string type) change it to String:
var notStringArray = [1, 2, 3, 4]
var array: [String] = []
for value in notStringArray{
array.append(String(value))
}
Then reduce the array to one string:
var array = ["1", "2", "3", "4", "5"] //Ignore this line if your array wasn't of type String and you did the step above
var stringFromArray = reduce(array, "") { $0.isEmpty ? $1 : "\($0)\n\($1)" }
This create an string that looks like this:
"1
2
3
4
5"
And then to write and read a file add this class at the top of your file:
class File {
class func open (path: String, utf8: NSStringEncoding = NSUTF8StringEncoding) -> String? {
var error: NSError? //
return NSFileManager().fileExistsAtPath(path) ? String(contentsOfFile: path, encoding: utf8, error: &error)! : nil
}
class func save (path: String, fileContent: String, utf8: NSStringEncoding = NSUTF8StringEncoding) -> Bool {
var error: NSError? //
return fileContent.writeToFile(path, atomically: true, encoding: utf8, error: &error)
}
}
(Don't forget to import UIKit)
To save to a file:
let didSave = File.save("DirectoryOfFile", content: stringFromArray)
if didSave {
println("file saved")
} else {
println("error saving file")
}
To get it back:
var stringFromFile = ""
if let loadData = File.open("DirectoryOfFile") {
stringFromFile = loadData
} else {
println("error reading file")
}
To put it back in an array:
var newArray: [String] = [] //Creates empty string array
newArray = stringFromFile.componentsSeparatedByString("\n")
And there you have it

How to create a single-color Bitmap to display a given hue?

I have a requirement to create an image based on a certain color. The color will vary and so will the size of the output image. I want to create the Bitmap and save it to the app's temporary folder. How do I do this?
My initial requirement came from a list of colors, and providing a sample of the color in the UI. If the size of the image is variable then I can create them for certain scenarios like result suggestions in the search pane.
This isn't easy. But it's all wrapped in this single method for you to use. I hope it helps. ANyway, here's the code to create a Bitmap based on a given color & size:
private async System.Threading.Tasks.Task<Windows.Storage.StorageFile> CreateThumb(Windows.UI.Color color, Windows.Foundation.Size size)
{
// create colored bitmap
var _Bitmap = new Windows.UI.Xaml.Media.Imaging.WriteableBitmap((int)size.Width, (int)size.Height);
byte[] _Pixels = new byte[4 * _Bitmap.PixelWidth * _Bitmap.PixelHeight];
for (int i = 0; i < _Pixels.Length; i += 4)
{
_Pixels[i + 0] = color.B;
_Pixels[i + 1] = color.G;
_Pixels[i + 2] = color.R;
_Pixels[i + 3] = color.A;
}
// update bitmap data
// using System.Runtime.InteropServices.WindowsRuntime;
using (var _Stream = _Bitmap.PixelBuffer.AsStream())
{
_Stream.Seek(0, SeekOrigin.Begin);
_Stream.Write(_Pixels, 0, _Pixels.Length);
_Bitmap.Invalidate();
}
// determine destination
var _Folder = Windows.Storage.ApplicationData.Current.TemporaryFolder;
var _Name = color.ToString().TrimStart('#') + ".png";
// use existing if already
Windows.Storage.StorageFile _File;
try { return await _Folder.GetFileAsync(_Name); }
catch { /* do nothing; not found */ }
_File = await _Folder.CreateFileAsync(_Name, Windows.Storage.CreationCollisionOption.ReplaceExisting);
// extract stream to write
// using System.Runtime.InteropServices.WindowsRuntime;
using (var _Stream = _Bitmap.PixelBuffer.AsStream())
{
_Pixels = new byte[(uint)_Stream.Length];
await _Stream.ReadAsync(_Pixels, 0, _Pixels.Length);
}
// write file
using (var _WriteStream = await _File.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
{
var _Encoder = await Windows.Graphics.Imaging.BitmapEncoder
.CreateAsync(Windows.Graphics.Imaging.BitmapEncoder.PngEncoderId, _WriteStream);
_Encoder.SetPixelData(Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8,
Windows.Graphics.Imaging.BitmapAlphaMode.Premultiplied,
(uint)_Bitmap.PixelWidth, (uint)_Bitmap.PixelHeight, 96, 96, _Pixels);
await _Encoder.FlushAsync();
using (var outputStream = _WriteStream.GetOutputStreamAt(0))
await outputStream.FlushAsync();
}
return _File;
}
Best of luck!

How to use ScalaQuery to insert a BLOB field?

I used ScalaQuery and Scala.
If I have an Array[Byte] object, how do I insert it into the table?
object TestTable extends BasicTable[Test]("test") {
def id = column[Long]("mid", O.NotNull)
def extInfo = column[Blob]("mbody", O.Nullable)
def * = id ~ extInfo <> (Test, Test.unapply _)
}
case class Test(id: Long, extInfo: Blob)
Can I define the method used def extInfo = column[Array[Byte]]("mbody", O.Nullable), how to operate(UPDATE, INSERT, SELECT) with the BLOB type field?
BTW: no ScalaQuery tag
Since the BLOB field is nullable, I suggest changing its Scala type to Option[Blob], for the following definition:
object TestTable extends Table[Test]("test") {
def id = column[Long]("mid")
def extInfo = column[Option[Blob]]("mbody")
def * = id ~ extInfo <> (Test, Test.unapply _)
}
case class Test(id: Long, extInfo: Option[Blob])
You can use a raw, nullable Blob value if you prefer, but then you need to use orElse(null) on the column to actually get a null value out of it (instead of throwing an Exception):
def * = id ~ extInfo.orElse(null) <> (Test, Test.unapply _)
Now for the actual BLOB handling. Reading is straight-forward: You just get a Blob object in the result which is implemented by the JDBC driver, e.g.:
Query(TestTable) foreach { t =>
println("mid=" + t.id + ", mbody = " +
Option(t.extInfo).map { b => b.getBytes(1, b.length.toInt).mkString })
}
If you want to insert or update data, you need to create your own BLOBs. A suitable implementation for a stand-alone Blob object is provided by JDBC's RowSet feature:
import javax.sql.rowset.serial.SerialBlob
TestTable insert Test(1, null)
TestTable insert Test(2, new SerialBlob(Array[Byte](1,2,3)))
Edit: And here's a TypeMapper[Array[Byte]] for Postgres (whose BLOBs are not yet supported by ScalaQuery):
implicit object PostgresByteArrayTypeMapper extends
BaseTypeMapper[Array[Byte]] with TypeMapperDelegate[Array[Byte]] {
def apply(p: BasicProfile) = this
val zero = new Array[Byte](0)
val sqlType = java.sql.Types.BLOB
override val sqlTypeName = "BYTEA"
def setValue(v: Array[Byte], p: PositionedParameters) {
p.pos += 1
p.ps.setBytes(p.pos, v)
}
def setOption(v: Option[Array[Byte]], p: PositionedParameters) {
p.pos += 1
if(v eq None) p.ps.setBytes(p.pos, null) else p.ps.setBytes(p.pos, v.get)
}
def nextValue(r: PositionedResult) = {
r.pos += 1
r.rs.getBytes(r.pos)
}
def updateValue(v: Array[Byte], r: PositionedResult) {
r.pos += 1
r.rs.updateBytes(r.pos, v)
}
override def valueToSQLLiteral(value: Array[Byte]) =
throw new SQueryException("Cannot convert BYTEA to literal")
}
I just post an updated code for Scala and SQ, maybe it will save some time for somebody:
object PostgresByteArrayTypeMapper extends
BaseTypeMapper[Array[Byte]] with TypeMapperDelegate[Array[Byte]] {
def apply(p: org.scalaquery.ql.basic.BasicProfile) = this
val zero = new Array[Byte](0)
val sqlType = java.sql.Types.BLOB
override val sqlTypeName = "BYTEA"
def setValue(v: Array[Byte], p: PositionedParameters) {
p.pos += 1
p.ps.setBytes(p.pos, v)
}
def setOption(v: Option[Array[Byte]], p: PositionedParameters) {
p.pos += 1
if(v eq None) p.ps.setBytes(p.pos, null) else p.ps.setBytes(p.pos, v.get)
}
def nextValue(r: PositionedResult) = {
r.nextBytes()
}
def updateValue(v: Array[Byte], r: PositionedResult) {
r.updateBytes(v)
}
override def valueToSQLLiteral(value: Array[Byte]) =
throw new org.scalaquery.SQueryException("Cannot convert BYTEA to literal")
}
and then usage, for example:
...
// defining a column
def content = column[Array[Byte]]("page_Content")(PostgresByteArrayTypeMapper)