29 Replies Latest reply on Aug 5, 2014 7:29 AM by BCuzzillo

    CS5.5 (MAC) script to fix random dots in lineart scans

    Colin Flashman Adobe Community Professional

      Hello there.

       

      In my line of work, I often have to scan text only documents to  print offset. The majority of the scans are clean but ultimately there will be random dots which need to be tidied up. I am looking for a way to streamline this process.

       

      I was able to find a solution which I had in mind but it requires converting the lineart scan to 8-bit first. The example can be found at: http://verlagmartinkoch.at/software/cleanup/index.html

       

      However, has anyone heard of an action or javascript that could do this without having to convert to greyscale and then back to lineart?

       

      I have read DOZENS of DIY guides and posts suggesting always doing black and white scans as greyscale first and then converting them, but without going into tremendous detail, I will simply say that the scans I receive will output as lineart.

       

      Many thanks

       

      colly

        • 1. Re: CS5.5 (MAC) script to fix random dots in lineart scans
          c.pfaffenbichler Level 9

          As Photoshop does not allow Filters and Quick Mask for 1bit bitmap images I see no reasonable way of avoiding going through grayscale and later on converting back to bitmap again. (Using Paths might be an option but I guess that would likely be more detrimental and slower.)

          But as the conversions can be automated I don’t get why you even want to avoid them.

          • 2. Re: CS5.5 (MAC) script to fix random dots in lineart scans
            Muppet Mark Level 5

            I can't see a problem with mode conversion… here is a script that did something along these lines a while back…

             

            http://forums.adobe.com/message/2558998#2558998

            • 3. Re: CS5.5 (MAC) script to fix random dots in lineart scans
              Colin Flashman Adobe Community Professional

              Thank you Muppet Mark. I did read that thread which you had linked from your post, but I'm not sure if it's quite the same thing that I'm looking for. In that thread, the OP had a desired size and wanted to remove stray pixels which were attached to a larger item. I'm not really trying to do that, but just remove stray black dots in a sea of white; or stray white dots in a sea of black... much like the example which i'd linked to in the opening post. The primary purpose of such a script would be used to clean up lineart scans of text only.

               

              Put simply, the hard-copy scans are from a document feeder and scanned into a PDF. At the moment, I have been using the "edit object" feature within Acrobat to launch Photoshop and then do the necessary touchups, but am aware that it is possible to export all the scans to a folder of tiffs so that images can be changed en masse. The scans are lineart mainly to keep file sizes down and the fact that the scans are of text only and don't really need the general level of attention that cartoons or illustrations would. I suppose there is a general reluctance to convert to greyscale as it is an added step, and over what could be 400+ images, any timesavings are important.

               

              I suppose the way that I believed the script may work would be to detect any black (or white) object < a certain amount of pixels in area... and invert the selection accordingly... but the reality is that I have no idea how that would work.

              • 4. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                c.pfaffenbichler Level 9

                The scans are lineart mainly to keep file sizes down and the fact that the scans are of text only and don't really need the general level of attention that cartoons or illustrations would.

                That should not be the only reason when working for print (and if the resolution of the bitmaps is high enough); grayscale images would get rasterized whereas 1bit bitmap images can utilize the full resolution of the ooutput device.

                • 5. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                  Muppet Mark Level 5

                  Did you try the script…? The filters used will clean out single pixel black dots in white invert and do the same with white dots in black… You didn't post a sample of your scans but can't you OCR them… That would be best

                  1 person found this helpful
                  • 6. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                    Colin Flashman Adobe Community Professional

                    @ c.pfaffenbichler

                     

                    I think what was quoted was taken out of context. In my quest for this solution, many of the articles online point to scanning in greyscale first, tidying up and then ultimately converting to bitmap. The quote taken about lineart scans is meant as the scans are done as lineart FIRST as opposed to greyscale first and then all ultimately saved down to 1-bit bitmaps.

                     

                    @ muppet mark

                     

                    To take a line out of the other thread, I SHOULD go to specsavers . I continued reading past the first 15 posts (where i'd stopped before) and saw it through to the end. Yes, i tried the script and found an unforeseen fault (won't open tiffs with LZW compression) but otherwise seems to do what I want. Have to play with the size settings as I think 4pix is good for fine white spots but turns out the bits and pieces are a little bigger than that... but otherwise yes this appears to be the solution. cheers for that!

                     

                    I can't post a sample of the art as I don't have the client's permission, and we're looking to reproduce the books "as is" rather than reset them via OCR. Luckily the books only have imprint changes and the content remains the same... thankfully! Have tried with a sample letter here and all appears to "do what it says on the jar"

                     

                    colly

                    • 7. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                      Colin Flashman Adobe Community Professional

                      OK, have now had a chance to do some before and after comparisons and sadly, while the script is good, it is as I said in post 3 which is "not quite the same thing that I'm looking for".

                       

                      With the before and after I've noticed that thin type is being "destroyed"

                       

                      Screen shot 2013-01-08 at 12.26.50 AM.png

                      whereas other type and the little dots are being fixed nicely

                      Screen shot 2013-01-08 at 12.27.24 AM.png

                      but again, that's not quite what I was hoping the outcome would be. Again, I imagined that the script would look for any instance of black pixels with an area less than figure X and then invert them... It's hard for me to articulate so let me use this example:

                      Screen shot 2013-01-08 at 12.31.06 AM.png

                      in the image above, I imagine the script would work in a manner of "find all black pixels less than 9px" and that would remove the three dots on the sample (two of the dots are 3px in area, one is 4px) but leave everything else as it is without cleaning the edges.

                       

                      I hope I have explained myself a little better.

                      • 8. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                        c.pfaffenbichler Level 9

                        Once again I think working with Paths is a viable option.

                        It’s (to me at least) not possible in Photoshop to determine the area circumscribed by a Path without Selections, but creating a Selection for each SubPathItem would likely make a Script too slow for practical purposes.

                        But if a check for a maximum width and height would suffice that might work out.

                        • 9. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                          c.pfaffenbichler Level 9

                          Could you post a sample page (best with the antiqua text that proved problematic)?

                          • 10. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                            Colin Flashman Adobe Community Professional

                            Like I say, I can't post a sample of the art as I don't have the client's permission but any lineart scan from a scanner would do. The result I am trying to achieve is effectively the same as the third image in post 7 with the exception of the three rogue dots that appear on the sample.

                             

                            I have since tried to make selections of <9 square pixels by using the selection and filter tools and can now see the difficulty if a javascript is going to call on selection and filter tools to try and create the kind of selection that I want...  but would there be other ways to achieve the end result, perhaps at a binary level?

                             

                            colly

                            • 11. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                              c.pfaffenbichler Level 9

                              Like I say, I can't post a sample of the art as I don't have the client's permission but any lineart scan from a scanner would do.

                              So we can create our own test files.

                              Will that help make results easily or reliably transferable to your files?

                               

                              Anyway … a Scripting approach utilizing paths (barbaric, I guess, and not fast, about 22sec for a 2000px x 2000px image) can get this

                              birmapDirtScr2_2.jpg

                              from this

                              birmapDirtScr2_1.jpg

                              But if the letters (or their serifs) were only 1px wide and individual pixels only connected diagonally wholes might still result, as fas as I can tell.

                              Furthermore this also switches the image to grayscale and back intermediately.

                              1 person found this helpful
                              • 12. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                Colin Flashman Adobe Community Professional

                                @ c.pfaffenbichler

                                 

                                good point, i suppose anything with type could have been supplied by me as a sample... put simply i couldn't upload bitmap tiffs to my wordpress blog for people to download. can however upload a PDF of the bitmap tiff, which is what i've done: http://wp.me/a1x3Yg-8k - it's really awful. on that sample I don't expect the jaggedness on the edges to be fixed, just the loose dots to go.

                                 

                                nevertheless i think your approach is the way to go. In your screengrabs it appears that the spicks and specks were 1px... what if they were larger, such as between 1 px and 9px across (81px square)? would the solution still work?

                                 

                                I think your demonstration is a good proof of principle. the time... well spotting the scans manually takes 5-6 minutes on average to do a decent job of them... as for the diagonals 1px... too bad.

                                 

                                but yes i think you are well on the right track  

                                • 13. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                  Yelnats1 Level 1

                                  Assuming you're working on a thresholded image in 8 bit, you can record a simple action. Make sure your eyedropper is set to a single pixel Sample Size.

                                   

                                  1. Select-> color range.  click on a black pixel, and click OK
                                  2. Select-> Modify -> contract.  Set to 1 to get rid of spots of with no area above 2X2, or set to 2 to get rid of spots without an area bigger than 4x4.  OK
                                  3. Select-> Grow
                                  4. Select -> Inverse
                                  5. Edit -> Fill.    Set to Use: White. OK.
                                  6. Repeat steps 2 - 4
                                  7. Edit -> Fill.    Set to Use: Black. OK.
                                  1 person found this helpful
                                  • 15. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                    Colin Flashman Adobe Community Professional

                                    @David

                                     

                                    It's a great solution which gets the results, but again has issues.

                                     

                                    Because of the way the modify/contract method works, it does not take long before any increase in selection values is not only removing dots, but lines and underlines as well. A selection of 1, it will remove spots 2x2 (4px) as stated... with a selection of 2 it will remove spots 4x4, (16px) with a selection of 3, it will remove any graphics with a width or height less than or equal to 6x6. (36px)

                                     

                                    This solution will work well for type but not so great for thin lines such as text which may be underlined, or thin lines in general. For example, an underline of a word may only be 6px high but would be hundreds of pixels across. If a script was to search by min area (e.g. min 81 px) the line would survive, but if the action is used with a contract threshold of 3, then the line will ultimately be removed despite the fact that it is more than 81px in total area.

                                     

                                    However, David's suggestion is the closest solution to the problem presented at the moment.

                                    • 16. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                      c.pfaffenbichler Level 9

                                      Here’s a screenshot of part of the image before and after.

                                      birmapDirtScr3.jpg

                                       

                                      You could give the Script a try if you want.

                                      The line

                                      if (theWidth < 7 && theHeight < 7) {theNewArray.push(theSubArray)};
                                      

                                      sets the with and height under which a segment is supposed to get removed and the pretty much arbitrary number 19 in line

                                      var theArray = collectPathInfoFromDesc2012belowXPoints(theCopy, thePath, 19);
                                      

                                      is intended to exclude SubPathItems with a lot of PathPoints from evaluation right away to speed things up.

                                       

                                      // cover up anything under 7x7px;
                                      // 2012,  use it at your own risk;
                                      #target photoshop
                                      if (app.documents.length > 0 && app.activeDocument.mode = DocumentMode.BITMAP) {
                                      var myDocument = app.activeDocument;
                                      var originalRulerUnits = app.preferences.rulerUnits;
                                      app.preferences.rulerUnits = Units.PIXELS;
                                      var theResolution = myDocument.resolution;
                                      myDocument.resizeImage(null, null, 72, ResampleMethod.NONE);
                                      // make copy and scale up to ascertain making pathpoints for pixel corners;
                                      var theCopy = myDocument.duplicate ("thecopy", true);
                                      theCopy.resizeImage(null, null, 144, ResampleMethod.NEARESTNEIGHBOR);
                                      // make seletion from rgb-channel;
                                      // =======================================================
                                      var idsetd = charIDToTypeID( "setd" );
                                          var desc3 = new ActionDescriptor();
                                          var idnull = charIDToTypeID( "null" );
                                              var ref1 = new ActionReference();
                                              var idChnl = charIDToTypeID( "Chnl" );
                                              var idfsel = charIDToTypeID( "fsel" );
                                              ref1.putProperty( idChnl, idfsel );
                                          desc3.putReference( idnull, ref1 );
                                          var idT = charIDToTypeID( "T   " );
                                              var ref2 = new ActionReference();
                                              var idChnl = charIDToTypeID( "Chnl" );
                                              var idChnl = charIDToTypeID( "Chnl" );
                                              var idRGB = charIDToTypeID( "RGB " );
                                              ref2.putEnumerated( idChnl, idChnl, idRGB );
                                          desc3.putReference( idT, ref2 );
                                      executeAction( idsetd, desc3, DialogModes.NO );
                                      // =======================================================
                                      var idInvs = charIDToTypeID( "Invs" );
                                      executeAction( idInvs, undefined, DialogModes.NO );
                                      // create path;
                                      theCopy.selection.makeWorkPath(0.5);
                                      var thePath = theCopy.pathItems[theCopy.pathItems.length - 1];
                                      // scale back down;
                                      theCopy.resizeImage(null, null, 72, ResampleMethod.NEARESTNEIGHBOR);
                                      // get path info for subpathitems with less than x pathpoints;
                                      var theArray = collectPathInfoFromDesc2012belowXPoints(theCopy, thePath, 19);
                                      // close copy;
                                      theCopy.close(SaveOptions.DONOTSAVECHANGES);
                                      app.activeDocument = myDocument;
                                      ////////////////////////////////////
                                      // get just the pathpoints;
                                      var theNewArray = new Array;
                                      // work through the original array;
                                      for (var m = 0; m < theArray.length; m++) {
                                      //$.writeln (m);
                                                var theSubArray = theArray[m];
                                                          var checkHorArray = new Array;
                                                          var checkVerArray = new Array;
                                                          for (var n = 0; n < theSubArray.length - 2; n++) {
                                                                    checkHorArray.push(theSubArray[n][0][0]);
                                                                    checkVerArray.push(theSubArray[n][0][1]);
                                                                    };
                                                          checkHorArray.sort();
                                                          checkVerArray.sort();
                                                          var theWidth = checkHorArray[checkHorArray.length -1] - checkHorArray[0];
                                                          var theHeight = checkVerArray[checkVerArray.length -1] - checkVerArray[0];
                                      // use subpathitem only if width and height below x px;
                                                          if (theWidth < 7 && theHeight < 7) {theNewArray.push(theSubArray)};
                                                };
                                      //create path;
                                      var thisDate = new Date();
                                      var thisPath = createPath2012(theNewArray, "heights_"+thisDate.getTime());
                                      // =======================================================
                                      var idCnvM = charIDToTypeID( "CnvM" );
                                          var desc2 = new ActionDescriptor();
                                          var idT = charIDToTypeID( "T   " );
                                              var desc3 = new ActionDescriptor();
                                              var idRt = charIDToTypeID( "Rt  " );
                                              desc3.putInteger( idRt, 1 );
                                          var idGrys = charIDToTypeID( "Grys" );
                                          desc2.putObject( idT, idGrys, desc3 );
                                      executeAction( idCnvM, desc2, DialogModes.NO );
                                      //
                                      myDocument.pathItems[myDocument.pathItems.length - 1].makeSelection(0, false);
                                      myDocument.layers[0].invert();
                                      myDocument.selection.deselect();
                                      // =======================================================
                                      var idCnvM = charIDToTypeID( "CnvM" );
                                          var desc4 = new ActionDescriptor();
                                          var idT = charIDToTypeID( "T   " );
                                              var desc5 = new ActionDescriptor();
                                              var idRslt = charIDToTypeID( "Rslt" );
                                              var idRsl = charIDToTypeID( "#Rsl" );
                                              desc5.putUnitDouble( idRslt, idRsl, myDocument.resolution );
                                              var idMthd = charIDToTypeID( "Mthd" );
                                              var idMthd = charIDToTypeID( "Mthd" );
                                              var idThrh = charIDToTypeID( "Thrh" );
                                              desc5.putEnumerated( idMthd, idMthd, idThrh );
                                          var idBtmM = charIDToTypeID( "BtmM" );
                                          desc4.putObject( idT, idBtmM, desc5 );
                                      executeAction( idCnvM, desc4, DialogModes.NO );
                                      // fill path;
                                      //fillPathWhite();
                                      // reset;
                                      app.preferences.rulerUnits = originalRulerUnits;
                                      };
                                      ////////////////////////////////////
                                      ////////////////////////////////////
                                      ////////////////////////////////////
                                      ////// collect path info from actiondescriptor, smooth added //////
                                      function collectPathInfoFromDesc2012belowXPoints (myDocument, thePath, theNumber) {
                                      var originalRulerUnits = app.preferences.rulerUnits;
                                      app.preferences.rulerUnits = Units.POINTS;
                                      // based of functions from xbytor’s stdlib;
                                      var ref = new ActionReference();
                                      for (var l = 0; l < myDocument.pathItems.length; l++) {
                                                var thisPath = myDocument.pathItems[l];
                                                if (thisPath == thePath && thisPath.name == "Work Path") {
                                                          ref.putProperty(cTID("Path"), cTID("WrPt"));
                                                          };
                                                if (thisPath == thePath && thisPath.name != "Work Path" && thisPath.kind != PathKind.VECTORMASK) {
                                                          ref.putIndex(cTID("Path"), l + 1);
                                                          };
                                                if (thisPath == thePath && thisPath.kind == PathKind.VECTORMASK) {
                                              var idPath = charIDToTypeID( "Path" );
                                              var idPath = charIDToTypeID( "Path" );
                                              var idvectorMask = stringIDToTypeID( "vectorMask" );
                                              ref.putEnumerated( idPath, idPath, idvectorMask );
                                                          };
                                                };
                                      var desc = app.executeActionGet(ref);
                                      var pname = desc.getString(cTID('PthN'));
                                      // create new array;
                                      var theArray = new Array;
                                      var pathComponents = desc.getObjectValue(cTID("PthC")).getList(sTID('pathComponents'));
                                      // for subpathitems;
                                      for (var m = 0; m < pathComponents.count; m++) {
                                                var listKey = pathComponents.getObjectValue(m).getList(sTID("subpathListKey"));
                                                var operation1 = pathComponents.getObjectValue(m).getEnumerationValue(sTID("shapeOperation"));
                                                switch (operation1) {
                                                          case 1097098272:
                                                          var operation = 1097098272 //cTID('Add ');
                                                          break;
                                                          case 1398961266:
                                                          var operation = 1398961266 //cTID('Sbtr');
                                                          break;
                                                          case 1231975538:
                                                          var operation = 1231975538 //cTID('Intr');
                                                          break;
                                                          default:
                                      //                    case 1102:
                                                          var operation = sTID('xor') //ShapeOperation.SHAPEXOR;
                                                          break;
                                                          };
                                      // for subpathitem’s count;
                                                for (var n = 0; n < listKey.count; n++) {
                                                          var points = listKey.getObjectValue(n).getList(sTID('points'));
                                      if (points.count < theNumber) {
                                                          theArray.push(new Array);
                                                          try {var closed = listKey.getObjectValue(n).getBoolean(sTID("closedSubpath"))}
                                                          catch (e) {var closed = false};
                                      // for subpathitem’s segment’s number of points;
                                                          for (var o = 0; o < points.count; o++) {
                                                                    var anchorObj = points.getObjectValue(o).getObjectValue(sTID("anchor"));
                                                                    var anchor = [anchorObj.getUnitDoubleValue(sTID('horizontal')), anchorObj.getUnitDoubleValue(sTID('vertical'))];
                                                                    var thisPoint = [anchor];
                                                                    try {
                                                                              var left = points.getObjectValue(o).getObjectValue(cTID("Fwd "));
                                                                              var leftDirection = [left.getUnitDoubleValue(sTID('horizontal')), left.getUnitDoubleValue(sTID('vertical'))];
                                                                              thisPoint.push(leftDirection)
                                                                              }
                                                                    catch (e) {
                                                                              thisPoint.push(anchor)
                                                                              };
                                                                    try {
                                                                              var right = points.getObjectValue(o).getObjectValue(cTID("Bwd "));
                                                                              var rightDirection = [right.getUnitDoubleValue(sTID('horizontal')), right.getUnitDoubleValue(sTID('vertical'))];
                                                                              thisPoint.push(rightDirection)
                                                                              }
                                                                    catch (e) {
                                                                              thisPoint.push(anchor)
                                                                              };
                                                                    try {
                                                                              var smoothOr = points.getObjectValue(o).getBoolean(cTID("Smoo"));
                                                                              thisPoint.push(smoothOr)
                                                                              }
                                                                    catch (e) {thisPoint.push(false)};
                                                                    theArray[theArray.length - 1].push(thisPoint);
                                                                    };
                                                          theArray[theArray.length - 1].push(closed);
                                                          theArray[theArray.length - 1].push(operation);
                                                          };
                                      };
                                                };
                                      // by xbytor, thanks to him;
                                      function cTID (s) { return cTID[s] || cTID[s] = app.charIDToTypeID(s); };
                                      function sTID (s) { return sTID[s] || sTID[s] = app.stringIDToTypeID(s); };
                                      // reset;
                                      app.preferences.rulerUnits = originalRulerUnits;
                                      return theArray;
                                      };
                                      ////// create a path from collectPathInfoFromDesc2012-array //////
                                      function createPath2012(theArray, thePathsName) {
                                      var originalRulerUnits = app.preferences.rulerUnits;
                                      app.preferences.rulerUnits = Units.POINTS;
                                      // thanks to xbytor;
                                      cTID = function(s) { return app.charIDToTypeID(s); };
                                      sTID = function(s) { return app.stringIDToTypeID(s); };
                                      
                                      
                                          var desc1 = new ActionDescriptor();
                                          var ref1 = new ActionReference();
                                          ref1.putProperty(cTID('Path'), cTID('WrPt'));
                                          desc1.putReference(sTID('null'), ref1);
                                          var list1 = new ActionList();
                                      
                                      for (var m = 0; m < theArray.length; m++) {
                                                var thisSubPath = theArray[m]; 
                                          var desc2 = new ActionDescriptor();
                                          desc2.putEnumerated(sTID('shapeOperation'), sTID('shapeOperation'), thisSubPath[thisSubPath.length - 1]);
                                          var list2 = new ActionList();
                                          var desc3 = new ActionDescriptor();
                                          desc3.putBoolean(cTID('Clsp'), thisSubPath[thisSubPath.length - 2]);
                                          var list3 = new ActionList();
                                      
                                      for (var n = 0; n < thisSubPath.length - 2; n++) {
                                                var thisPoint = thisSubPath[n];
                                      
                                          var desc4 = new ActionDescriptor();
                                          var desc5 = new ActionDescriptor();
                                          desc5.putUnitDouble(cTID('Hrzn'), cTID('#Rlt'), thisPoint[0][0]);
                                          desc5.putUnitDouble(cTID('Vrtc'), cTID('#Rlt'), thisPoint[0][1]);
                                          desc4.putObject(cTID('Anch'), cTID('Pnt '), desc5);
                                          var desc6 = new ActionDescriptor();
                                          desc6.putUnitDouble(cTID('Hrzn'), cTID('#Rlt'), thisPoint[1][0]);
                                          desc6.putUnitDouble(cTID('Vrtc'), cTID('#Rlt'), thisPoint[1][1]);
                                          desc4.putObject(cTID('Fwd '), cTID('Pnt '), desc6);
                                          var desc7 = new ActionDescriptor();
                                          desc7.putUnitDouble(cTID('Hrzn'), cTID('#Rlt'), thisPoint[2][0]);
                                          desc7.putUnitDouble(cTID('Vrtc'), cTID('#Rlt'), thisPoint[2][1]);
                                          desc4.putObject(cTID('Bwd '), cTID('Pnt '), desc7);
                                          desc4.putBoolean(cTID('Smoo'), thisPoint[3]);
                                          list3.putObject(cTID('Pthp'), desc4);
                                      
                                                };
                                      
                                          desc3.putList(cTID('Pts '), list3);
                                          list2.putObject(cTID('Sbpl'), desc3);
                                          desc2.putList(cTID('SbpL'), list2);
                                          list1.putObject(cTID('PaCm'), desc2);
                                                };
                                      
                                          desc1.putList(cTID('T   '), list1);
                                          executeAction(cTID('setd'), desc1, DialogModes.NO);
                                      
                                      
                                      if (hasVectorMask() == false) {
                                      var myPathItem = app.activeDocument.pathItems[app.activeDocument.pathItems.length - 1];
                                      }
                                      else {
                                      var myPathItem = app.activeDocument.pathItems[app.activeDocument.pathItems.length - 2];
                                      };
                                      myPathItem.name = thePathsName;
                                      app.preferences.rulerUnits = originalRulerUnits;
                                      return myPathItem
                                      };
                                      // from »Flatten All Masks.jsx« by jeffrey tranberry;
                                      ///////////////////////////////////////////////////////////////////////////////
                                      // Function: hasVectorMask
                                      // Usage: see if there is a vector layer mask
                                      // Input: <none> Must have an open document
                                      // Return: true if there is a vector mask
                                      ///////////////////////////////////////////////////////////////////////////////
                                      function hasVectorMask() {
                                                var hasVectorMask = false;
                                                try {
                                                          var ref = new ActionReference();
                                                          var keyVectorMaskEnabled = app.stringIDToTypeID( 'vectorMask' );
                                                          var keyKind = app.charIDToTypeID( 'Knd ' );
                                                          ref.putEnumerated( app.charIDToTypeID( 'Path' ), app.charIDToTypeID( 'Ordn' ), keyVectorMaskEnabled );
                                                          var desc = executeActionGet( ref );
                                                          if ( desc.hasKey( keyKind ) ) {
                                                                    var kindValue = desc.getEnumerationValue( keyKind );
                                                                    if (kindValue == keyVectorMaskEnabled) {
                                                                              hasVectorMask = true;
                                                                    }
                                                          }
                                                }catch(e) {
                                                          hasVectorMask = false;
                                                }
                                                return hasVectorMask;
                                      };
                                      function fillPathWhite () {
                                      // =======================================================
                                      var idRset = charIDToTypeID( "Rset" );
                                          var desc8 = new ActionDescriptor();
                                          var idnull = charIDToTypeID( "null" );
                                              var ref6 = new ActionReference();
                                              var idClr = charIDToTypeID( "Clr " );
                                              var idClrs = charIDToTypeID( "Clrs" );
                                              ref6.putProperty( idClr, idClrs );
                                          desc8.putReference( idnull, ref6 );
                                      executeAction( idRset, desc8, DialogModes.NO );
                                      
                                      
                                      // =======================================================
                                      var idExch = charIDToTypeID( "Exch" );
                                          var desc9 = new ActionDescriptor();
                                          var idnull = charIDToTypeID( "null" );
                                              var ref7 = new ActionReference();
                                              var idClr = charIDToTypeID( "Clr " );
                                              var idClrs = charIDToTypeID( "Clrs" );
                                              ref7.putProperty( idClr, idClrs );
                                          desc9.putReference( idnull, ref7 );
                                      executeAction( idExch, desc9, DialogModes.NO );
                                      
                                      
                                      // =======================================================
                                      var idFl = charIDToTypeID( "Fl  " );
                                          var desc10 = new ActionDescriptor();
                                          var idnull = charIDToTypeID( "null" );
                                              var ref8 = new ActionReference();
                                              var idPath = charIDToTypeID( "Path" );
                                              var idOrdn = charIDToTypeID( "Ordn" );
                                              var idTrgt = charIDToTypeID( "Trgt" );
                                              ref8.putEnumerated( idPath, idOrdn, idTrgt );
                                          desc10.putReference( idnull, ref8 );
                                          var idWhPt = charIDToTypeID( "WhPt" );
                                          desc10.putBoolean( idWhPt, true );
                                      executeAction( idFl, desc10, DialogModes.NO );
                                      };
                                      //
                                      
                                      • 17. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                        Evgeny_Trefilov Level 2

                                        I have created plugin for this

                                        feel free to use it:

                                        https://dl.dropbox.com/u/167681/ReprintMaster.plugin.zip

                                         

                                        unfortunately filters don't work in lineart mode, so you'll have to convert image to Grayscale first. but my plugin is free unlike the one you mention in startpost, and works on mac - the one mentioned is windows only )

                                        it shouldn't be a problem, just record action which converts to GS, calls my plugin and then converts back to lineart

                                         

                                        If you need to work upon RGB/CMYK - you'll have to process each channel separately, I didn't code it yet.

                                        Rough white/rough balck option will not account for diagonal pixel connections

                                         

                                        before - after

                                        https://dl.dropbox.com/u/167681/scan0329.png

                                         

                                        here's a quick demo

                                         

                                        https://dl.dropbox.com/u/167681/reprint_master_1.gif

                                        https://dl.dropbox.com/u/167681/Screen-shot-2.gif

                                         

                                         

                                         

                                        (plugin is 32bit only, going to update for CS6 soon)

                                        • 18. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                          Colin Flashman Adobe Community Professional

                                          @Evgeny_Trefilov

                                           

                                          I think we have the answer! still have to do more testing but on first inspection it appears that this is correct.

                                           

                                          The slider "black size" i've worked out, but "white size" I'm not sure.

                                           

                                          to get this to work on text with pinholes in it, the procedure appears to be run reprintmaster (with a threshold of 128, black of 70, white of 1), then invert, run reprintmaster with the same settings, then invert again.

                                           

                                          Would be great to see the script once it is ready for 64 bit too, please keep us posted.

                                           

                                          @c.pfaffenbichler

                                           

                                          I did try the javascript but found that, as you say, isn't fast, but doesn't remove a lot of the stray dots either. For example, stray dots which measure 8px wide by 2px high remain in the art because the script will only remove items under 7px AND 7px... (49 square pixels). This means that anything which has an area under 49px BUT has a width or height over 7px will be missed by the script.

                                           

                                          Thank you everyone for all the efforts for determining a solution for this issue.

                                           

                                          colly

                                          • 19. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                            c.pfaffenbichler Level 9

                                            You could edit the line that sets the 7px limit, but a proper plug-in is a better approach anyway and probably much faster.

                                            • 20. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                              Evgeny_Trefilov Level 2

                                              >The slider "black size" i've worked out, but "white size" I'm not sure.

                                              >to get this to work on text with pinholes in it, the procedure appears to be run reprintmaster (with a threshold of 128, black of 70, white of 1), then invert, run reprintmaster with >the same settings, then invert again.

                                               

                                              no need to run in 2 phases with invert - white size does exactly that. i.e. set white to 10, and it will fill white holes with size <=10 with black.

                                              • 21. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                                Colin Flashman Adobe Community Professional

                                                 

                                                no need to run in 2 phases with invert - white size does exactly that. i.e. set white to 10, and it will fill white holes with size <=10 with black.

                                                well... it's not working in my case. to demonstrate, here is a sample of some white pinholes in the E to eliminate, along with black pinholes in the white.

                                                Screen shot 2013-01-15 at 11.50.40 PM.png

                                                and here is the result

                                                Screen shot 2013-01-15 at 11.50.51 PM.png

                                                I have also tried this with 10 and to no avail. Have I missed something?

                                                 

                                                Running Photoshop CS5.1 on Mac in 32bit mode

                                                • 22. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                                  Evgeny_Trefilov Level 2

                                                  hm, could be some experimental build - I've started to improve defects on edges, but cancelled somewhere.

                                                  I have tried version I have installed on my production mac, and it works fine - here it goes

                                                  https://dl.dropbox.com/u/167681/ReprintMaster_production.plugin.zip

                                                   

                                                  (original link is corrected as well)

                                                  • 23. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                                    Evgeny_Trefilov Level 2

                                                    Here's 64bit version, as promised

                                                     

                                                    Plugin is pretty different now, I've added lots of thresholding methods (it's using OpenCV now)

                                                     

                                                    Preview is available if you run it from Automate->Threshold

                                                     

                                                    It can be run from Filter->Evgeny Trefilov->Threshold as well, but there's no preview in this case, just parameters dialog

                                                     

                                                    https://dl.dropboxusercontent.com/u/167681/Threshold.plugin.zip

                                                    • 24. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                                      Colin Flashman Adobe Community Professional

                                                      Thank you very much for that. It would certain benefit us if the how the sliders work could be explained.

                                                       

                                                      But thank you for providing a 64 bit version!

                                                       

                                                      Colin

                                                      • 26. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                                        BCuzzillo Level 1

                                                        Evgeny, Excellent work. Is it possible to port this to Windows? Thanks.

                                                        • 27. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                                          Evgeny_Trefilov Level 2

                                                          theoretically yes... biggest issue is dialogs. not sure when will I have some spare time for this though.

                                                          • 28. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                                            Evgeny_Trefilov Level 2

                                                            I just thought a bit. I have ols version for windows (32-bit) with non functioning preview and old algorithm, but usually it's pretty sufficient for main purpose.

                                                            https://dl.dropboxusercontent.com/u/167681/ReprintMaster.8bf

                                                            • 29. Re: CS5.5 (MAC) script to fix random dots in lineart scans
                                                              BCuzzillo Level 1

                                                              Evgeny_Trefilov,

                                                              Thank you. I'll try that.