I'm building an implementation of Croppie as an AngularJS directive to provide a UI for users to crop their profile images.
My backend is PHP, and I need a way for the UI selections to be reflected in the server-side manipulations.
I have a 150 by 150 square in the center of my image, as the linked Croppie example similarly shows. As you can see however, you can move and scale the image around, which means cropping from center in Imagick wouldn't always work depending on how the user positions their image around the center point.
I know I can scale the image and then crop from the center in Imagick, but how do I account for the fact that the image will be translated as well?
When I move the image around in my implementation, I get the following data-points to parse and send to the server:
{transform: "translate3d(-60px, -121px, 0px) scale(1)"}
This shows for example, that the image has been shifted along the X and Y axis, and has not been scaled. How do I shift the center of the image accordingly in Imagick?
Thank you!
EDIT:
I see these commands: Imagick::cropThumbnailImage and Imagick::cropImage is there some way to kind of combine them where the cropped area remains in the center as the image is scaled and the image can be shifted on the x or y axis?
EDIT 2
Well, I figured out I need to use a combination of Imagick::cropImage and Imagick::scaleImage but I can't figure out the correct math to send to the server.
I'm attaching an image so you can see what I mean, I'm getting very close but the crop is off on some images:
My HTML is like so:
<div class="viewBox">
<img class="bigTuna">
<div class="enclosedCrop small"></div>
<div class="overlay small"></div>
</div>
The image you are seeing, which I want to crop using .encloseCrop.small which is the circle, is .bigTuna.
I am using the following to calculate the offset of the image (which I can drag around the .encloseCrop.small) relative to the scale of the image (.bigTuna). The offset of .encloseCrop.small is .viewBox, and the image takes up the entire .viewBox with a max-width: 100%;
Because the image has a width, naturalWidth and getBoundingClientRect().width (and respective properties for height) I'm unsure how to accomplish this where I can send to Imagick just an X and Y for the cropImage() arguments.
This is the closest I have gotten:
var Xvalue = (angular.element(".enclosedCrop")[0].offsetLeft + ( -1 * $scope.matrixobject.x )) * ((angular.element('.bigTuna')[0].getBoundingClientRect().width/angular.element('.bigTuna')[0].width)*(angular.element('.bigTuna')[0].naturalWidth/angular.element('.bigTuna')[0].width));
var Yvalue = (angular.element(".enclosedCrop")[0].offsetTop + ( -1 * $scope.matrixobject.y )) * ((angular.element('.bigTuna')[0].getBoundingClientRect().height/angular.element('.bigTuna')[0].height)*(angular.element('.bigTuna')[0].naturalHeight/angular.element('.bigTuna')[0].height));
The bounding width divided by the width is the scale factor, but I need to account for the natural width somehow as well I believe. The issue is that the image you see in the modal where the Croppie-like directive resides already is scaled because it isn't the natural dimensions. On top of that, I'm scaling this (already) scaled image again using CSS transforms.
But when I send the image to PHP, it doesn't know about this. I just receives the natural dimensions and wants to know how to crop it. I need that crop to reflect the UI crop.
$scope.matrixobject.x is the value of the transform of the image, in this case, the amount of pixels it was translated left. I can get all these values just fine, I just don't know what equation is actually the correct one utilizing said values.
EDIT 3:
I've refined my equation like so, but this equation, although it makes the most sense to me, gives me completely off crops.
var Xvalue = (angular.element(".enclosedCrop")[0].offsetLeft + ( -1 * $scope.matrixobject.x )) * (angular.element('.bigTuna')[0].naturalWidth/angular.element('.bigTuna')[0].getBoundingClientRect().width);
var Yvalue = (angular.element(".enclosedCrop")[0].offsetTop + ( -1 * $scope.matrixobject.y )) * (angular.element('.bigTuna')[0].naturalHeight/angular.element('.bigTuna')[0].getBoundingClientRect().height);
The equation first tries to get the offset of the 150 x 150 circle (.enclosedCrop) from from the top and left of the image's container:
In the case of the height, this looks like so:
angular.element(".enclosedCrop")[0].offsetTop + ( -1 * $scope.matrixobject.y )
The first part of this excerpt of the equation gets the offsetTop, which would remain constant as .enclosedCrop itself is stationary in the center of the container. $scope.matrixobject.y is the transform of the image around the container, and by inverting it, we can get the transform needed if instead the .enclosedCrop moved around the image. By adding this to the offset, we know where the crop is happening on the image.
However, the offset and transforms are relative to the size of the image in the container (max-width:100%) which means that they need to be scaled to reflect the natural size of the image and any transforms that may be occurring using CSS scale property.
So I'm multiplying the offset by this:
* (angular.element('.bigTuna')[0].naturalHeight/angular.element('.bigTuna')[0].getBoundingClientRect().height);
The natural height divided by the height of the image. Importantly, this "height of the image" is derived from getBoundingClientRect() which means it takes CSS scaling into account.
So what is wrong with my logic here? I get crops all over the image, not in the coordinates I have specified.
EDIT 4:
I got the very close given the following equation, which I don't really understand (got from Croppie's source code)
var Xvalue = angular.element(".enclosedCrop")[0].getBoundingClientRect().left - angular.element(".bigTuna")[0].getBoundingClientRect().left + angular.element(".enclosedCrop")[0].offsetWidth + (angular.element(".enclosedCrop")[0].getBoundingClientRect().width - angular.element(".enclosedCrop")[0].offsetWidth) / 2;
var Yvalue = angular.element(".enclosedCrop")[0].getBoundingClientRect().top - angular.element(".bigTuna")[0].getBoundingClientRect().top + angular.element(".enclosedCrop")[0].offsetHeight + (angular.element(".enclosedCrop")[0].getBoundingClientRect().height - angular.element(".enclosedCrop")[0].offsetHeight) / 2;
Xvalue = parseFloat(Xvalue).toFixed(0);
Yvalue = parseFloat(Yvalue).toFixed(0);
However it is always a few pixels off, usually slightly down and to the right.
Can someone explain this equation so I can better edit it and find the mistake?
This tricky part by css and js.
Markup html:
<div class="viewBox layer-image">
<img class="bigTuna">
<div class="enclosedCrop small"></div>
<div class="overlay small"></div>
</div>
Css
.layer-image {
background-image: url('sample/image.png');
position: relative;
height: 800px; /* actual height sample*/
weight: 800px; /* actual weight sample*/
}
.enclosedCrop.small {
position: absolute;
}
We set class layer-image have background image and position as relative. well you know base absolute position is relative.
Javascript
Well for dragging, sizing you can use your favorite library or use own code. The big question is how to get x and y. If you see the code, we have already how to get x y. Imagine x y start from top left corner. So what just you need is get margin top of .enclosedCrop.small and margin left of .enclosedCrop.small from layer-image. for ex:
var offsetLayerBase = $('.enclosedCrop.small').offset();
var offsetCropping = $('.enclosedCrop.small').offset();
var yPositionCrop = offsetCropping.top - offsetLayerBase.top;
var xPositionCrop = offsetCropping.left - offsetLayerBase.left;
set offsetLayerBase as base from window (you need any custom if have css custom).
let me know if work for you. Cheers ;)
Related
I am trying to embed a pdf within an iframe but when I set height to 100% it is really small.
Is there a way to make the height exactly one page?
my code
<iframe src="/wp-content/uploads/test.pdf#view=FitH" width="100%" height="100%"></iframe>
Try to add some CSS into your code as below:
<iframe src="/wp-content/uploads/test.pdf#view=FitH" style="width: 100%; height: 100vh"></iframe>
There are two parts to the question
Part 1
"when I set height="100%" the frame is too small
it will be 150px on whatever device since you cannot use % for frame height. The correct way is to set a frame to 100vh (viewport height as suggested by Baris Taskiran in their answer) but there are frame imbedding values that suggest say style as width: calc(100vw - 18px)!important; min-height: calc(100vh - 18px)!important ; can be preferable to avoid drag resizing issues.
see https://stackoverflow.com/a/74354395/10802527
Part 2
You cannot force a browser internal PDF view (it is after PDF download, or not, or download and view. Embed, iFrame or Object it makes no difference the PDF is out of your control and in the application/PDF) but you may suggest it attempt to FitV (fit the vertical) in the viewers downloaded frame.
However that can be meaningless for some PDF viewing plugins, if they are not Acrobat since those are Adobe Acrobat "fragments" and do not need to be supported by plugin extensions such as Chromes Foxit/Skia or Firefoxs PDF.js etc.
For more on the topic see https://stackoverflow.com/a/72265519/10802527 and https://stackoverflow.com/a/72106063/10802527
The question asked is why the middle FitV appears not to be working and since both the HTML and the PDF now belong to the user, they may edit or control view as they wish. This allows users to change font if they wish to inverted W&B Comic Sans or allow for different screen sizes/dpi etc. Both the files are 100% theirs.
The following answer does NOT work:
=====
This may not be practical for you, but this is how I guarantee that only one page of a pdf is displayed in an .
Give your a class--I use "x85x110" for 8.5" x 11" paper and use the following CSS:
iframe.x85x110 { height:calc(103% * (8.5 / 11)); }
The "103%" is a fudge factor that you can change to get exactly the height you want, i.e., to get just a hair of the blank space between one page and the next. The white-space on either side of the "*" and "/" is critical--calc won't work without it.
=====
This answer, however, DOES work:
=====
First the CSS:
iframe.x85x110 { width:80%; }
Second, the HTML:
<iframe class="x85x110" src="A Boy And His Dog/docs/Downunder Expansion - 8.5 x 11 - 10pt.pdf"></iframe>
Third, the javascript:
<script type="text/javascript" >
x85x110();
window.addEventListener('resize', x85x110);
function x85x110()
{
array_x85x110 = document.getElementsByClassName("x85x110");
for (count=0; count<array_x85x110.length; count++)
{
array_x85x110[count].style.height = Math.round(array_x85x110[count].offsetWidth * (11.0 / 8.5)) + "px";
} // for (count=0; count<array_x85x110.length; count++)
} // function x85x110()
Fourth, the explanation:
Give your <iframe> a class name, I used x85x110 because my documents are 8.5" x 11".
I use width:80% because I want the frame to be 80% of the width of the column width in which the .pdf and its containing <iframe> lives--this is NOT necessary.
The x85x110(); calls the function x85x110() when the page loads.
The window.addEventListener('resize', x85x110); calls the x85x110() function whenever the page is resized.
The array_x85x110 = document.getElementsByClassName("x85x110"); collects all of the <iframe> elements of the class x85x110 in an array named array_x85x110.
Then, for each element of array_x85x110, i.e., for each <iframe> of the class x85x110, we loop using the for (count=0; count<array_x85x110.length; count++) {} and set the height of the <iframe> to (11.0 /8.5) times the offsetWidth of the <iframe> with the the:
array_x85x110[count].style.height = Math.round(array_x85x110[count].offsetWidth * (11.0 / 8.5)) + "px";
Math.round() rounds the resizing of the <iframe>'s height to the nearest pixel.
The (11.0 / 8.5) divides the <iframe>'s .offsetWidth by 8.5 (the width of my pdf page in inches), which changes as the browser window is resized, and multiplies by 11 (the height of my pdf page in inches), to maintain the pdf's natural aspect ratio.
If for some bizarre reason you're using A4 paper, you European wierdo :-), the (11.0 / 8.5) would be (11.69 / 8.27), i.e., the height of a piece of A4 paper divided by its width.)
=====
You can see this CSS at work, for real now at my board game design page.
Sorry for the confusion.
You need to set the following settings in CSS (suitable for PDF page size):
width="594px"
height="580px"
Background
Hi there, I have been recently working on a project of mine which allows users to login and signup to the system. This has been done in PHP. Once the user logs in to the system I have allowed them to upload a profile picture. The upload works and the profile picture displays.
What I would like to happen
I want to allow the user to crop the image they have uploaded to a 150x150 image so that it fits nicely when shown on the page.
What have I already tried
I have uploaded the image as normal and used GD from PHP to crop the image. When this happened, the image didn't crop to where I think the user would have wanted to crop it. The subject of the image was on the right like this example: https://i.pinimg.com/originals/29/a1/9b/29a19bb78244f8a7229fa13c21dbcd50.jpg
In this example I think the user would have chosen the tree as the subject. (I know I can select a crop area but I will not know where the subject of the image is hence my question)
What I have achieved so far
Here is an image of what I have created so far:
The slightly opaque overlay over the image is what I want the cropped area to be. This area is draggable using js. I have managed to choose the direction of the image using JS.
Here is the function that moves the overlay when a user clicks and drags it:
function elementDrag(e)
{
e = e || window.event;
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
// decides which direction is allowed for dragging
if(width > height)
{
//landscape
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
//elmnt.style.left = (l+p_dims.left) + "px";
}
else
{
//portrait or sqaure
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
//elmnt.style.top = (elmnt.offsetTop - (t+p_dims.top)) + "px";
}
}
This is the area where I would potentially like to change it so that overlay doesn't go past the image dimensions on screen
What I have failed to do
I wanted to make the draggable overlay only over the area of the image and not the whole page. Once the overlay has been placed the user should be allowed to click the crop button to crop the image. I know how to crop the image using a crop area in PHP and upload it afterwards.
I did find this js library but not keen on using it, I will though if it is a last resort. https://github.com/Foliotek/Croppie
So how do I do this without using any PHP libraries if possible? Thanks in advance.
I've been dealing with something like this. Croppie seamed like a very viable option. I tried it out and it works wonders. Have been using it every since. Great little tool. Highly recommend you use it.
I am working on a web app and am pretty new to web development.
Currently my program gets an and asks for user input relating to the photo.
For my project to be done I need to be able to do one of two things:
Select a random square in the photo and display only that portion. I want this portion of the image to change everytime the page is reloaded to show a different portion.
Detect a facial feature, like an eye or a mouth and show only that portion of the image.
Any free libraries or easy ways to implement either of these features?
Thank You!
For the first question, it's relatively easy. All you need is to set the image url as the background image of a square element, say, a <div>, and then use JS to randomly generate a x% and y% for the background-position: x% y% property:
$(document).ready(function() {
// Generate random x-y coordinates
var x = parseInt(100*Math.random(0,1)),
y = parseInt(100*Math.random(0,1));
// Set background-image and position
$('#img').css({
'background-image':'url('+$('#img').data('img-src')+')',
'background-position':x+'% '+y+'%'
});
});
For the HTML part, we take advantage of the HTML data- attribute:
<div id="img" data-img-src="/path/to/image"></div>
The CSS is also pretty straight forward:
#img {
width: 400px;
height: 400px;
}
You can see the fiddle here - http://jsfiddle.net/teddyrised/gabxj/
The second question - what have you tried? I did a quick search on Google and SO - Any library for face recognition in JavaScript?
I am using Lightview 3 to display an image within an iframe. This has a form that allows the user to zoom in and out of the image and submit the form to generate a thumbnail based on the image in view when the form has been submitted.
The issue I have is that we have to use massive images (width 1100px+) etc.. so having this open in a lightview doesn't really look great as you have scrolling bars within the iframe.
What is the best way to have the image displayed at half of its size and using some form of scaling when it does create the thumbnail of the fullsize image correctly. Can anyone suggest some methods to do this?
I have done this type of thing many times. My environment is ASP.NET using Visual Basic and the technologies I used to achieve my desired result where FancyBox, JCrop, and Uploadify.
First I set up FancyBox (haven't used FancyBox2 yet) to open a modal popup window with a iframe with a page that has a preview area (344x270 in my case) and a place to upload an image using uploadify.
Once an image is uploaded, validated, and thumbnail created I create an object that holds information about this image. This includes file name, extension, original width and height, and a new width and height to scale the image to fit my 344x270 preview (cropbox) area.
To find this new width and height I use the following code written in VB.NET:
Dim objImage As System.Drawing.Image = System.Drawing.Image.FromFile(path)
Dim orig_h = objImage.Height
Dim orig_w = objImage.Width
Dim cropbox_width, cropbox_height As Integer
If objImage.Width > objImage.Height Then
cropbox_width = 344
cropbox_height = (344 / objImage.Width) * objImage.Height
If cropbox_height > 270 Then
Do Until cropbox_height <= 270
cropbox_width = cropbox_width - 1
cropbox_height = (cropbox_width / objImage.Width) * objImage.Height
Loop
End If
Else
cropbox_height = 270
cropbox_width = (270 / objImage.Height) * objImage.Width
If cropbox_width > 344 Then
Do Until cropbox_width <= 344
cropbox_height = cropbox_height - 1
cropbox_width = (cropbox_height / objImage.Height) * objImage.Width
Loop
End If
End If
Basically, I'm trying to determine if its portrait or landscape then find the aspect ratio to scale it down to fit my preview (cropbox) area.
Once this is determined I add them to my object, serialize it and send it back to the upload page (FancyBox iframe), set the image path of the preview (cropbox) area, set it's height and width from the returned object, store the original height and width, and then initiate JCrop.
From here they can crop the image for which I have code to crop the original based on how they have cropped the preview image. I won't go over this code and technique because you didn't ask about cropping.
I know this isn't exactly what you asked for since it sounds like there will be no uploading or cropping going on, but I thought my code for scaling the image down might point you in the right direction.
Fancybox - my favourite (supports many things, not just images)
http://www.designyourway.net/blog/resources/30-efficient-jquery-lightbox-plugins/ This is a fine compiled list of alternatives
I'm working on project where we are trying to adopt and resize template images to the various resolutions. For example if the website is viewed in 800px width (800x600) and 1024px width or larger the image size should be viewed in same quality.
I've had in mind to use sprite with 3 types of images for each range of this template , but I'm looking for other ideas , php gd maybe ? Any python solution ?
Well, for resizing it would of course be better to use GD... But indexed, I think. So that you have an upload script that automatically generates the images' in other sizes, and saves them somewhere.
However, it matters whether you have more disk space, or performance... Performance would get worse IF you have many people viewing these images. Disk space would get worse IF you have A LOT of these images.
Python Imaging Library will give you dynamic resizing, processing, etc.
If you are resizing to a known set of resolutions, you can just resize your images once and store them.
If you need to resize for any possible resolution, you will need a library to do that for you. In PHP, GD or ImageMagik are both good.
If you do this, you may want to add caching for the most common resolutions. This will take up more disc space, but will save you the cost of recalculating all the images every time.
Note that it can be difficult to detect the true resolution though. If the browser window is resized, the resolution you think the screen is may not be the actual resolution the user can see. The same can happen if they have toolbars or sidebars opened.
Why not resize the image on the client using JavaScript?
<head>
<script>
function resize() {
ww = window.innerWidth
wh = window.innerHeight
photo = document.getElementById("photo")
// You probably wouldn't actually make the image fill the window, you'd pick
// some appropriate size.
photo.setAttribute("width", ww)
photo.setAttribute("height", wh)
}
</head>
<body onload="resize()" onresize="resize()">
<img id="photo" src="photo.jpg">
Getting the inner window width is quite hard, as different browsers use different variables. However, this is what I use on my website. It gets the inner window width rather reliably, and then sets the image width/height. It shouldn't be too hard to modify this code to set the src of the image desired.
function set_image_sizes(){
if (window.innerHeight != undefined) {
height = window.innerHeight;
width = window.innerWidth;
} else if (document.documentElement.clientHeight > 0) {
height = document.documentElement.clientHeight;
width = document.documentElement.clientWidth;
} else {
height = document.body.clientHeight;
width = document.body.clientWidth;
}
$('#image').css('height', height);
$('#image').css('width', width);
}