#ifndef tools_toojpeg
#define tools_toojpeg

// G.Barrand: pure header version of toojpeg found at https://github.com/stbrumme/toojpeg
//            The original namespace TooJpeg had been changed to tools::toojpeg to avoid
//            clashes with potential other usage of toojpeg within the same software.

/*
zlib License

Copyright (c) 2011-2016 Stephan Brumme

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
   If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/

// //////////////////////////////////////////////////////////
// toojpeg.h
// written by Stephan Brumme, 2018-2019
// see https://create.stephan-brumme.com/toojpeg/
//

// This is a compact baseline JPEG/JFIF writer, written in C++ (but looks like C for the most part).
// Its interface has only one function: writeJpeg() - and that's it !

namespace tools {
namespace toojpeg
{
  // write one byte (to disk, memory, ...)
  typedef void (*WRITE_ONE_BYTE)(unsigned char,void*);
  // this callback is called for every byte generated by the encoder and behaves similar to fputc
  // if you prefer stylish C++11 syntax then it can be a lambda, too:
  // auto myOutput = [](unsigned char oneByte) { fputc(oneByte, output); };

  // output       - callback that stores a single byte (writes to disk, memory, ...)
  // pixels       - stored in RGB format or grayscale, stored from upper-left to lower-right
  // width,height - image size
  // isRGB        - true if RGB format (3 bytes per pixel); false if grayscale (1 byte per pixel)
  // quality      - between 1 (worst) and 100 (best)
  // downsample   - if true then YCbCr 4:2:0 format is used (smaller size, minor quality loss) instead of 4:4:4, not relevant for grayscale
  // comment      - optional JPEG comment (0/NULL if no comment), must not contain ASCII code 0xFF
  bool writeJpeg(WRITE_ONE_BYTE output,void*, const void* pixels, unsigned short width, unsigned short height,
                 bool isRGB = true, unsigned char quality = 90, bool downsample = false, const char* comment = 0/*nullptr*/);
}}

// My main inspiration was Jon Olick's Minimalistic JPEG writer
// ( https://www.jonolick.com/code.html => direct link is https://www.jonolick.com/uploads/7/9/2/1/7921194/jo_jpeg.cpp ).
// However, his code documentation is quite sparse - probably because it wasn't written from scratch and is (quote:) "based on a javascript jpeg writer",
// most likely Andreas Ritter's code: https://github.com/eugeneware/jpeg-js/blob/master/lib/encoder.js
//
// Therefore I wrote the whole lib from scratch and tried hard to add tons of comments to my code, especially describing where all those magic numbers come from.
// And I managed to remove the need for any external includes ...
// yes, that's right: my library has no (!) includes at all, not even #include <stdlib.h>
// Depending on your callback WRITE_ONE_BYTE, the library writes either to disk, or in-memory, or wherever you wish.
// Moreover, no dynamic memory allocations are performed, just a few bytes on the stack.
//
// In contrast to Jon's code, compression can be significantly improved in many use cases:
// a) grayscale JPEG images need just a single Y channel, no need to save the superfluous Cb + Cr channels
// b) YCbCr 4:2:0 downsampling is often about 20% more efficient (=smaller) than the default YCbCr 4:4:4 with only little visual loss
//
// TooJpeg 1.2+ compresses about twice as fast as jo_jpeg (and about half as fast as libjpeg-turbo).
// A few benchmark numbers can be found on my website https://create.stephan-brumme.com/toojpeg/#benchmark
//
// Last but not least you can optionally add a JPEG comment.
//
// Your C++ compiler needs to support a reasonable subset of C++11 (g++ 4.7 or Visual C++ 2013 are sufficient).
// I haven't tested the code on big-endian systems or anything that smells like an apple.
//
// USE AT YOUR OWN RISK. Because you are a brave soul :-)

#include "toojpeg.icc"

//G.Barrand specific:

#include "sout"

#include <cstdio>
#include <ostream>

namespace tools {
namespace toojpeg {

inline void write_one_byte(unsigned char a_byte,void* a_tag) {::fputc(a_byte,(FILE*)a_tag);}

inline bool write(std::ostream& a_out,
                  const std::string& a_file,
                  unsigned char* a_buffer,
                  unsigned int a_width,
                  unsigned int a_height,
                  unsigned int a_bpp,
                  int a_quality) {
  if(a_bpp!=3) {
    a_out << "tools::toojpeg::write : bpp " << a_bpp << " not handled." << std::endl;
    return false;
  }		  
  FILE* file = ::fopen(a_file.c_str(),"wb");
  if(!file) {
    a_out << "tools::toojpeg::write : can't open file " << sout(a_file) << "." << std::endl;
    return false;
  }
  if(!writeJpeg(write_one_byte,file,a_buffer,(unsigned short)a_width,(unsigned short)a_height,true,(unsigned char)a_quality)) {
    ::fclose(file);
    a_out << "tools::toojpeg::write : writeJpeg failed for file " << sout(a_file) << "." << std::endl;
    return false;
  }
  ::fclose(file);
  return true;
}

}}

#endif
