text: // Copyright 2018 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include <fuchsia/ui/scenic/cpp/fidl.h>
  #include <lib/async-loop/cpp/loop.h>
  #include <trace-provider/provider.h>
  
  #include <cstdlib>
  #include <iostream>
  #include <memory>
  
  #include "lib/component/cpp/startup_context.h"
  #include "lib/fsl/vmo/vector.h"
  #include "src/lib/fxl/command_line.h"
  #include "src/lib/fxl/log_settings_command_line.h"
  #include "src/lib/fxl/logging.h"
  
  class ScreenshotTaker {
   public:
    explicit ScreenshotTaker(async::Loop* loop)
        : loop_(loop), context_(component::StartupContext::CreateFromStartupInfo()) {
      // Connect to the Scenic service.
      scenic_ = context_->ConnectToEnvironmentService<fuchsia::ui::scenic::Scenic>();
      scenic_.set_error_handler([this](zx_status_t status) {
        FXL_LOG(ERROR) << "Lost connection to Scenic service.";
        encountered_error_ = true;
        loop_->Quit();
      });
    }
  
    bool encountered_error() const { return encountered_error_; }
  
    void TakeScreenshot() {
      FXL_LOG(INFO) << "start TakeScreenshot";
      // If we wait for a call back from GetDisplayInfo, we are guaranteed that
      // the GFX system is initialized, which is a prerequisite for taking a
      // screenshot. TODO(SCN-678): Remove call to GetDisplayInfo once bug done.
      scenic_->GetDisplayInfo(
          [this](fuchsia::ui::gfx::DisplayInfo /*unused*/) { TakeScreenshotInternal(); });
    }
  
   private:
    void TakeScreenshotInternal() {
      FXL_LOG(INFO) << "start TakeScreenshotInternal";
      scenic_->TakeScreenshot([this](fuchsia::ui::scenic::ScreenshotData screenshot, bool status) {
        FXL_LOG(INFO) << "start pixel capture";
        std::vector<uint8_t> imgdata;
        if (!status || !fsl::VectorFromVmo(screenshot.data, &imgdata)) {
          FXL_LOG(ERROR) << "TakeScreenshot failed";
          encountered_error_ = true;
          loop_->Quit();
          return;
        }
  
        std::cout << "P6\n";
        std::cout << screenshot.info.width << "\n";
        std::cout << screenshot.info.height << "\n";
        std::cout << 255 << "\n";
  
        FXL_LOG(INFO) << "capturing pixels";
        const uint8_t* pchannel = &imgdata[0];
        for (uint32_t pixel = 0; pixel < screenshot.info.width * screenshot.info.height; pixel++) {
          uint8_t rgb[] = {pchannel[2], pchannel[1], pchannel[0]};
          std::cout.write(reinterpret_cast<const char*>(rgb), 3);
          pchannel += 4;
        }
        loop_->Quit();
      });
    }
    async::Loop* loop_;
    std::unique_ptr<component::StartupContext> context_;
    bool encountered_error_ = false;
    fuchsia::ui::scenic::ScenicPtr scenic_;
  };
  
  int main(int argc, const char** argv) {
    FXL_LOG(INFO) << "starting screen capture";
    auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
    if (!fxl::SetLogSettingsFromCommandLine(command_line))
      return 1;
  
    if (!command_line.positional_args().empty()) {
      FXL_LOG(ERROR) << "Usage: screencap\n"
                     << "Takes a screenshot in PPM format and writes it "
                     << "to stdout.\n"
                     << "To write to a file, redirect stdout, e.g.: "
                     << "screencap > \"${DST}\"";
      return 1;
    }
  
    async::Loop loop(&kAsyncLoopConfigAttachToThread);
    trace::TraceProviderWithFdio trace_provider(loop.dispatcher());
  
    ScreenshotTaker taker(&loop);
    taker.TakeScreenshot();
    loop.Run();
  
    return taker.encountered_error() ? EXIT_FAILURE : EXIT_SUCCESS;
  }
  