Lightroom Classic 7.3.1 update is released

Today we have released the update based on the feedback we received for profiles introduced in 7.3.
Please see the complete list of bug fixes here.

Lightroom Classic 7.3 is released

Lightroom Classic 7.3 is released today. You will start getting the Update notification soon.
Here is a  comprehensive list of major updates went in:

  • New Profiles
    Adobe Lightroom Classic allows you to choose a camera profile option. A camera profile determines the color treatment applied to a raw image after it’s imported into Lightroom. It ensures that all images taken with the same settings look similarly in Lightroom. The default profile used to be Adobe Standard. From Lightroom 7.3 on wards, Adobe Color is going to be the default camera profile.
    Adobe Color profile is more contrasty and saturated compared with Adobe Standard.
    You are provided with the following profiles as a drop-down list:

    • Adobe Monochrome
    • Adobe Neutral
    • Adobe Vivid
    • Adobe Portrait
    • Adobe Landscape
      These profiles have been moved to a much prominent place in the Basic panel of the Development module.

      In addition, you are provided with a set of following Creative Profiles.
    • Modern
    • Vintage
    • Artistic
    • B&W
      These profiles help you to apply a certain style to your photo effortlessly. Applying a creative profile will not update the changes you already applied to an image. In addition, it also provides with an amount slider to change the intensity of the applied profile. Select the Browse button, shown in the previous image, to see the creative profiles.


  • Import grid performance
    On Windows machines, when you connect to a mobile phone (Android / iPhone) and then open the Import window, the images should appear faster. Previously, Lightroom Classic used to display all the images at a time, after the image scanning is complete. In the latest version, 7.3, it displays images in batch wise.
  • Face detection
    The underlying face detection engine is changed resulting better face detection and face recognition. Now, you can regenerate faces using the Library > Find Faces Again option at any point in time.
  • The Dehaze slider location
    The Dehaze slider is moved to the Basic panel as per your request.
  • Bigger tone curve
    Updated the Facebook API that uses for authentication in Facebook plugin. As a part of this change, you won’t be able to add a comment to a photo from Lightroom Classic.
    Bug Fixes
  • In the Filename Template Editor, when you insert a token as shown below, it always used to go to the end of the tokens string. Lightroom Classic 7.3 fixes the issue.
  • This version also fixes an issue on Mac that the Import window doesn’t appear after connecting an SD card while Lightroom is running.

Lightroom Classic 7.2 with better performance is released

Lightroom Classic 7.2 is released today. Let me introduce some of the changes went in:

  • Performance Improvements
    In the past, many users have reported that Lightroom becomes slower after a prolonged usage. This issue should have been fixed with this version. Also, resource-intensive activities, such as export, import, preview generation, and HD/panorama merge should be faster if your machine has 12 GM or more RAM.
    We, specifically, have implemented changes related to Threading Building Blocks (TBB). This should be effective on machines with 12 GB or more RAM.
  • Filter Folders
    You can search for folders.

    You can also mark some folders as favorite.  And, easily filter them out.

    Note that if you select multiple folders and mark them as favorite as a group, you need to unmark them favorite as a group itself. If you don’t remember the folders that you marked favorite as a group, see the same from filmstrip panel.

    There are some known issues with this feature:

    • When you clear the Search field after a search, Lightroom Classic re-calculates the image number; it takes some time to display the image numbers.
    • At a time, the drives names disappear following a search for a short duration of time.
  • Sort edited and unedited images

  • Create collection or collection set quickly
    You can create collection or collection set quickly from folders.
    If the folder has sub folders, the Create Collection option appears in the context menu. The directory structure is retained while creating the collection set, with all parent directories are retained as collection set.

Embedded Preview workflow in Lightroom Classic CC

Lightroom Classic 2018 introduces the embedded preview workflow that helps you to reduce the time to select the right images for developing (culling). While importing the images, select the Embedded and Sidecar option for building the previews.

When you import an image into Lightroom, it creates various previews for you. By default, Lightroom creates a minimal preview, which is the thumbnail that you see in the Library grid view. When you move to the Loupe view, it generates the standard preview. Further, when you zoom the image, it generates the 1:1 preview on the fly. These previews are different from the camera-generated previews. Since Lightroom needs to create these previews, when you navigate through many images in the Loupe view, you see the loading bezel. In other words, images take time to load. One way to overcome this issue is to create standard or 1:1 previews while importing itself; however, this process takes more time, since Lightroom builds previews.

