[
  {
    "path": ".gitignore",
    "content": ".DS_Store\napplet\napplication.linux32\napplication.linux64\napplication.windows32\napplication.windows64\napplication.macosx\n*.glic\n*.bak\n*.*~\n*.jpg\n*.jpeg\n*.png\n\n"
  },
  {
    "path": "GLIC.pde",
    "content": "// GLIC - GLitch Image Codec, ready for databending\n\n//////////////////// Config\n\n// Hidden stuff (not in GUI)\n\n// Press CTRL-Y to encode image with all presets\n// Press CTRL-I to iterate [encoding -> keep image...] `iterate_count` times.\nint iterate_count = 5;\n\n// batch stuff\nimport java.util.ArrayList.*;\nimport java.io.*;\nimport java.io.File;\nint curFrame=0;\nboolean isBatch = false;\nString filenames[];\njava.io.FilenameFilter extfilter = new java.io.FilenameFilter() {\n  boolean accept(File dir, String name) {\n    if (name.toLowerCase().endsWith(\"png\") || name.toLowerCase().endsWith(\"jpeg\")\n      || name.toLowerCase().endsWith(\"jpg\") || name.toLowerCase().endsWith(\"bmp\")) return true;\n    else return false;\n  }\n}; \njava.io.FilenameFilter glicfilter = new java.io.FilenameFilter() {\n  boolean accept(File dir, String name) {\n    if (name.toLowerCase().endsWith(\"glic\")) return true;\n    else return false;\n  }\n}; \n\n\nString filename;\nString fileext;\nString foldername = \".\"+File.separator;\nString session_id;\n\n////// size of windows\nfinal static int max_display_size = 750;\n\n//////\nPImage img, result, isegm, ipred;\nString origname;\n\nPImage current;\nint neww, newh, posx=0, posy=0;\nPGraphics buffer;\n\nvoid setup() {\n  size(750, 750);\n  smooth(8);\n  frameRate(20);\n\n  //  img = loadImage(\"face.jpg\");\n  //  \n  //  buffer=createGraphics(img.width,img.height);\n  //  neww=img.width;\n  //  newh=img.height;\n  //  result = encode(img,\"faa.glic\");\n  //  current = result;\n\n  gui();\n\n  println();\n  println(\"Press TAB to hide/show GUI\");\n  println(\"Press CTRL-L to load image\");\n  println(\"Press CTRL-E to encode image\");\n  println(\"Press CTRL-D to decode image\");\n  println(\"Press CTRL-S to save image\");\n  println(\"Press CTRL-Y to apply all presets\");\n  println();\n  println(\"Presets provided by: Myrto, Saturn Kat, Letsglitchit, Vivi, NoNoNoNoNo, Pandy Chan, GenerateMe, Jay Di, José Irion Neto.\");\n  println();\n}\n\nvoid draw() {\n  background(0);\n  if (buffer != null && !resetting_buffer) {\n    image(buffer, posx, posy, neww, newh);\n  }\n}\n\nboolean isCtrlPressed = false;\n\nvoid keyPressed() {\n  if (keyCode == TAB) {\n    if (cp5.isVisible()) {\n      cp5.hide();\n    } else {\n      cp5.show();\n    }\n  } else if (keyCode == CONTROL && isCtrlPressed == false)\n    isCtrlPressed = true;\n  else if (isCtrlPressed) {    \n    if (char(keyCode) == 'S') {\n      save_button();\n    } else if (char(keyCode) == 'L') {\n      load_button();\n    } else if (char(keyCode) == 'D') {\n      decode_button();\n    } else if (char(keyCode) == 'E') {\n      encode_button();\n    } else if (char(keyCode) == 'I') {\n      println(\"***** ITERATING ENCODING \" + iterate_count + \" times!\");\n      println(\"be patient\");\n      for (int i=0; i<iterate_count; i++) {\n        println(\"----------> Iteration number: \"+i+\"/\"+iterate_count);\n        encode_button();\n        keep_image();\n      }\n    } else if (char(keyCode) == 'Y') {\n      if (img != null) {\n        for (int i=0; i<presets_count; i++) {\n          presets(i);\n          if(isBatch) {\n            readValues();\n            encode_batch(true);\n          } else {\n            encode_button();\n            save_buffer(current_preset);\n          }\n        }\n      }\n    }\n  }\n}\n\nvoid keyReleased() {\n  if (keyCode == CONTROL) isCtrlPressed = false;\n}\n\r\n"
  },
  {
    "path": "GUI.pde",
    "content": "import controlP5.*;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nControlP5 cp5;\n\nCheckBox separate_channels;\nCheckBox batch, skip_header, skip_session;\nTab ch1, ch2, ch3;\n\nController ch1mn, ch1mx, ch2mn, ch2mx, ch3mn, ch3mx;\nSlider co_r, co_g, co_b;\nScrollableList sl_cs, presets_list;\n\nButton lbutton, ebutton, dbutton;\nButtonBar bbar;\n\nTextfield save_filename, glic_filename, preset_name;\n\nString[] bbar_names = new String[] {\n  \"Image\", \"Segm\", \"Pred\", \"Result\"\n};\n\nHashMap<String, ControllerInterface>[] chmap = new HashMap[3];\n\nboolean separate_channels_toggle = false;\nboolean do_skip_session = false;\n\nint presets_count = 0;\nString current_preset = null;\n\nSimpleDateFormat sdf = new SimpleDateFormat(\"yyyyMMddHHmmss\");\n\nvoid gui() {\n  cp5 = new ControlP5(this);\n\n  Tab global = cp5.getTab(\"default\").setLabel(\"Global config\");\n\n  ch1 = cp5.addTab(\"Channel 1\").setLabel(\"All channels\");\n  ch2 = cp5.addTab(\"Channel 2\").setVisible(false);\n  ch3 = cp5.addTab(\"Channel 3\").setVisible(false);\n\n  cp5.addLabel(\"color_outside_label\")\n    .setText(\"Color outside\")\n      .setPosition(10, 150)\n        .moveTo(global);\n\n  co_r = cp5.addSlider(\"R\")\n    .setPosition(10, 160)\n      .setWidth(170)\n        .setRange(0, 255)\n          .setValue(128)\n            .setScrollSensitivity(0.02)\n              .moveTo(global);\n\n  co_g = cp5.addSlider(\"G\")\n    .setPosition(10, 170)\n      .setWidth(170)\n        .setRange(0, 255)\n          .setValue(128)\n            .setScrollSensitivity(0.02)\n              .moveTo(global);\n\n  co_b = cp5.addSlider(\"B\")\n    .setPosition(10, 180)\n      .setWidth(170)\n        .setRange(0, 255)\n          .setValue(128)\n            .setScrollSensitivity(0.02)\n              .moveTo(global);\n\n  separate_channels = cp5.addCheckBox(\"separate_channels\")\n    .setPosition(10, 200)\n      .addItem(\"Separate channels\", 1)\n        .deactivate(0)\n          .moveTo(global);\n\n  batch = cp5.addCheckBox(\"batch\")\n    .setPosition(110, 200)\n      .addItem(\"Batch run\", 1)\n        .deactivate(0)\n          .moveTo(global);\n\n  sl_cs = cp5.addScrollableList(\"Color space\")\n    .setType(ScrollableList.LIST)\n      .setPosition(10, 20)\n        .setSize(180, 120)\n          .moveTo(global);\n\n  for (int i=0; i<COLORSPACES; i++) {\n    sl_cs.addItem(getColorspaceName(i), i);\n  }\n\n  sl_cs.getItem(1).put(\"state\", true);\n  sl_cs.setValue(1);\n\n  lbutton = cp5.addButton(\"load_button\")\n    .setPosition(10, 220)\n      .setSize(120, 20)\n        .setLabel(\"LOAD IMAGE (ctrl-l)\")\n          .moveTo(global);\n\n  cp5.addButton(\"reload_image\")\n    .setPosition(140, 220)\n      .setSize(50, 20)\n        .setLabel(\"RELOAD\")\n          .moveTo(global);          \n\n  ebutton = cp5.addButton(\"encode_button\")\n    .setPosition(10, 250)\n      .setSize(180, 20)\n        .setLabel(\"ENCODE (ctrl-e)\")\n          .moveTo(global);\n\n  skip_header = cp5.addCheckBox(\"skip_header\")\n    .setPosition(10, 280)\n      .addItem(\"Use config during decoding (skip header)\", 1)\n        .deactivate(0)\n          .moveTo(global);\n\n  dbutton = cp5.addButton(\"decode_button\")\n    .setPosition(10, 290)\n      .setSize(180, 20)\n        .setLabel(\"DECODE (ctrl-d)\")\n          .moveTo(global);\n\n  cp5.addButton(\"save_button\")\n    .setPosition(10, 320)\n      .setSize(180, 20)\n        .setLabel(\"SAVE RESULT (ctrl-s)\")\n          .moveTo(global);\n\n  save_filename = cp5.addTextfield(\"Save filename\")\n    .setPosition(10, 350)\n      .setWidth(180)\n        .setAutoClear(false)\n          .moveTo(global);\n\n  glic_filename = cp5.addTextfield(\"GLIC filename\")\n    .setPosition(10, 390)\n      .setWidth(180)\n        .setAutoClear(false)\n          .moveTo(global);\n\n  skip_session = cp5.addCheckBox(\"skip_session\")\n    .setPosition(10, 430)\n      .addItem(\"Skip generating session id\", 1)\n        .deactivate(0)\n          .moveTo(global);\n\n  bbar = cp5.addButtonBar(\"image_switch\")\n    .setPosition(10, 450)\n      .setWidth(180)\n        .addItems(bbar_names)\n          .moveTo(global);\n\n  cp5.addButton(\"keep_image\")\n    .setPosition(10, 470)\n      .setWidth(180)\n        .setLabel(\"KEEP IMAGE\")\n          .moveTo(global);\n\n  cp5.addLabel(\"presets_label\")\n    .setText(\"Presets\")\n      .setPosition(10, 500)\n        .moveTo(global);\n\n  presets_list = cp5.addScrollableList(\"presets\")\n    .setType(ScrollableList.LIST)\n      .setPosition(10, 510)\n        .setSize(180, 120)\n          .moveTo(global);\n\n  updatePresets();\n\n  preset_name = cp5.addTextfield(\"Preset name\")\n    .setPosition(10, 650)\n      .setWidth(180)\n        .setAutoClear(false)\n          .moveTo(global);  \n\n  cp5.addButton(\"save_preset\")\n    .setPosition(10, 690)\n      .setSize(180, 20)\n        .setLabel(\"SAVE PRESET\")\n          .moveTo(global);\n\n  chmap[0] = addToTab(ch1);\n  chmap[1] = addToTab(ch2);\n  chmap[2] = addToTab(ch3);\n\n  ch1mn = cp5.getController(ch1.getName() + \"min\");\n  ch1mx = cp5.getController(ch1.getName() + \"max\");\n  ch2mn = cp5.getController(ch2.getName() + \"min\");\n  ch2mx = cp5.getController(ch2.getName() + \"max\");\n  ch3mn = cp5.getController(ch3.getName() + \"min\");\n  ch3mx = cp5.getController(ch3.getName() + \"max\");\n}\n\nHashMap<String, ControllerInterface> addToTab(Tab t) {\n  HashMap<String, ControllerInterface> h = new HashMap<String, ControllerInterface>();\n\n  cp5.addLabel(t.getName() + \"segmentation_label\")\n    .setText(\"Segmentation, min/max are powers of 2\")\n      .setPosition(10, 20)\n        .moveTo(t);\n\n  Slider mn_blocksize = cp5.addSlider(t.getName() + \"min\")\n    .setLabel(\"MIN\")\n      .setPosition(10, 30)\n        .setWidth(160)\n          .setRange(1, 9)\n            .setNumberOfTickMarks(9)\n              .showTickMarks(false)\n                .setValue(2)\n                  .moveTo(t);  \n\n  h.put(\"min\", mn_blocksize);\n\n  Slider mx_blocksize = cp5.addSlider(t.getName() + \"max\")\n    .setLabel(\"MAX\")\n      .setPosition(10, 40)\n        .setWidth(160)\n          .setRange(1, 9)\n            .setNumberOfTickMarks(9)\n              .showTickMarks(false)\n                .setValue(8)\n                  .moveTo(t);\n\n  h.put(\"max\", mx_blocksize);\n\n  Slider thr_block = cp5.addSlider(t.getName() + \"thr\")\n    .setLabel(\"THR\")\n      .setPosition(10, 50)\n        .setWidth(160)\n          .setRange(5, 250)\n            .setValue(15)\n              .setScrollSensitivity(0.02)\n                .moveTo(t);\n\n  h.put(\"thr\", thr_block);\n\n  ScrollableList pred = cp5.addScrollableList(t.getName() + \"pred\")\n    .setLabel(\"Predictions\")\n      .setType(ScrollableList.LIST)\n        .setPosition(10, 70)\n          .setSize(180, 120)\n            .moveTo(t);\n\n  h.put(\"pred\", pred);\n\n  for (int i=0; i<MAX_PRED; i++) {\n    pred.addItem(predict_name(i), i);\n  }\n  pred.addItem(predict_name(-1), -1);\n  pred.addItem(predict_name(-2), -2);\n  pred.addItem(predict_name(-3), -3);\n\n  pred.getItem(7).put(\"state\", true);\n  pred.setValue(7);\n\n  cp5.addLabel(t.getName()+\"quantization_label\")\n    .setText(\"Quantization value\")\n      .setPosition(10, 200)\n        .moveTo(t);\n\n  Slider quant = cp5.addSlider(t.getName() + \"quant\")\n    .setLabel(\"\")\n      .setPosition(10, 210)\n        .setWidth(180)\n          .setRange(0, 255)\n            .setValue(0)\n              .setScrollSensitivity(0.02)\n                .moveTo(t);\n\n  h.put(\"quant\", quant);\n\n  RadioButton clamp = cp5.addRadioButton(t.getName() + \"clamp\")\n    .setPosition(10, 230)\n      .addItem(t.getName() + \"CLAMP_NONE\", CLAMP_NONE)\n        .addItem(t.getName() + \"CLAMP_MOD256\", CLAMP_MOD256)\n          .activate(0)\n            .moveTo(t);\n\n  clamp.getItem(0).setLabel(\"CLAMP_NONE\");\n  clamp.getItem(1).setLabel(\"CLAMP_MOD256\");\n\n  h.put(\"clamp\", clamp);\n\n  ScrollableList trans = cp5.addScrollableList(t.getName() + \"trans\")\n    .setLabel(\"Wavelet\")\n      .setType(ScrollableList.LIST)\n        .setPosition(10, 260)\n          .setSize(180, 120)\n            .moveTo(t);\n\n  h.put(\"trans\", trans);\n\n  trans.addItem(\"NONE\", 0);\n  for (int i=1; i<WAVELETNO; i++) {\n    trans.addItem(getWavelet(i).getName(), i);\n  }\n  trans.addItem(\"RANDOM\", -1);\n\n  trans.getItem(0).put(\"state\", true);\n  trans.setValue(0);\n\n  cp5.addLabel(t.getName() + \"compression_label\")\n    .setText(\"Compression\")\n      .setPosition(10, 390)\n        .moveTo(t);\n\n  Slider compress = cp5.addSlider(t.getName() + \"compress\")\n    .setLabel(\"\")\n      .setPosition(10, 400)\n        .setWidth(180)\n          .setRange(0, 255)\n            .setValue(0)\n              .setScrollSensitivity(0.02)\n                .moveTo(t);\n\n  h.put(\"compress\", compress);\n\n  cp5.addLabel(t.getName() + \"scaler_label\")\n    .setText(\"Scale transformation (2^x)\")\n      .setPosition(10, 420)\n        .moveTo(t);\n\n  Slider scaler = cp5.addSlider(t.getName() + \"scale\")\n    .setLabel(\"\")\n      .setPosition(10, 430)\n        .setWidth(180)\n          .setRange(2, 24)\n            .setValue(20)\n              .setScrollSensitivity(0.02)\n                .moveTo(t);\n\n  h.put(\"scale\", scaler);\n\n  RadioButton ttype = cp5.addRadioButton(t.getName() + \"ttype\")\n    .setPosition(10, 450)\n      .addItem(t.getName()+\"TRANSTYPE_FWT\", TRANSTYPE_FWT)\n        .addItem(t.getName()+\"TRANSTYPE_WPT\", TRANSTYPE_WPT)\n          .addItem(t.getName()+\"TRANSTYPE_RANDOM\", -1)\n            .activate(0)\n              .moveTo(t);\n\n  ttype.getItem(0).setLabel(\"TRANSTYPE_FWT\");\n  ttype.getItem(1).setLabel(\"TRANSTYPE_WPT\");\n  ttype.getItem(2).setLabel(\"TRANSTYPE_RANDOM\");\n\n  h.put(\"transtype\", ttype);\n\n  ScrollableList encoding = cp5.addScrollableList(t.getName() + \"encoding\")\n    .setLabel(\"Final encoding\")\n      .setType(ScrollableList.LIST)\n        .setPosition(10, 490)\n          .setSize(180, 100)\n            .moveTo(t);\n\n  h.put(\"encoding\", encoding);\n\n  for (int i=0; i<ENCODINGNO; i++) {\n    encoding.addItem(encoding_name(i), i);\n  }\n\n  encoding.getItem(1).put(\"state\", true);\n  encoding.setValue(1);\n\n  return h;\n}\n\nvoid image_switch(int v) {\n  switch(v) {\n  case 0: \n    current = img;\n    break;\n  case 1: \n    current = isegm; \n    break;\n  case 2: \n    current = ipred; \n    break;\n  case 3: \n    current = result; \n    break;\n  }\n  reset_buffer();\n}\n\nvoid presets(int i) {\n  current_preset = (String)presets_list.getItem(i).get(\"text\");\n  try {\n    println(\"Loading preset: \" + current_preset);\n    ObjectInputStream ois = new ObjectInputStream(createInput(\"presets\"+File.separator+current_preset));\n    HashMap<String, Object> map = (HashMap)ois.readObject();\n    fromHashMap(map);\n    ois.close();\n  } \n  catch (IOException e) {\n    println(\"Failed to load preset: \" + current_preset);\n    current_preset = null;\n  } \n  catch (ClassNotFoundException e) {\n    println(\"Failed to load preset: \" + current_preset);\n    current_preset = null;\n  }\n}\n\nvoid save_preset() {\n  String s = preset_name.getText();\n  if (s != null && !s.trim().isEmpty()) {\n    try {\n      println(\"Saving preset: \" + s);\n      ObjectOutputStream oos = new ObjectOutputStream(createOutput(\"presets\"+File.separator+s.toLowerCase()));\n      oos.writeObject(toHashMap());\n      oos.close();\n    } \n    catch (IOException e) {\n      println(\"Failed to save preset: \" + s);\n    }\n  }\n  updatePresets();\n}\n\nvoid updatePresets() {\n  String[] filenames;\n  println(\"Loading presets\");\n  java.io.File folder = new java.io.File(sketchPath(\"presets\"));\n  filenames = folder.list();\n  if (filenames != null) {\n    presets_list.clear(); \n    for (String s : sort (filenames)) {\n      presets_list.addItem(s, s);\n    }\n  }\n  presets_count = filenames.length;\n}\n\nvoid readValues() {\n  ccfg.colorspace = (int)sl_cs.getValue();\n  ccfg.color_outside = color(co_r.getValue(), co_g.getValue(), co_b.getValue());\n\n  for (int p=0; p<3; p++) {\n    HashMap<String, ControllerInterface> map = separate_channels_toggle ? chmap[p] : chmap[0];\n\n    ccfg.min_block_size[p] = 1<<(int)map.get(\"min\").getValue();\n    ccfg.max_block_size[p] = 1<<(int)map.get(\"max\").getValue();\n    ccfg.segmentation_precision[p] = map.get(\"thr\").getValue();\n\n    ccfg.prediction_method[p] = (Integer)((ScrollableList)map.get(\"pred\")).getItem((int)map.get(\"pred\").getValue()).get(\"value\");\n    ccfg.quantization_value[p] = (int)map.get(\"quant\").getValue();\n    ccfg.clamp_method[p] = (int)map.get(\"clamp\").getValue();\n\n    ccfg.transform_type[p] = (int)map.get(\"transtype\").getValue();\n    ccfg.transform_method[p] = (Integer)((ScrollableList)map.get(\"trans\")).getItem((int)map.get(\"trans\").getValue()).get(\"value\");\n    ccfg.transform_compress[p] = map.get(\"compress\").getValue();\n    ccfg.transform_scale[p] = (int)pow(2.0, map.get(\"scale\").getValue());\n\n    ccfg.encoding_method[p] = (Integer)((ScrollableList)map.get(\"encoding\")).getItem((int)map.get(\"encoding\").getValue()).get(\"value\");\n  }\n}\n\nHashMap<String, Object> toHashMap() {\n  HashMap<String, Object> m = new HashMap();\n\n  m.put(\"colorspace\", sl_cs.getValue());\n  m.put(\"color_outside_r\", co_r.getValue());\n  m.put(\"color_outside_g\", co_g.getValue());\n  m.put(\"color_outside_b\", co_b.getValue());\n  m.put(\"separate_channels\", separate_channels.getArrayValue());\n\n  for (int p=0; p<3; p++) {\n    HashMap<String, ControllerInterface> map = chmap[p];\n    String ch = \"ch\"+p;\n\n    for (String k : map.keySet ()) {\n      if (map.get(k) instanceof RadioButton) {\n        m.put(ch+k, map.get(k).getArrayValue());\n      } else {\n        m.put(ch+k, map.get(k).getValue());\n      }\n    }\n  }\n\n  return m;\n}\n\nvoid fromHashMap(HashMap<String, Object> m) {\n  sl_cs.setValue((Float)m.get(\"colorspace\"));\n  co_r.setValue((Float)m.get(\"color_outside_r\"));\n  co_g.setValue((Float)m.get(\"color_outside_g\"));\n  co_b.setValue((Float)m.get(\"color_outside_b\"));\n  if (m.get(\"separate_channels\") != null)\n    separate_channels.setArrayValue((float[])m.get(\"separate_channels\"));\n  else\n    separate_channels.deactivate(0);\n\n  for (int p=0; p<3; p++) {\n    HashMap<String, ControllerInterface> map = chmap[p];\n    String ch = \"ch\"+p;\n\n    for (String k : map.keySet ()) {\n      if (map.get(k) instanceof RadioButton) {\n        map.get(k).setArrayValue((float[])m.get(ch+k));\n      } else {\n        map.get(k).setValue((Float)m.get(ch+k));\n      }\n    }\n  }\n\n  toggle_sep_chan();\n}\n\nvoid reload_image() {\n  println(\"Reload image done\");\n  load_image(origname, false);\n  ipred = isegm = null;\n  reset_buffer();\n}\n\nvoid keep_image() {\n  img = current;\n}\n\nString session_prefix() {\n  if (do_skip_session) \n    return \"\";\n  else\n    return \"_\" + session_id;\n}\n\nvoid encode_batch(boolean dopresets) {\n  println(\"batch: \"+foldername);\n  java.io.File folder = new java.io.File(dataPath(foldername)); // set up a File object for the directory\n  filenames = folder.list(extfilter); // fill the fileNames string array with the filter result\n  curFrame = 0;\n  String preset_dir = dopresets ? File.separator + current_preset : \"\";\n  while (curFrame<filenames.length) {\n    String curr_name = foldername+File.separator+\"batch\"+session_prefix()+preset_dir+File.separator+filenames[curFrame];\n    println(\"Encoding: \" + curr_name);\n    img = loadImage(foldername+File.separator+filenames[curFrame]);\n    result = encode(img, curr_name.replace(\".png\", \"\").replace(\".jpg\", \"\").replace(\".jpeg\", \"\").replace(\".bmp\", \"\")+\".glic\"); // todo: make filename without extension\n    result.save(curr_name);\n    current = result;\n    reset_buffer();\n    curFrame++;\n  }\n}\n\nvoid encode_button() {\n  readValues();\n  if (!isBatch) {\n    println(\"Encoding: \" + foldername+File.separator+filename+session_prefix()+File.separator+glic_filename.getText());\n    result = encode(img, foldername+File.separator+filename+session_prefix()+File.separator+glic_filename.getText());\n    current = result;\n    reset_buffer();\n  } else {\n    encode_batch(false);\n  }\n  bbar_reset(\"Result\");\n}\n\nvoid decode_button() {\n  if (!isBatch) {\n    println(\"Decoding: \" + foldername+File.separator+filename+session_prefix()+File.separator+glic_filename.getText());\n    result = decode(foldername+File.separator+filename+session_prefix()+File.separator+glic_filename.getText());\n    current = result;\n    reset_buffer();\n  } else {\n    println(\"Batch: \"+foldername);\n    java.io.File folder = new java.io.File(dataPath(foldername)+File.separator + \"batch\" + session_prefix()); // set up a File object for the directory\n    filenames = folder.list(glicfilter); // fill the fileNames string array with the filter result\n    curFrame = 0;\n    while (curFrame<filenames.length) {\n      String curr_name = foldername+File.separator+\"batch\"+session_prefix()+File.separator+filenames[curFrame];\n      println(\"Decoding: \" + curr_name);\n      result = decode(curr_name);\n      result.save(curr_name.replace(\".glic\", \"\")+\".png\");\n      current = result;\n      reset_buffer();\n      curFrame++;\n    }\n  }\n  bbar_reset(\"Result\");\n}\n\nvoid save_buffer(String pref) {\n  if (buffer != null) {\n    String ppref = \"\".equals(pref) ? \"\" : (pref + \"_\");\n    String fn = foldername+File.separator+filename+session_prefix()+File.separator+ppref+save_filename.getText();\n    println(\"Saving: \" + fn);\n    buffer.save(fn);\n    save_filename.setText(get_next_filename());\n    println(\"Saved\");\n  }\n}\n\nvoid save_button() {\n  save_buffer(\"\");\n}\n\nint filename_cnt = 0;\nString get_next_filename() {\n  return filename+\"_\"+nf(filename_cnt++, 6)+\".png\";\n}\n\nvoid bbar_reset(String h) {\n  for (String s : bbar_names) {\n    if (h.equals(s)) {\n      bbar.changeItem(s, \"selected\", true);\n    } else {\n      bbar.changeItem(s, \"selected\", false);\n    }\n  }\n}\n\nvoid new_session() {\n\n  if (!do_skip_session) {\n    session_id = hex(sdf.format(new Date()).hashCode());\n    println(\"Session name: \" + session_id);\n  } else {\n    session_id = \"\";\n  }\n  filename_cnt = 0;\n  save_filename.setText(get_next_filename());\n  glic_filename.setText(filename+\".glic\");\n}\n\nvoid load_image(String fname, boolean reset_session) {\n  println(\"Loading file: \" + fname);\n\n  if (\"jpg\".equals(fileext)\n    || \"jpeg\".equals(fileext)\n    || \"gif\".equals(fileext)\n    || \"png\".equals(fileext)\n    || \"bmp\".equals(fileext)) {\n    img = loadImage(fname);\n    bbar_reset(\"Image\");\n  } else {\n    result = img = decode(fname);\n    bbar_reset(\"Result\");\n  }\n\n  if (reset_session) new_session();\n\n  current = img;\n  reset_buffer();\n}\n\nvoid fileSelected(File selection) {\n  if (selection != null) {\n    current = null;\n\n    String fn = selection.getName();\n    int i = fn.lastIndexOf('.');\n    fileext = fn.substring(i+1).toLowerCase();\n    filename = fn.substring(0, i);\n    foldername = selection.getParent();\n\n    origname = selection.getAbsolutePath();\n    load_image(origname, true);\n  }\n}\n\nboolean resetting_buffer = false;\nvoid reset_buffer() {\n  resetting_buffer = true;\n  if (current != null) { \n    float ratio = (float)current.width/(float)current.height;\n    neww = ratio < 1.0 ? (int)(max_display_size * ratio) : max_display_size;\n    newh = ratio < 1.0 ? max_display_size : (int)(max_display_size / ratio);\n    posx = ratio < 1.0 ? (max_display_size-neww) / 2 : 0;\n    posy = ratio < 1.0 ? 0 : (max_display_size-newh) / 2;\n    buffer = createGraphics(current.width, current.height);\n    buffer.beginDraw();\n    buffer.image(current, 0, 0);\n    buffer.endDraw();\n  }\n  resetting_buffer = false;\n}\n\nvoid load_button() {\n  selectInput(\"Select a file to process:\", \"fileSelected\");\n}\n\nvoid toggle_sep_chan() {\n  if (separate_channels.getArrayValue()[0]==1) {\n    ch1.setLabel(\"Channel 1\");\n    ch2.setVisible(true);\n    ch3.setVisible(true);\n    separate_channels_toggle = true;\n  } else {\n    ch1.setLabel(\"All channels\");\n    ch2.setVisible(false);\n    ch3.setVisible(false);\n    separate_channels_toggle = false;\n  }\n}\n\nvoid controlEvent(ControlEvent e) {\n  if (e.isFrom(separate_channels)) {\n    toggle_sep_chan();\n  }\n\n  if (e.isFrom(batch)) {\n    isBatch = !isBatch;\n  }\n\n  if (e.isFrom(skip_header)) {\n    do_skip_header = !do_skip_header;\n  }\n\n  if (e.isFrom(skip_session)) {\n    do_skip_session = !do_skip_session;\n    new_session();\n  }\n\n  if (e.isFrom(ch1mn)) {\n    float mn = ch1mn.getValue();\n    float mx = ch1mx.getValue();\n    if (mn>mx) ch1mx.setValue(mn);\n  }\n  if (e.isFrom(ch2mn)) {\n    float mn = ch2mn.getValue();\n    float mx = ch2mx.getValue();\n    if (mn>mx) ch2mx.setValue(mn);\n  }\n  if (e.isFrom(ch3mn)) {\n    float mn = ch3mn.getValue();\n    float mx = ch3mx.getValue();\n    if (mn>mx) ch3mx.setValue(mn);\n  }\n\n  if (e.isFrom(ch1mx)) {\n    float mn = ch1mn.getValue();\n    float mx = ch1mx.getValue();\n    if (mx<mn) ch1mn.setValue(mx);\n  }\n  if (e.isFrom(ch2mx)) {\n    float mn = ch2mn.getValue();\n    float mx = ch2mx.getValue();\n    if (mx<mn) ch2mn.setValue(mx);\n  }\n  if (e.isFrom(ch3mx)) {\n    float mn = ch3mn.getValue();\n    float mx = ch3mx.getValue();\n    if (mx<mn) ch3mn.setValue(mx);\n  }\n}\n\r\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 GlitchCodec\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# GLIC\nGlitch Image Codec\n\nDocumentation: https://docs.google.com/document/d/1cdJvEmSKNAkzkU0dFUa-kb_QJB2ISQg-QfCqpHLFlck/edit?usp=sharing\n"
  },
  {
    "path": "codec.pde",
    "content": "import com.github.jinahya.bit.io.*;\nimport java.io.*;\n\nboolean do_skip_header = false;\n\nclass CodecConfig {\n  // Color space to operate\n  int colorspace = HWB;\n  // color outside image, always RGB\n  color color_outside = color(128, 128, 128);\n\n  // Segmentation configuration.\n  // Minimum/maximum block size for each channel\n  int[] min_block_size = {\n    2, 2, 2\n  };\n  int[] max_block_size = {\n    256, 256, 256\n  };\n  // Precision (lower better), values between 5 and 50+\n  float[] segmentation_precision = {\n    15, 15, 15\n  };\n\n  // Final encoding configuration\n  int[] encoding_method = {\n    0, 0, 0\n  };\n\n  // Global prediction method\n  int[] prediction_method = {\n    9, 9, 9\n  };\n\n  // prediction quantization 0-255\n  int[] quantization_value = {\n    110, 110, 110\n  };\n\n  int[] clamp_method = {\n    0, 0, 0\n  };\n\n  // type of transformation\n  int[] transform_type = {\n    0, 0, 0\n  };\n\n  // Transform method\n  int[] transform_method = {\n    29, 29, 29\n  };\n\n  // transform compression 0-255\n  float[] transform_compress = {\n    0, 0, 0\n  };\n\n  int[] transform_scale = {\n    20, 20, 20\n  };\n\n  public CodecConfig() {\n    super();\n  }\n}\n\nCodecConfig ccfg = new CodecConfig();\n\nfloat trans_compression_value(float v) {\n  return 50*sq(v/255.0);\n}\n\nfloat quant_value(int v) {\n  return v/2.0;\n}\n\nPImage encode(PImage img, String fname) {\n  System.gc();\n  img.loadPixels();\n  try {\n    println(\"Encoding started\");\n    GlicCodecWriter gcw = new GlicCodecWriter(fname, img.width, img.height);\n    println(\"Write first header\");\n    // fourcc, width, height, colorspace, border color\n    gcw.writeFirstHeader();\n\n    println(\"Color space: \"+getColorspaceName(ccfg.colorspace));\n\n    // prepare transform method and type, skip TRANS_NONE (0)\n    for (int p=0; p<3; p++) {\n      ccfg.transform_method[p] = ccfg.transform_method[p]==WAVELET_RANDOM ? (int)random(1, WAVELETNO) : ccfg.transform_method[p];\n      ccfg.transform_type[p] = ccfg.transform_type[p]==TRANSTYPE_RANDOM ? (int)random(TRANSTYPENO) : ccfg.transform_type[p];\n    }\n\n    println(\"Write second header\");\n    // prediction method, quantization and clamping, transformations and final encoding per channel\n    gcw.writeSecondHeader();\n\n    // img -> planes structure\n    Planes planes = new Planes(img.pixels, img.width, img.height, ccfg.colorspace);\n\n    // Segmentation is stored as quad tree encoded binary (1 - go deeper, 0 - leaf)\n    // where to store all segments\n    ArrayList<Segment> segments[] = new ArrayList[3];\n\n    gcw.writeSegmentationMark();\n    for (int p=0; p<3; p++) {\n      println(\"Channel \"+p+\" segmentation. Structure.\");\n\n      gcw.writeChannelMark(p);\n\n      ByteArrayOutputStream segm_arr_out = new ByteArrayOutputStream();\n      DefaultBitOutput segm_out = new DefaultBitOutput(new StreamByteOutput(segm_arr_out));\n\n      segments[p] = makeSegmentation(segm_out, planes, p, ccfg.min_block_size[p], ccfg.max_block_size[p], ccfg.segmentation_precision[p]);\n      println(\"Created \" + segments[p].size() + \" segments.\");\n\n      // allign to byte\n      segm_out.align(1);\n      // store size to update later\n      gcw.segmentation_sizes[p]=segm_arr_out.size();\n\n      gcw.writeArray(segm_arr_out.toByteArray(), segm_arr_out.size());\n    }\n\n    println(\"Store segmentation visualization\");\n    isegm = visualize_segmentation(segments, planes);\n\n    // set separator, 512 bytes of 0xff\n    gcw.writeSeparator(512, (byte)0xff);\n\n    // process of encoding involves decoding, we have to store somewhere only encoded data\n    Planes result = planes.clone();\n    Planes planes_pred = planes.clone();\n\n    println(\"Data encoding: predictions and transformations\");\n    for (int p=0; p<3; p++) {\n\n      Wavelet wavelet = ccfg.transform_method[p] == WAVELET_NONE ? null : createWavelet(ccfg.transform_method[p]);\n      WaveletTransform trans = wavelet == null ? null : createTransform(ccfg.transform_type[p], wavelet);\n      Compressor comp = ccfg.transform_compress[p] > 0 ? new CompressorMagnitude(trans_compression_value(ccfg.transform_compress[p])) : null;\n\n      println(\"Wavelet for plane \" + p + \" -> \" + (wavelet==null?\"NONE\":wavelet.getName()));\n      println(\"Transformation for plane \" + p + \" -> \" + (trans==null?\"NONE\":trans.getName()));\n\n      println(\"Prediction for plane \" + p + \" -> \" + predict_name(ccfg.prediction_method[p]));\n\n      // gather SAD/BSAD statistics\n      pred_sad_stats = new int[MAX_PRED];\n\n      float pq = quant_value(ccfg.quantization_value[p]);\n\n      for (Segment s : segments[p]) {\n\n        // predict\n\n        int[][] pred = predict(ccfg.prediction_method[p], planes, p, s);\n        // calculate residuals and clamp\n        planes.subtract(p, s, pred, ccfg.clamp_method[p]);\n\n        // quantize result\n        if (pq > 0) quantize(planes, p, s, pq, true); \n\n        // if transformation applied transform and compress\n        // maximum value after transformation is s.size * max_value\n        try {\n          if (trans != null) {\n            double[][] tr = planes.get(p, s);\n            tr = trans.forward(tr);\n\n            if (comp != null) {\n              tr = comp.compress(tr);\n            }\n\n            // store result as ints\n            for (int x=0; x<s.size; x++) {\n              for (int y=0; y<s.size; y++) {\n                planes.set(p, s.x+x, s.y+y, round((float)((tr[x][y]*ccfg.transform_scale[p])/(float)s.size)));\n              }\n            }\n          }\n        } \n        catch (JWaveException e) {\n          // ignore\n        }\n\n        // store encoding value in result planes to save later\n        for (int x=0; x<s.size; x++) {\n          for (int y=0; y<s.size; y++) {\n            result.set(p, s.x+x, s.y+y, planes.get(p, s.x+x, s.y+y));\n          }\n        }\n\n        // decompress now\n        // wavelets\n        try {\n          if (trans != null) {\n            double[][] tr = new double[s.size][s.size];\n\n            for (int xx=0; xx<tr.length; xx++) {\n              for (int yy=0; yy<tr.length; yy++) {\n                tr[xx][yy] = (s.size*planes.get(p, s.x+xx, s.y+yy))/(float)ccfg.transform_scale[p];\n              }\n            }\n\n            tr = trans.reverse(tr);\n            planes.set(p, s, tr, ccfg.clamp_method[p]);\n          }\n        } \n        catch (JWaveException e) {\n          // ignore\n        }\n\n        // reverse quantization\n        if (pq > 0) quantize(planes, p, s, pq, false);\n        // add back residuals and clamp\n\n        pred = predict(s.pred_type, planes, p, s);\n        planes.add(p, s, pred, ccfg.clamp_method[p]);\n\n        for (int x=0; x<s.size; x++) {\n          for (int y=0; y<s.size; y++) {\n            planes_pred.set(p, s.x+x, s.y+y, pred[x][y]);\n          }\n        }\n      }\n    }\n\n    ipred = planes_pred.toImage();\n    planes_pred=null;\n\n    gcw.writePredictDataMark();\n    // store another config, prediction additional info\n    for (int p=0; p<3; p++) {\n      println(\"Channel \"+p+\" segmentation. Configuration.\");\n      gcw.writeChannelMark(p);\n      gcw.writeSegmentsData(p, segments[p]);\n    }\n\n    gcw.writeSeparator(512, (byte)0xff);\n    gcw.writeDataMark();\n    println(\"Encoding data\"); \n    for (int p=0; p<3; p++) {   \n      gcw.writeChannelMark(p);   \n      gcw.data_sizes[p] = gcw.writeData(ccfg.encoding_method[p], result, p, segments[p]);\n    }\n    println(gcw.data_sizes);\n\n    gcw.close();\n    \n    result = null;\n    PImage rrr = planes.toImage();\n    \n    println(\"FINISHED\");\n    println(\"\");\n    \n    return rrr;\n  } \n  catch (Exception e) {\n    println(\"Encoding failed\");\n    e.printStackTrace();\n  }\n  return null;\n}\n\nPImage decode(String fname) {\n  System.gc();\n  if (do_skip_header) readValues();\n  println(\"Decoding started\");\n  try {\n    GlicCodecReader gcr = new GlicCodecReader(fname);\n    println(\"Read first header\");\n    gcr.readFirstHeader();\n    println(\"Color space: \"+getColorspaceName(gcr.colorspace));\n\n    println(\"Read second header\");\n    gcr.readSecondHeader();\n\n    println(\"Reading segmentation structure\");\n\n    Planes planes = new Planes(gcr.w, gcr.h, gcr.colorspace, new RefColor(gcr.color_outside[0], gcr.color_outside[1], gcr.color_outside[2], gcr.colorspace));\n\n    ArrayList<Segment> segments[] = new ArrayList[4];\n\n    gcr.skip(13); // segmentation mark\n    for (int p=0; p<3; p++) {\n      println(\"Channel \"+p+\" segmentation\");\n\n      gcr.skip(4);\n\n      byte[] segmentation_info = gcr.readArray(gcr.segmentation_sizes[p]);\n      ArrayByteInput segm_arr_in = new ArrayByteInput(segmentation_info, 0, segmentation_info.length);\n      DefaultBitInput segm_in = new DefaultBitInput(segm_arr_in);\n\n      segments[p] = readSegmentation(segm_in, planes);\n    }\n\n    gcr.skip(512);\n    println(\"Reading segmentation data\");\n    gcr.skip(12); // predict data mark\n    for (int p=0; p<3; p++) {\n      gcr.skip(4);\n      gcr.readSegmentsData(p, segments[p]);\n    }\n\n    gcr.skip(512);\n    gcr.skip(10); // image data mark\n    println(\"Decoding data\"); \n    for (int p=0; p<3; p++) {\n      gcr.skip(4);\n      gcr.readData(gcr.encoding_method[p], planes, p, segments[p]);\n    }\n\n    Planes planes_pred = planes.clone();\n\n    for (int p=0; p<3; p++) {\n\n      Wavelet wavelet = gcr.transform_method[p] == WAVELET_NONE ? null : createWavelet(gcr.transform_method[p]);\n      WaveletTransform trans = wavelet == null ? null : createTransform(gcr.transform_type[p], wavelet);\n\n      println(\"Wavelet for plane \" + p + \" -> \" + (wavelet==null?\"NONE\":wavelet.getName()));\n      println(\"Transformation for plane \" + p + \" -> \" + (trans==null?\"NONE\":trans.getName()));\n\n      println(\"Prediction for plane \" + p + \" -> \" + predict_name(gcr.prediction_method[p]));\n\n      float pq = quant_value(gcr.quant_value[p]);\n      for (Segment s : segments[p]) {\n\n        try {\n          if (trans != null) {\n            double[][] tr = new double[s.size][s.size];\n\n            for (int xx=0; xx<tr.length; xx++) {\n              for (int yy=0; yy<tr.length; yy++) {\n                tr[xx][yy] = (s.size*planes.get(p, s.x+xx, s.y+yy))/(float)gcr.transform_scale[p];\n              }\n            }\n\n            tr = trans.reverse(tr);\n            planes.set(p, s, tr, gcr.clamp_method[p]);\n          }\n        } \n        catch (JWaveException e) {\n          // ignore\n        }\n\n        if (pq>0) quantize(planes, p, s, pq, false);\n\n        int[][] pred = predict(s.pred_type, planes, p, s);\n        planes.add(p, s, pred, gcr.clamp_method[p]);\n\n        for (int x=0; x<s.size; x++) {\n          for (int y=0; y<s.size; y++) {\n            planes_pred.set(p, s.x+x, s.y+y, pred[x][y]);\n          }\n        }\n      }\n    }\n\n    gcr.close();\n\n    println(\"Store segmentation visualization\");\n    isegm = visualize_segmentation(segments, planes);\n\n    ipred = planes_pred.toImage();\n\n    println(\"FINISHED\");\n    println(\"\");\n\n    return planes.toImage();\n  } \n  catch (Exception e) {\n    println(\"Decoding failed\");\n    e.printStackTrace();\n  }\n  return null;\n}\n\nPImage visualize_segmentation(ArrayList<Segment> segments[], Planes source) {\n  Planes res = source.clone();\n  for (int p=0; p<3; p++) {\n    for (Segment ss : segments[p]) {\n      int v = source.get(p, ss.x+(ss.size>>1), ss.y+(ss.size>>1));\n      for (int x=0; x<ss.size; x++) {\n        for (int y=0; y<ss.size; y++) {\n          res.set(p, ss.x+x, ss.y+y, v);\n        }\n      }\n    }\n  }\n  return res.toImage();\n}\n\nclass GlicCodecReader {\n  DataInputStream o;\n  String filename; \n  int w, h;\n  int colorspace;\n  int[] color_outside = {\n    0, 0, 0\n  };\n  int[] segmentation_sizes = {\n    0, 0, 0, 0\n  };\n  int[] data_sizes = {\n    0, 0, 0, 0\n  };\n  int[] segmdata_sizes = {\n    0, 0, 0, 0\n  };\n  // Final encoding configuration\n  int[] encoding_method = {\n    0, 0, 0\n  };\n  // Global prediction method\n  int[] prediction_method = {\n    0, 0, 0\n  };\n  int[] clamp_method = {\n    0, 0, 0\n  };\n  // prediction quantization 0-255\n  int[] quant_value = {\n    0, 0, 0\n  };\n  // Transform method\n  int[] transform_method = {\n    0, 0, 0\n  };\n  // type of transformation\n  int[] transform_type = {\n    0, 0, 0\n  };\n\n  int[] transform_scale = {\n    0, 0, 0\n  };\n\n  public GlicCodecReader(String filename) {\n    this.filename = filename;\n    o = new DataInputStream(new BufferedInputStream(createInput(filename)));\n  }\n\n  byte[] readArray(int size) throws IOException {\n    byte[] res = new byte[size];\n    try {\n      o.readFully(res, 0, size);\n    } \n    catch (java.io.EOFException e) {\n      // ignore\n    }\n    return res;\n  }\n\n  void readSegmentsData(int p, ArrayList<Segment> segments) throws IOException {\n    DataInputStream in = new DataInputStream(new ByteArrayInputStream(readArray(segmdata_sizes[p])));\n    try {\n      for (Segment s : segments) {\n        s.pred_type = in.readUnsignedByte();\n        s.pred_type = s.pred_type == PRED_NONE ? prediction_method[p] : s.pred_type;\n        s.refx = in.readShort();\n        s.refy = in.readShort();\n        s.refa = in.readUnsignedByte() % 3;\n        s.angle = (float)in.readShort()/0x7000;\n      }\n    } \n    catch (EOFException e) {\n      // ignore\n    }\n    finally {\n      in.close();\n    }\n  }\n\n  void readData(int method, Planes p, int pno, ArrayList<Segment> s) {\n    switch (method) {\n    case ENCODING_PACKED:\n      decode_packed(p, pno, s); \n      break;  \n    case ENCODING_RLE:\n      decode_rle(p, pno, s); \n      break;  \n    default:\n      decode_raw(p, pno, s);\n    }\n  }\n\n  void decode_raw(Planes p, int pno, ArrayList<Segment> s) {\n    try {\n      int idx=0;\n      for (Segment segm : s) {\n        for (int x=0; x<segm.size; x++) {\n          for (int y=0; y<segm.size; y++) {\n            if (idx < data_sizes[pno]) {\n              p.set(pno, segm.x+x, segm.y+y, o.readInt());\n              idx+=4;\n            }\n          }\n        }\n      }\n    } \n    catch (IOException e) {\n      println(\"decode raw failed\");\n      // ignore\n    }\n  }\n\n  void decode_packed(Planes p, int pno, ArrayList<Segment> s) {\n    try {\n      byte[] d = readArray(data_sizes[pno]);\n      DefaultBitInput in = new DefaultBitInput(new ArrayByteInput(d, 0, d.length));\n\n      int bits = (int)ceil(log(transform_scale[pno])/log(2.0));\n\n\n      for (Segment segm : s) {\n        for (int x=0; x<segm.size; x++) {\n          for (int y=0; y<segm.size; y++) {\n            p.set(pno, segm.x+x, segm.y+y, decodePackedBits(in, pno, bits));\n          }\n        }\n      }\n    } \n    catch(EOFException e) {\n      println(\"decode packed failed (EOF)\");\n      // ignore\n    } \n    catch(IOException e) {\n      println(\"decode packed failed (IO)\");\n      // ignore\n    }\n    catch(IllegalStateException e) {\n      println(\"decode packed failed\");\n      // ignore\n    }\n  }\n\n  void decode_rle(Planes p, int pno, ArrayList<Segment> s) {\n    try {\n      byte[] d = readArray(data_sizes[pno]);\n      DefaultBitInput in = new DefaultBitInput(new ArrayByteInput(d, 0, d.length));\n\n      int bits = (int)ceil(log(transform_scale[pno])/log(2.0));\n      int currentval = 0;\n      boolean do_read_type = true;\n      int currentcnt = 0;\n\n\n      for (Segment segm : s) {\n        for (int x=0; x<segm.size; x++) {\n          for (int y=0; y<segm.size; y++) {\n\n            if (do_read_type) {\n              if (in.readBoolean()) { // size\n                currentcnt = in.readInt(true, 7)+2;\n                do_read_type = false;\n              }\n              currentval = decodePackedBits(in, pno, bits);\n            }\n            p.set(pno, segm.x+x, segm.y+y, currentval);\n            currentcnt--;\n            if (currentcnt <= 0) {\n              do_read_type = true;\n            }\n          }\n        }\n      }\n    } \n    catch(EOFException e) {\n      println(\"decode rle failed (EOF)\");\n      // ignore\n    } \n    catch(IOException e) {\n      println(\"decode rle failed (IO)\");\n      // ignore\n    }\n    catch(IllegalStateException e) {\n      println(\"decode rle failed\");\n      // ignore\n    }\n  }\n\n  int decodePackedBits(DefaultBitInput in, int pno, int bits) throws IOException {\n    if (transform_method[pno] == WAVELET_NONE) {\n      if (clamp_method[pno] == CLAMP_NONE) {\n        return in.readInt(false, 9);\n      } else if (clamp_method[pno] == CLAMP_MOD256) {\n        return in.readInt(true, 8);\n      }\n    } else {\n      return in.readInt(false, bits+1);\n    }\n    return 0;\n  } \n\n  void skip(int bytes) {\n    try {\n      for (int i=0; i<bytes; i++) o.readByte();\n    } \n    catch (IOException e) {\n      println(\"skip failed\");\n      // ignore\n    }\n  }\n\n  void readFirstHeader() throws IOException {\n    // GLIC\n    skip(4);\n\n    // width, height\n    w = max(64,abs(o.readInt())%8192); // 4\n    h = max(64,abs(o.readInt())%8192); // 4\n\n    // colorspace\n    colorspace = o.readUnsignedByte(); // 1\n    if (do_skip_header) colorspace = ccfg.colorspace;\n\n    // color outside image\n    color_outside[0] = o.readUnsignedByte();\n    color_outside[1] = o.readUnsignedByte();\n    color_outside[2] = o.readUnsignedByte();\n    if (do_skip_header) {\n      color_outside[0] = getR(ccfg.color_outside);\n      color_outside[1] = getG(ccfg.color_outside);\n      color_outside[2] = getB(ccfg.color_outside);\n    }\n\n    segmentation_sizes[0] = o.readInt()&0x7ffff;\n    segmentation_sizes[1] = o.readInt()&0x7ffff;\n    segmentation_sizes[2] = o.readInt()&0x7ffff;\n    segmentation_sizes[3] = o.readInt()&0x7ffff;\n\n    segmdata_sizes[0] = o.readInt()&0xffffff;\n    segmdata_sizes[1] = o.readInt()&0xffffff;\n    segmdata_sizes[2] = o.readInt()&0xffffff;\n    segmdata_sizes[3] = o.readInt()&0xffffff;\n\n    data_sizes[0] = o.readInt()&0x3ffffff;\n    data_sizes[1] = o.readInt()&0x3ffffff;\n    data_sizes[2] = o.readInt()&0x3ffffff;\n    data_sizes[3] = o.readInt()&0x3ffffff;\n\n    println(\"Segmentation sizes\");\n    println(segmentation_sizes);\n\n    println(\"Segmentation data sizes\");\n    println(segmdata_sizes);\n\n    println(\"Data sizes\");\n    println(data_sizes);\n\n    skip(128-16-16-16-16);\n  }\n\n  void readSecondHeader() throws IOException {\n    for (int p=0; p<3; p++) {\n      skip(4);\n\n      prediction_method[p] = o.readUnsignedByte();\n      quant_value[p] = o.readUnsignedByte();\n      clamp_method[p] = o.readUnsignedByte();\n\n      transform_method[p] = o.readUnsignedByte();\n      transform_type[p] = o.readUnsignedByte();\n\n      transform_scale[p] = o.readInt();\n\n      encoding_method[p] = o.readUnsignedByte();\n\n      if (do_skip_header) {\n        println(separate_channels_toggle);\n        int pp = separate_channels_toggle ? p : 0;\n        prediction_method[p] = max(0,ccfg.prediction_method[pp]);\n        quant_value[p] = ccfg.quantization_value[pp];\n        clamp_method[p] = ccfg.clamp_method[pp];\n\n        transform_method[p] = ccfg.transform_method[pp];\n        transform_type[p] = ccfg.transform_type[p];\n\n        transform_scale[p] = ccfg.transform_scale[pp];\n\n        encoding_method[p] = ccfg.encoding_method[pp];\n      }\n\n      skip(32-4-6-4);\n    }\n  }\n\n\n  void close() throws IOException {\n    o.close();\n  }\n}\n\n\nclass GlicCodecWriter {\n  DataOutputStream o;\n  String filename; \n  int w, h;\n  int current_written;\n\n  int[] segmentation_sizes = {\n    0, 0, 0, 0\n  };\n  int[] data_sizes = {\n    0, 0, 0, 0\n  };\n  int[] segmdata_sizes = {\n    0, 0, 0, 0\n  };\n\n  public GlicCodecWriter(String filename, int w, int h) {\n    this.w = w;\n    this.h = h;\n    this.filename = filename;\n    o = new DataOutputStream(new BufferedOutputStream(createOutput(filename)));\n    current_written = o.size();\n  }\n\n  int writeData(int method, Planes p, int pno, ArrayList<Segment> s) throws IOException {\n    int current = o.size();\n\n    switch (method) {\n    case ENCODING_PACKED: \n      encode_packed(p, pno, s); \n      break;\n    case ENCODING_RLE:\n      encode_rle(p, pno, s);\n      break;\n    default:\n      encode_raw(p, pno, s);\n    }\n\n    return (o.size() - current);\n  }\n\n  void encode_raw(Planes p, int pno, ArrayList<Segment> s) throws IOException {\n    for (Segment segm : s) {\n      for (int x=0; x<segm.size; x++) {\n        for (int y=0; y<segm.size; y++) {\n          o.writeInt(p.get(pno, segm.x+x, segm.y+y));\n        }\n      }\n    }\n  }\n\n  void encode_packed(Planes p, int pno, ArrayList<Segment> s) throws IOException {\n    DefaultBitOutput out = new DefaultBitOutput(new StreamByteOutput(o));\n\n    int bits = (int)ceil(log(ccfg.transform_scale[pno])/log(2.0));\n\n    for (Segment segm : s) {\n      for (int x=0; x<segm.size; x++) {\n        for (int y=0; y<segm.size; y++) {\n          emitPackedBits(out, pno, bits, p.get(pno, segm.x+x, segm.y+y));\n        }\n      }\n    }\n    out.align(1);\n  }\n\n  void encode_rle(Planes p, int pno, ArrayList<Segment> s) throws IOException {\n    DefaultBitOutput out = new DefaultBitOutput(new StreamByteOutput(o));\n\n    int bits = (int)ceil(log(ccfg.transform_scale[pno])/log(2.0));\n    int currentval = 0;\n    boolean firstval = true;\n    int currentcnt = 0;\n\n    for (Segment segm : s) {\n      for (int x=0; x<segm.size; x++) {\n        for (int y=0; y<segm.size; y++) {\n          int val = p.get(pno, segm.x+x, segm.y+y);\n\n          if (firstval) {\n            currentval = val;\n            currentcnt = 1;\n            firstval = false;\n          } else {\n            if (currentval != val || currentcnt == 129) {\n              if (currentcnt == 1) {\n                out.writeBoolean(false);\n              } else {\n                out.writeBoolean(true);\n                out.writeInt(true, 7, currentcnt-2);\n              }\n              emitPackedBits(out, pno, bits, currentval);\n              currentval = val;\n              currentcnt = 1;\n            } else {\n              currentcnt++;\n            }\n          }\n        }\n      }\n    }\n\n    if (currentval == 1) {\n      out.writeBoolean(false);\n    } else {\n      out.writeBoolean(true);\n      out.writeInt(true, 7, currentcnt-2);\n    }\n    emitPackedBits(out, pno, bits, currentval);\n    out.align(1);\n  }\n\n  void emitPackedBits(DefaultBitOutput out, int pno, int bits, int val) throws IOException {\n    if (ccfg.transform_method[pno] == WAVELET_NONE) {\n      if (ccfg.clamp_method[pno] == CLAMP_NONE) {\n        out.writeInt(false, 9, val);\n      } else if (ccfg.clamp_method[pno] == CLAMP_MOD256) {\n        out.writeInt(true, 8, val);\n      }\n    } else {\n      out.writeInt(false, bits+1, val);\n    }\n  } \n\n  void writeSegmentsData(int pno, ArrayList<Segment> segments) throws IOException {\n    ByteArrayOutputStream baus = new ByteArrayOutputStream();\n    DataOutputStream out = new DataOutputStream(baus);\n    for (Segment s : segments) {\n      int pred_type = ccfg.prediction_method[pno] < 0 ? s.pred_type : PRED_NONE; // if prediction is different than NONE, store it, other cases are NONE\n      out.writeByte(pred_type);\n      out.writeShort(s.refx);\n      out.writeShort(s.refy);\n      out.writeByte(s.refa);\n      out.writeShort((int)(0x7000 * s.angle) );\n    }\n    out.flush();\n    out.close();\n    segmdata_sizes[pno] = baus.size();\n    writeArray(baus.toByteArray(), baus.size());\n  }\n\n  void align(int bytes) throws IOException {\n    int to_write = bytes - (o.size()-current_written);\n    writeSeparator(to_write, 0);\n    current_written = o.size();\n  }\n\n  void writeArray(byte[] a, int size) throws IOException {\n    o.write(a, 0, size);\n  }\n\n  void writeSeparator(int size, int val) throws IOException {\n    for (int i=0; i<size; i++) {\n      o.writeByte(val);\n    }\n  }\n\n  void writeChannelMark(int ch) throws IOException {\n    o.writeByte(0x43);\n    o.writeByte(0x48);\n    o.writeByte(0x30);\n    o.writeByte(0x31+ch);\n  }\n\n  void writeSegmentationMark() throws IOException { //12\n    o.writeByte(0x53);\n    o.writeByte(0x45);\n    o.writeByte(0x47);\n    o.writeByte(0x4D);\n    o.writeByte(0x45);\n    o.writeByte(0x4E);\n    o.writeByte(0x54);\n    o.writeByte(0x41);\n    o.writeByte(0x54);\n    o.writeByte(0x49);\n    o.writeByte(0x4F);\n    o.writeByte(0x4E);\n    o.writeByte(0x20);\n  }\n\n  void writePredictDataMark() throws IOException { //11\n    o.writeByte(0x50);\n    o.writeByte(0x52);\n    o.writeByte(0x45);\n    o.writeByte(0x44);\n    o.writeByte(0x49);\n    o.writeByte(0x43);\n    o.writeByte(0x54);\n    o.writeByte(0x44);\n    o.writeByte(0x41);\n    o.writeByte(0x54);\n    o.writeByte(0x41);\n    o.writeByte(0x20);\n  }\n\n  void writeDataMark() throws IOException { //9\n    o.writeByte(0x49);\n    o.writeByte(0x4D);\n    o.writeByte(0x41);\n    o.writeByte(0x47);\n    o.writeByte(0x45);\n    o.writeByte(0x44);\n    o.writeByte(0x41);\n    o.writeByte(0x54);\n    o.writeByte(0x41);\n    o.writeByte(0x20);\n  }\n  void writeFirstHeader() throws IOException {\n    // GLIC\n    o.writeByte(0x47);\n    o.writeByte(0x4C);\n    o.writeByte(0x49);\n    o.writeByte(0x43);\n\n    // width, height\n    o.writeInt(w); // 4\n    o.writeInt(h); // 4\n\n    // colorspace\n    o.writeByte(ccfg.colorspace); // 1\n\n    // color outside image\n    o.writeByte(getR(ccfg.color_outside)); // 1\n    o.writeByte(getG(ccfg.color_outside)); // 1\n    o.writeByte(getB(ccfg.color_outside)); // 1\n    align(128);\n  }\n\n  void writeSecondHeader() throws IOException {\n    for (int p=0; p<3; p++) {\n      writeChannelMark(p);\n\n      int pred = ccfg.prediction_method[p];\n      // write PRED_NONE if random or sad/bsad, specific prediction method will be stored separately\n      if (pred<0) pred = PRED_NONE;\n      o.writeByte(pred); // what prediction\n      o.writeByte(ccfg.quantization_value[p]); // quantization value\n      o.writeByte(ccfg.clamp_method[p]); // how to clamp / encode residuals\n\n      o.writeByte(ccfg.transform_method[p]); // which wavelet\n      o.writeByte(ccfg.transform_type[p]); // which transform\n      o.writeInt(ccfg.transform_scale[p]);\n\n      o.writeByte(ccfg.encoding_method[p]); // final encoding / compression\n\n      align(32);\n    }\n  }\n\n  void size() throws IOException {\n    o.size();\n  }\n\n  void close() throws IOException {\n    o.flush();\n    o.close();\n\n    RandomAccessFile raf = new RandomAccessFile(sketchPath(filename), \"rw\");\n    raf.seek(16);\n    raf.writeInt(segmentation_sizes[0]);\n    raf.writeInt(segmentation_sizes[1]);\n    raf.writeInt(segmentation_sizes[2]);\n    raf.writeInt(segmentation_sizes[3]);\n    raf.writeInt(segmdata_sizes[0]);\n    raf.writeInt(segmdata_sizes[1]);\n    raf.writeInt(segmdata_sizes[2]);\n    raf.writeInt(segmdata_sizes[3]);\n    raf.writeInt(data_sizes[0]);\n    raf.writeInt(data_sizes[1]);\n    raf.writeInt(data_sizes[2]);\n    raf.writeInt(data_sizes[3]);\n    raf.close();\n\n    println(\"Segmentation sizes\");\n    println(segmentation_sizes);\n\n    println(\"Segmentation data sizes\");\n    println(segmdata_sizes);\n\n    println(\"Data sizes\");\n    println(data_sizes);\n  }\n}\n\r\n"
  },
  {
    "path": "colorspaces.pde",
    "content": "final static int COLORSPACES = 16;\n\nfinal static int OHTA = 0;\n// RGB == 1; defined in processing\nfinal static int CMY = 2;\n// HSB == 3; defined in processing\nfinal static int XYZ = 4;\nfinal static int YXY = 5;\nfinal static int HCL = 6;\nfinal static int LUV = 7;\nfinal static int LAB = 8;\nfinal static int HWB = 9;\nfinal static int RGGBG = 10;\nfinal static int YPbPr = 11;\nfinal static int YCbCr = 12;\nfinal static int YDbDr = 13;\nfinal static int GS = 14;\nfinal static int YUV = 15;\n\n// name\nString getColorspaceName(int cs) {\n  switch(cs) {\n  case OHTA: \n    return \"OHTA\";\n  case CMY: \n    return \"CMY\"; \n  case XYZ: \n    return \"XYZ\";\n  case YXY: \n    return \"YXY\";\n  case HCL: \n    return \"HCL\";\n  case LUV: \n    return \"LUV\";\n  case LAB: \n    return \"LAB\";\n  case HWB: \n    return \"HWB\";  \n  case HSB:\n    return \"HSB\";\n  case RGGBG:\n    return \"R-GGB-G\";\n  case YPbPr:\n    return \"YPbPr\";\n  case YCbCr:\n    return \"YCbCr\";\n  case YDbDr:\n    return \"YDbDr\";\n  case GS:\n    return \"Greyscale\";\n  case YUV:\n    return \"YUV\";\n  default: \n    return \"RGB\";\n  }\n}\n\n// colorspace converters\ncolor fromColorspace(color c, int cs) {\n  switch(cs) {\n  case OHTA: \n    return fromOHTA(c);\n  case CMY: \n    return fromCMY(c); \n  case XYZ: \n    return fromXYZ(c);\n  case YXY: \n    return fromYXY(c);\n  case HCL: \n    return fromHCL(c);\n  case LUV: \n    return fromLUV(c);\n  case LAB: \n    return fromLAB(c);\n  case HWB: \n    return fromHWB(c);\n  case HSB:\n    return fromHSB(c);\n  case RGGBG:\n    return fromRGGBG(c);\n  case YPbPr:\n    return fromYPbPr(c);\n  case YCbCr:\n    return fromYCbCr(c);\n  case YDbDr:\n    return fromYDbDr(c);\n  case GS:\n    return tofromGS(c);\n  case YUV:\n    return fromYUV(c);  \n  default: \n    return c;\n  }\n}\n\ncolor toColorspace(color c, int cs) {\n  switch(cs) {\n  case OHTA: \n    return toOHTA(c); \n  case CMY: \n    return toCMY(c);\n  case XYZ: \n    return toXYZ(c);\n  case YXY: \n    return toYXY(c);\n  case HCL: \n    return toHCL(c);\n  case LUV: \n    return toLUV(c);\n  case LAB: \n    return toLAB(c);\n  case HWB: \n    return toHWB(c);\n  case HSB:\n    return toHSB(c);\n  case RGGBG:\n    return toRGGBG(c);\n  case YPbPr:\n    return toYPbPr(c);\n  case YCbCr:\n    return toYCbCr(c);\n  case YDbDr:\n    return toYDbDr(c);\n  case YUV:\n    return toYUV(c);\n  case GS:\n    return tofromGS(c); \n  default: \n    return c;\n  }\n}\n\n// Colorspace converters\n\nfinal int getA(color c) { \n  return (c & 0xff000000) >> 24;\n}\nfinal int getR(color c) { \n  return (c & 0xff0000) >> 16;\n}\nfinal int getG(color c) { \n  return (c & 0xff00) >> 8;\n}\nfinal int getB(color c) { \n  return c & 0xff;\n}\n\nfinal int getLuma(color c) { \n  return constrain((int)(0.2126*getR(c)+0.7152*getG(c)+0.0722*getB(c)), 0, 255);\n}\n\nint getChannel(color c, int ch) {\n  switch(ch) {\n  case 0 : \n    return getR(c);\n  case 1 : \n    return getG(c);\n  case 2 : \n    return getB(c);\n  case 3 : \n    return getA(c);\n  default: \n    return 0;\n  }\n}\n\n// normalized versions\nfinal float getNR(color c) { \n  return r255[(c & 0xff0000) >> 16];\n}\nfinal float getNG(color c) { \n  return r255[(c & 0xff00) >> 8];\n}\nfinal float getNB(color c) { \n  return r255[c & 0xff];\n}\nfinal float getNLuma(color c) { \n  return r255[getLuma(c)];\n}\n\ncolor blendRGB(color c, int r, int g, int b) {\n  return (c & 0xff000000) | (constrain(r, 0, 255) << 16) |  (constrain(g, 0, 255) << 8 ) | constrain(b, 0, 255);\n}\n\ncolor blendRGB(color c, float r, float g, float b) {\n  return blendRGB(c, (int)(r*255), (int)(g*255), (int)(b*255));\n}\n\n/**************\n * Greyscale\n **************/\n\ncolor tofromGS(color c) {\n  int l = getLuma(c);\n  return blendRGB(c, l, l, l);\n}\n\n/**************\n * YUV\n **************/\n\nfinal static float Umax = 0.436 * 255.0;\nfinal static float Vmax = 0.615 * 255.0;\n\ncolor toYUV(color c) {\n  int R = getR(c);\n  int G = getG(c);  \n  int B = getB(c);\n  \n  int Y =  (int)(  0.299*R+0.587*G+0.114*B);\n  int U = (int)map(-0.14713*R-0.28886*G+0.436*B,-Umax,Umax,0,255);\n  int V = (int)map(0.615*R-0.51499*G-0.10001*B,-Vmax,Vmax,0,255);\n\n  return blendRGB(c, Y, U, V);\n}\n\ncolor fromYUV(color c) {\n  int Y = getR(c);  \n  float U = map(getG(c),0,255,-Umax,Umax);\n  float V = map(getB(c),0,255,-Vmax,Vmax);\n  \n  int R = (int)(Y + 1.13983*V);\n  int G = (int)(Y - 0.39465*U - 0.58060*V);\n  int B = (int)(Y + 2.03211*U);\n  \n  return blendRGB(c, R, G, B);\n}\n\n/**************\n * YDbDr\n **************/\n\ncolor toYDbDr(color c) {\n  int R = getR(c);\n  int G = getG(c);  \n  int B = getB(c);\n  \n  int Y =  (int)(  0.299*R+0.587*G+0.114*B);\n  int Db = (int)(127.5+(-0.450*R-0.883*G+1.333*B)/2.666);\n  int Dr = (int)(127.5+(-1.333*R+1.116*G+0.217*B)/2.666);\n\n  return blendRGB(c, Y, Db, Dr);\n}\n\ncolor fromYDbDr(color c) {\n  int Y = getR(c);  \n  float Db = (getG(c)-127.5)*2.666;\n  float Dr = (getB(c)-127.5)*2.666;\n  \n  int R = (int)(Y + 9.2303716147657e-05*Db-0.52591263066186533*Dr);\n  int G = (int)(Y - 0.12913289889050927*Db+0.26789932820759876*Dr);\n  int B = (int)(Y + 0.66467905997895482*Db-7.9202543533108e-05*Dr);\n  \n  return blendRGB(c, R, G, B);\n}\n\n/**************\n * YCbCr\n **************/\n\ncolor toYCbCr(color c) {\n  int R = getR(c);\n  int G = getG(c);  \n  int B = getB(c);\n  \n  int Y =  (int)( 0.2988390*R+0.5868110*G+0.1143500*B);\n  int Cb = (int)(-0.168736*R-0.3312640*G+0.5000000*B+127.5);\n  int Cr = (int)( 0.5000000*R-0.4186880*G-0.0813120*B+127.5);\n\n  return blendRGB(c, Y, Cb, Cr);\n}\n\ncolor fromYCbCr(color c) {\n  int Y = getR(c);  \n  float Cb = getG(c) - 127.5;\n  float Cr = getB(c) - 127.5;\n  \n  int R = (int)(Y + 1.402*Cr)+1; // some fix\n  int G = (int)(Y-0.344136*Cb-0.714136*Cr);\n  int B = (int)(Y+1.772000*Cb)+1; // some fix\n  \n  return blendRGB(c, R, G, B);\n}\n\n/**************\n * YPbPr\n **************/\n\ncolor toYPbPr(color c) {\n  int R = getR(c);  \n  int B = getB(c);\n  \n  int Y = getLuma(c);\n  int Pb = B - Y;\n  int Pr = R - Y;\n  if(Pb<0) Pb+=256;\n  if(Pr<0) Pr+=256;\n  return blendRGB(c, Y, Pb, Pr);\n}\n\ncolor fromYPbPr(color c) {\n  int Y = getR(c);  \n  int B = getG(c) + Y;\n  int R = getB(c) + Y;\n  if(R>255) R-=256;\n  if(B>255) B-=256;\n  \n  int G = (int)((Y-0.2126*R-0.0722*B)/0.7152);\n  \n  return blendRGB(c, R, G, B);\n}\n\n\n/**************\n * R-G,G,B-G\n **************/\n\ncolor toRGGBG(color c) {\n  int G = getG(c);  \n  int R = getR(c)-G;\n  int B = getB(c)-G;\n  if(R<0) R+=256;\n  if(B<0) B+=256;\n  return blendRGB(c, R, G, B);\n}\n\ncolor fromRGGBG(color c) {\n  int G = getG(c);  \n  int R = getR(c)+G;\n  int B = getB(c)+G;\n  if(R>255) R-=256;\n  if(B>255) B-=256;\n  return blendRGB(c, R, G, B);\n}\n\n/**************\n * HWB\n **************/\n\ncolor toHSB(color c) {\n  int R = getR(c);\n  int G = getG(c);\n  int B = getB(c);\n\n  int _min = min(R, G, B);\n  int _max = max(R, G, B);\n  float delta = _max-_min;\n  float saturation = delta/_max;\n  float brightness = r255[_max];\n  if (delta == 0.0) return blendRGB(c, 0.0, saturation, brightness);\n  float hue = 0;\n  if (R == _max) hue = (G-B)/delta;\n  else if (G == _max) hue = 2.0 + (B-R)/delta;\n  else hue = 4.0 + (R-G)/delta;\n  hue /= 6.0;\n  if (hue < 0.0) hue += 1.0;\n  return blendRGB(c, hue, saturation, brightness);\n}\n\ncolor fromHSB(color c) {\n  float S = getNG(c);\n  float B = getNB(c);\n  if (S == 0.0) return blendRGB(c, B, B, B); \n\n  float h = 6.0 * getNR(c);\n  float f = h-floor(h);\n  float p = B*(1.0-S);\n  float q = B*(1.0-S*f);\n  float t = B*(1.0-(S*(1.0-f))); \n\n  float r, g, b;\n  switch((int)h) {\n  case 1: \n    r=q; \n    g=B; \n    b=p; \n    break;\n  case 2: \n    r=p; \n    g=B; \n    b=t; \n    break;\n  case 3: \n    r=p; \n    g=q; \n    b=B; \n    break;\n  case 4: \n    r=t; \n    g=p; \n    b=B; \n    break;\n  case 5: \n    r=B; \n    g=p; \n    b=q; \n    break;\n  default: \n    r=B; \n    g=t; \n    b=p; \n    break;\n  }\n  return blendRGB(c, r, g, b);\n}\n\n\n\n/**************\n * HWB\n **************/\n\ncolor toHWB(color c) {\n  int R = getR(c);\n  int G = getG(c);\n  int B = getB(c);\n\n  int w = min(R, G, B);\n  int v = max(R, G, B);\n\n  int hue;\n  if (v == w) hue = 255;\n  else {\n    float f = ((R == w) ? G-B : ((G == w) ? B-R : R-G));\n    float p = (R == w) ? 3.0 : ((G == w) ? 5.0 : 1.0);\n    hue = (int)map((p-f/(v-w))/6.0, 0, 1, 0, 254);\n  }\n  return blendRGB(c, hue, w, 255-v);\n}\n\ncolor fromHWB(color c) {\n  int H = getR(c);\n  int B = 255-getB(c);\n  if (H == 255) return blendRGB(c, B, B, B);\n  else {\n    float hue = map(H, 0, 254, 0, 6);\n    float v = r255[B];\n    float whiteness = getNG(c);\n    int i = (int)floor(hue);\n    float f = hue-i;\n    if ((i&0x01)!= 0) f=1.0-f;\n    float n = whiteness+f*(v-whiteness);\n    float r, g, b;\n    switch(i) {\n    case 1: \n      r=n; \n      g=v; \n      b=whiteness; \n      break;\n    case 2: \n      r=whiteness; \n      g=v; \n      b=n; \n      break;\n    case 3: \n      r=whiteness; \n      g=n; \n      b=v; \n      break;\n    case 4: \n      r=n; \n      g=whiteness; \n      b=v; \n      break;\n    case 5: \n      r=v; \n      g=whiteness; \n      b=n; \n      break;\n    default: \n      r=v; \n      g=n; \n      b=whiteness; \n      break;\n    }\n    return blendRGB(c, r, g, b);\n  }\n}\n\n/**************\n * Lab\n **************/\n\nfinal static float D65X=0.950456;\nfinal static float D65Y=1.0;\nfinal static float D65Z=1.088754;\nfinal static float CIEEpsilon=(216.0/24389.0);\nfinal static float CIEK=(24389.0/27.0);\nfinal static float CIEK2epsilon = CIEK * CIEEpsilon;\nfinal static float D65FX_4 = 4.0*D65X/(D65X+15.0*D65Y+3.0*D65Z);\nfinal static float D65FY_9 = 9.0*D65Y/(D65X+15.0*D65Y+3.0*D65Z);\nfinal static float RANGE_X = 100.0 * (0.4124+0.3576+0.1805);\nfinal static float RANGE_Y = 100.0;\nfinal static float RANGE_Z = 100.0 * (0.0193+0.1192+0.9505);\nfinal static float mepsilon = 1.0e-10;\nfinal static float corrratio = 1.0/2.4;\nfinal static float One_Third = 1.0/3.0;\nfinal static float one_hsixteen = 1.0/116.0;\n\ncolor toLAB(color c) {\n  PVector xyz = _toXYZ(getNR(c), getNG(c), getNB(c));\n  xyz.div(100.0);\n  xyz.x /= D65X;\n  xyz.y /= D65Y;\n  xyz.z /= D65Z;\n  float x, y, z;\n\n  if (xyz.x > CIEEpsilon) {\n    x = pow(xyz.x, One_Third);\n  } else {\n    x= (CIEK*xyz.x+16.0)*one_hsixteen;\n  }\n\n  if (xyz.y > CIEEpsilon) {\n    y = pow(xyz.y, One_Third);\n  } else {\n    y = (CIEK*xyz.y+16.0)*one_hsixteen;\n  }\n\n  if (xyz.z > CIEEpsilon) {\n    z = pow(xyz.z, One_Third);\n  } else {\n    z = (CIEK*xyz.z+16.0)*one_hsixteen;\n  }\n\n  float L = 255.0*(((116.0*y)-16.0)*0.01);\n  float a = 255.0*(0.5*(x-y)+0.5);\n  float b = 255.0*(0.5*(y-z)+0.5);\n\n  return blendRGB(c, round(L), round(a), round(b));\n}\n\ncolor fromLAB(color c) {\n  float L = 100*getNR(c);\n  float a = getNG(c)-0.5;\n  float b = getNB(c)-0.5;\n\n  float y = (L+16.0)*one_hsixteen;\n  float x = y+a;\n  float z = y-b;\n\n  float xxx=x*x*x;\n  if (xxx>CIEEpsilon) {\n    x = xxx;\n  } else {\n    x = (116.0*x-16.0)/CIEK;\n  }\n\n  float yyy=y*y*y;\n  if (yyy>CIEEpsilon) {\n    y = yyy;\n  } else {\n    y = L/CIEK;\n  }\n\n  float zzz=z*z*z;\n  if (zzz>CIEEpsilon) {\n    z = zzz;\n  } else {\n    z = (116.0*z-16.0)/CIEK;\n  }\n\n  return _fromXYZ(c, RANGE_X*x, RANGE_Y*y, RANGE_Z*z);\n}\n\n/**************\n * Luv\n **************/\n\nfinal float PerceptibleReciprocal(float x) {\n  float sgn = x < 0.0 ? -1.0 : 1.0;\n  if ((sgn * x) >= mepsilon) return (1.0 / x);\n  return (sgn/mepsilon);\n} \n\ncolor toLUV(color c) {\n  PVector xyz = _toXYZ(getNR(c), getNG(c), getNB(c));\n  xyz.div(100.0);\n  float d = xyz.y; // / D65Y;\n  float L;\n  if (d > CIEEpsilon) L = 116.0*pow(d, One_Third)-16.0;\n  else L = CIEK * d;\n  float alpha = PerceptibleReciprocal(xyz.x + 15.0 * xyz.y + 3.0 * xyz.z);\n  float L13 = 13.0 * L;\n  float u = L13 * ((4.0 * alpha * xyz.x)-D65FX_4);\n  float v = L13 * ((9.0 * alpha * xyz.y)-D65FY_9);\n  L /= 100.0;\n  u=(u+134.0)/354.0;\n  v=(v+140.0)/262.0;\n  return blendRGB(c, round(L*255), round(u*255), round(v*255));\n}\n\ncolor fromLUV(color c) {\n  float L = 100.0*getNR(c);\n  float u = 354.0*getNG(c)-134.0;\n  float v = 262.0*getNB(c)-140.0;\n  float X, Y, Z;\n  if (L > CIEK2epsilon) Y = pow((L+16.0)*one_hsixteen, 3.0);\n  else Y = L/CIEK;\n  float L13 = 13.0*L;\n  float L52 = 52.0*L;\n  float Y5 = 5.0*Y;\n  float L13u = L52/(u+L13*D65FX_4);\n  X=((Y*((39.0*L/(v+L13*D65FY_9))-5.0))+Y5)/((((L13u)-1.0)/3.0)+One_Third);\n  Z=(X*(((L13u)-1.0)/3.0))-Y5;\n  return _fromXYZ(c, 100*X, 100*Y, 100*Z);\n}\n\n/**************\n * HCL\n **************/\n\ncolor toHCL(color c) {\n  float r = getNR(c);\n  float g = getNG(c);\n  float b = getNB(c);\n  float max = max(r, max(g, b));\n  float chr = max - min(r, min(g, b));\n  float h = 0.0;\n  if ( chr != 0) {\n    if (r == max) {\n      h = ((g-b)/chr+6.0) % 6.0;\n    } else if (g == max) {\n      h = (b-r)/chr + 2.0;\n    } else {\n      h = (r-g)/chr + 4.0;\n    }\n  }\n  return blendRGB(c, round((h/6.0)*255), round(chr*255), round(255*(0.298839*r+0.586811*g+0.114350*b)));\n}\n\ncolor fromHCL(color c) {\n  float h = 6.0*getNR(c);\n  float chr = getNG(c);\n  float l = getNB(c);\n  float x = chr*(1.0-abs((h%2.0)-1.0));\n  float r = 0.0;\n  float g = 0.0;\n  float b = 0.0;\n  if ((0.0 <= h) && (h < 1.0)) {\n    r=chr;\n    g=x;\n  } else if ((1.0 <= h) && (h < 2.0)) {\n    r=x;\n    g=chr;\n  } else if ((2.0 <= h) && (h < 3.0)) {\n    g=chr;\n    b=x;\n  } else if ((3.0 <= h) && (h < 4.0)) {\n    g=x;\n    b=chr;\n  } else if ((4.0 <= h) && (h < 5.0)) {\n    r=x;\n    b=chr;\n  } else {//if ((5.0 <= h) && (h < 6.0)) {\n    r=chr;\n    b=x;\n  }\n  float m = l - (0.298839*r+0.586811*g+0.114350*b);\n  return blendRGB(c, round(255*(r+m)), round(255*(g+m)), round(255*(b+m)));\n}\n\n/**************\n * Yxy\n **************/\n\ncolor toYXY(color c) {\n  PVector xyz = _toXYZ(getNR(c), getNG(c), getNB(c));\n  float sum = xyz.x + xyz.y + xyz.z;\n  float x = xyz.x > 0 ? xyz.x / sum : 0.0;\n  float y = xyz.y > 0 ? xyz.y / sum : 0.0;\n  return blendRGB(c, \n  (int)map(xyz.y, 0, RANGE_Y, 0, 255), \n  (int)map(x, 0.0, 1.0, 0, 255), \n  (int)map(y, 0.0, 1.0, 0, 255));\n}\n\ncolor fromYXY(color c) {\n  float Y = map(getR(c), 0, 255, 0, RANGE_Y);\n  float x = map(getG(c), 0, 255, 0, 1.0);\n  float y = map(getB(c), 0, 255, 0, 1.0);\n  float divy = Y / (y>0 ? y : 1.0e-6);\n\n  return _fromXYZ(c, x * divy, Y, (1-x-y)*divy);\n}\n\n/**************\n * XYZ\n **************/\n\n// FIXME: range from 0 to 1\nfloat correctionxyz(float n) {\n  return (n > 0.04045 ? pow((n + 0.055) / 1.055, 2.4) : n / 12.92) * 100.0;\n}\n\nPVector _toXYZ(float rr, float gg, float bb) {\n  float r = correctionxyz(rr);\n  float g = correctionxyz(gg);\n  float b = correctionxyz(bb);\n  return new PVector(r * 0.4124 + g * 0.3576 + b * 0.1805, \n  r * 0.2126 + g * 0.7152 + b * 0.0722, \n  r * 0.0193 + g * 0.1192 + b * 0.9505);\n}\n\ncolor toXYZ(color c) {\n  PVector xyz = _toXYZ(getNR(c), getNG(c), getNB(c));\n  return blendRGB(c, \n  (int)map(xyz.x, 0, RANGE_X, 0, 255), \n  (int)map(xyz.y, 0, RANGE_Y, 0, 255), \n  (int)map(xyz.z, 0, RANGE_Z, 0, 255));\n}\n\nfloat recorrectionxyz(float n) {\n  return n > 0.0031308 ? 1.055 * pow(n, corrratio) - 0.055 : 12.92 * n;\n}\n\n// FIXME: range from 0 to 1\ncolor _fromXYZ(color c, float xx, float yy, float zz) {\n  float x = xx/100.0;\n  float y = yy/100.0;\n  float z = zz/100.0;\n\n  int r = round(255.0*recorrectionxyz(x * 3.2406 + y * -1.5372 + z * -0.4986));\n  int g = round(255.0*recorrectionxyz(x * -0.9689 + y * 1.8758 + z * 0.0415));\n  int b = round(255.0*recorrectionxyz(x * 0.0557 + y * -0.2040 + z * 1.0570));\n\n  return blendRGB(c, r, g, b);\n}\n\ncolor fromXYZ(color c) {\n  float x = map(getR(c), 0, 255, 0, RANGE_X);\n  float y = map(getG(c), 0, 255, 0, RANGE_Y);\n  float z = map(getB(c), 0, 255, 0, RANGE_Z);\n\n  return _fromXYZ(c, x, y, z);\n}\n\n/**************\n * CMY\n **************/\n\ncolor toCMY(color c) {\n  return blendRGB(c, 255-getR(c), 255-getG(c), 255-getB(c));\n}\n\ncolor fromCMY(color c) {\n  return toCMY(c);\n}\n\n/**************\n * OHTA\n **************/\n\ncolor fromOHTA(color c) {\n  int I1 = getR(c);\n  float I2 = map(getG(c), 0, 255, -127.5, 127.5);\n  float I3 = map(getB(c), 0, 255, -127.5, 127.5);\n\n  int R = (int)(I1+1.00000*I2-0.66668*I3);\n  int G = (int)(I1+1.33333*I3);\n  int B = (int)(I1-1.00000*I2-0.66668*I3);\n\n  return blendRGB(c, R, G, B);\n}\n\ncolor toOHTA(color c) {\n  int R = getR(c);\n  int G = getG(c);\n  int B = getB(c);\n\n  int I1 = (int)(0.33333*R+0.33334*G+0.33333*B);\n  int I2 = (int)map(0.5*(R-B), -127.5, 127.5, 0, 255);\n  int I3 = (int)map(-0.25000*R+0.50000*G-0.25000*B, -127.5, 127.5, 0, 255);\n\n  return blendRGB(c, I1, I2, I3);\n}\n\n////\n// 1/n table for n=0..255 - to speed up color conversions things\nfinal static float[] r255 = {\n  0.0, 0.003921569, 0.007843138, 0.011764706, 0.015686275, 0.019607844, 0.023529412, 0.02745098, 0.03137255, 0.03529412, 0.039215688, \n  0.043137256, 0.047058824, 0.050980393, 0.05490196, 0.05882353, 0.0627451, 0.06666667, 0.07058824, 0.07450981, 0.078431375, 0.08235294, \n  0.08627451, 0.09019608, 0.09411765, 0.09803922, 0.101960786, 0.105882354, 0.10980392, 0.11372549, 0.11764706, 0.12156863, 0.1254902, \n  0.12941177, 0.13333334, 0.13725491, 0.14117648, 0.14509805, 0.14901961, 0.15294118, 0.15686275, 0.16078432, 0.16470589, 0.16862746, \n  0.17254902, 0.1764706, 0.18039216, 0.18431373, 0.1882353, 0.19215687, 0.19607843, 0.2, 0.20392157, 0.20784314, 0.21176471, 0.21568628, \n  0.21960784, 0.22352941, 0.22745098, 0.23137255, 0.23529412, 0.23921569, 0.24313726, 0.24705882, 0.2509804, 0.25490198, 0.25882354, \n  0.2627451, 0.26666668, 0.27058825, 0.27450982, 0.2784314, 0.28235295, 0.28627452, 0.2901961, 0.29411766, 0.29803923, 0.3019608, 0.30588236, \n  0.30980393, 0.3137255, 0.31764707, 0.32156864, 0.3254902, 0.32941177, 0.33333334, 0.3372549, 0.34117648, 0.34509805, 0.34901962, 0.3529412, \n  0.35686275, 0.36078432, 0.3647059, 0.36862746, 0.37254903, 0.3764706, 0.38039216, 0.38431373, 0.3882353, 0.39215687, 0.39607844, 0.4, \n  0.40392157, 0.40784314, 0.4117647, 0.41568628, 0.41960785, 0.42352942, 0.42745098, 0.43137255, 0.43529412, 0.4392157, 0.44313726, \n  0.44705883, 0.4509804, 0.45490196, 0.45882353, 0.4627451, 0.46666667, 0.47058824, 0.4745098, 0.47843137, 0.48235294, 0.4862745, 0.49019608, \n  0.49411765, 0.49803922, 0.5019608, 0.5058824, 0.50980395, 0.5137255, 0.5176471, 0.52156866, 0.5254902, 0.5294118, 0.53333336, 0.5372549, \n  0.5411765, 0.54509807, 0.54901963, 0.5529412, 0.5568628, 0.56078434, 0.5647059, 0.5686275, 0.57254905, 0.5764706, 0.5803922, 0.58431375, \n  0.5882353, 0.5921569, 0.59607846, 0.6, 0.6039216, 0.60784316, 0.6117647, 0.6156863, 0.61960787, 0.62352943, 0.627451, 0.6313726, 0.63529414, \n  0.6392157, 0.6431373, 0.64705884, 0.6509804, 0.654902, 0.65882355, 0.6627451, 0.6666667, 0.67058825, 0.6745098, 0.6784314, 0.68235296, \n  0.6862745, 0.6901961, 0.69411767, 0.69803923, 0.7019608, 0.7058824, 0.70980394, 0.7137255, 0.7176471, 0.72156864, 0.7254902, 0.7294118, \n  0.73333335, 0.7372549, 0.7411765, 0.74509805, 0.7490196, 0.7529412, 0.75686276, 0.7607843, 0.7647059, 0.76862746, 0.77254903, 0.7764706, \n  0.78039217, 0.78431374, 0.7882353, 0.7921569, 0.79607844, 0.8, 0.8039216, 0.80784315, 0.8117647, 0.8156863, 0.81960785, 0.8235294, 0.827451, \n  0.83137256, 0.8352941, 0.8392157, 0.84313726, 0.84705883, 0.8509804, 0.85490197, 0.85882354, 0.8627451, 0.8666667, 0.87058824, 0.8745098, \n  0.8784314, 0.88235295, 0.8862745, 0.8901961, 0.89411765, 0.8980392, 0.9019608, 0.90588236, 0.9098039, 0.9137255, 0.91764706, 0.92156863, \n  0.9254902, 0.92941177, 0.93333334, 0.9372549, 0.9411765, 0.94509804, 0.9490196, 0.9529412, 0.95686275, 0.9607843, 0.9647059, 0.96862745, \n  0.972549, 0.9764706, 0.98039216, 0.9843137, 0.9882353, 0.99215686, 0.99607843, 1.0\n};\r\n"
  },
  {
    "path": "encoding.pde",
    "content": "// final encoding\n\nfinal static int ENCODING_RAW = 0;\nfinal static int ENCODING_PACKED = 1;\nfinal static int ENCODING_RLE = 2;\n\nfinal static int ENCODINGNO = 3;\n\nString encoding_name(int v) {\n  switch(v) {\n    case ENCODING_RAW: return \"ENCODING RAW\";\n    case ENCODING_PACKED: return \"ENCODING PACKED\";\n    case ENCODING_RLE: return \"ENCODING RLE\";\n  }\n  return null;\n}\r\n"
  },
  {
    "path": "planes.pde",
    "content": "final static float LOG2 = log(2.0);\n\nfinal static int CLAMP_NONE = 0;\nfinal static int CLAMP_MOD256 = 1;\n\nint clamp_in(int method, int x) {\n  switch(method) {\n  case CLAMP_MOD256:\n    return x<0?x+256:x>255?x-256:x;\n  default: \n    return x;\n  }\n}\n\nint clamp_out(int method, int x) {\n  switch(method) {\n  case CLAMP_MOD256: \n    return x<0?x+256:x>255?x-256:x;\n  default: \n    return constrain(x, 0, 255);\n  }\n}\n\nint clamp(int method, int x) {\n  switch(method) {\n  case CLAMP_MOD256:\n    return constrain(x, 0, 255);\n  default:\n    return constrain(x, -255, 255);\n  }\n}\n\nclass RefColor {\n  int[] c;\n  public RefColor() {\n    c = new int[] {\n      128, 128, 128, 255\n    };\n  }\n\n  public RefColor(int r, int g, int b) {\n    this(color(r, g, b));\n  }\n\n  public RefColor(int r, int g, int b, int cs) {\n    this(color(r, g, b), cs);\n  }\n\n  public RefColor(color cc) {\n    c = new int[4];\n    c[2] = cc & 0xff;\n    c[1] = (cc >> 8) & 0xff;\n    c[0] = (cc >> 16) & 0xff;\n    c[3] = (cc >> 24) & 0xff;\n  }\n\n  public RefColor(color cc, int cs) {\n    this(toColorspace(cc, cs));\n  }\n}\n\nclass Planes {\n  int ww, hh;\n  int w, h, cs;\n  int[][][] channels;\n  RefColor ref;\n\n  public Planes(int[] pxls, int w, int h, int cs, RefColor ref) {\n    this(w, h, cs, ref);\n    extractPlanes(pxls);\n  }\n\n  public Planes(int w, int h, int cs) {\n    this(w, h, cs, new RefColor(ccfg.color_outside, cs));\n  }\n\n  public Planes(int w, int h, int cs, RefColor ref) {\n    this.w = w;\n    this.h = h;\n    this.cs = cs;\n    ww = 1<<(int)ceil(log(w)/LOG2);\n    hh = 1<<(int)ceil(log(h)/LOG2);\n    //channels = new int[4][w][h];\n    channels = new int[3][w][h];\n    for (int x=0; x<w; x++) {\n      for (int y=0; y<h; y++) {\n        channels[0][x][y] = ref.c[0];\n        channels[1][x][y] = ref.c[1];\n        channels[2][x][y] = ref.c[2];\n  //      channels[3][x][y] = ref.c[3];\n      }\n    }\n    this.ref = ref;\n  }\n\n  public Planes(int[] pxls, int w, int h, int cs) {\n    this(pxls, w, h, cs, new RefColor(ccfg.color_outside, cs));\n  }\n\n  public Planes clone() {\n    return new Planes(w,h,cs,ref);\n  }\n\n  private void extractPlanes(int[] pxls) {\n    for (int x=0; x<w; x++) {\n      for (int y=0; y<h; y++) {\n        color c = toColorspace(pxls[y*w+x], cs);\n        channels[2][x][y] = c & 0xff;\n        channels[1][x][y] = (c >> 8) & 0xff;\n        channels[0][x][y] = (c >> 16) & 0xff;\n    //    channels[3][x][y] = (c >> 24) & 0xff;\n      }\n    }\n  }\n\n  public int[] toPixels() {\n    int[] pxls = new int[w*h];\n    for (int x=0; x<w; x++) {\n      for (int y=0; y<h; y++) {\n        int off = y*w+x;\n\tint alpha = img == null ? 0xff000000 : (img.pixels[off]&0xff000000);\n        pxls[off] = fromColorspace(\n        (channels[2][x][y] ) |\n          ((channels[1][x][y] ) << 8) |\n          ((channels[0][x][y] ) << 16) |\n          alpha\n        //  ((channels[3][x][y] ) << 24)\n          , cs);\n      }\n    }\n    return pxls;\n  }\n\n  public PImage toImage() {\n    PImage i = createImage(w, h, ARGB);\n    i.loadPixels();\n    i.pixels = toPixels();\n    i.updatePixels();\n    return i;\n  }\n\n  public int get(int pno, int x, int y) {\n    if (x<0 || x>=w || y<0 || y>=h) {\n      return ref.c[pno];\n    } else {\n      return channels[pno][x][y];\n    }\n  }\n\n  void set(int pno, int x, int y, int val) {\n    if (x>=0 && x<w && y>=0 && y<h) {\n      channels[pno][x][y] = val;\n    }\n  }\n\n  double[][] get(int pno, Segment s) {\n    double[][] res = new double[s.size][s.size];\n    for (int x=0; x<s.size; x++) {\n      for (int y=0; y<s.size; y++) {\n        res[x][y] = get(pno, x+s.x, y+s.y)/255.0;\n      }\n    }\n    return res;\n  }\n\n  void set(int pno, Segment s, double[][] values, int method) {\n    for (int x=0; x<s.size; x++) {\n      for (int y=0; y<s.size; y++) {\n  //     set(pno, x+s.x, y+s.y, clamp(method,round((float)values[x][y])));\n       set(pno, x+s.x, y+s.y, clamp(method,round((float)(values[x][y]*255.0))));\n      }\n    }\n  }\n\n  void subtract(int pno, Segment s, int[][] values, int clamp_method) {\n    for (int x=0; x<s.size; x++) {\n      for (int y=0; y<s.size; y++) {\n        int v = get(pno, x+s.x, y+s.y) - values[x][y];\n        set(pno, x+s.x, y+s.y, clamp_in(clamp_method, v));\n      }\n    }\n  }\n\n  void add(int pno, Segment s, int[][] values, int clamp_method) {\n    for (int x=0; x<s.size; x++) {\n      for (int y=0; y<s.size; y++) {\n        int v = get(pno, x+s.x, y+s.y) + values[x][y];\n        set(pno, x+s.x, y+s.y, clamp_out(clamp_method, v));\n      }\n    }\n  }\n}\r\n"
  },
  {
    "path": "predictions.pde",
    "content": "static final int PRED_SAD = -1;\nstatic final int PRED_BSAD = -2;\nstatic final int PRED_RANDOM = -3;\n\nstatic final int PRED_NONE = 0;\nstatic final int PRED_CORNER = 1;\nstatic final int PRED_H = 2;\nstatic final int PRED_V = 3;\nstatic final int PRED_DC = 4;\nstatic final int PRED_DCMEDIAN = 5;\nstatic final int PRED_MEDIAN = 6;\nstatic final int PRED_AVG = 7;\nstatic final int PRED_TRUEMOTION = 8;\nstatic final int PRED_PAETH = 9;\nstatic final int PRED_LDIAG = 10;\nstatic final int PRED_HV = 11;\nstatic final int PRED_JPEGLS = 12;\nstatic final int PRED_DIFF = 13;\nstatic final int PRED_REF = 14;\nstatic final int PRED_ANGLE = 15;\n\nstatic final int MAX_PRED = 16;\n\nint[][] predict(int prediction, Planes p, int pno, Segment s) {\n  switch(prediction) {\n  case PRED_CORNER: \n    return pred_gen(p, pno, s, 0);\n  case PRED_H: \n    return pred_gen(p, pno, s, 1);\n  case PRED_V: \n    return pred_gen(p, pno, s, 2);\n  case PRED_DC: \n    return pred_dc(p, pno, s);\n  case PRED_DCMEDIAN: \n    return pred_dcmedian(p, pno, s);\n  case PRED_MEDIAN: \n    return pred_median(p, pno, s);\n  case PRED_AVG: \n    return pred_avg(p, pno, s);\n  case PRED_TRUEMOTION: \n    return pred_truemotion(p, pno, s);\n  case PRED_PAETH: \n    return pred_paeth(p, pno, s);\n  case PRED_LDIAG: \n    return pred_ldiag(p, pno, s);\n  case PRED_HV: \n    return pred_hv(p, pno, s);\n  case PRED_JPEGLS: \n    return pred_jpegls(p, pno, s);\n  case PRED_DIFF: \n    return pred_diff(p, pno, s);\n  case PRED_REF: \n    return pred_ref(p, pno, s);\n  case PRED_ANGLE: \n    return pred_angle(p, pno, s);\n  case PRED_RANDOM: \n    return predict((int)random(MAX_PRED), p, pno, s);\n  case PRED_SAD: \n    return pred_sad(p, pno, s, true);\n  case PRED_BSAD: \n    return pred_sad(p, pno, s, false);\n  default: \n    return new int[s.size][s.size];\n  }\n}\n\nString predict_name(int prediction) {\n  switch(prediction) {\n  case PRED_CORNER: \n    return \"PRED_CORNER\";\n  case PRED_H: \n    return \"PRED_H\";\n  case PRED_V: \n    return \"PRED_V\";\n  case PRED_DC: \n    return \"PRED_DC\";\n  case PRED_DCMEDIAN: \n    return \"PRED_DCMEDIAN\";\n  case PRED_MEDIAN: \n    return \"PRED_MEDIAN\";\n  case PRED_AVG: \n    return \"PRED_AVG\";\n  case PRED_TRUEMOTION: \n    return \"PRED_TRUEMOTION\";\n  case PRED_PAETH: \n    return \"PRED_PAETH\";\n  case PRED_LDIAG: \n    return \"PRED_LDIAG\";\n  case PRED_HV: \n    return \"PRED_HV\";\n  case PRED_JPEGLS: \n    return \"PRED_JPEGLS\";\n  case PRED_DIFF: \n    return \"PRED_DIFF\";\n  case PRED_REF: \n    return \"PRED_REF\";\n  case PRED_ANGLE: \n    return \"PRED_ANGLE\";\n  case PRED_RANDOM: \n    return \"PRED_RANDOM\";\n  case PRED_SAD: \n    return \"PRED_SAD\";\n  case PRED_BSAD: \n    return \"PRED_BSAD\";\n  default: \n    return \"PRED_NONE\";\n  }\n}\n\nint getSAD(int[][] pred, Planes p, int pno, Segment s) {\n  int sum = 0;\n  for (int x=0; x<s.size; x++) {\n    for (int y=0; y<s.size; y++) {\n      sum+=abs(p.get(pno, s.x+x, s.y+y)-pred[x][y]);\n    }\n  }\n  return sum;\n}\n\nint[] pred_sad_stats = new int[MAX_PRED];\nint[][] pred_sad(Planes p, int pno, Segment s, boolean do_sad) {\n  int[][] currres = null;\n  int currsad = do_sad ? MAX_INT : MIN_INT;\n  int currtype = -1;\n\n  for (int i=0; i<MAX_PRED; i++) {\n    int[][] res = predict(i, p, pno, s);\n    int sad = getSAD(res, p, pno, s);\n    if ( (do_sad && sad<currsad) || (!do_sad && sad>currsad) ) {\n      currsad = sad;\n      currtype = s.pred_type;\n      currres = res;\n    }\n  }\n\n  s.pred_type = currtype;\n  pred_sad_stats[currtype]++;\n  return currres;\n}\n\nint[][] pred_gen(Planes p, int pno, Segment s, int type) {\n  int[][] res = new int[s.size][s.size];\n\n  for (int x=0; x<s.size; x++) {\n    for (int y=0; y<s.size; y++) {\n      switch(type) {\n      case 0: \n        res[x][y] = p.get(pno, s.x-1, s.y-1); \n        break;\n      case 1: \n        res[x][y] = p.get(pno, s.x-1, s.y+y); \n        break;\n      case 2: \n        res[x][y] = p.get(pno, s.x+x, s.y-1); \n        break;\n      }\n    }\n  }\n\n  switch(type) {\n  case 0: \n    s.pred_type = PRED_CORNER; \n    break;\n  case 1: \n    s.pred_type = PRED_H; \n    break;\n  case 2: \n    s.pred_type = PRED_V; \n    break;\n  }\n  return res;\n}\n\nint getDC(Planes p, int pno, Segment s) {\n  int v = 0;\n  for (int i=0; i<s.size; i++) {\n    v += p.get(pno, s.x-1, s.y+i);\n    v += p.get(pno, s.x+i, s.y-1);\n  }\n  v += p.get(pno, s.x-1, s.y-1);\n  v /= (s.size+s.size+1);\n  return v;\n}\n\nint getMedian(int a, int b, int c) {\n  return max(min(a, b), min(max(a, b), c));\n}\n\nint[][] pred_dc(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n  int c = getDC(p, pno, s);\n\n  for (int x=0; x<s.size; x++) {\n    for (int y=0; y<s.size; y++) {\n      res[x][y] = c;\n    }\n  } \n\n  s.pred_type = PRED_DC;\n  return res;\n}\n\nint[][] pred_dcmedian(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n  int c = getDC(p, pno, s);\n\n  for (int x=0; x<s.size; x++) {\n    int v1 = p.get(pno, s.x+x, s.y-1);\n    for (int y=0; y<s.size; y++) {\n      int v2 = p.get(pno, s.x-1, s.y+y);\n      res[x][y] = getMedian(c, v1, v2);\n    }\n  } \n\n  s.pred_type = PRED_DCMEDIAN;\n  return res;\n}\n\nint[][] pred_median(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n  int c = p.get(pno, s.x-1, s.y-1);\n\n  for (int x=0; x<s.size; x++) {\n    int v1 = p.get(pno, s.x+x, s.y-1);\n    for (int y=0; y<s.size; y++) {\n      int v2 = p.get(pno, s.x-1, s.y+y);\n      res[x][y] = getMedian(c, v1, v2);\n    }\n  } \n\n  s.pred_type = PRED_MEDIAN;\n  return res;\n}\n\nint[][] pred_truemotion(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n  int c = p.get(pno, s.x-1, s.y-1);\n\n  for (int x=0; x<s.size; x++) {\n    int v1 = p.get(pno, s.x+x, s.y-1);\n    for (int y=0; y<s.size; y++) {\n      int v2 = p.get(pno, s.x-1, s.y+y);\n      res[x][y] = constrain(v1+v2-c, 0, 255);\n    }\n  } \n\n  s.pred_type = PRED_TRUEMOTION;\n  return res;\n}\n\nint[][] pred_paeth(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n  int c = p.get(pno, s.x-1, s.y-1);\n\n  for (int x=0; x<s.size; x++) {\n    int v1 = p.get(pno, s.x+x, s.y-1);\n    for (int y=0; y<s.size; y++) {\n      int v2 = p.get(pno, s.x-1, s.y+y);\n      int pp = v1+v2-c;\n      int pa = abs(pp-v2);\n      int pb = abs(pp-v1);\n      int pc = abs(pp-c);\n      int v = ((pa<=pb) && (pa<=pc))?v2:(pb<=pc?v1:c);\n      res[x][y] = constrain(v, 0, 255);\n    }\n  } \n\n  s.pred_type = PRED_PAETH;\n  return res;\n}\n\nint[][] pred_avg(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n\n  for (int x=0; x<s.size; x++) {\n    int v1 = p.get(pno, s.x+x, s.y-1);\n    for (int y=0; y<s.size; y++) {\n      int v2 = p.get(pno, s.x-1, s.y+y);\n      res[x][y] = (v1+v2)>>1;\n    }\n  } \n\n  s.pred_type = PRED_AVG;\n  return res;\n}\n\nint[][] pred_ldiag(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n\n  for (int x=0; x<s.size; x++) {\n    for (int y=0; y<s.size; y++) {\n      int ss = x+y;\n      int xx = p.get(pno, s.x+(ss+1<s.size?ss+1:s.size-1), s.y-1);\n      int yy = p.get(pno, s.x-1, s.y+(ss<s.size?ss:s.size-1));\n      int c = ((x+1)*xx+(y+1)*yy)/(x+y+2);\n      res[x][y] = c;\n    }\n  } \n\n  s.pred_type = PRED_LDIAG;\n  return res;\n}\n\nint[][] pred_hv(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n\n  for (int x=0; x<s.size; x++) {\n    for (int y=0; y<s.size; y++) {\n      int c;\n      if (x>y) c = p.get(pno, s.x+x, s.y-1);\n      else if (y>x) c = p.get(pno, s.x-1, s.y+y);\n      else c = (p.get(pno, s.x+x, s.y-1) + p.get(pno, s.x-1, s.y+y)) >> 1;\n      res[x][y] = c;\n    }\n  } \n\n  s.pred_type = PRED_HV;\n  return res;\n}\n\nint[][] pred_jpegls(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n\n  for (int x=0; x<s.size; x++) {\n    int c = p.get(pno, s.x+x-1, s.y-1);\n    int a = p.get(pno, s.x+x, s.y-1);\n    for (int y=0; y<s.size; y++) {\n      int b = p.get(pno, s.x-1, s.y+y); \n      int v;\n      if (c>=max(a, b)) v = min(a, b);\n      else if (c<=min(a, b)) v=max(a, b);\n      else v = a+b-c;\n      res[x][y] = v;\n    }\n  } \n\n  s.pred_type = PRED_JPEGLS;\n  return res;\n}\n\nint[][] pred_diff(Planes p, int pno, Segment s) {\n  int[][] res = new int[s.size][s.size];\n\n  for (int x=0; x<s.size; x++) {\n    int x1 = p.get(pno, s.x+x, s.y-1);\n    int x2 = p.get(pno, s.x+x, s.y-2);\n    for (int y=0; y<s.size; y++) {\n      int y1 = p.get(pno, s.x-1, s.y+y);\n      int y2 = p.get(pno, s.x-2, s.y+y);\n      int v = constrain((y2+y2-y1+x2+x2-x1)>>1, 0, 255);\n      res[x][y] = v;\n    }\n  } \n\n  s.pred_type = PRED_DIFF;\n  return res;\n}\n\nint[][] findBestRef(Planes p, int pno, Segment s) {\n  int currsad = MAX_INT;\n  int[][] currres = null;\n  for (int i=0; i<45; i++) {\n    int[][] res = new int[s.size][s.size];\n    int xx = (int)random(-s.size, s.x);\n    int yy;\n    if (xx<s.x-s.size) {\n      yy = (int)random(-s.size, s.y);\n    } else {\n      yy = (int)random(-s.size, s.y-s.size);\n    }\n    for (int x=0; x<s.size; x++) {\n      for (int y=0; y<s.size; y++) {\n        res[x][y] = p.get(pno, xx+x, yy+y);\n      }\n    }\n    int sad = getSAD(res, p, pno, s);\n    if (sad<currsad) {\n      currres = res;\n      currsad = sad;\n      s.refx = xx;\n      s.refy = yy;\n    }\n  }\n  return currres;\n}\n\nint[][] pred_ref(Planes p, int pno, Segment s) {\n  s.pred_type = PRED_REF;\n  if (s.refx == Short.MAX_VALUE || s.refy == Short.MAX_VALUE) {\n    return findBestRef(p, pno, s);\n  } else {\n    int[][] res = new int[s.size][s.size];\n    for (int x=0; x<s.size; x++) {\n      for (int y=0; y<s.size; y++) {\n        res[x][y] = p.get(pno, s.refx+x, s.refy+y);\n      }\n    }\n    return res;\n  }\n}\n\nPVector getAngleRef(int i, int x, int y, float a, int w) {\n  float xx=-1;\n  float yy=-1;\n  switch(i%3) {\n  case 0: \n    {\n      float v = (w-y-1)+x*a;\n      xx = (v-w)/a;\n      yy = (w-1-a-v);\n      break;\n    }\n  case 1: \n    {\n      float v = (w-x-1)+y*a;\n      yy = (v-w)/a;\n      xx = (w-1-a-v);\n      break;\n    }\n  case 2: \n    {\n      float v = x+y*a;\n      yy = -1.0;\n      xx = v + a;\n      break;\n    }\n  }\n\n  if (xx>yy)\n    return new PVector(round(xx), -1);\n  else\n    return new PVector(-1, round(yy));\n}\n\nint[][] findBestAngle(Planes p, int pno, Segment s) {\n  float stepa = 1.0/min(16, s.size);\n  int[][] currres = null;\n  int currsad = MAX_INT;\n\n  for (int i=0; i<3; i++) {\n    for (float a=0; a<1.0; a+=stepa) {\n      float aa = ((int)(a*0x8000))/(float)0x8000;\n      int[][] res = new int[s.size][s.size];\n\n      for (int x=0; x<s.size; x++) {\n        for (int y=0; y<s.size; y++) {\n          PVector angref = getAngleRef(i, x, y, aa, s.size);\n          int xx = angref.x >= s.size ? s.size-1 : (int)angref.x;\n          res[x][y] = p.get(pno, xx+s.x, (int)angref.y+s.y);\n        }\n      }\n\n      int sad = getSAD(res, p, pno, s);\n      if (sad<currsad) {\n        currres = res;\n        currsad = sad;\n        s.angle = a;\n        s.refa = i;\n      }\n    }\n  }\n  return currres;\n}\n\nint[][] pred_angle(Planes p, int pno, Segment s) {\n  s.pred_type = PRED_ANGLE;\n  if (s.angle<0 || s.refa<0) {\n    return findBestAngle(p, pno, s);\n  } else {\n    int[][] res = new int[s.size][s.size];\n    for (int x=0; x<s.size; x++) {\n      for (int y=0; y<s.size; y++) {\n        PVector angref = getAngleRef(s.refa, x, y, s.angle, s.size);\n        int xx = angref.x >= s.size ? s.size-1 : (int)angref.x;\n        res[x][y] = p.get(pno, xx+s.x, (int)angref.y+s.y);\n      }\n    }\n    return res;\n  }\n}\r\n"
  },
  {
    "path": "quantization.pde",
    "content": "void quantize(Planes planes, int p, Segment s, float val, boolean forward) {\r\n  if (val > 1) {\r\n    for (int x=0; x<s.size; x++) {\r\n      for (int y=0; y<s.size; y++) {\r\n        float col = planes.get(p, x+s.x, y+s.y); \r\n\r\n        if (forward)\r\n          col = col / val;\r\n        else\r\n          col = col * val;\r\n\r\n        planes.set(p, x+s.x, y+s.y, (int)round(col));\r\n      }\r\n    }\r\n  }\r\n}"
  },
  {
    "path": "segmentation.pde",
    "content": "class Segment {\n  int x,y,size;\n  \n  // needed for prediction\n  int pred_type = PRED_NONE;\n  float angle = -1;\n  int refa = -1;\n  int refx = Short.MAX_VALUE; /// set to -1 if you want grid effect\n  int refy = Short.MAX_VALUE; /// set to -1 if you want grid effect\n  \n  public String toString() {\n    return \"x=\"+x+\", y=\"+y+ \", size=\" + size;\n  }\n}\n\nArrayList<Segment> makeSegmentation(DefaultBitOutput segm_out, Planes p, int pno, int min_size, int max_size, float thr) throws IOException {\n  ArrayList<Segment> s = new ArrayList<Segment>();\n  \n  segment(segm_out, s, p, pno, 0, 0, max(p.ww,p.hh), max(1,min_size), min(512,max_size), thr);\n  \n  return s;\n}\n\nvoid segment(DefaultBitOutput segm_out, ArrayList<Segment> s, Planes p, int pno, int x, int y, int size, int min_size, int max_size, float thr) throws IOException {\n  if(x>=p.w || y>=p.h) return;\n  float currStdDev = calcStdDev(p, pno, x, y, size);\n  if(size>max_size || (size>min_size && currStdDev>thr)) {\n    segm_out.writeBoolean(true);\n    int mid = size/2;\n    segment(segm_out,s,p,pno,x,y,mid,min_size,max_size,thr);\n    segment(segm_out,s,p,pno,x+mid,y,mid,min_size,max_size,thr);\n    segment(segm_out,s,p,pno,x,y+mid,mid,min_size,max_size,thr);\n    segment(segm_out,s,p,pno,x+mid,y+mid,mid,min_size,max_size,thr);\n  } else {\n    segm_out.writeBoolean(false);\n    Segment segm = new Segment();\n    segm.x = x;\n    segm.y = y;\n    segm.size = size;\n    s.add(segm);\n  }\n}\n\nArrayList<Segment> readSegmentation(DefaultBitInput segm_in, Planes p) {\n  ArrayList<Segment> s = new ArrayList<Segment>();\n  \n  segment(segm_in, s, p, 0, 0, max(p.ww,p.hh));\n  \n  return s;\n}\n\nvoid segment(DefaultBitInput segm_in, ArrayList<Segment> s, Planes p, int x, int y, int size) {\n  if(x>=p.w || y>=p.h) return;\n  boolean decision;\n  try { \n    decision = segm_in.readBoolean();\n  } catch (Exception e) {\n    decision = false;\n  }\n  if(decision && size > 2) {\n    int mid = size/2;\n    segment(segm_in,s,p,x,y,mid);\n    segment(segm_in,s,p,x+mid,y,mid);\n    segment(segm_in,s,p,x,y+mid,mid);\n    segment(segm_in,s,p,x+mid,y+mid,mid);\n  } else {\n    Segment segm = new Segment();\n    segm.x = x;\n    segm.y = y;\n    segm.size = size;\n    s.add(segm);\n  }\n}\n\nfloat calcStdDev(Planes planes, int pno, int x, int y, int size) {\n  int limit = (int)(max(0.1*sq(size),4));\n  \n  float A = 0;\n  float Q = 0;\n  for(int k=1;k<=limit;k++) {\n    int posx = (int)random(size);\n    int posy = (int)random(size);\n    \n    int xk = planes.get(pno,x+posx,y+posy);\n    \n    float oldA = A;\n    A+=(xk-A)/k;\n    Q+=(xk-oldA)*(xk-A);\n  }\n  \n  return sqrt(Q/(limit-1));\n}\r\n"
  },
  {
    "path": "transformation.pde",
    "content": "import jwave.transforms.*;\nimport jwave.transforms.wavelets.Wavelet;\nimport jwave.transforms.wavelets.WaveletBuilder;\nimport jwave.Transform;\nimport jwave.TransformBuilder;\nimport jwave.compressions.Compressor;\nimport jwave.compressions.CompressorMagnitude;\nimport jwave.compressions.CompressorPeaksAverage;\nimport jwave.exceptions.JWaveException;\n\nfinal static int TRANSTYPE_RANDOM = -1;\nfinal static int TRANSTYPE_FWT = 0;\nfinal static int TRANSTYPE_WPT = 1;\n//final static int TRANSTYPE_SWT = 2;\n\nfinal static int TRANSTYPENO = 2;\n\nWaveletTransform createTransform(int transtype, Wavelet wavelet) {\n  switch (transtype) {\n  case TRANSTYPE_FWT: \n    return new FastWaveletTransform(wavelet);\n  case TRANSTYPE_WPT: \n    return new WaveletPacketTransform(wavelet);\n//  case TRANSTYPE_SWT:\n//    return new ShiftingWaveletTransform(wavelet);\n  default: \n    return createTransform((int)random(TRANSTYPENO), wavelet);\n  }\n}\n\nfinal static int WAVELETNO = 68;\n\nfinal static int WAVELET_RANDOM = -1;\nfinal static int WAVELET_NONE = 0;\nfinal static int HAARORTHOGONAL = 1;\nfinal static int BIORTHOGONAL11 = 2;\nfinal static int BIORTHOGONAL13 = 3;\nfinal static int BIORTHOGONAL15 = 4;\nfinal static int BIORTHOGONAL22 = 5;\nfinal static int BIORTHOGONAL24 = 6;\nfinal static int BIORTHOGONAL26 = 7;\nfinal static int BIORTHOGONAL28 = 8;\nfinal static int BIORTHOGONAL31 = 9;\nfinal static int BIORTHOGONAL33 = 10;\nfinal static int BIORTHOGONAL35 = 11;\nfinal static int BIORTHOGONAL37 = 12;\nfinal static int BIORTHOGONAL39 = 13;\nfinal static int BIORTHOGONAL44 = 14;\nfinal static int BIORTHOGONAL55 = 15;\nfinal static int BIORTHOGONAL68 = 16;\nfinal static int COIFLET1 = 17;\nfinal static int COIFLET2 = 18;\nfinal static int COIFLET3 = 19;\nfinal static int COIFLET4 = 20;\nfinal static int COIFLET5 = 21;\nfinal static int SYMLET2 = 22;\nfinal static int SYMLET3 = 23;\nfinal static int SYMLET4 = 24;\nfinal static int SYMLET5 = 25;\nfinal static int SYMLET6 = 26;\nfinal static int SYMLET7 = 27;\nfinal static int SYMLET8 = 28;\nfinal static int SYMLET9 = 29;\nfinal static int SYMLET10 = 30;\nfinal static int SYMLET11 = 31;\nfinal static int SYMLET12 = 32;\nfinal static int SYMLET13 = 33;\nfinal static int SYMLET14 = 34;\nfinal static int SYMLET15 = 35;\nfinal static int SYMLET16 = 36;\nfinal static int SYMLET17 = 37;\nfinal static int SYMLET18 = 38;\nfinal static int SYMLET19 = 39;\nfinal static int SYMLET20 = 40;\nfinal static int LEGENDRE1 = 41;\nfinal static int LEGENDRE2 = 42;\nfinal static int LEGENDRE3 = 43;\nfinal static int DAUBECHIES2 = 44;\nfinal static int DAUBECHIES3 = 45;\nfinal static int DAUBECHIES4 = 46;\nfinal static int DAUBECHIES5 = 47;\nfinal static int DAUBECHIES6 = 48;\nfinal static int DAUBECHIES7 = 49;\nfinal static int DAUBECHIES8 = 50;\nfinal static int DAUBECHIES9 = 51;\nfinal static int DAUBECHIES10 = 52;\nfinal static int DAUBECHIES11 = 53;\nfinal static int DAUBECHIES12 = 54;\nfinal static int DAUBECHIES13 = 55;\nfinal static int DAUBECHIES14 = 56;\nfinal static int DAUBECHIES15 = 57;\nfinal static int DAUBECHIES16 = 58;\nfinal static int DAUBECHIES17 = 59;\nfinal static int DAUBECHIES18 = 60;\nfinal static int DAUBECHIES19 = 61;\nfinal static int DAUBECHIES20 = 62;\nfinal static int BATTLE23 = 63;\nfinal static int CDF53 = 64;\nfinal static int CDF97 = 65;\nfinal static int DISCRETEMAYER = 66;\nfinal static int HAAR = 67;\n\nWavelet createWavelet(int wavelettype) {\n  switch(wavelettype) {\n  case HAAR: \n    return new Haar1();\n  case HAARORTHOGONAL: \n    return new Haar1Orthogonal();\n  case DAUBECHIES2: \n    return new Daubechies2();\n  case DAUBECHIES3: \n    return new Daubechies3();\n  case DAUBECHIES4: \n    return new Daubechies4();\n  case DAUBECHIES5: \n    return new Daubechies5();\n  case DAUBECHIES6: \n    return new Daubechies6();\n  case DAUBECHIES7: \n    return new Daubechies7();\n  case DAUBECHIES8: \n    return new Daubechies8();\n  case DAUBECHIES9: \n    return new Daubechies9();\n  case DAUBECHIES10: \n    return new Daubechies10();\n  case DAUBECHIES11: \n    return new Daubechies11();\n  case DAUBECHIES12: \n    return new Daubechies12();\n  case DAUBECHIES13: \n    return new Daubechies13();\n  case DAUBECHIES14: \n    return new Daubechies14();\n  case DAUBECHIES15: \n    return new Daubechies15();\n  case DAUBECHIES16: \n    return new Daubechies16();\n  case DAUBECHIES17: \n    return new Daubechies17();\n  case DAUBECHIES18: \n    return new Daubechies18();\n  case DAUBECHIES19: \n    return new Daubechies19();\n  case DAUBECHIES20: \n    return new Daubechies20();\n  case COIFLET1: \n    return new Coiflet1();\n  case COIFLET2: \n    return new Coiflet2();\n  case COIFLET3: \n    return new Coiflet3();\n  case COIFLET4: \n    return new Coiflet4();\n  case COIFLET5: \n    return new Coiflet5();\n  case LEGENDRE1: \n    return new Legendre1();\n  case LEGENDRE2: \n    return new Legendre2();\n  case LEGENDRE3: \n    return new Legendre3();\n  case SYMLET2: \n    return new Symlet2();\n  case SYMLET3: \n    return new Symlet3();\n  case SYMLET4: \n    return new Symlet4();\n  case SYMLET5: \n    return new Symlet5();\n  case SYMLET6: \n    return new Symlet6();\n  case SYMLET7: \n    return new Symlet7();\n  case SYMLET8: \n    return new Symlet8();\n  case SYMLET9: \n    return new Symlet9();\n  case SYMLET10: \n    return new Symlet10();\n  case SYMLET11: \n    return new Symlet11();\n  case SYMLET12: \n    return new Symlet12();\n  case SYMLET13: \n    return new Symlet13();\n  case SYMLET14: \n    return new Symlet14();\n  case SYMLET15: \n    return new Symlet15();\n  case SYMLET16: \n    return new Symlet16();\n  case SYMLET17: \n    return new Symlet17();\n  case SYMLET18: \n    return new Symlet18();\n  case SYMLET19: \n    return new Symlet19();\n  case SYMLET20: \n    return new Symlet20();\n  case BIORTHOGONAL11: \n    return new BiOrthogonal11();\n  case BIORTHOGONAL13: \n    return new BiOrthogonal13();\n  case BIORTHOGONAL15: \n    return new BiOrthogonal15();\n  case BIORTHOGONAL22: \n    return new BiOrthogonal22();\n  case BIORTHOGONAL24: \n    return new BiOrthogonal24();\n  case BIORTHOGONAL26: \n    return new BiOrthogonal26();\n  case BIORTHOGONAL28: \n    return new BiOrthogonal28();\n  case BIORTHOGONAL31: \n    return new BiOrthogonal31();\n  case BIORTHOGONAL33: \n    return new BiOrthogonal33();\n  case BIORTHOGONAL35: \n    return new BiOrthogonal35();\n  case BIORTHOGONAL37: \n    return new BiOrthogonal37();\n  case BIORTHOGONAL39: \n    return new BiOrthogonal39();\n  case BIORTHOGONAL44: \n    return new BiOrthogonal44();\n  case BIORTHOGONAL55: \n    return new BiOrthogonal55();\n  case BIORTHOGONAL68: \n    return new BiOrthogonal68();\n  case DISCRETEMAYER: \n    return new DiscreteMayer();\n  case BATTLE23: \n    return new Battle23();\n  case CDF53: \n    return new CDF53();\n  case CDF97: \n    return new CDF97();\n  default: \n    return createWavelet((int)random(1, WAVELETNO));\n  }\n}\n\nWavelet[] waveletTab = new Wavelet[WAVELETNO];\nWavelet getWavelet(int wavelettype) {\n  if (wavelettype>=0 && wavelettype<WAVELETNO) {\n    Wavelet w = waveletTab[wavelettype];\n    if (w == null) {\n      w = createWavelet(wavelettype);\n      waveletTab[wavelettype] = w;\n    }\n    return w;\n  } else {\n    return createWavelet(-1);\n  }\n}\r\n"
  }
]