I'd like to be able to return an image in Black&white in a controller, so I can use it in a template. On this page I found that the GD class has a greyscale method. Unfortunately I don't understand the GD class and how I can use it. I tried doing
$final = $image->getFormattedImage('greyscale',36,36,36);
But that didn't work. It does return an image object with a new URL but the image does not exist.
Can anyone explain to me how to make an imageobject into a greyscale image in a Silverstripe page Controller?
Well I had a go myself and this is what I came up with:
_config.php
Object::add_extension('Image', 'Greyscaled');
UPDATE: as of SilverStripe 3.1, you should use the config system instead of _config.php. Put the following in your mysite/_config/config.yml (Don't forget to ?flush=1 to reload the config cache after adding it):
Image:
extensions:
- 'Greyscaled'
Greyscaled.php
<?php
class Greyscaled extends DataExtension {
//This allows the template to pick up "GreyscaleImage" property, it requests a copy of the image from the cache or if it doesn't exist, generates a new one
public function GreyscaleImage($RGB = '76 147 29') {
return $this->owner->getFormattedImage('GreyscaleImage', $RGB);
}
//This is called internally by "generateFormattedImage" when the item is not already cached
public function generateGreyscaleImage(GD $gd, $RGB) {
$Vars = explode(' ', $RGB);
return $gd->greyscale($Vars[0], $Vars[1], $Vars[2]);
}
}
UPDATE2: With newer Versions of 3.1 ?? you can pass in more than 2 parameters and GD has been renamed to Image_Backend. This way you do not have spaces between the RGB-values in the image-name. Be aware $gd->greyscale needs a lot of juice - so you probable better downsize first and GreyscaleImage afterwards.
UPDATE3: Since this answer got some votes recently I assume people still using it, but I think in 2017 CSS filters are in many cases a better choice. Prefixed you'll have close to 90% coverage.
css-filters on caniuse.com
<?php
class Greyscaled extends DataExtension {
public function GreyscaleImage($R = '76', $G = '147', $B = '29') {
return $this->owner->getFormattedImage('GreyscaleImage', $R, $G, $B);
}
public function generateGreyscaleImage(Image_Backend $gd, $R, $G, $B) {
return $gd->greyscale($R, $G, $B);
}
}
and in the template:
<img src="$Images.GreyscaleImage.CroppedImage(1000,400).URL" alt="$Images.Title" />
Silverstripe 3.1 Image API
There is a module for this. Sorry but it's not on packagist just yet.
https://github.com/NightJar/ssrigging-greyscaleimages
Related
I'm calling these 3 functions one after other in this exact order
public function setPrintFitToWidth()
{
$this->sheet->getPageSetup()->setFitToWidth(1);
}
public function setPrintArea($cell_area)
{
$this->sheet->getPageSetup()->setPrintArea($cell_area);
}
public function setPrintMargins($top, $right, $bottom, $left)
{
$this->sheet->getPageMargins()->setTop($top);
$this->sheet->getPageMargins()->setRight($right);
$this->sheet->getPageMargins()->setLeft($left);
$this->sheet->getPageMargins()->setBottom($bottom);
}
The problem is that, opening resulting Excel file, I've page margin set to 'custom' but, in fact, set to different values instead of margin I passed to my function. In fact I called with argument (1,0.5,0.5,1) but I got, in the same orders, 2, 0.8, 0.8, 2. It's really strange ...
Also: I cannot get working setFittoWidth(1); I expect to see adapted for all column in one page, but Excel tell me It's setup on adapt sheet on a page.
What am I doing wrong?
Resolved:
changed
public function setPrintFitToWidth()
{
$this->sheet->getPageSetup()->setFitToWidth(1);
}
to
public function setPrintFitToWidth()
{
$this->sheet->getPageSetup()->setFitToWidth(1);
$this->sheet->getPageSetup()->setFitToHeight(0);
}
About the margins: I tried with zero and margin are respected, so I concluded than PHPExcel unit are in someway 'scaled down'... So, after some 'try' and 'redo', I found the values that generate the correct magins
I have pagination with links [1, 2, 3, 4, 5, 6, 7, 8 ... 99, 100] and how can I change limit to display [1, 2, 3, ... 98, 99, 100] ? I have custom paginator class, but I can't find this limit to override in my new class.
By checking the classes I found that you have to override the presenter used by the Paginator.
Its done by calling render($presenter) your presenter must extend BootstrapThreePresenter If you wish to use bootstrap links and you just have to override the constructor and pass number of links you want on each side $this->window = UrlWindow::make($numberOfLinksEachSide)
These are just instructions you'll have to look by yourself, I'm sorry for not being able to provide complete code, I'm on phone.
Please let me know if this worked.
This is my solution to the same problems... In LengthAwarePaginator updated function links:
public function links($view = null, $data = [], $onEachSide = 3)
{
if(!$data){
$data = [];
}
$this->onEachSide = $onEachSide;
return $this->render($view, $data);
}
And in URLWindow function make:
public static function make(PaginatorContract $paginator)
{
return (new static($paginator))->get($paginator->onEachSide);
}
This removes the parameter $onEachSide from function make - which is never passed in anywhere - and allows it to be passed to function links as a parameter.
To use this you need to call this links method like this:
{{ $collection->links('view-to-use'|null, $dataArray|null, 2)}}
Where 2 is the number on each side.
You can do this easily by changing some core fields (although not recommended to change core files).
Find- vendor/laravel/framework/src/Illuminate/Pagination and go to UrlWindow. On this page find some parameters like- $onEachSide, $window. Change and play with these.
I finally got doxygen to work with php and PHPDoc styled comments (I'm removing '#package' with filter since it breaks up doxygen) though there's one thing I would love to have and are not able to figure out how.
In PHP I'm writing multiple property declaration in a class like this:
class Foo
{
private
/// the blue color
$blue,
/// the red color
$red,
/// the yellow color
$yellow;
public
/// the orange color
$orange,
/// black (no color)
$black;
public function bar() {}
}
If I'm now generating the docs, only the first property is shown as private Attribute while all other properties are simply referenced as Data Fields. So doxygen obviously doesn't parse the accesors of every property after the first one.
Is it possible to make this commentation style compatible to doxygen ?
P.S: I thought about applying a filter which converts it in doxygen-parsable code style. Though this would only be a fix I'm currently working on it.
I wrote this filter, that works for the example you provided. I think it should also work for more complex examples.
// Get the input
$source = file_get_contents($argv[1]);
$count = 0;
do {
$source = preg_replace('#(private|public|protected)(\s*[^$]*)(\$[^,;]+),#',
"$2 $1 $3;\n$1 ", $source, -1, $count);
} while($count > 0);
// Output
echo $source;
You can find this and other filters at my GitHub repository doxygen-php-filters.
hi i've got a gallery page. this gallery page has a gallery image object with an has_many relation.
private static $has_many = array(
'GalleryImages' => 'GalleryObject'
);
my gallery object has an image upload field. I want to set the upload folder to the title of the gallery page
i tried this with no result
$visual->setFolderName('Galerie/'.$this->Gallery()->Title);
and this (what i would prefer)
public function getGalleryTitle() {
$galleryTitle = $this->Gallery()->Title->First();
$uploadFolder = str_replace(' ', '-', $this->$galleryTitle);
return $uploadFolder;
}
$visual->setFolderName('Galerie/'.$this->$uploadFolder);
the second returns and error (undefined variable uploadFolder ?!) and my upload folder is now set to "Galerie/DataList"
can someone tell me how to convert the output of $uploadFolder so that i get back the title?
EDIT:
GalleryHolder: http://www.sspaste.com/paste/show/5267dea3579a6
GalleryPage: http://www.sspaste.com/paste/show/5267dee4c9752
GalleryObject: http://www.sspaste.com/paste/show/5267df0af1a65
you where almost there..
Here is your edited getGalleryTitle() function.
It is basically checking if the GalleryObject has a parent Gallery via $this->GalleryID. Since it is a has_one relation the column will be named GalleryID.
Then we get the Gallery object with $this->Gallery() and get it's title with $gallery->Title.
I've also replaced your str_replace with SilverStripe's URLSegmentFilter class. Which will removed spaces and other special characters non welcome in URL, a better solution.
public function getGalleryTitle()
{
if ( $this->GalleryID )
{
$gallery = $this->Gallery();
$filter = new URLSegmentFilter();
return $filter->filter( $gallery->Title );
}
else{
return 'default';
}
}
Then in the getCMSFields() function, when creating your UploadField we just call the getGalleryTitle() function that returns the string for the folder name.
$visual = new UploadField('Visual', _t('Dict.IMAGE', 'Image'));
$visual->setFolderName('Galerie/'.$this->getGalleryTitle());
A few notes..
$this references the current Object instance, so you can't use $this->$galleryTitle to access a variable you just created in your function, $galleryTitle by itself is enough.
You were calling $this->$uploadFolder in setFolderName, this doesn't work for the same reason, and also, using $uploadFolder by itself wouldn't work since this variable was created in the scope of another function. So we just call the function we defined on our Object with $this->getGalleryTitle() since it returns the value we want.
This should work fine, but keep in mind that if the Title of the Gallery changes at some point, the folder name will change too. So you might end up with images uploaded in many different folders for the same gallery... I personally wouldn't advise it, unless you implement some kind of "Title locking system" or some way to keep the "correct" or first "valid/acceptable" Gallery title in a separate object property that can't be edited and use this in the folder name.
I usually only use the ID in those case ($gallery->ID), as this will not change.
edit
Another version of getGalleryTitle() that should work even if the GalleryObject isn't saved yet.
public function getGalleryTitle()
{
$parentID = Session::get('CMSMain')['currentPage'];
if ( $parentID )
{
$gallery = Page::get()->byID( $parentID );
$filter = new URLSegmentFilter();
return $filter->filter( $gallery->Title );
}
else{
return 'default';
}
}
First, I check to see whether we're on the CMSSettingsPage or in a ModelAdmin page (Should you be using them). You want to get all the information about which class the controller is managing as it's data record. (If you have firebug, FB($this) in getCMSFields() on the related DataObject (DO) will show you the page managed under DataRecord)
Controller::curr()->currentPage() will get you the current page the DO is being managed on, and ->URLSegment will get the page url name, though you could use Title or MenuTitle also.
Here is an example which will set up a folder underneath assets/Headers to save images in. Running this on the HomePage (ie URL Segment 'home') will create and save objects into the folder /assets/Headers/home.
if (Controller::curr()->class == 'CMSSettingsController' || Controller::curr() instanceof Modeladmin) {
$uploadField->setFolderName('Headers');
}
else
{
$uploadField->setFolderName('Headers/' . Controller::curr()->currentPage()->URLSegment);
}
I'm wondering if there's a keep together function for TCPDF. I have one for FPDF, but I can't get it to work in TCPDF.
Here's how I see it working within the PDF generation code:
// ... PDF code/stuff
// while not kept together
// add PDF stuff that should be kept together
// .. more PDF code/stuff
I'm thinking the function would return false if the a new page was added, roll back and then do the while loop again.
I do have the following working, but I'd rather it was in a function/method of TCPDF so it was more reusable:
$pdf->startTransaction();
$block_page = $pdf->getPage();
$print_block = 2; // max 2 tries
while ($print_block > 0) {
// do PDF stuff
if ($pdf->getPage() == $block_page) {
$print_block = 0;
} else {
// rollback
$pdf = $pdf->rollbackTransaction();
$pdf->AddPage();
$block_page = $pdf->getPage();
-- $print_block;
}
}
It would also be cool if it didn't depend on the built in transaction functionality so transactions can be used within the loop, since things like writeHTML() use transactions.
I wanted similar functionality and settled on using transactions. This on TCPDF version 5.9.125.
I inherited my own PDF class from TCPDF and added my own method:
public function writeHTMLTogether($html, $ln=true, $fill=false, $reseth=false, $cell=false, $align='') {
$cp = $this->getPage();
$this->startTransaction();
$this->writeHTML($html, $ln, $fill, $reseth, $cell, $align);
if ($this->getPage() > $cp) {
$this->rollbackTransaction(true);//true is very important
$this->AddPage();
$this->writeHTML($html, $ln, $fill, $reseth, $cell, $align);
} else {
$this->commitTransaction();
}
}
Seemed to work fine. Without the true in the rollback it breaks horribly, as writeHTML seems to store lots of properties somewhere.
May not need to create a local variable for current page ($cp) as I think it's stored. But hey.
If you're inheriting to write your own Header and Footer functions anyway, not much extra work.