Visualizzazione post con etichetta 2-Up Saddle Stitch. Mostra tutti i post
Visualizzazione post con etichetta 2-Up Saddle Stitch. Mostra tutti i post

venerdì 3 ottobre 2014

Background threads

Studying background threads

These days FitPlot 5.1 is under the lens of the MAS examiners to be finally (hoping) approved.
In the meantime I want to write down, so I'll remember when needed, about the try to use a background thread.



I do not like the rainbow spinning cursor in my app. The user loose its control and have just to wait the end of the operation.
This usually appears in loops (for cycles) and the only way to avoid the user to panic (and ctrl-alt-esc the program), is to show the progress of the operation with a progress bar or a with a field showing what is happening.

This is what I have tried to do in the latest added feature in imposition (see  2-Up Saddle Stitch update).


The problem

I had a - loop in a loop - situation and a progress bar showing only the inner loop.
For example, in a 120 pages imposition, the pages grouped in 12 pages booklets, I had a first for cycle (from 1 to 10) that at each loop called the imposition procedure of the first 12 pages and so on.
The imposition procedure has its own loop showing a progress bar (from 1 to 12 in this case).
What the user was seeing while running was the rainbow spinning wheel and a progress bar going from 0 to 12 for twelve times.
The user knows that the program is not idle, but he does not have idea unless it counts the number of times the progress bar reaches the end.
So first idea was to couple the progress bar with a field showing the first loop cycle value (1/12 to 12/12 in this case).
I prepared the NIB, the necessary outlet was connected, program ok, but the field does not changed until the end of the loop taking suddenly the 12/12 value. Why?
NSLog testified that the values was changing in the loop but the field value was not updated until the end.


The answer

A search on the web led me to this discussion:

http://stackoverflow.com/questions/343088/nstextview-not-updating-in-a-loop-while-writing-to-a-usb-device

Where Chris Hanson answered textually:
"Mac OS X does not flush changes to views to the screen immediately, to avoid the flicker and tearing that's common in such situations. This means you can't just sit in a loop and perform blocking operations while you update a view; if you do this, neither the view nor anything else in your application's human interface will update, and your application will appear hung and eventually get the spinning cursor."

That was the problem! The next step was to use a background thread (as suggested) while updating the field on the main thread.


Implementation

Implementation of background threads it is straightforward:


            __block BOOL redraw = NO;

            dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                
                for (int i = 0; i < numeroCicli; i++)
                {
                    // Update the text field on the main queue
                    dispatch_async(dispatch_get_main_queue(), ^{
                    //Code here to which needs to update the UI in the UI thread goes here
                    [progressFiled setStringValue setStringValue: [NSString stringWithFormat:@"%i / %i",i+1, numeroCicli];

                    });
                    
                  
                    [self impose:sender
                             pdf:elem
                   startingFromY:newImpoSize.height*i*[groupImpo selectedTag]/[pagineFormatoImpo selectedTag]*2
                          redraw:redraw];
                    
                    //NSLog(@"giro %i di %i, da: %i a: %i", i, (int)numeroCicli, (int)[rangeImpoDa integerValue], (int)[rangeImpoA integerValue]);
                }
            });

Put your loop in the bracketed block, leave a dispatch in the main queue to update the field in the same bracketed way. Just remember to  __block needed variables declared outside the block and it is done.


Results

The result is that the spinning rainbow cursor disappear, the field is updated and the user maintains the control throughout all the time of the operation.


What? Has he the control?
Yes!
Can he change, move, delete objects?
Yes! What's wrong?
What's wrong? He can delete an object while another thread is using this same object!
This is utterly dangerous!


And the winner is…

At the end I learned a new powerful programming technique I didn't know, but I am not using it.
Instead I have, for this particular doble loop case, two independent progress bar, the first counting the cycles in the first loop and the second one for the second loop.
NSProgressBar bar are updated regularly while in a loop, where NSTextField is not.

You will see it in FitPlot 5.1.0, soon, I hope.


venerdì 26 settembre 2014

2-Up Saddle Stitch update

FitPlot 5.1

2-Up Saddle Stitch

Think about a 100 pages PDF: you are able to use the 2-up Saddle imposition, then print front / back the result, but, when you goes to stitch, you realise that the pages thickness is too much to bend and stitch.
The user who suggest me to find a solution, had 991 pages to print grouped in booklets by 24 pages (to give to the bookbinder), so a solution had to be found…
Reverse page order

Technically speaking, the imposition is done by few actions / procedures:
Reverse page order
2-Up Saddle Stitch is an imposition mode that is present in FitPlot since the first imposition implementation (FitPlot 2.5, 2008-05-31).
It has remained unchanged until now, when, on a user suggestion, I have introduced the option to group the imposition in groups (booklets).


Of course, there has always been the possibility to impose from page 1 to page X then from page X to Y … and then from Z to the end, but…



- (IBAction) checkImpo:(id) sender
has the task to control the user input in the imposition dialog. Based on user input, checkImpo  calculates the number of empty pages to add (to complete the 24 pages booklet, in this case), to show the number of sheets needed etc.


- (IBAction) imposition:(id)sender
When Confirm is pressed, imposition is called. It is an intermediate action to leave things that worked unchanged (2-Up Perfect Bound and 2-Up Saddle Stitch with a sigle booklet as it was before).
The two old modes (just above mentioned) are then sent to the old action impose: (see below) while the 2-Up Saddle Stitch with booklet splitting has to enter a loop and at each cycle it calls impose: changing the Y (multiplying by the page vertical size).

- (IBAction) impose:(id) sender pdf:(FP_Image*) elem startingFromY:(float) Y

It works! Few changes in a well structured IBAction allowed to easily implement such useful new feature (and make happy Mr. Franco!).
The only problem, still unresolved, is that 991 pages means 41 loops of impose: and it is a pain to arrive at an end. Each impose: has its own undoManager and this cause a RAM and CPU payment in terms of process time.
But it works and, thanks to the 64 bit architecture, it doesn't crash (at least in my tests), just take a coffee while waiting.

Reverse page order

Asked from a friend from Pakistan, in its FitPlot customer review, it has been easy to introduce a reverse page order check box.

- (void) imponi: (NSInteger) sinistra
         destra: (NSInteger) destra
           dove: (NSPoint) quadrante
       centrato: (NSPoint) centro
     daElemento: (FP_Image*) elemento
   conRotazione: (BOOL) rotazione
    perLePagine: (NSRange) pagineEsistenti
     inversione:(BOOL)inverti

Just introduced the inversione:(BOOL)inverti variable in the core of the imposition task and the reversion is obtained.
For what I understand, inversion means that the last page become first and so all other pager are exchanged symmetrically, obtained by the following simple function:

- (NSInteger) inverti:(NSInteger) numero specchia:(BOOL)specchia da:(int)impoDa a:(int)impoA
{
    if (!specchia)
        return numero;
    
    return impoDa-1+impoA-1-numero;
}

I just need a confirmation that what I have done is right. The request was the following:
Arabic or Right hand book support - I think this is an affordable alternate to Imposition Studio. It lacks just right to left books support. Shibli313