The new feature helps you to overcome both these issues to certain extent.  In this workflow, Lightroom, instead of creating its own previews, reads and makes use of the embedded previews in the Library module. This process takes less time in most of the computers.

Embedded preview is a camera preview, which is created by the camera, and is available with the raw image. Latest Nikon and Canon cameras have full size embedded previews. Means, the camera-generated embedded previews can be used for culling. Sony, Olympus, and Fuji cameras don’t have full sized embedded previews. In this case, Lightroom checks if the embedded preview size is 50% of that of the raw image. If not, the standard preview is created instead of reading the embedded preview. Create a jpg sidecar image along with the raw. If the image has the sidecar file, it’s being read for creating the preview in the Library module.

While the importing is in progress, you can start culling, since Lightroom would be responsive while embedded preview is being read, than standard preview is created. Similarly, if you import images into multiple folders, the embedded preview generation is prioritized based on the folder you view. Embedded previews are available only in the Library module. After the culling, when you move to the Develop module, after edit, the standard preview is created. Means, you start seeing the Lightroom preview.

Images with embedded previews are marked by a symbol in both Library and Loupe views. Click it if you wish to convert an embedded preview into standard preview.

There is an option provided in Preferences’ General tab that converts the embedded previews into standard previews when your system is idle.

We hope you will enjoy the new culling experience.

Some of the caveats:

  • Generating embedded preview, if you convert the raw files into DNGs, may not be a great idea.
  • If you apply a Develop preset, while importing, you may see two different previews. Library preview won’t have the Develop preset you applied. The preview gets updated after you make a change in the Develop module.
  • Performance can vary based on the machine configurations.

We will wait for you feedback to improve this further. Thanks for your feedback!!

Adobe Experience Manager Learning Series – Part 2

This is my first post in this year. With my last post, I have completed second series of video tutorials that covers some of the main concepts in AEM development. We didn’t do anything complex; however, it will help you to get a quick start.

If you are learning, see my blog too. It has the transcripts available. Also, you could see the correct order in which you need to progress. The exercise files are available in my GitHub account.

Stay connected.
Happy New Year and Happy Learning!!

Create a custom workflow

In this post, we will see how to implement a workflow using AEM. As the name suggests, a workflow represents a step-by-step process to accomplish a common task. For example, author creates the content. Then, the content goes to an editor for approval. After the approval, the content can be published. As usual, we will see a simple implementation.

(Get the code samples from my GitHub account.)

After executing the workflow, we will log the name of the page into the custom log. I know it’s so simple – but it will give you an idea of how executing a workflow can kick off a method in a bundle.

  1. Create a WorkflowImpl class in the com.aemcompany.myproject.impl package.
    public class WorkflowImpl implements WorkflowProcess{
    private Logger log = LoggerFactory.getLogger(this.getClass());
    public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException
    {
    WorkflowData data = workItem.getWorkflowData();
    String payload = (String)data.getPayload(); 
    log.info(payload);
    } 
    }
  2. Implement WorkflowProcess interface.
  3. Implement WorkflowProcess interface.
  4. Use a WorkflowData object to get the workflow data.
  5. Get the payload from the workflow data.
  6. Write it to the log.

Now let us create a workflow using the AEM interface.

  1. Go to the workflow console:
  2. Select New.
  3. Enter the name.
  4. Double-click the newly created workflow.
  5. Drag and drop a process step
  6. Select AEM Workflow Process we created.
  7. Select Handler Advance. Selecting this advances the workflow to the next step automatically, without executing any additional steps.
  8. Select OK.

Let us execute the workflow.

  1. On the page we created, go to the Workflow tab.
  2. Select AEM Company and select Start Workflow.
  3. Select Step 1 and select Complete.
  4. Select OK.
  5. Open the log.

See the name of the page where it’s executed is added to the log. It was a small demo – hope it gave a basic idea of implementing workflow.

See you soon.

 

Create a custom JCR event

In this session, we will see how to create a custom event and manage it. A custom event helps you to manage a specific activity happened on an AEM instance. For example, you want to send an e-mail to an editor as soon as an AEM page is created by a content creator; so that the editor is aware that the page needs to be edited at a later stage.

