Jump to content


Photo

Cloudinary image management

cloudinary image management

  • Please log in to reply
2 replies to this topic

#1 Nico Wouterse

Nico Wouterse
  • Moderators
  • 255 posts
  • LocationAustralia

Posted 22 November 2015 - 04:43 PM

A while ago I got the request to make an image gallery.

Not the most challenging of tasks maybe, but after some discussion and thinking about it the list of requirements did become rather large.

 
What about having to provide an easy management system of uploaded images, making it fit for all mobile and desktop devices - not only screen sizes but also resolution, building an easy upload facility of images, include a one-step upload process using the device camera if there is one, automatic client-side re-sampling to reduce file size etc.
 
Fortunately there are a number of mature image management systems available, so not everything needs to be developed from scratch.
The choice for this project was to have a deeper look at Cloudinary (www.cloudinary.com).
 
Cloudinary provides image (and video) management for web developers which includes image upload services, cloud storage, administration management and especially image manipulation, transformation services and fast delivery.
And it offers all of this as a freemium service : free up to a (rather large) number of uploaded images, with a subscription mechanism for larger quantities.
 
Accessing uploaded images is as simple as 
 
//  AString := 'res/myimage01.png';   
  AString := 'http://res.cloudinary.com/your-account/image/upload/' +
             'w_' + inttostr(W3Image.Width) +
             ',h_' + inttostr(W3Image.Height) +
             ',dpr_' + GetDPR +
             ',c_fill/v1438317145/myimage01_abcdef.png';
 
    W3Image1.LoadFromURL(AString);
 
The good thing is that the image is on the fly server-side re-sized to the right dimensions (w_ and h_ parameters), that it fills this dimension (c_fill parameter) and that it fits the correct device pixel ratio, which covers anything from low-res to retina displays.
The GetDPR function is included at the end of this post.
 
 
To get the available images I used a small server-side php file to serve this content and make it available in array-format.
 
//  cloudinary.php :
  <?php
  header("Access-Control-Allow-Origin: *");
  $url_cloudinary = $_POST['url_cloudinary'];
  $arr = file_get_contents($url_cloudinary);
  echo $arr;
  ?>
 
The first header line is superfluous if this file is located on the same server location as our project.
The second line reads the Cloudinary account information as a parameter while the third and fourth line populate and serve the info of available images.
Obviously this approach has an upper limit in what the functions used (file_get_contents, echo) can handle but for a reasonable number of images this works fine.
 
The gallery-page has a scrollable panel and initialises as :
 
procedure TForm1.FormActivated;
begin
  inherited;
  If not assigned(FHttp) then begin
    FHttp := TW3HttpRequest.Create;
    ReadImages;
  end;
end;
 
procedure TForm1.ReadImages;
var
  cloudinaryurl: string;
begin                                                //retrieve list
 
  FHttp.OnDataReady := RetrieveImages;
 
  cloudinaryurl := 'https://123456789012345:abcdefghijklmnopqrstuvwxyz@api.cloudinary.com/v1_1/your-account/resources/image/upload/?max_results=500';
  FHttp.open("POST","http://..wherever../cloudinary.php");   //where the php file resides
  FHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
  FHttp.send('url_cloudinary=' + cloudinaryurl);
  FullScreenSpinner.Enter;
 
end;
 
This is actually a bad design.
The cloudinaryurl account parameter contains access and password information and should not be send from the client.
Better to hard-code it server-side in the php file rather than sending it as a parameter.
 
Once the image info is available the ondataready callback is invoked.
This procedure sets up the scroll-environment and populates it with all images as 70 x 70 thumbnails.
It also sets up a larger image at the end, which will be populated with a larger version of the thumbnail when pressed/clicked.
 
post-914-0-94508800-1448197507.png
procedure TForm1.RetrieveImages(Sender: TW3HttpRequest);
begin
//showmessage(sender.responsetext);                     //callback 'ondataready'
  cursor := JSON.parse(FHttp.ResponseText);
  MaxRows := cursor.resources.length;
  FullScreenSpinner.Leave;
 
  Panel1 := TW3Panel.Create(self);
  ScrollElement1 := TW3ScrollWindow.Create(Panel1);
  Panel1.SetBounds(0,20,ClientWidth, ClientHeight-40);
  ScrollElement1.SetBounds(0,0,panel1.width-40,panel1.height);
  dy := 5;
  dx := 25;
 
  For var i := 0 to MaxRows-1 do begin
    PopuLateScrollList(i);
  end;
 
  inc(dy,90);
  BigImage:=TW3Image.Create(ScrollElement1.Content);
 
  BigImage.SetBounds(trunc(Panel1.Width * 0.15),
                     dy+35,
                     trunc(Panel1.Width * 0.7),
                     trunc(Panel1.Width * 0.7));
  AString := 'http://res.cloudinary.com/your-account/image/upload/' +
             'w_' + inttostr(BigImage.Width) +
             ',h_' + inttostr(BigImage.Height) +
             ',c_pad/v' +
             cursor.resources[0].version + '/' +
             cursor.resources[0].public_id + '.' +
             cursor.resources[0].format;
  BigImage.LoadFromURL(AString);
 
  ScrollElement1.Content.Height:=dy + trunc(Panel1.Width * 0.7)+70; //Size content to all images
  ScrollElement1.ScrollAPI.Refresh; //Update IScroll
  scrollelement1.ScrollApi.Options.VerticalScrollbar := true;
  ScrollElement1.SetBounds(0,0,panel1.width,panel1.height);
