Make FilePond Image Transform plugin ignore (animated) GIFs - filepond

I'm using FilePond with an image editor, so I also load the Image Transform plugin.
However, when a user uploads a GIF file, I want the outputted image to remain a GIF file. Currently it's transformed to a PNG by the Image Transform plugin.
Is there a way to make FilePond disable the Image Transform plugin when a GIF file is uploaded, or somehow change the output mime-type?

Please install version 3.6.0 of the image transform plugin and use the function below to filter out animated GIF images.
Animated GIF filter code snippet from
Is it possible to detect animated gif images client side?
FilePond.create({
imageTransformImageFilter: (file) => new Promise(resolve => {
// no gif mimetype, do transform
if (!/image\/gif/.test(file.type)) return resolve(true);
const reader = new FileReader();
reader.onload = () => {
var arr = new Uint8Array(reader.result),
i, len, length = arr.length, frames = 0;
// make sure it's a gif (GIF8)
if (arr[0] !== 0x47 || arr[1] !== 0x49 ||
arr[2] !== 0x46 || arr[3] !== 0x38) {
// it's not a gif, we can safely transform it
resolve(true);
return;
}
for (i=0, len = length - 9; i < len, frames < 2; ++i) {
if (arr[i] === 0x00 && arr[i+1] === 0x21 &&
arr[i+2] === 0xF9 && arr[i+3] === 0x04 &&
arr[i+8] === 0x00 &&
(arr[i+9] === 0x2C || arr[i+9] === 0x21)) {
frames++;
}
}
// if frame count > 1, it's animated, don't transform
if (frames > 1) {
return resolve(false);
}
// do transform
resolve(true);
}
reader.readAsArrayBuffer(file);
})
});

Related

App MediaFrameReader always returns null Bitmap

I am using MediaCapture to preview camera on the screen, which is working fine.
However, I need to access the current frames in my App. Therefore I added FrameReader to the MediaCapture to get the event Reader_FrameArrived.
So the event is working, however the bitmap itself is always null.
I implemented the ecent callback just like shown in the examples:
var mediaFrameReference = sender.TryAcquireLatestFrame();
var videoMediaFrame = mediaFrameReference?.VideoMediaFrame;
var softwareBitmap = videoMediaFrame?.SoftwareBitmap;
if (softwareBitmap != null)
{
Debug.WriteLine("here");
}
else
{
return;
}
and this is how I initialize the reader:
var frameSourceGroups = await MediaFrameSourceGroup.FindAllAsync();
var allGroups = await MediaFrameSourceGroup.FindAllAsync();
var eligibleGroups = allGroups.Select(g => new
{
Group = g,
// For each source kind, find the source which offers that kind of media frame,
// or null if there is no such source.
SourceInfos = new MediaFrameSourceInfo[]
{
g.SourceInfos.FirstOrDefault(info => info.SourceKind == MediaFrameSourceKind.Color),
g.SourceInfos.FirstOrDefault(info => info.SourceKind == MediaFrameSourceKind.Depth),
g.SourceInfos.FirstOrDefault(info => info.SourceKind == MediaFrameSourceKind.Infrared),
}
}).Where(g => g.SourceInfos.Any(info => info != null)).ToList();
if (eligibleGroups.Count == 0)
{
System.Diagnostics.Debug.WriteLine("No source group with color, depth or infrared found.");
return;
}
var selectedGroupIndex = 0; // Select the first eligible group
MediaFrameSourceGroup selectedGroup = eligibleGroups[selectedGroupIndex].Group;
MediaFrameSourceInfo colorSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[0];
MediaFrameSourceInfo infraredSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[1];
MediaFrameSourceInfo depthSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[2];
//_mediaCapture.FrameSources.TryGetValue(cameraDevice.Id, out _source);
var colorFrameSource = _mediaCapture.FrameSources[colorSourceInfo.Id];
if (colorFrameSource != null)
{
_reader = await _mediaCapture.CreateFrameReaderAsync(colorFrameSource, MediaEncodingSubtypes.Argb32);
_reader.FrameArrived += Reader_FrameArrived;
MediaFrameReaderStartStatus result = await _reader.StartAsync();
Debug.WriteLine(result.ToString());
}
Any ideas why the bitmap could be null?
I am using MediaCapture to preview camera on the screen, which is working fine.
For the scenario, we suggest you use MediaCapture class capture bitmap, it contains GetPreviewFrameAsync method gets a preview frame from the capture device than convert it to SoftwareBitmap.
private async Task GetPreviewFrameAsSoftwareBitmapAsync()
{
// Get information about the preview
var previewProperties = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;
// Create the video frame to request a SoftwareBitmap preview frame
var videoFrame = new VideoFrame(BitmapPixelFormat.Bgra8, (int)previewProperties.Width, (int)previewProperties.Height);
// Capture the preview frame
using (var currentFrame = await _mediaCapture.GetPreviewFrameAsync(videoFrame))
{
// Collect the resulting frame
SoftwareBitmap previewFrame = currentFrame.SoftwareBitmap;
// Show the frame information
FrameInfoTextBlock.Text = String.Format("{0}x{1} {2}", previewFrame.PixelWidth, previewFrame.PixelHeight, previewFrame.BitmapPixelFormat);
// Add a simple green filter effect to the SoftwareBitmap
if (GreenEffectCheckBox.IsChecked == true)
{
ApplyGreenFilter(previewFrame);
}
// Show the frame (as is, no rotation is being applied)
if (ShowFrameCheckBox.IsChecked == true)
{
// Create a SoftwareBitmapSource to display the SoftwareBitmap to the user
var sbSource = new SoftwareBitmapSource();
await sbSource.SetBitmapAsync(previewFrame);
// Display it in the Image control
PreviewFrameImage.Source = sbSource;
}
// Save the frame (as is, no rotation is being applied)
if (SaveFrameCheckBox.IsChecked == true)
{
var file = await _captureFolder.CreateFileAsync("PreviewFrame.jpg", CreationCollisionOption.GenerateUniqueName);
Debug.WriteLine("Saving preview frame to " + file.Path);
await SaveSoftwareBitmapAsync(previewFrame, file);
}
}
}
And here is official code sample that you could refer directly.

