Screenshot Webpage with html2canvas and Save the Image to Laravel Backend

https://postsrc.com/storage/E66UDCZqY5q68i4ErmhUYmgg18qj3r7Pkk2hO495.jpg

In this short post, you will learn how to implement/take a screenshot of a webpage using

html2canvas library

. The screenshot will then be sent back to the Laravel as the backend using Axios HTTP client. The implementation steps are very simple so let’s get started.

Html2canvas Homepage

Step 1: Install html2canvas

To install the

html2canvas

library you can either use npm or yarn.

npm install --save html2canvas

yarn add html2canvas

For an alternative, if you prefer the CDN version then just reference the script at the end of your body tag.

<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>

Step 2: Import html2canvas to your project

To import the library to your project you make use of JavaScript “import” module. Do note that if you are not using a build library, you can use the “require” keyword and reference it to the windows object.

import html2canvas from 'html2canvas';
window.html2canvas = html2canvas;

The “require” keywords are as follows.

window.html2canvas = require('html2canvas');

Step 3: Take Screenshot with html2canvas

To take a screenshot with this library you can call the function directly from within your page script section. The code below will take a screenshot of the “document.body” and then append it to the body to show a preview of the page being screenshotted.

<script>
    html2canvas(document.body).then(function(canvas) {
        document.body.appendChild(canvas);
    });
</script>

If you want to make use of html2canvas to take a screenshot of a “div” tag or an “iframe” tag, you can “query select” the tag and pass it into the html2canvas function.

let specialDiv = document.getElementById('special-div'); // getting special div
let someIframe = document.querySelector('.some-iframe'); // getting some iframe

And when you have the reference to the element, you can just pass in and call the “then” method.

html2canvas(specialDiv).then(function(canvas) {
    document.body.appendChild(canvas);
});

Step 4: Save the screenshot as JPEG or PNG

To save the screenshot as a “jpeg” or “png” format, you can pass the canvas object to any of your backends by sending an ajax like below. In this case we’ll be using the Axios HTTP library.
If you have not install axios HTTP library, then do run the command below.

npm install axios
yarn install axios

Do note that the image will be passed as a “FormData” object and the Axios have a “multiplart/form-data” set as the headers. For this example, we’ll just console log the message that will be retrieved from the backend. In the normal scenario, you can provide a notification or some sort of alert to notify the user.

let specialDiv = document.getElementById('special-div'); // getting special div

html2canvas(specialDiv)
    .then(canvas => {
        let data = new FormData();
        data.set('image', canvas.toDataURL("image/jpeg", 1));
    
        axios.post('/save-screenshot', data, {
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        })
        .then((data) => {
            console.log('message: ', data.data.message);
        })
        .catch(error => {
            console.log('error: ', error);
        })
    });

Step 5: Setup the backend Logic

For this example, we’ll be using the Laravel framework as the backend. The backend logic should load the image as a stream and then save the image to the disk using the “Storage” facade. Do note that the code below only shows how the image is saved but the filename itself is returned to the client/front-end (possibly to show the user that the image is already inside the storage).

Route::post('/save-screenshot', function (Request $request) {
    /* generate the image stream */
    $imageStream = Image::make($request->image) /* base64_decode */
        ->stream('webp', 100);

    /* create the image path */
    $imagePath = '/img/image-name.png';

    /* store image to disk */
    Storage::disk('public')
        ->put($imagePath, $imageStream, 'public');

    return response()->json([
        'message' => 'The image has been successfully saved',
        'image_path' => $imagePath
    ]);
});

Optional: Store Filename to DB

To store the file name into the database you can directly call the “Laravel Model” or the “DB” facade itself. For example, if this screenshot is for an article, you can write your code like below.

Article::first()->update(['poster' => $imagePath]);

Laravel News Links

Flask vs Django: Comparing the Two Most Popular Python Web Frameworks

https://blog.finxter.com/wp-content/uploads/2021/08/image-33.png

When it comes to developing web applications in Python there are lots of frameworks. Some examples are Pyramid, Web2Py, Bottle or CherryPy, among others. However, the two most popular ones are Flask and Django.

We can confirm this fact by having a look at the most starred Python libraries in GitHub:

As we will see in this post, both of these frameworks follow very different design principles. Thus, we can not conclude that one is superior to the other. To choose the one that is best for you comes down to which type of application you want to build. In this article we will deep in the advantages and disadvantages of both of these frameworks. Therefore, you can make an informed decision on which one better fits your needs.

What is Flask?