end;
 
Procedure TForm1.PopulateScrollList(row:integer);
var
  mImage: TW3Image;
  mLabel: TW3Label;
Begin
  mImage := TW3Image.Create(ScrollElement1.Content);
  mImage.SetBounds(dx,dy,70,70);
  AString := 'http://res.cloudinary.com/your-account/image/upload/' +
             'w_70,h_70,c_thumb/v' +
             cursor.resources[row].version + '/' +
             cursor.resources[row].public_id + '.' +
             cursor.resources[row].format;
  mImage.LoadFromURL(AString);
  w3_setStyle(mImage.Handle,'cursor','pointer');
  mImage.OnClick := procedure(Sender:TObject)
  begin
    FullScreenSpinner.Enter;
    AString := 'http://res.cloudinary.com/your-account/image/upload/' +
               'w_' + inttostr(BigImage.Width) +
               ',h_' + inttostr(BigImage.Height) +
               ',c_pad/v' +
               cursor.resources[row].version + '/' +
               cursor.resources[row].public_id + '.' +
               cursor.resources[row].format;
    AIndex := row;
    BigImage.LoadFromURL(AString);
    ScrollElement1.ScrollApi.ScrollTo(0,-BigImage.Top,1,false);
    FullScreenSpinner.Leave;
  end;
//
  mLabel:=TW3Label.Create(ScrollElement1.Content);
  mLabel.setBounds(dx,dy+75,70,16);
  mLabel.Caption := 'Image' + inttostr(row+1);
  mLabel.OnClick := procedure (sender: TObject)
  begin
    AIndex := row;
  end;
 
  inc(dx,75);
  if dx > Panel1.width - 85 then
  begin
    dx := 25;
    inc(dy,95);
  end;
 
end;
 
The last piece of the puzzle is the use of the device camera.
Cloudinary has a simple widget which takes care of that. 
 
  W3Button1.OnClick :=
    procedure (Sender: TObject)
    begin
      asm
        cloudinary.openUploadWidget({ cloud_name: 'your-account',
                                  upload_preset: 'your-account',
                                  cropping: 'server'});
      end;
    end;
 
Select the camera, take a picture and upload in one go.
 
post-914-0-11419100-1448197414.png
Function TForm1.GetDPR:String;
var
  DPRString: String;
  DPR : Float;
  DPR_Supported_F : Array of Float;
  DPR_Supported_S : Array of String;
begin
  DPRString := '1';
  DPR := BrowserApi.DevicePixelRatio;
  DPR_Supported_F := [0.75, 1.0, 1.3, 1.5, 2.0, 3.0];
  DPR_Supported_S := ['0.75', '1.0', '1.3', '1.5', '2.0', '3.0'];
  for var x := Low(DPR_Supported_F) to High(DPR_Supported_F) do begin
    if DPR_Supported_F[x] >= DPR then begin
      DPR := DPR_Supported_F[x];
      DPRString := DPR_Supported_S[x];
      Break;
    end;
  end;
  Result := DPRString;
//  ShowMessage(Result);
end;
 

Attached Files


  • Jørn E. Angeltveit, ielite and Dany like this
Nico Wouterse

#2 BobLawrence

BobLawrence
  • Members
  • 78 posts
  • LocationBeaver Bank Nova Scotia Canada

Posted 22 November 2015 - 09:56 PM

Very nIce job. Just being able to  meet the requirement for " making it fit for all mobile and desktop devices - not only screen sizes but also resolution" is usually challenged enough. That's what I like about SMS, it makes it possible .I'm new to SMS so it's nice to see  the complete code for any project to get a few news ideas. Thanks! for posting.

 

Bob

 

:)


  • ielite likes this

#3 Jørn E. Angeltveit

Jørn E. Angeltveit
  • Administrators
  • 297 posts
  • LocationNorway

Posted 27 November 2015 - 01:08 AM

Wow!

 

What a great writeup.

 

 

We will dig into the details in this article, and perhaps we can reuse some of it in a demo or sample component?


  • ielite likes this





Also tagged with one or more of these keywords: cloudinary, image, management

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users