Class ImageInfo

  • All Implemented Interfaces:
    java.io.Serializable, java.lang.Cloneable

    public class ImageInfo
    extends java.lang.Object
    implements java.lang.Cloneable, java.io.Serializable
    ImageScraper-Suite Class
    The ImageScraper Tool itself includes three 'Helper-Classes' that facilitate its operations. These three Helpers include: Request, Results and ImageInfo.

    Building a Request:
    Building an Image-Download Request instance really should be extremely easy, and there is an example of doing just that at the top of the Request class. Properly configuring the class to handle any / all possible errors or exceptions that might occur when downloading images from a web-server requires a little reading of the JavaDoc pages provided by these tools.

    The Request class includes several boolean's for supressing / skipping exception if they occur during the download loop / process iteration. If an exception is thrown and suppressed, it will simply be logged to the Results class.

    Once a Request Object has been built, simply pass that object-instance to the ImageScraper method download and a download-process will begin.

    Request's Lambda-Targets:
    If the Request object contained any Lambda-Target / Function-Pointers, then those Lambda-Methods will be passed instances of the 'Helper-Class' ImageInfo when they are invoked by the download-loop. These Function-Pointers provide just a few features that allow a programmer to do things like filter-out certain Image-URL's and also do things like decide where a downloaded Image is ultimately stored.

    Finally, when the download-loop has run to completely, it will return an instance of class Results

    Getting Results:
    After the ImageScraper.download(...) loop has run to completion, an instance of class Results will be returned tot he user, and it will simply contain several parallel-arrays that hold / store data about what transpired when trying to download each of the Image-URL's which were passed to the Request-Object.

    For instance the 'skipped' array will indicate which pictures didn't download. The 'fileNames' array will hold the name of the file of each image that was successfully downloaded. And the 'imageFormats' will identify which format was ultimately decided-upon when saving the image.

    Remember that each of these return-arrays are parallel to eachother, and (or course) will be identical in length. Furthermore, as per the definition of "Parallel-Arrays", the element residing at any index will always correspond to the same image in any one of the other arrays.
    Simple Image Data-Class that is instantiated by the ImageScraper, and passed to any of the FunctionalInterface's or Lambda-Targets that are non-null / available in the user's Request object instance.



    In the following example, the programmer is providing a certain method / function to one of the Request class' Lambda-Targets. The particular Functional-Interface involved in this example is the one named 'keeperPredicate'.

    The 'keeperPredicate' allows a user to review everything that is known about a downloaded image before saving it to disk. In this particular example, the Function-Pointer assigned to 'keeperPredicate' is one that simple checks whether the most recently downloaded image is a duplicate of the previous one (and if it is, rejects it telling the downloader not to save the image to disk!)

    The most important point to understand about the class ImageInfo is that it is solely used as a "Data-Flow Record" (meaning a small class with lots of data to be passed around) that is transferred to the user whenever the one of the user's FunctionalInterface's are invoked by the download-loop!

    Example:
    private static ImageInfo prevImageInfo = null;
    
    // Note that the instance passed to this Function-Pointer / Lambda-Target is an instance of
    // 'ImageInfo'.  All Function-Pointer's in the ImageScraper Request-Object will be passed
    // an instance of this class.
    
    private static boolean keepImage(ImageInfo imageInfo)
    {
        if (prevImageInfo == null)
        {
            prevImageInfo = imageInfo;
            return true;
        }
    
        // Simply checks whether two consecutively downloaded images are identical.
        boolean equal =
                (imageInfo.width == prevImageInfo.width)
            &&  (imageInfo.height == prevImageInfo.height)
            &&  (imageInfo.imgByteArr.length == prevImageInfo.imgByteArr.length);
    
        prevImageInfo = imageInfo;
    
        // Returns 'TRUE' if-and-only-if the previous-image was different than the current image.
        return !equal;
    }
    
    public static void main(String[] argv)
    {
        ...
    
        Request req = new Request(images, originalPageURL, true);
    
        // Skip-and-move-on for all Image-Download Exceptions
        req.skipOnAllExceptions();
    
        // Assign the method (defined-above) as the Lambda-Target for the 'keeperPredicate'
        req.keeperPredicate = MyExampleClass::keepImage;
    
        Results r = ImageScraper.download(req, System.out);
    }
    
    See Also:
    Serialized Form


    • Field Detail

      • serialVersionUID

        🡇     🗕  🗗  🗖
        public static final long serialVersionUID
        This fulfils the SerialVersion UID requirement for all classes that implement Java's interface java.io.Serializable. Using the Serializable Implementation offered by java is very easy, and can make saving program state when debugging a lot easier. It can also be used in place of more complicated systems like "hibernate" to store data as well.
        See Also:
        Constant Field Values
        Code:
        Exact Field Declaration Expression:
         public static final long serialVersionUID = 1;
        
      • url

        🡅  🡇     🗕  🗗  🗖
        public final java.net.URL url
        The URL that was used to download the image. Note that anytime this instance of ImageInfo represents an image that was located on a web-page encoded using a Base-64 String, then this field will be null, and the B-64 Fields will contain the relevant image data (not this URL).
      • isB64EncodedImage

        🡅  🡇     🗕  🗗  🗖
        public final boolean isB64EncodedImage
        If the image whose details are contained by this class-instance are from an image that was encoded using the String-literal Base-64 Encoding Algorithm, then this boolean flag will contain TRUE.

        An HTML <IMG SRC=...> Tag is the only way to enter a Base-64 Image into the Image-Scraper class.
      • imageFormatStr

        🡅  🡇     🗕  🗗  🗖
        public final java.lang.String imageFormatStr
        A web-page has the ability to inline (smaller) images directly into an HTML <IMG SRC=...> tag by encoding the picture into a Base-64 String. The String is saved inside the SRC-Attribute of the <IMG> tag, and contains two separate sub-strings.

        This is the first sub-string, and it just identifies / lists the format (.jpg, .gif, .png etc...) in which the picture was saved before translating it into Base-64 Encoded Text.

        If the picture represented by this instance of ImageInfo was downloaded from a URL, then this field will be null, and the url field will contain the Image URL.
        See Also:
        isB64EncodedImage, b64EncodedImage
        Code:
        Exact Field Declaration Expression:
         public final String imageFormatStr;
        
      • b64EncodedImage

        🡅  🡇     🗕  🗗  🗖
        public final java.lang.String b64EncodedImage
        A web-page has the ability to inline (smaller) images directly into an HTML <IMG SRC=...> tag by encoding the picture into a Base-64 String. The String is saved inside the SRC-Attribute of the <IMG> tag, and contains two separate sub-strings.

        This is the second sub-string, and it is the text after translating the picture into Base-64 Encoded Text.

        If the picture represented by this instance of ImageInfo was downloaded from a URL, then this field will be null, and the url field will contain the Image URL.
        See Also:
        isB64EncodedImage, imageFormatStr
        Code:
        Exact Field Declaration Expression:
         public final String b64EncodedImage;
        
      • guessedExtension

        🡅  🡇     🗕  🗗  🗖
        public final IF guessedExtension
        This shall help identify whether the image-in-question is a GIF, JPG, PNG, etc.... The field 'guessedImageFormat' shall simply contain the image-type based on the extension found in the URL's file-name.

        There are web-pages & web-sites that do not provide a file-name extension for the images they use on their page(s). In such cases, the downloader will eventually attempt to 'guess' the format of an image that has been downloaded. In these cases, this parameter will be passed null, and the parameter actualImageFormat will contain the format that was actually used to successfully save the data to disk.
      • actualExtension

        🡅  🡇     🗕  🗗  🗖
        public final IF actualExtension
        If the image has been properly converted, and is ready to be written to disk, this parameter will contain the IF / image-format that was used to successfully save the image.

        Note that often (but not always), this extension / IF instance will be identical to the parameter 'guessedImageFormat'. There will be cases, as mentioned above, when 'guessImageFormat' is null. Furthermore, there may be (very rare) situations when an image-format for a particular URL was incorrect, and was saved properly using a different format & extension.
      • iteratorCounter

        🡅  🡇     🗕  🗗  🗖
        public final int iteratorCounter
        Identifies the count in the Iterator's retrieval. Since this int is used as an array-index pointer, it is initialized to '0' (zero). Specifically, if this method were called upon completion of three iterations of Image-URL retrieval, this counter would contain the integer '2' (two).
      • successCounter

        🡅  🡇     🗕  🗗  🗖
        public final int successCounter
        This identifies how many images have successfully downloaded, not the number of images for which a "download attempt" occurred. Since this int is used as an array-index pointer, it is initialized to '0' (zero). If on the third iteration of the source-Iterator, an IOException occurred between the Java-Virtual-Machine and the internet, the following invocation of this method would have successCounter as '2', but the iteratorCounter would be '3'.
    • Method Detail

      • fileName

        🡅  🡇     🗕  🗗  🗖
        public java.lang.String fileName()
        A "getter" (Accessor-Method) for the private-Field named fileName. This field is kept private because it cannot be declared final - since it is initialized several steps after construction.

        If a user Lambda-Expression / Functional-Interface has recevied 'this' instance of ImageInfo, and needs access to the ultimately-decided-upon image file-name, then this field may be retrieved using this 'Getter' Method.

        Unitialized at Construction:
        Note that this method will return null if a user attempts to retrieve the file-name before it has been decided upon and set in this class. This is actually the whole reason that it cannot be declared final, and therefore cannot be declared public (and requires this Getter-Method).
      • clone

        🡅  🡇     🗕  🗗  🗖
        public ImageInfo clone()
        Generates a Shallow Copy of 'this' instance. This means that the images themselves are not copied - rather only the references to the images are copied into the clone.

        The non-reference, non-instance (primitive-type) fields are all "just copied like normal" :)
        Overrides:
        clone in class java.lang.Object
        Returns:
        A duplicate instance of this class.
        Code:
        Exact Method Body:
         return new ImageInfo(this);
        
      • toString

        🡅  🡇     🗕  🗗  🗖
        public java.lang.String toString()
        Converts this class into a simple, readable String
        Overrides:
        toString in class java.lang.Object
        Returns:
        A java.lang.String representation of 'this' instance.
        Code:
        Exact Method Body:
         return
             ((this.url != null)
                 ? ("URL: " + StrPrint.abbrev(this.url.toString(), 40, true, " ... ", 80))
                 : "") +
        
             (this.isB64EncodedImage
                 ? ("B64-Encoded Format: " + this.imageFormatStr + ", IMG: " +
                     StrPrint.abbrev(this.b64EncodedImage, 30, true, " ... ", 60))
                 : "") +
        
             '\n' +
                    
             "Byte-Array.length: "   + StringParse.commas(this.imgByteArr.length) + '\n' +
        
             "W: "                   + StringParse.commas(this.width) + ", " +
             "H: "                   + StringParse.commas(this.height) + ", " +
             "File-Extension: "      + Objects.toString(this.actualExtension) + ", " +
             "URL-Extension: "       + Objects.toString(this.guessedExtension) + '\n' +
        
             "Iterator-Count: "      + this.iteratorCounter + ", " +
             "Downloaded-Count: "    + this.successCounter + '\n' +
        
             "Saving File-Name: "    + this.fileName + '\n';
        
      • equals

        🡅  🡇     🗕  🗗  🗖
        public boolean equals​(java.lang.Object other)
        Checks whether 'this' instance is equal to 'other'.
        Overrides:
        equals in class java.lang.Object
        Parameters:
        other - Any Java Object, but only an instance ImageInfo (or a class that is assignable to it) could possible generate a TRUE-return value.
        Returns:
        TRUE If and only if 'other' is an instance of ImageInfo, and if the contents of that are instance are identical to the contents of 'this' instance.
        Code:
        Exact Method Body:
         if (other == null) return false;
        
         if (! ImageInfo.class.isAssignableFrom(other.getClass())) return false;
        
         ImageInfo ii = (ImageInfo) other;
        
         // Note that using 'Objects.equals(...)' and 'Objects.deepEquals(...)' primarily prevents
         // a NullPointerException from being thrown if the left side of an '.equals(...)' were to
         // be null.  It's really nothing more than that.  (A small 'Convenience' that makes this
         // method look less ridiculous than it already does.)
         //
         // 'deepEquals(...)' actually checks the entire contents of two array's for equality.
        
         return
                
             // Image-URL (very common)
             Objects.equals(this.url, ii.url)
        
             // Base-64 Image Stuff (rare, but not impossible)
             &&  (this.isB64EncodedImage == ii.isB64EncodedImage)
             &&  (Objects.equals(this.imageFormatStr, ii.imageFormatStr))
             &&  (Objects.equals(this.b64EncodedImage, ii.b64EncodedImage))
        
             // The actual downloaded and converted images, themselves
             &&  Objects.deepEquals(this.imgByteArr, ii.imgByteArr)
             &&  Objects.equals(this.bufferedImage, ii.bufferedImage)
        
             // Image-Width, Image-Height
             &&  (this.width == ii.width)
             &&  (this.height == ii.height)
        
             // URL-Aquired Extension & Ultimately-Decided-Upon Extension
             &&  Objects.equals(this.guessedExtension, ii.guessedExtension)
             &&  Objects.equals(this.actualExtension, ii.actualExtension)
        
             // class 'Results' Array-Counters (index-pointers)
             &&  (this.iteratorCounter == ii.iteratorCounter)
             &&  (this.successCounter == ii.successCounter)
        
             // This is the lone / only 'non-final' field
             &&  Objects.equals(this.fileName, ii.fileName);
        
      • hashCode

        🡅     🗕  🗗  🗖
        public int hashCode()
        Java's hash-code requirement. The code is computed by summing the first 15 imgByteArr array elements.
        Overrides:
        hashCode in class java.lang.Object
        Returns:
        A hash-code that may be used when storing this node in a java sorted-collection.
        Code:
        Exact Method Body:
         if (url != null) return url.toString().hashCode();
        
         int sum = 0;
        
         for (int i=0; (i < 15) && (i < imgByteArr.length); i++) sum += imgByteArr[i];
        
         return sum;