Flask is a microframework conceived to develop web applications in Python. It started in 2010 as an April Fools Day Joke. The key concept in Flask is the word “micro” that refers to the fact that its core is simple but extensible. Because of that it can be learned fast and has a good learning curve. For instance, the Flask hello world app can be written in just five lines of code.

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

And to initialize the server you must type the following command in the terminal, which runs the app by default on the URL http://127.0.0.1:5000.

$ FLASK_APP=hello.py flask run

Flask Advantages and Drawbacks

Flask has been designed to start web development quickly and easily. This makes it ideal for building prototype applications. The word that best defines it is “minimalism”, as all that Flask includes are four main components: a template engine (named Jinja2), URL routing, error handling and a debugger. That means that a Flask application is lightweight. In turn, as it does not have to run a lot of code it is also a little bit faster than Django.

But Flask’s minimalism does not mean that you can’t build great web applications with it. Instead Flask is flexible, like a Lego construction set. All the functionalities expected from a web application like an Object-Relational mapping (ORM), security, authentication, data validation, etc. are delegated to third-party libraries that you must choose on. Moreover, there are extensions like Flask-Security that bundle together security libraries that people typically use with Flask.

However, Flask’s flexibility comes with many drawbacks. First, two Flask applications can follow very different patterns, which means that it can be hard for a developer to switch from one to another. Second, as Flask’s extensions are developed by different teams, a Flask app is more prone to security risks and requires more time to keep it updated. Last, because of the use of different libraries the documentation that you can find is very spread over the internet.

What is Django?

Django is a “full stack” web framework that can tackle scalable and high quality web applications. It was publicly released in 2005, but it started earlier as a Python CMS at the Lawrence Journal-World newspaper. In contrast with Flask, Django forces you to do things their own way. Thus, it has a steeper learning curve and can be more intimidating to beginners.

A Django application involves at least the use of three files, and four when a data model is involved. To create a hello world application with Django is as follows.

First, we create a Django project in a folder called config.

$ django-admin startproject config .

We then create an app named pages by typing the following command. This creates a pages folder, located at the same level of the config folder, containing different files. 

$ python manage.py startapp pages

In the next step we update the file pages/views.py to make it look as follows:

from django.http import HttpResponse

def helloPageView(request):
    return HttpResponse("Hello, World!")

Then we update the file pages/urls.py with the following code:

from django.urls import path
from .views import helloPageView

urlpatterns = [
    path('', helloPageView, name='home')
]

The last file to update is the config/urls.py file:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('pages.urls'))
]

Finally, we can run our Django hello world application with the following command, which starts the server on the URL http://127.0.0.1:8000.

$ python manage.py runserver

As we have seen in this example, the hello world Django application involves much more steps than the same application with Flask.

Django Advantages and Drawbacks

Django follows the principle of “Don’t Repeat Yourself” and includes all the components that are needed to build a web application. It has out of the box templating, forms, routing, authentication, database administration among other features. It requires less decisions to be made by you. Because of that, an experienced Python developer who wants to dig into web development can do it in a relatively short amount of time. This also means that Django projects follow a pattern making them very similar one to another.

When you use Django you are forced to use its ORM, which assumes that you are going to use a relational database. It officially supports databases like MariaDB, MySQL or SQLite among others. With Django’s ORM you can do almost every operation that an ordinary web app needs. In addition to that, it allows you to write your own SQL queries. The negative side of it is that you can forget about using a NoSQL database like MongoDB with Django.

In terms of security, Django is very reliable as it incorporates features like protection against SQL injection and cross site scripting (XSS) attacks, the possibility to enable HTTPS protection, or JSON web tokens (through external libraries). So it is very suitable for applications that require their users to authenticate or that involve monetary transactions. 

Another great aspect of Django is its community. As a popular web framework, Django has a very big community with lots of documentation available online. For instance it has more than 200k tagged questions on Stack Overflow. 

But the Django way of doing things, handling everything for you, can also be a drawback as it produces monolithic servers that act as a single unit. This means that it is not possible to develop a microservice architecture with Django.

Differences Side by Side

As a summary these are the main differences between Flask and Django.

