I am wanting to alter the following php code so that it resizes and displays images one at a time, with a 'next' and 'previous' button, in order to browse through the photos. I don't want any image gallery or lightbox solutions, rather the photos to just show on the page. I'm new to php so If someone can help out or point me in the right direction all help is appreciated.
$sql = "select * from people";
$result = mysql_query($sql) or die ("Could not access DB: " . mysql_error());
while ($row = mysql_fetch_assoc($result))
{
echo "<div class=\"picture\">";
echo "<p>";
// Note that we are building our src string using the filename from the database
echo "<img src=\"images/" . $row['filename'] . "\" alt=\"\" /><br />";
echo $row['fname'] . " " . $row['lname'] . "<br />";
echo "</p>";
echo "</div>";
source of above code
You can scale them in the browser using width and height attributes (or just one will maintain aspect ratio) however this is bad for many reasons including bandwidth, page performance and image quality.
You can re-size the images using libraries such as GD or Imagick
A quick sample with IMagick:
$hThumb = new Imagick($path_to_file); // Source file
$hThumb->thumbnailImage($x, $y); // You can use 300, 0 to do 300 width and maintain aspect ratio.
$hThumb->stripImage(); // remove meta data
$hThumb->writeImage($path_to_thumb); // write the image to disk
Note
Be sure to have permissions to read/write. You can verify this permissions by using is_readable and is_writable.
Loading
It's recommended to load the images using AJAX which is quite easy if using JQuery or a similar library.
$('#nextBtn').click(function() {
var index = 0; // Store this in your image ID tag perhaps
// e.g. $('#theImage').attr('id').replace('image', '')
// where ID is imageX
$.ajax({
url: 'getImages.php?index=' + index,
type: "GET",
success: function(data) {
var result = $.parseJSON(data);
if (result.success) {
// Set your image src with the new path.
// Use result.image_data.src etc...
}
}
});
});
The PHP would be relatively simple too, a structure similar to this:
<?php
$return = array('success' => false, 'image_data' => array());
if (isset($_GET['index']) && is_numeric($_GET['index')) {
// Fetch your image
$return = array(
'success' => true,
'image_data' => array(
'src' => $src,
'title' => $title,
'index' => $index
)
);
}
echo json_encode($return);
?>
** Another note **
As stated by kgb you should resize these on upload, however, they may not be user submitted so you can also check if the thumbs exist on output and generate any as required. Certainly don't generate them for every view though.
You should resize images on upload, not on output. Store both the original and the resized images, show small images in the list and full size when user wants it...
A sample code from imagecopyresampled() docs:
// Get new dimensions
list($width, $height) = getimagesize($filename);
$widthNew = 320; // You decide
$heightNew = 240; // You decide
// Resample
$imageNew = imagecreatetruecolor($widthNew, $heightNew);
$imageOld = imagecreatefromjpeg($filename);
imagecopyresampled($imageNew, $imageOld, 0, 0, 0, 0, $widthNew, $heightNew, $width, $height);
// Output
imagejpeg($imageNew, $newFilename, 100);
This example expects gd extension to be included with php. Imagick extension mentioned by Martin is more powerful and provides nicer interface, but is rarely included on web hostings.
Also googled this for you: http://www.9lessons.info/2009/03/upload-and-resize-image-with-php.html
Related
I need to create PDF's thumbnail every time it gets loaded via POST method.
Once I upload the file inside Controller, it runs getThumb function that uses Imagick to create thumbnail. The problem is that everytime I do that, this request breaks and shows this error - The "/tmp/phpY14gRo" file does not exist or is not readable..
Imagick is properly installed. I use php-7.2-apache docker image.
But if I run shell_excec script that does absolutely the same thing, it works! That eliminates all suspicions of the wrong dependency installation
Here's the function from my controller:
public function createThumb($source, $target, $size = 256, $page = 1)
{
if (file_exists($source) && !is_dir($source)): // source path must be available and not be a directory
if (mime_content_type($source) != 'application/pdf'):
return FALSE; // source is not a pdf file returns a failure
endif;
$sepa = '/'; // using '/' as file separation for nfs on linux.
$target = dirname($source) . $sepa . $target;
$size = intval($size); // only use as integer, default is 256
$page = intval($page); // only use as integer, default is 1
$page--; // default page 1, must be treated as 0 hereafter
if ($page < 0) {
$page = 0;
} // we cannot have negative values
//It breaks exactly right here
$img = new Imagick($source . "[$page]"); // [0] = first page, [1] = second page
$imH = $img->getImageHeight();
$imW = $img->getImageWidth();
if ($imH == 0) {
$imH = 1;
} // if the pdf page has no height use 1 instead
if ($imW == 0) {
$imW = 1;
} // if the pdf page has no width use 1 instead
$sizR = round($size * (min($imW, $imH) / max($imW, $imH))); // relative pixels of the shorter side
$img->setImageColorspace(255); // prevent image colors from inverting
$img->setImageBackgroundColor('white'); // set background color and flatten
$img = $img->flattenImages(); // prevents black zones on transparency in pdf
$img->setimageformat('jpeg');
if ($imH == $imW) {
$img->thumbnailimage($size, $size);
} // square page
if ($imH < $imW) {
$img->thumbnailimage($size, $sizR);
} // landscape page orientation
if ($imH > $imW) {
$img->thumbnailimage($sizR, $size);
} // portrait page orientation
if (!is_dir(dirname($target))) {
mkdir(dirname($target), 0777, true);
} // if not there make target directory
$img->writeimage($target);
$img->clear();
$img->destroy();
if (file_exists($target)) {
return $target;
} // return the path to the new file for further processing
endif;
return FALSE; // the source file was not available, or Imagick didn't create a file, so returns a failure
}
I thought that it was permission problems but found out that it's not.
Update:
If I initialize Imagick without parameters it won't throw errors and thus won't create thumbnail as it doesn't get file path. So, whenever I add file path and PHP starts searching for that file, and the error occurs. Inside the log, I noticed that the InvalidArgumentException exception was thrown by a Symfony framework.
Here's an image of the error:
After debugging I found out that Imagick was not imported into the project.
So, I just added use Imagick at the top of my Controller.
In my case i call $validator->fails() two times.
In my case, the first call $validator->fails() in my Controller action, after checking deleted the file. The second call could not find this file.
I'm using Intervention in a laravel app (as everyone does) and have come across an issue where black borders are being applied around an image when cropped, like so:
Seems odd that it's preserving the transparency of the image file, and then filling the rest of the image with black.
My method for cropping and saving these images is as follows:
/**
* Accept parameter array (
'_token' => 'E1seBDvsEBj1aNpLmenIKkAoNSKct878tqnIwOQO',
'x' => 55,
'y' => '30',
'width' => '200',
'height' => '200',
'filename' => '1_somerandomhash.jpg',
)
*
* Move the given filename from TMP_ORG_LOGOS to ORGANIZATION_LOGOS_DIRECTORY, apply
* cropped dimensions, rename to organization slug name plus small random hash, return
* true or false
*
* #param array $params
* #return bool
*/
public function saveLogo(int $userId, array $params) : bool {
try{
$org = $this->userService->getUserDefaultOrg($userId);
$newImageName = $org->slug . '-' . uniqid() . '.png';
Image::make(getenv('TMP_ORG_LOGOS') . $params['filename'])
->crop(round($params['width']), round($params['height']),
round($params['x']), round($params['y']))
->save(getenv('ORGANIZATION_LOGOS_DIRECTORY') . $newImageName, 100);
$org->logo = $newImageName;
$org->save();
return true;
} catch (\Exception $e){
return false;
}
}
Has anyone run across this before? Is there a way within intervention to make these black borders transparent?
EDIT
I should also mention that intervention is using php's default GD library for image manipulation.
Was able to resolve this by creating a separate image using intervention's canvas() method. I then used trim() on the cropped image to remove the surrounding borders, and inserted that image into the center of the new canvas image. A little convoluted, and slow (3-4 seconds on the server) but it solves the problem. Still open to better solutions (if any exist).
public function saveLogo(int $userId, array $params) : bool {
try{
$org = $this->userService->getUserDefaultOrg($userId);
$newImageName = $org->slug . '-' . uniqid() . '.png';
$cropped = Image::make(getenv('TMP_ORG_LOGOS') . $params['filename'])
->crop(round($params['width']), round($params['height']),
round($params['x']), round($params['y']))
->encode('png', 100)->trim();
$canvas = \Image::canvas(round($params['width']), round($params['height']));
$canvas->insert($cropped, 'center');
$canvas->save(getenv('ORGANIZATION_LOGOS_DIRECTORY') . $newImageName, 100);
$org->logo = $newImageName;
$org->save();
return true;
} catch (\Exception $e){
return false;
}
}
#Importing modules opencv + numpy
import cv2
import numpy as np
#Reading an image (you can use PNG or JPG)
img = cv2.imread('Robo.jpg')
## 0.5 means 50% of image to be scaling
img = cv2.resize(img,None,fx=0.5,fy=0.5)
# black
img1 = np.zeros((600,600,3))
#Getting the bigger side of the image
s = max(img1.shape[0:2])
#Creating a dark square with NUMPY
f = np.zeros((s,s,3),np.uint8)
#Getting the centering position
ax,ay = (s - img.shape[1])//2,(s - img.shape[0])//2
#Pasting the 'image' in a centering position
f[ay:img.shape[0]+ay,ax:ax+img.shape[1]] = img
#Showing results (just in case)
cv2.imshow("IMG",f)
cv2.imshow("IMG2",img)
#A pause, waiting for any press in keyboard
cv2.waitKey(0)
#Saving the image
# cv2.imwrite("img2square.png",f)
cv2.destroyAllWindows()
I'm using the PHPPowerPoint lib to generate some powerpoint files. The problem is that the images that are coming from the server are too big, and are breaking the limits of the slide.
Here is some code that I'm using for the images:
if(file_exists($dir.$image)){
// Add logo
$shape = $slide->createDrawingShape();
$shape->setName('PHPPowerPoint logo');
$shape->setDescription('PHPPowerPoint logo');
$shape->setPath($dir.$image);
$shape->setWidth(310);
$shape->setHeight(608);
$shape->setOffsetX(330);
$shape->setOffsetY(70);
//$shape->setOffsetY(720 - 10 - 40);
}
Notice that Im already setting the width and height, but the image is not respecting those configurations. Is there anything that I can do to make the images respect the size that I need or get a responsive behavior?
Edit:
This the code for the function createTemplateSlide:
function createTemplatedSlide(PHPPowerPoint $objPHPPowerPoint, $dir, $image, $razao, $nome, $data, $contador)
{
// Create slide
$slide = $objPHPPowerPoint->createSlide();
if(file_exists($dir.$image)){
// echo("$contador) o arquivo: '".$dir.$image."' existe <br>");
// Add logo
$shape = $slide->createDrawingShape();
$shape->setName('PHPPowerPoint logo');
$shape->setDescription('PHPPowerPoint logo');
$shape->setPath($dir.$image);
$shape->setWidth(310);
$shape->setHeight(608);
$shape->setOffsetX(330);
$shape->setOffsetY(70);
//$shape->setOffsetY(720 - 10 - 40);
}
// Create a shape (text)
// echo date('H:i:s') . " Create a shape (rich text)<br>";
$shape = $slide->createRichTextShape();
$shape->setHeight(60);
$shape->setWidth(960);
$shape->setOffsetX(0);
$shape->setOffsetY(20);
$shape->getAlignment()->setHorizontal( PHPPowerPoint_Style_Alignment::HORIZONTAL_CENTER );
$textRun = $shape->createTextRun($razao." ".$data);
$textRun->getFont()->setBold(true);
$textRun->getFont()->setSize(16);
$textRun->getFont()->setColor( new PHPPowerPoint_Style_Color( '00000000' ) );
for ($i=0; $i <23 ; $i++) {
$shape->createBreak();
}
$textRun = $shape->createTextRun(utf8_encode($nome));
$textRun->getFont()->setBold(true);
$textRun->getFont()->setSize(16);
$textRun->getFont()->setColor( new PHPPowerPoint_Style_Color( '00000000' ) );
// Return slide
return $slide;
}
Following the suggestion given by #MadeInDreams, I found this topic:
Resize image in PHP
I used the solution there and the function imagejpeg to copy the new generated image to some folder of my project.
I want to rotate an uploaded and retrieved image from one location. Yes i am almost done. But the problem is, due to header("content-type: image/jpeg") the page redirected to another/or image format. I want to display it in same page as original image in. Here my code..
$imgnames="upload/".$_SESSION["img"];
header("content-type: image/jpeg");
$source=imagecreatefromjpeg($imgnames);
$rotate=imagerotate($source,$degree,0);
imagejpeg($rotate);
i also did with css property.
echo "<img src='$imgnames' style='image-orientation:".$degree."deg;' />";
But anyway my task is to done only with php. Please guide me, or give any reference you have
thanks advance.
<?php
// Okay, so in your upload page
$imgName = "upload/".$_SESSION["img"];
$source=imagecreatefromjpeg($imgName);
$rotate=imagerotate($source, $degree,0);
// you generate a PHP uniqid,
$uniqid = uniqid();
// and use it to store the image
$rotImage = "upload/".$uniqid.".jpg";
// using imagejpeg to save to a file;
imagejpeg($rotate, $rotImage, $quality = 75);
// then just output a html containing ` <img src="UniqueId.000.jpg" />`
// and another img tag with the other file.
print <<<IMAGES
<img src="$imgName" />
<img src="$rotName" />
IMAGES;
// The browser will do the rest.
?>
UPDATE
Actually, while uniqid() usually works, we want to use uniqid() to create a file. That's a specialized usage for which there exists a better function, tempnam().
Yet, tempnam() does not allow a custom extension to be specified, and many browsers would balk at downloading a JPEG file called "foo" instead of "foo.jpg".
To be more sure that there will not be two identical unique names we can use
$uniqid = uniqid('', true);
adding the "true" parameter to have a longer name with more entropy.
Otherwise we need a more flexible function that will check if a unique name already exists and, if so, generate another: instead of
$uniqid = uniqid();
$rotImage = "upload/".$uniqid.".jpg";
we use
$rotImage = uniqueFile("upload/*.jpg");
where uniqueFile() is
function uniqueFile($template, $more = false) {
for ($retries = 0; $retries < 3; $retries++) {
$testfile = preg_replace_callback(
'#\\*#', // replace asterisks
function() use($more) {
return uniqid('', $more); // with unique strings
},
$template // throughout the template
);
if (file_exists($testfile)) {
continue;
}
// We don't want to return a filename if it has few chances of being usable
if (!is_writeable($dir = dirname($testfile))) {
trigger_error("Cannot create unique files in {$dir}", E_USER_ERROR);
}
return $testfile;
}
// If it doesn't work after three retries, something is seriously broken.
trigger_error("Cannot create unique file {$template}", E_USER_ERROR);
}
You need to generate the image separately - something like <img src="path/to/image.php?id=123">. Trying to use it as a variable like that isn't going to work.
How can I make these images load faster? I have a loop that displays a profiles pictures and the photos take 1 to 2.5 seconds to load. Not one after another but pretty much all at once. I tried re-sizing with PHP but that didn't really change anything. I am not sure how I can pre-load these images with such a loop. What can I do to increase load performance?
PHP
$query = "SELECT `photoid` FROM `site`.`photos` WHERE `profileid`='$profileid'";
try{
$getphotos = $connect->prepare($query);
$getphotos->execute();
while ($array = $getphotos->fetch(PDO::FETCH_ASSOC)){
echo '<div id="photo"><img src="photoprocess.php?photo='.$array['photoid'].'"></div>';
}
} catch (PDOException $e) {
echo $e->getMessage();
}
CSS
#photo img {
max-width:100%;
max-height:100%;
}
photoprocess.php
$photoid = $_GET['photo'];
$query = "SELECT `ext` FROM `site`.`photos` WHERE `photoid`='$photoid'";
try{
$getphotos = $connect->prepare($query);
$getphotos->execute();
$array = $getphotos->fetch(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
echo $e->getMessage();
}
$ext = $array['ext'];
$image = imagecreatefromjpeg('userphotos/'.$photoid.''.$ext.'');
$imagearray = imagejpeg($image, null);
header('Content-type: image/jpeg');
echo $imagearray;
I also have extension checks as "if statements" but those can't be slowing it down this much.
This part
$image = imagecreatefromjpeg('userphotos/'.$photoid.''.$ext.'');
$imagearray = imagejpeg($image, null);
shouldn't be necessary* and is going to be heavy on the server. You're loading (decoding) and saving (re-encoding) the image for no apparent reason.
Use something like fpasshtru():
$name = 'userphotos/'.$photoid.''.$ext.'';
$fp = fopen($name, 'rb');
header('Content-type: image/jpeg');
fpassthru($fp);
Or just link directly to the image. Unless you do some security checks or something, or the images are stored outside the web root, there is no need to go through PHP at all here.
* = unless you have a very specific use case like removing EXIF data from the stored images. In which case you should use some form of caching.
Currently, you are loading image data from disk into an image buffer, which is validated by PHP. After that, you re-encode the image data to a jpg image buffer again and output it.
This is useless. You can just load an thruput the file (read about fpassthru). This is also much more memory efficient, since the image doesn't need to be entrely loaded in memory entirely at once.
That will be way, way faster, but it can be faster still, because I think you can use just .htaccess to redirect an url with an image id to the actual image. You don't even need PHP for that.