Let us start. We will create a new AEM component for creating a custom event.

  1. Inside com.aemcompany.myproject.impl, create a new class EventManagerImpl.java.
    Note that the class is extended by EventListener interface that provides you the methods to manage the event.
  2. Create the following class variables:
    private SlingRepository repository;
    private ResourceResolverFactory resolverFactory;
    private Session session;
    private ObservationManager observationManager;
  3. Create an activate() method.
    This method gets called when the component get activated.
  4. Create a session object.
    session = repository.loginAdministrative(null);
  5. Create an  observationManager object.
    observationManager = session.getWorkspace().getObservationManager();
  6. Use the observationManager’s addEventListener method to create a custom event.
    observationManager.addEventListener(this, Event.NODE_ADDED, "/content", true, null, null, false);
  7. Implement an onEvent method.
    We will use this method to log an event whenever the custom event is fired.

    public void onEvent(EventIterator itr) {
    log.info("A new node was added to /content ");                       
    }
  8. Create deactivate() method basically to ensure to log the session out before the component gets deactivated. (Which is not explained, since it’s not directly related to the custom event.)
  9. Now, let us test it. Got to the Content folder and create a new test page.
  10. Open the log file and observe that the onEvent method is called.

 

Search in AEM repository

In the last session, we have seen how to add a property to a JCR node. We primarily created a resourceResolver object and created a resource using the path to the node where we wanted to set the property. Converted the resource into a Node using the adptTo() method. And, then used the setProperty() method to set the property. Finally, we created a session object in the similar manner, and then saved the property.

In this session, we will see how to perform a basic search option. There are many ways to accomplish the same. We will see the simplest way. The intention is to be cognizant of how a search operation is performed. In the repository, we will search for the page that contains a property author which is set to Sunil.

  1. Go to the SearchService.java interface and add the following method:
    public String getResult();
  2. In the SearchServiceImpl class, create a Resource Resolver. We have discussed this in length in of the previous sessions.
    Map<String, Object> param = new HashMap<String, Object>(); 
    param.put(ResourceResolverFactory.SUBSERVICE, "readService");
    ResourceResolver resourceResolver=null;
    resourceResolver = resolverFactory.getServiceResourceResolver(param);
  3. Create a session object using the adptTo method.
    Session session = resourceResolver.adaptTo(Session.class);
  4. Create a QueryManager object as follows:
    javax.jcr.query.QueryManager queryManager = session.getWorkspace().getQueryManager();
  5. Create a query String.
    We need to find the page that contains author property as Sunil.

    String sqlStatement = "SELECT * FROM [cq:PageContent] WHERE CONTAINS(author, 'Sunil')";
  6. Create a JCR query.
    javax.jcr.query.Query query = queryManager.createQuery(sqlStatement,"JCR-SQL2");
  7. Obtain the result as follows:
    javax.jcr.query.QueryResult result = query.execute();
  8. Create a JCR node iterator and convert the result into an iterator.
    javax.jcr.NodeIterator nodeIter = result.getNodes();
  9. Use the following code to find the node and get its properties, such as author and title.
    while ( nodeIter.hasNext() ) {
     LOGGER.info("From the search");
     javax.jcr.Node node = nodeIter.nextNode();
     title = node.getProperty("jcr:title").getString();
     author = node.getProperty("author").getString();
     }
  10. Return author.
  11. Access the bundleservice component. Add the following code in the default script.
    <%= searchService.getResult()%>
  12. Refresh the page we created. It should display the value of the author property.

Update a node property using an AEM bundle

In the previous session, we have seen how to obtain a Resource. We later, translated the Resource into a Page object, and then programmatically obtained its title. We will see one more example. Here, using an AEM bundle, we will write a property to the Page we created. In this case too, we need to use a Resource object to obtain a Session object using which we can save what we write.