Flask Django
Type of framework Microframework with lightweight code Full stack, provides everything you need
Learning Easy to learn Steeper learning curve
Project size For smaller and less complicated projects For larger projects
Project layout Arbitrary Follows a pattern
Templates Relies on Jinja2 engine Built-in engine
Databases Lack of ORM but can work with many different databases through libraries Own ORM for relational databases like MariaBD, MySQL, SQLite, etc.
Admin Can be done with the Flask-Admin extension Built-in panel for admin tasks
Security Depends on the security of external libraries Built-in security features
API Supports API Does not support API
Flexibility Very flexible, allowing developers to add their own libraries Low, developers must follow Django’s rules
Performance Slightly better Sufficient for any application
Table: Flask vs Django

What in Terms of Freelance Projects?

As you might know, Finxter.com promotes remote work by helping people to start their careers as Python freelance developers. Two well established websites where freelancers can apply to projects posted by companies are Freelancer.com and Upwork.

At the time of writing, we can find at Freelancer.com 82 projects when we search for the keyword Django and 14 projects when we search for Flask.

Figure: Freelancer.com has 82 Django gigs
Figure: Freelancer.com has 14 Flask gigs

If we look at Upwork the number of projects are higher for both frameworks. In particular, we find 717 Django projects and 336 Flask projects.

Figure: Upwork has 717 Django gigs
Figure: Upwork has 336 Flask gigs

We see that Upwork has a substantially higher number of projects to apply in terms of Python web development. We also see a higher number of Django projects on both websites .

However, the above numbers are snapshots and can vary depending on the time we take them. But if we look at time series like worldwide searches of Flask and Django in the last five years, provided by Google trends, we can confirm that there is a higher interest in Django.

Figure: Django is still more popular than Flask.

When to Use One or the Other?

As we have seen in this post Flask and Django are two sides of the same coin. Now that we know all that they offer, this is my recommendation on which cases are best to use one or the other.

Better to use Flask if:

  • You are new to Python.
  • You just want to build a simple prototype application.
  • You want to know how your application works and operates internally.
  • Your application is based on NoSQL.
  • You plan to build a microservice architecture.
  • You want to build simple web apps like REST APIs, IoT apps or small websites with static content.

But you better use Django if:

  • You are already experienced in Python.
  • Your application will use a SQL database.
  • Your application will have users that need to be authenticated.
  • You want an application with user administration panels.
  • Your application will serve dynamic content.

The post Flask vs Django: Comparing the Two Most Popular Python Web Frameworks first appeared on Finxter.Finxter

kdion4891/laravel-livewire-tables

https://packalyst.com/assets/img/logo.png

Laravel Livewire Tables

Laravel Livewire Tables

A dynamic, responsive Laravel Livewire table component with searching, sorting, checkboxes, and pagination.

Installation

Make sure you’ve installed Laravel Livewire.

Installing this package via composer:

composer require kdion4891/laravel-livewire-tables

This package was designed to work well with Laravel frontend scaffolding.

If you’re just doing scaffolding now, you’ll need to add the Livewire @livewireScripts and @livewireStyles blade directives to your resources/views/layouts/app.blade.php file:

<!-- Styles -->
<link href="" rel="stylesheet">
@livewireStyles

...

<!-- Scripts -->
<script src=""></script>
@livewireScripts

This package also uses Font Awesome for icons. If you don’t already have it installed, it’s as simple as:

npm install @fortawesome/fontawesome-free

Then add the following line to resources/sass/app.scss:

@import '~@fortawesome/fontawesome-free/css/all.min.css';

Now all that’s left is to compile the assets:

npm install && npm run dev

Making Table Components

Using the make command:

php artisan make:table UserTable --model=User

This creates your new table component in the app/Http/Livewire folder.

After making a component, you may want to edit the query and column methods:

class UserTable extends TableComponent
{
    public function query()
    {
        return User::query();
    }

    public function columns()
    {
        return [
            Column::make('ID')->searchable()->sortable(),
            Column::make('Created At')->searchable()->sortable(),
            Column::make('Updated At')->searchable()->sortable(),
        ];
    }
}

You don’t have to use the render() method in your table component or worry about a component view, because the package handles that automatically.

Using Table Components

You use table components in views just like any other Livewire component:

@livewire('user-table')

Now all you have to do is update your table component class!

Table Component Properties

$table_class

Sets the CSS class names to use on the <table>. Defaults to table-hover.

Example:

public $table_class = 'table-hover table-striped';

Or, via .env to apply globally:

TABLE_CLASS="table-hover table-striped"

$thead_class

Sets the CSS class names to use on the <thead>. Defaults to thead-light.

Example:

public $thead_class = 'thead-dark';

Or, via .env to apply globally:

TABLE_THEAD_CLASS="thead-dark"

$header_view

Sets a custom view to use for the table header (displayed next to the search).

