You are here

function recipe_pdf35_export_single in Recipe 6

1 string reference to 'recipe_pdf35_export_single'
recipe_pdf35_recipeio in plugins/recipe_pdf35.module
Implementation of hook_recipeio($type).

File

plugins/recipe_pdf35.module, line 31
recipe_pdf35.module - Enables exporting of 3x5" cards in pdf format. This is incredibly rudimentary at this point. 1 and only 1 card and if you go over, the text is lost.

Code

function recipe_pdf35_export_single($nid = NULL) {
  if ($nid === NULL) {
    drupal_set_message(t('Recipe not found.'));
    drupal_not_found();
  }
  $node = node_load(array(
    'nid' => $nid,
    'type' => 'recipe',
  ));

  // you should not be able to export unpublished recipes
  if ($node->status == 0) {
    drupal_access_denied();
    return;
  }
  $recipe_data = prepare_receipe_data($node);
  $pdf_pages = get_pdf_pages($recipe_data);

  // This is a non-indented section for ease of making byte-accurate pdf strings.
  // The newlines and spacing is pretty critical for this to work.
  $pdf_index = array();
  $objects = array(
    'first item in the objects array is thrown out.',
  );

  // Resource Object, required by page objects.
  $obj = <<<EOS
[/PDF /Text]
EOS;
  array_push($objects, $obj);
  $pdf_index['resource'] = count($objects) - 1;

  // Font 1 Object, required by page objects.
  $obj = <<<EOS
<< /Type /Font
/Subtype /Type1
/Name /F1
/BaseFont /Arial
/Encoding /WinAnsiEncoding
>>
EOS;
  array_push($objects, $obj);
  $pdf_index['font1'] = count($objects) - 1;

  // Font 2 Object, required by page objects.
  $obj = <<<EOS
<< /Type /Font
/Subtype /Type1
/Name /F2
/BaseFont /Courier
/Encoding /WinAnsiEncoding
>>
EOS;
  array_push($objects, $obj);
  $pdf_index['font2'] = count($objects) - 1;
  $current_pos = count($objects) + 1;
  $page_refs = array();
  for ($i = 0; $i < count($pdf_pages); $i++) {
    if (count($pdf_pages) > 1) {
      $page_item_count = get_page_item_count($pdf_pages[$i]) + 1;
    }
    else {
      $page_item_count = get_page_item_count($pdf_pages[$i]);
    }
    $page_refs[] = $current_pos + $page_item_count . ' 0 R';
    $current_pos = $current_pos + $page_item_count + 1;
  }
  $kid_refs = implode(" ", $page_refs);
  $kid_count = count($page_refs);

  // Pages Object, required by root.
  $obj = <<<EOS
<< /Type /Pages
/Kids [{<span class="php-variable">$kid_refs</span>}]
/Count {<span class="php-variable">$kid_count</span>}
>>
EOS;
  array_push($objects, $obj);
  $pdf_index['pages'] = count($objects) - 1;

  // Render the objects for each page, then the page item.
  for ($i = 0; $i < count($pdf_pages); $i++) {
    foreach ($pdf_pages[$i]['header'] as $obj) {
      array_push($objects, $obj);
      $pdf_pages[$i]['items'][] = "" . count($objects) - 1 . ' 0 R';
    }
    foreach ($pdf_pages[$i]['column_0'] as $obj) {
      array_push($objects, $obj);
      $pdf_pages[$i]['items'][] = "" . count($objects) - 1 . ' 0 R';
    }
    foreach ($pdf_pages[$i]['column_1'] as $obj) {
      array_push($objects, $obj);
      $pdf_pages[$i]['items'][] = "" . count($objects) - 1 . ' 0 R';
    }
    foreach ($pdf_pages[$i]['column_2'] as $obj) {
      array_push($objects, $obj);
      $pdf_pages[$i]['items'][] = "" . count($objects) - 1 . ' 0 R';
    }
    foreach ($pdf_pages[$i]['footer'] as $obj) {
      array_push($objects, $obj);
      $pdf_pages[$i]['items'][] = "" . count($objects) - 1 . ' 0 R';
    }

    // Page Numbers
    if (count($pdf_pages) > 1) {
      $page_nbr = t('Page ' . ($i + 1));
      $obj = "BT /F1 6 Tf 12 TL 325 17 Td ({$page_nbr})' ET";
      $len = strlen($obj);
      $obj = "<< /Length {$len} >>\nstream\n{$obj}\nendstream";
      array_push($objects, $obj);
      $pdf_pages[$i]['items'][] = "" . count($objects) - 1 . ' 0 R';
    }

    // Page Object
    $content_refs = implode(' ', $pdf_pages[$i]['items']);
    $obj = "<< /Type /Page\n/Parent {$pdf_index['pages']} 0 R\n/MediaBox [0 0 360 216]\n/Contents [{$content_refs}]\n/Resources << /ProcSet 4 0 R\n/Font << /F1 {$pdf_index['font1']} 0 R /F2 {$pdf_index['font2']} 0 R >>\n>>\n>>";
    array_push($objects, $obj);
  }

  // Root Object, required by trailer.
  $obj = <<<EOS
<< /Type /Catalog
  /Pages {<span class="php-variable">$pdf_index</span>[<span class="php-string">'pages'</span>]} 0 R
>>
EOS;
  array_push($objects, $obj);
  $pdf_index['root'] = count($objects) - 1;

  /* Loop the objects array for the actual pdf with object refs.
   *
   */
  $xref = array();
  $pdf = "%PDF-1.4\n";
  $pdf .= '%' . pack("c*", 128, 200, 225, 255) . "\n";
  foreach ($objects as $obj_num => $o) {

    // We skip array index 0.
    if ($obj_num != 0) {

      // Save the xref byte offset.
      $xref[$obj_num] = strlen($pdf);
      $pdf .= "{$obj_num} 0 obj\n";
      $pdf .= "{$o}\n";
      $pdf .= "endobj\n";
    }
  }
  $xref_start_pos = strlen($pdf);
  $xref_entry_count = count($xref) + 1;
  $pdf .= "xref\n";
  $pdf .= "0 {$xref_entry_count}\n";
  $pdf .= "0000000000 65535 f \n";
  foreach ($xref as $obj_num => $offset) {
    $pdf .= sprintf("%010u 00000 n \n", $offset);
  }

  // Start of trailer section.
  $pdf .= "trailer\n";
  $pdf .= "<< /Size {$xref_entry_count}\n";

  // Hard coded warning, /Root is the 1 0 object in this module.
  $pdf .= "/Root {$pdf_index['root']} 0 R\n";
  $pdf .= ">>\n";
  $pdf .= "startxref\n";
  $pdf .= "{$xref_start_pos}\n";
  $pdf .= '%%EOF';
  $file_name = strtolower($node->title) . '.pdf';
  $file_name = str_replace(' ', '_', $file_name);
  drupal_set_header('Content-type: application/pdf');
  drupal_set_header($header = "Content-Disposition: attachment; filename={$file_name}");
  return $pdf;
}