Flutter/Dart rewriting image in the same format

After reading an image with the ImageDescriptor API and resizing it by instantiating a codec I am trying to write the resized version in the application directory.
I saw that the when converting the frame into byte data I have a format which is rawUnmodified which I assumed would write the resized image in the same format as the original image. But when I tried to load the resized image I get an image format exception.
Example code:
//read the original image and obtain the image descriptor
var imageData = await file.readAsBytes();
final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(imageData);
final imDescr = await ImageDescriptor.encoded(buffer);
//resize the image, get the first frame and convert it to bytes
Codec codec = await imDescr.instantiateCodec(targetWidth: 100, targetHeight: 100);
FrameInfo frameInfo = await codec.getNextFrame();
var bytes = await frameInfo.image.toByteData(
format: ImageByteFormat.rawUnmodified,
//note when using the png format it works, but I would like to have it in the original image format(in this case its jpg)
);
//write the resized image
Directory appDir = await getApplicationDocumentsDirectory();
var path = appDir.path;
var file = File('$path/test1.jpg');
await file.writeAsBytes(bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes));
In the ImageByteFormat api it says: rawUnmodified -> Unencoded bytes, in the image's existing format. For example, a grayscale image may use a single 8-bit channel for each pixel.
But when I try to show this image the format is wrong. Anybody have an idea how to fix this?
Why use image ImageDescriptor, You can do it easily by image package
File resizeImage(File imageFile, String imageFormat, int targetWidth, int targetHeight) {
im.Image tempImage = im.decodeImage(imageFile.readAsBytesSync());
tempImage = im.bakeOrientation(tempImage);
tempImage = im.copyResize(tempImage, width: targetWidth, height: targetHeight);
File newImage;
if (imageFormat == 'jpg') {
newImage = File('newpath/test.jpg');
newImage.writeAsBytesSync(im.encodeJpg(tempImage));
return newImage;
} else if (imageFormat == 'png') {
newImage = File('newpath/test.png');
newImage.writeAsBytesSync(im.encodePng(tempImage));
return newImage;
} else {
throw ('Unknown Image Format');
}
}

Triggering a Lottie animation onScroll