Example:

public $header_view = 'users.table-header';

Protip: any view you reference in your table component can use Livewire actions, triggers, etc!


<button class="btn btn-primary" wire:click="createUser">Create User</button>

$footer_view

Sets a custom view to use for the table footer (displayed next to the pagination).

Example:

public $footer_view = 'users.table-footer';

$checkbox

Boolean for if the table should use checkboxes or not. Defaults to true.

Example:

public $checkbox = false;

Or, via .env to apply globally:

TABLE_CHECKBOX=false

$checkbox_side

The side of the table to place checkboxes on. Accepts left or right. Defaults to right.

Example:

public $checkbox_side = 'left';

Or, via .env to apply globally:

TABLE_CHECKBOX_SIDE="left"

$checkbox_attribute

Sets the attribute name to use for $checkbox_values. Defaults to id. I recommend keeping this as id.

Example:

public $checkbox_attribute = 'id';

$checkbox_values

Contains an array of checked values. For example, if $checkbox_attribute is set to id, this will contain an array of checked model ids.
Then you can use those ids to do whatever you want in your component. For example, a deleteChecked button inside a custom $header_view.

Example deleteChecked button:

<button class="btn btn-danger" onclick="confirm('Are you sure?') || event.stopImmediatePropagation();" wire:click="deleteChecked">
    Delete Checked
</button>

Example deleteChecked method:

public function deleteChecked()
{
    Car::whereIn('id', $this->checkbox_values)->delete();
}

$sort_attribute

Sets the default attribute to sort by. Defaults to id. This also works with counts and relationships.

Example:

public $sort_attribute = 'created_at';

Count example (if you added ->withCount('relations') to the query() method):

public $sort_attribute = 'relations_count';

Relationship example (if you added ->with('relation') to the query() method):

public $sort_attribute = 'relation.name';

Notice the use of the dot notation. You use this when declaring column relationship attributes as well.

$sort_direction

Sets the default direction to sort by. Accepts asc or desc. Defaults to desc.

Example:

public $sort_direction = 'asc';

$per_page

Sets the amount of results to display per page. Defaults to 15.

Example:

public $per_page = 25;

Or, via .env to apply globally:

TABLE_PER_PAGE=25

Table Component Methods

query()

This method returns an Eloquent model query to be used by the table.

Example:

public function query()
{
    return Car::with('brand')->withCount('accidents');
}

columns()

This method returns an array of Columns to use in the table.

Example:

public function columns()
{
    return [
        Column::make('ID')->searchable()->sortable(),
        Column::make('Brand Name', 'brand.name')->searchable()->sortable(),
        Column::make('Name')->searchable()->sortable(),
        Column::make('Color')->searchable()->sortable()->view('cars.table-color'),
        Column::make('Accidents', 'accidents_count')->sortable(),
        Column::make()->view('cars.table-actions'),
    ];
}

Declaring Columns is similar to declaring Laravel Nova fields. Jump to the column declaration section to learn more.

thClass($attribute)

This method is used to compute the <th> CSS class for the table header.

$attribute

The column attribute.

Example:

public function thClass($attribute)
{
    if ($attribute == 'name') return 'font-italic';
    if ($attribute == 'accidents_count') return 'text-right';
    if ($attribute == 'brand.name') return 'font-weight-bold';

    return null;
}

trClass($model)

This method is used to compute the <tr> CSS class for the table row.

$model

The model instance for the table row.

Example:

public function trClass($model)
{
    if ($model->name == 'Silverado') return 'table-secondary';
    if ($model->accidents_count > 8) return 'table-danger';
    if ($model->brand->name == 'Ford') return 'table-primary';

    return null;
}

tdClass($attribute, $value)

This method is used to compute the <td> CSS class for the table data.

$attribute

The column attribute.

$value

The column value.

Example:

public function tdClass($attribute, $value)
{
    if ($attribute == 'name' && $value == 'Silverado') return 'table-secondary';
    if ($attribute == 'accidents_count' && $value < 2) return 'table-success';
    if ($attribute == 'brand.name' && $value == 'Ford') return 'table-primary';

    return null;
}

mount()

This method sets the initial table properties. If you have to override it, be sure to call $this->setTableProperties().

Example:

public function mount()
{
    $this->setTableProperties();
    
    // my custom code
}

render()

This method renders the table component view. If you have to override it, be sure to return $this->tableView().

Example:

public function render()
{
    // my custom code
    
    return $this->tableView();
}

Table Column Declaration