Let us start:

  1. Create a new interface: SearchService.java.
    (There is a reason for using this name. In the next session, we are going to discuss about searching.)
  2. Add the following method.
    public void addProperty();.
  3. Create the implementation class: SearchServiceImpl.java
  4. Implement the addProperty() method.
  5. Get the ResourceResolver.
    (Visit the previous post to see what the code accomplishes.)

    Map<String, Object> param = new HashMap<String, Object>();  
    param.put(ResourceResolverFactory.SUBSERVICE, "readService");
    ResourceResolver resourceResolver=null;
    resourceResolver = resolverFactory.getServiceResourceResolver(param);
  6. Obtain the resource.
    Resource pageResource = resourceResolver.getResource("/content/aem-company/jcr:content");

    Note that we need to add the property to the jcr:content node of the page we created.

  7. Translate the resource into a node using the adaptTo() class.
    Node myNode = pageResource.adaptTo(Node.class);
  8. Set a property to the node.
    myNode.setProperty("author", "sunil");
  9. Obtain the session from resourceResolver.
    Session session = resourceResolver.adaptTo(Session.class);
  10. Save the session:
    session.save();
  11. Deploy the bundle.
  12. Add a method in the bundleservice component.
    <%
    com.aemcompany.myproject.SearchService searchService=sling.getService(com.aemcompany.myproject.SearchService.class);
    searchService.addProperty();
    %>
  13. Access the page so that the method is called.
  14. Log into CRXDELite.
  15. See the page properties and ensure that the new property is added.
    That’s it. See you soon.

Access a resource property using an AEM bundle

In this session, we will learn about how to access resources using bundles deployed in the Felix console.  After all, for Sling, everything is a resource. We will update the bundle we developed with a method that accesses a node and prints its title. Though it sounds very simple, we will learn about a very important interface ResourceResolverFactory, that helps us to get ResourveResolver. ResourceResolver gets the Resource object that provides the functionalities to manipulate the nodes and its properties. We will also learn about the adptTo() method that helps to translate an object into a different object type.

So, let us start:

  1. Add the following method in HelloService interface:
    public String getPageTitle();
  2. Add the following ResourceResolveFactory reference:@Reference ResourceResolverFactory resolverFactory;
  3. Implement the getPageTitle() method.
  4. Create a hashmap object with a string & object combination as shown below:
    Map<String, Object> param = new HashMap<String, Object>();
  5. Put ResourceResolverFactory.SUBSERVICE and the service associated to the HashMap object.
    param.put(ResourceResolverFactory.SUBSERVICE, "readService");

    This is a new security layer added in AEM on 6.1 version. It means that the resolveResolver object we create is used by a readService process that we would be created later.

  6. Now create a reference to the ResourseResolver.
     ResourceResolver resourceResolver=null;
  7. Create resourceResolver object as shown below:
    resourceResolver = resolverFactory.getServiceResourceResolver(param);

    As I mentioned earlier, for Sling, everything is a resource. Generally, you use Sling APIs for doing any content manipulation. Getting a ResourceResolver object is imperative for accessing the Nodes in Oak, and later doing various operations, such as Create, Read, Update, and Delete (CRUD). You can compare it to creating a connection object in Java to a database.

  8. Now create a resource object using the getResource() method with a path to the company page as argument.
     Resource pageResource = resourceResolver.getResource("/content/aem-company");
  9. Translate the resource into a Page object using the adaptTo() class.
    Page myPage = pageResource.adaptTo(Page.class);

    Note that the method takes the class name to which we want to translate the resource as an argument. We do this operation to avail various APIs associated with various objects, such as Node, Page, and so on. In this case, we use the getTitle() method in the Page object. This can throw a null or Login Failed exception, and that’s the reason we added a try catch block.

  10. Use the following Page method to get the resource title.
    String title = myPage.getTitle();

Update the bundle service component
Update the bundleservice page, so that we can test if the bundle returns the value.

  1. Login to CRXDE LIte.
  2. Update the bundleservice page.
     <%= repositoryService.getPageTitle()%>

Create a service user mapper

  1. Login to System console.
  2. In OSGI Configuration,  search for Apache Sling Service User Mapper Service.
  3. Create a new service mapping as shown below:
     aem-company.myproject-bundle:getResourceResolver=myUser
  4. The first part is the bundle name. Second part is the service name that we used in the method. (Step: 5) Third part is the system user who can access the service.
    We are yet to create the system user. Let us do that.

Create a system user and provide access rights

  1. Login to CRX Explorer.
    http://localhost:4502/crx/explorer/index.jsp
  2. Select User Administration > Create System User.
  3. Enter user ID.
  4. Select Yes for creation.
  5. Provide access to the user to avail the paths.
    http://localhost:4502/useradmin)
  6. Search for the user. (myUser)
  7. Provide full access to the content path.
  8. Then, Save the user.

Test the component

  1. Access the page we created.
    Note that it displays AEM Company, the title of the node.