A useful heuristic you might want to always keep in mind is this: when designing unit tests is hard, most of the times that's an indication of a design problem in the code you're trying to test. This turns the problem around, from a testing problem to a design problem. You can then think about design principles that might have been violated and that can indicate the general strategy to fix the situation.
As you point out, the Bulletproof class does a lot of things: uploading, cropping, resizing and watermarking. It also has to interact with the file system, the PHP environment, the HTTP context, etc. Sounds like this class is violating Uncle Bob's "Single Responsibility Principle": the idea that classes should do only one thing, or more precisely, have a single reason to change.
The solution to your problem, then, is to break apart this big class into a a bunch of smaller classes that are responsible for individual features. Those classes will be smaller and simpler to test.
For example, you could extract one class that knows how to apply a watermark, another that knows how to resize an image, etc.
To deal with external dependencies, like the file system or the HTTP context, you apply the same idea (extracting a class for each), and you define an interface (or abstract class) for those, so your other code doesn't depend directly on the implementation, but instead access it through a narrow, very specific interface. Then, in your tests you provide mocks to avoid having to deal with real files, real HTTP connections, etc.