The Column class is used to declare your table columns.

public function columns()
{
    return [
        Column::make('ID')->searchable()->sortable(),
        Column::make('Created At')->searchable()->sortable(),
        Column::make('Updated At')->searchable()->sortable(),
    ];
}

make($heading = null, $attribute = null)

$heading

The heading to use for the table column, e.g. Created At. Can be null for view-only columns.

$attribute

The attribute to use for the table column value. If null, it will use a snake cased $heading.

You can also specify _counts and relationship attributes with a dot notation.

For counts, let’s say I added withCount() to my query():

public function query()
{
    return Car::withCount('accidents');
}

Now I can create a column using this count like so:

Column::make('Accidents', 'accidents_count')->sortable(),

For relationships, let’s say I added with() to my query():

public function query()
{
    return Car::with('brand');
}

Now I can create a column using any of the relationship attributes like so:

Column::make('Brand ID', 'brand.id')->searchable()->sortable(),
Column::make('Brand Name', 'brand.name')->searchable()->sortable(),

searchable()

Sets the column to be searchable.

sortable()

Sets the column to be sortable.

sortUsing($callback)

Allows custom logic to be used for sorting. Your supplied callable will receive the following parameters:

  • $models: The current Eloquent query (\Illuminate\Database\Eloquent\Builder). You should apply your sort logic to this query, and return it.
  • $sort_attribute: The name of the column currently being sorted. If you used a nested relationship for sorting, it will be properly transformed to relationship_table.column_name format so the query will be scoped correctly.
  • $sort_direction: The direction sort direction requested, either asc, or desc.

Additionally, your callback will be passed through Laravel’s Container so you may inject any dependencies you need in your callback. Make sure your dependencies are listed before the parameters above.

Example:

Column::make('Paint Color')->searchable()->sortable()->sortUsing(function ($models, $sort_attribute, $sort_direction) {
    return $models->orderByRaw('?->\'$.color_code\' ?', [$sort_attribute, $sort_direction]);
});

This will sort the paint_color column using the JSON value color_code.

SQL Injection warning: Make sure if you are using any of Eloquent’s *Raw methods, you always use the bindings feature.

view($view)

Sets a custom view to use for the column.

Example:

Column::make('Paint Color')->searchable()->sortable()->view('cars.table-paint-color'),

Notice how the column is still searchable() and sortable(), because the Car model contains a paint_color attribute!

If you’re making a view-only column (for action buttons, etc), just don’t make it searchable or sortable:

Column::make()->view('cars.table-actions'),

Custom column views are passed $model and $column objects, as well as variables passed from the table component.

For the Paint Color example, we can use the paint_color attribute from the model like so:


<i class="fa fa-circle" style="color: ;"></i>

For the action buttons example, we can use the id attribute from the model like so:


<button class="btn btn-primary" wire:click="showCar()">Show</button>
<button class="btn btn-primary" wire:click="editCar()">Edit</button>

Using a custom view for a relationship column? No problem:



Publishing Files

Publishing files is optional.

Publishing the table view files:

php artisan vendor:publish --tag=table-views

Publishing the config file:

php artisan vendor:publish --tag=table-config

Packalyst :: Latest Packages

‘Whole Mouth’ Toothbrushes Are a Thing Now

Unnervingly futuristic, these bulky, high-tech toothbrushes promise to scrub your choppers thoroughly in 20 seconds. WSJ: Dentists like Dr. Lana Rozenberg are overly familiar with two eternal fibs: that their clients floss regularly, and that they brush their teeth for at least two minutes twice a day. "Most people don’t brush their teeth for two minutes," said the Manhattan-based industry veteran. "Thirty seconds is more like it," or under a second for each of their 32 teeth. But what if, in those 30 seconds, a device could reach the front, back and sides of every tooth at once? That’s the proposition of new "whole mouth" toothbrushes, which rely on vibration and a preponderance of bristles packed inside a structure resembling a mouthguard to deliver an up-to-snuff scrubbing in as little as 20 seconds — 10 each for top and bottom sets of teeth. "It helps make things way faster, way easier and feels a little more guaranteed because you actually feel it on each one of your teeth," said Kristopher Paul, a medical-transportation driver in St. Petersburg, Fla., who has bit down on a 360 Sonic Brush Pro ($70) each morning for the past year. Mr. Paul, 36, also likes the tool’s 15-minute whitening mode, which combines a blue LED light and whitening gel to fade bothersome coffee stains.


Read more of this story at Slashdot.

Slashdot