im currently building a website using fullpage js and lottie animations. Now im trying to trigger an animation when the user scrolls to the section with the animation. Here is what i tried:
(please note that im very new to js)
$(document).ready(function($) {'use strict';
$('#fullpage').fullpage({
sectionsColor: ['white', '#004E8A', 'white','#004E8A', 'white', '#004E8A',
'white','#004E8A', 'white'],
anchors:['startseite','pers_vermittler','team','konzept','rechner','mod_portfolio','sicherheit','absatz'],
onLeave: function(index, nextIndex, direction) {
if( index == 3 && direction == 'down' ) {
lottie.play('k2an');
}
(at the end of the body section ->)
<script>
var params = {
container: document.getElementById('k2an'),
renderer: 'svg',
loop: true,
autoplay: false,
path: 'k2an.json',
};
anim = lottie.loadAnimation(params);
You should be using fullPage.js callbacks to fire your JS animations.
See the example:
$('#fullpage').fullpage({
anchors: ['firstPage', 'secondPage', 'thirdPage', 'fourthPage', 'lastPage'],
afterLoad: function(anchorLink, index){
var loadedSection = $(this);
//using index
if(index == 3){
alert("Section 3 ended loading");
}
//using anchorLink
if(anchorLink == 'secondSlide'){
alert("Section 2 ended loading");
}
}
});
Feel free to also check my video tutorial on how to create animations using fullPage.js state classes.
Right now im using this approach on a couple production sites. It plays the animation as the user scrolls.
I basically check how much of the animation objects box is visible in the viewport, calculate the total length of the animation (in frames) and then project the percentage to a frame where i gotoAndStop().
var anim = <YOUR LOTTIE ANIMATION OBJECT>
// play around with these
var speed = 1; // speed of animation
var scrollOffset = 0; // start animation sooner / later
function scrollHandler() {
if (!anim.isLoaded) return;
p = percentageSeen(e) / 100 - (scrollOffset || 0);
if (p <= 0 || p >= 1) return
var length = anim.totalFrames / anim.frameModifier;
var pos = length * p * (speed || 1);
anim.goToAndStop(pos);
}
$(window).on('scroll', scrollHandler);
/**
* returns percentage of scrolling element through viewport
* 0% until element-middle is at bottom of viewport
* 100% if element-middle is at top of viewport
*
* #param id
* #returns {number}
*/
function percentageSeen(idOrElement) {
var $element;
if (typeof idOrElement === 'object') {
$element = idOrElement;
} else {
$element = $('#' + id);
if (!$element[0]) return 0;
}
var $win = $(window), viewportHeight = $(window).height(),
scrollTop = $win.scrollTop(),
elementOffsetTop = $element.offset().top,
elementHeight = $element.height();
if (elementOffsetTop > (scrollTop + viewportHeight)) {
return 0;
} else if ((elementOffsetTop + elementHeight) < scrollTop) {
return 100;
} else {
var distance = (scrollTop + viewportHeight) - elementOffsetTop - (elementHeight / 2);
if (distance < 0) return 0;
var percentage = distance / (viewportHeight / 100);
if (percentage > 100) return 100;
return percentage;
}
}
If you want to only start the animation and let it run (independently of further user-scrolling-behaviour), just use the jquery inview plugin, disable autoplay on your animation and trigger the play() once like this:
$(".animation-container").one("inview", function() {
anim.play()
});

Jcrop Image Intervention Laravel 5

i am using Image Intervention and jcrop to crop and resize image in laravel, but having problems. The issue which i think is that , when i save the file width and height is correct according to the selection, but the x & y is not correct, I am completely lost here, dont know what to do , Please help.
I have made but cropping area is wrong.
here is the code example.
// convert bytes into friendly format
function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB'];
if (bytes == 0) return 'n/a';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
}
// check for selected crop region
function checkForm() {
if (parseInt($('#w').val())) return true;
$('.setting-image-error').html('Select area').show();
return false;
}
// update info by cropping (onChange and onSelect events handler)
function updateInfo(e) {
$('#x1').val(e.x);
$('#y1').val(e.y);
$('#x2').val(e.x2);
$('#y2').val(e.y2);
$('#w').val(e.w);
$('#h').val(e.h);
}
// clear info by cropping (onRelease event handler)
function clearInfo() {
$('#w').val('');
$('#h').val('');
}
// Create variables (in this scope) to hold the Jcrop API and image size
var jcrop_api, boundx, boundy;
function fileSelectHandler() {
// get selected file
var oFile = $('#picture')[0].files[0];
// hide all errors
$('.setting-image-error').hide();
// check for image type (jpg and png are allowed)
var rFilter = /^(image\/jpeg|image\/png)$/i;
if (!rFilter.test(oFile.type)) {
$('.setting-image-error').html('Select only jpg, png').show();
return;
}
// check for file size
if (oFile.size > 10000000) {
$('.setting-image-error').html('Too Big file ').show();
return;
}
// preview element
var oImage = document.getElementById('preview');
// prepare HTML5 FileReader
var oReader = new FileReader();
oReader.onload = function (e) {
// e.target.result contains the DataURL which we can use as a source of the image
oImage.src = e.target.result;
oImage.onload = function () { // onload event handler
// display step 2
$('.setting-image-cropping-stage').fadeIn(500);
// display some basic image info
var sResultFileSize = bytesToSize(oFile.size);
$('#filesize').val(sResultFileSize);
$('#filetype').val(oFile.type);
$('#filedim').val(oImage.naturalWidth + ' x ' + oImage.naturalHeight);
// destroy Jcrop api if already initialized
if (typeof jcrop_api !== 'undefined') {
jcrop_api.destroy();
jcrop_api = null;
$('#preview').width(oImage.naturalWidth);
$('#preview').height(oImage.naturalHeight);
}
//Scroll the page to the cropping image div
$("html, body").animate({scrollTop: $(document).height()}, "slow");
// initialize Jcrop
$('#preview').Jcrop({
minSize: [32, 32], // min crop size
aspectRatio: 1, // keep aspect ratio 1:1
bgFade: true, // use fade effect
bgOpacity: .3, // fade opacity
onChange: updateInfo,
onSelect: updateInfo,
onRelease: clearInfo
}, function () {
// use the Jcrop API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
// Store the Jcrop API in the jcrop_api variable
jcrop_api = this;
});
}
}
// read selected file as DataURL
oReader.readAsDataURL(oFile);
}
and Controller code is below.
public function image_crop_resize_and_upload($file, $user_id,$width,$height,$x1,$y1)
{
$filename = $user_id . '.jpg';// image file name
$target_path = User::PICTURE_PATH . $filename;//path where to create picture with new dimensions
$img = \Image::make($file->getRealPath());// create the instance of image with the real path of the image
$filetype = $img->mime();//get file mime type
$filetypes = ['image/jpg', 'image/jpeg', 'image/png']; //allowed files types
//if file exists in the target folder, system will delete the file and next step will create new one.
if (File::exists($target_path)) {
File::delete($target_path);
}
if (in_array($filetype, $filetypes, true)) {
$img->crop($width, $height,$x1,$y1);
$img->encode('jpg', 85);
$img->resize($width,$height);
$img->save('uploads/' . $user_id . '.jpg');
return true;
} else {
return false;
}
}
When i have the file the file width and height is correct, but the selection area, x & y is not correct.
Yes , I have got the answer. The problem is very simple the x and y position of image are wrong because it is inside a bootstrap responsive class. the proper solution is just to remove the class . So the image actually dimension will be shown. and than select the are. Thats it.
<img id="preview" name="preview" class="img-responsive"/>
this should be
<img id="preview" name="preview"/>

detecting "we have no imagery" of google maps street view static images

I'm generating street view static images like so:
https://maps.googleapis.com/maps/api/streetview?size=1080x400&location=%s&fov=90&heading=235&pitch=0&key=%s
If you visit that link you see an image that says, "Sorry, we have no imagery for this..."
Is there any way to detect this "sorry" state so that I can fall back to another image?
One quick solution would be to load the image file using xmlrpc and check that its md5sum is 30234b543d5438e0a0614bf07f1ebd25, or that its size is 1717 bytes (it's unlikely that another image can have exactly the same size), but that's not very robust since I have seen Google change the position of the text in the image. Though it's a very good start for a prototype.
You could go for image processing instead. Note that it's still not perfectly robust since Google could decide to change the looks of the image anytime. You'll have to decide whether it's worth it.
Anyway, here is how I would do it using jQuery:
load the image and open a 2D context for direct pxiel access (see this question for how to do it)
analyse the image:
sample groups of 2×2 pixels at random locations; I recommend at least 30 groups
a group of 2×2 pixels is good if all the pixels have the same value and their R/G/B values do not differ by more than 10% (ie. they're grey)
count the ratio of good pixel groups in the image
if there are more than 70% good pixel groups, then we are pretty sure this is the “no imagery” version: replace it with another image of your choice.
The reason I do not recommend testing directly for an RGB value is because JPEG decompression may have slightly different behaviours on different browsers.
this situation is already build in in the 3.0 version due
the boolean test status === streetviewStatus.Ok, here is a snippet from my situation solving
if (status === google.maps.StreetViewStatus.OK) {
var img = document.createElement("IMG");
img.src = 'http://maps.googleapis.com/maps/api/streetview?size=160x205&location='+ lat +','+ lng +'&sensor=false&key=AIzaSyC_OXsfB8-03ZXcslwOiN9EXSLZgwRy94s';
var oldImg = document.getElementById('streetViewImage');
document.getElementById('streetViewContainerShow').replaceChild(img, streetViewImage);
} else {
var img = document.createElement("IMG");
img.src = '../../images/ProfilnoProfilPicture.jpg';
img.height = 205;
img.width = 160;
var oldImg = document.getElementById('streetViewImage');
document.getElementById('streetViewContainerShow').replaceChild(img, streetViewImage);
}
As of 2016, you can use the new Street View Image Metadata API.
Now you just need the status field to know if a panorama is found.
Example requests:
https://maps.googleapis.com/maps/api/streetview/metadata?size=600x300&location=78.648401,14.194336&fov=90&heading=235&pitch=10&key=YOUR_API_KEY
{
"status" : "ZERO_RESULTS"
}
https://maps.googleapis.com/maps/api/streetview/metadata?size=600x300&location=eiffel%20tower,%20paris,%20france&heading=-45&pitch=42&fov=110&key=YOUR_API_KEY
{
...
"status" : "OK"
}
You can use the getPanoramaByLocation function (see http://code.google.com/apis/maps/documentation/javascript/services.html#StreetViewService).
try something like this:
function handleMapClick()
{
var ll= new google.maps.LatLng(latitude,longitude);
sv.getPanoramaByLocation(ll, 50, processSVData);
}
function processSVData(data, status) {
if (status==google.maps.StreetViewStatus.ZERO_RESULTS)
{
<DO SOMETHING>
}
}
Request a google street view image and if it has a specific file size it is a 'Not street view avaible'. I did the follwing:
var url = 'google street view url';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function (e) {
if (this.status == 200) {
try {
var image = new Blob([this.response], {type: 'image/jpeg'});
if (image.size) {
if (url.indexOf('640x640') > -1 && image.size === 8410) {
// Not street view
}
if (url.indexOf('400x300') > -1 && image.size === 3946) {
// Not street view
}
}
} catch (err) {
// IE 9 doesn't support blob
}
}
};
xhr.send();
Another way is to load the image and then compare some pixels colors. The "no streetview" image from google is always the same. Here is how you would compare 2 pixels:
var url = STREETVIEWURL
var img = new Image();
// Add some info to prevent cross origin tainting
img.src = url + '?' + new Date().getTime();
img.setAttribute('crossOrigin', '');
img.crossOrigin = "Anonymous";
img.onload = function() {
var context = document.createElement('CANVAS').getContext('2d');
context.drawImage(img, 0, 0);
//load 2 pixels. I chose the first one and the 5th row
var data1 = context.getImageData(0, 0, 1, 1).data;
var data2 = context.getImageData(0, 5, 1, 1).data;
console.log(data1);
// google unknown image is this pixel color [228,227,223,255]
if(data1[0]==228 && data1[1]==227 && data1[2]==223 && data1[3]==255 &&
data2[0]==228 && data2[1]==227 && data2[2]==223 && data2[3]==255){
console.log("NO StreetView Available");
}else{
console.log("StreetView is Available");
}
};
Some potential issues:
I've seen some errors with CrossOrigin tainting. Also, if google changes the image returned this code will break.

Resources